line = ws? s:stmt eol { yy->v = s; } | eol { yy->v.kind = ASM_BLANK; } | . { yy->v.kind = ASM_SYNTAX_ERROR; } ws = [ \t]+ | "/*" (! "*/" . )* "*/" # XXX multiline comments break our line numbers. eol = ws? "\n" stmt = '.' d:directive {$$ = d;} | i:instr { $$ = i; } | l:label { $$ = l; } directive = "glob" 'o'? 'l' ws i:ident { $$.globl = (Globl){.kind = ASM_DIR_GLOBL, .name = i.charptr }; } | "ascii" <'z'?> ws s:string { s.kind = *yytext ? ASM_DIR_ASCII : ASM_DIR_ASCIIZ ; $$ = s; } | "data" { $$.kind = ASM_DIR_DATA; } | "text" { $$.kind = ASM_DIR_TEXT; } | "balign" ws n:number { $$.balign = (Balign){.kind = ASM_DIR_BALIGN, .align = n.i64 }; } | "byte" ws v:value { $$.dirbyte = (Byte){.kind = ASM_DIR_BYTE, .value = v.value }; } | "int" ws v:value { $$.dirint = (Int){.kind = ASM_DIR_INT, .value = v.value }; } | "quad" ws v:value { $$.dirquad = (Quad){.kind = ASM_DIR_QUAD, .value = v.value }; } | fd:fill-directive { $$ = fd; } | sd:section-directive { $$ = sd; } fill-directive = "fill" ws r:number ws? "," ws? s:number ws? "," ws? v:number { $$.fill = (Fill){ .kind=ASM_DIR_FILL, .repeat = r.i64, .size = s.i64, .value = v.i64 }; } section-directive = "section" ws? n:section-name ( ws? ',' ws? f:section-flags ws? ',' ws? t:section-type {$$.section = (DirSection){.kind=ASM_DIR_SECTION, .name=n.charptr, .flags=f.charptr, .type=t.i64}; } | ws? ',' ws? f:section-flags {$$.section = (DirSection){.kind=ASM_DIR_SECTION, .name=n.charptr, .flags=f.charptr, .type=SHT_PROGBITS}; } | {$$.section = (DirSection){.kind=ASM_DIR_SECTION, .name=n.charptr, .flags="", .type=SHT_PROGBITS}; } ) section-name = <[.a-zA-Z0-9\-]+> { $$.charptr = xstrdup(yytext); } section-flags = '"' <[awx]*> '"' { $$.charptr = xstrdup(yytext); } section-type = "@nobits" { $$.i64 = SHT_NOBITS; } | "@progbits" { $$.i64 = SHT_PROGBITS; } label = i:ident ':' { $$.label = (Label){.kind = ASM_LABEL, .name = i.charptr}; } instr = # XXX Order the rules by frequency to get better lookup time. "nop" { $$.kind = ASM_NOP; } | "leave" { $$.kind = ASM_LEAVE; } | "ret" { $$.kind = ASM_RET; } | "cltd" { $$.kind = ASM_CLTD; } | "cqto" { $$.kind = ASM_CQTO; } | i:push { $$ = i; } | i:pop { $$ = i; } | i:call { $$ = i; } | i:jmp { $$ = i; } | i:add { $$ = i; } | i:and { $$ = i; } | i:cvtss2sd { $$ = i; } | i:cvtsd2ss { $$ = i; } | i:cmp { $$ = i; } | i:div { $$ = i; } | i:idiv { $$ = i; } | i:lea { $$ = i; } | i:mulsd { $$ = i; } | i:mulss { $$ = i; } | i:mul { $$ = i; } | i:imul { $$ = i; } | i:neg { $$ = i; } | i:movsd { $$ = i; } | i:movss { $$ = i; } | i:movsx { $$ = i; } | i:movzx { $$ = i; } | i:mov { $$ = i; } | i:or { $$ = i; } | i:set { $$ = i; } | i:sub { $$ = i; } | i:sal { $$ = i; } | i:sar { $$ = i; } | i:shl { $$ = i; } | i:shr { $$ = i; } | i:test { $$ = i; } | i:ucomisd { $$ = i; } | i:ucomiss { $$ = i; } | i:test { $$ = i; } | i:xchg { $$ = i; } | i:xorpd { $$ = i; } | i:xorps { $$ = i; } | i:xor { $$ = i; } push = "push" ( 'q'? ws s:r64 { $$ = INSTR1(0, s); } | 'q' ws s:m { $$ = INSTR1(1, s); } ) { $$.instr.kind = ASM_PUSH; } pop = "pop" ( 'q'? ws d:r64 { $$ = INSTR1(0, d); } | 'q' ws d:m { $$ = INSTR1(1, d); } ) { $$.instr.kind = ASM_POP; } call = "call" 'q'? ws t:ident { $$.call = (Call){ .kind = ASM_CALL, .target=t.charptr } ; } jmp = 'j' v:jmp-variant ws t:ident { $$.jmp = (Jmp) {.kind = ASM_JMP, .variant=v.i64, .target=t.charptr}; } jmp-variant = "mp" { $$.i64 = 0; } | cc:condition-code { $$.i64 = cc.i64 + 1;} condition-code = "z" { $$.i64 = 0; } | "s" { $$.i64 = 1; } | "po" { $$.i64 = 2; } | "pe" { $$.i64 = 3; } | "p" { $$.i64 = 4; } | "o" { $$.i64 = 5; } | "nz" { $$.i64 = 6; } | "ns" { $$.i64 = 7; } | "np" { $$.i64 = 8; } | "no" { $$.i64 = 9; } | "nle" { $$.i64 = 10; } | "nl" { $$.i64 = 11; } | "nge" { $$.i64 = 12; } | "ng" { $$.i64 = 13; } | "ne" { $$.i64 = 14; } | "nc" { $$.i64 = 15; } | "nbe" { $$.i64 = 16; } | "nb" { $$.i64 = 17; } | "nae" { $$.i64 = 18; } | "na" { $$.i64 = 19; } | "le" { $$.i64 = 20; } | "l" { $$.i64 = 21; } | "ge" { $$.i64 = 22; } | "g" { $$.i64 = 23; } | "e" { $$.i64 = 24; } | "c" { $$.i64 = 25; } | "be" { $$.i64 = 26; } | "b" { $$.i64 = 27; } | "ae" { $$.i64 = 28; } | "a" { $$.i64 = 29; } lea = "lea" ( 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(1, s, d); } | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } ) { $$.instr.kind = ASM_LEA; } div = "div" ( args:m-opargs { $$ = args; } | args:r-opargs { args.instr.variant += 4 ; $$ = args; } ) { $$.instr.kind = ASM_DIV; } idiv = "idiv" ( args:m-opargs { $$ = args; } | args:r-opargs { args.instr.variant += 4 ; $$ = args; } ) { $$.instr.kind = ASM_IDIV; } # TODO XXX Combine the xmm variants into single instructions?? cvtss2sd = "cvtss2sd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_CVTSS2SD; } cvtsd2ss = "cvtsd2ss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_CVTSD2SS; } mulsd = "mulsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_MULSD; } mulss = "mulss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_MULSS; } movss = "movss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } | ws s:xmm ws? ',' ws? d:m { $$ = INSTR2(2, s, d); } ) { $$.instr.kind = ASM_MOVSS; } movsd = "movsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } | ws s:xmm ws? ',' ws? d:m { $$ = INSTR2(2, s, d); } ) { $$.instr.kind = ASM_MOVSD; } ucomiss = "ucomiss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_UCOMISS; } ucomisd = "ucomisd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_UCOMISD; } xorpd = "xorpd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_XORPD; } xorps = "xorps" ( ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } | ws s:m ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } ) { $$.instr.kind = ASM_XORPS; } mul = "mul" ( args:m-opargs { $$ = args; } | args:r-opargs { args.instr.variant += 4 ; $$ = args; } ) { $$.instr.kind = ASM_MUL; } neg = "neg" ( args:m-opargs { $$ = args; } | args:r-opargs { args.instr.variant += 4 ; $$ = args; } ) { $$.instr.kind = ASM_NEG; } imul = "imul" ( ( 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(8, s, d); } | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(9, s, d); } | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(10, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(11, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(12, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(13, s, d); } | 'w'? ws i:imm16 ws? ',' ws? s:m ws? ',' ws? d:r16 { $$ = INSTR3(14, s, d, i); } | 'l'? ws i:imm32 ws? ',' ws? s:m ws? ',' ws? d:r32 { $$ = INSTR3(15, s, d, i); } | 'q'? ws i:imm32 ws? ',' ws? s:m ws? ',' ws? d:r64 { $$ = INSTR3(16, s, d, i); } | 'w'? ws i:imm16 ws? ',' ws? s:r16 ws? ',' ws? d:r16 { $$ = INSTR3(17, s, d, i); } | 'l'? ws i:imm32 ws? ',' ws? s:r32 ws? ',' ws? d:r32 { $$ = INSTR3(18, s, d, i); } | 'q'? ws i:imm32 ws? ',' ws? s:r64 ws? ',' ws? d:r64 { $$ = INSTR3(19, s, d, i); } ) # Must come last due to peg ordering. | args:m-opargs { $$ = args; } | args:r-opargs { args.instr.variant += 4 ; $$ = args; } ) { $$.instr.kind = ASM_IMUL; } m-opargs = 'b' ws a:m { $$ = INSTR1(0, a); } | 'w' ws a:m { $$ = INSTR1(1, a); } | 'l' ws a:m { $$ = INSTR1(2, a); } | 'q' ws a:m { $$ = INSTR1(3, a); } r-opargs = 'b'? ws a:r8 { $$ = INSTR1(0, a); } | 'w'? ws a:r16 { $$ = INSTR1(1, a); } | 'l'? ws a:r32 { $$ = INSTR1(2, a); } | 'q'? ws a:r64 { $$ = INSTR1(3, a); } imm-r-opargs = 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR2(0, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR2(1, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } imm-m-opargs = 'b' ws s:imm8 ws? ',' ws? d:m { $$ = INSTR2(0, s, d); } | 'w' ws s:imm16 ws? ',' ws? d:m { $$ = INSTR2(1, s, d); } | 'l' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR2(2, s, d); } | 'q' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR2(3, s, d); } r-r-opargs = 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(0, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(1, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } r-m-opargs = 'b'? ws s:r8 ws? ',' ws? d:m { $$ = INSTR2(0, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:m { $$ = INSTR2(1, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:m { $$ = INSTR2(2, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:m { $$ = INSTR2(3, s, d); } m-r-opargs = 'b'? ws s:m ws? ',' ws? d:r8 { $$ = INSTR2(0, s, d); } | 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(1, s, d); } | 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } imm-rm-opargs = args:imm-m-opargs { $$ = args; } | args:imm-r-opargs { args.instr.variant += 4 ; $$ = args; } r-rm-opargs = args:m-r-opargs { $$ = args; } | args:r-m-opargs { args.instr.variant += 4; $$ = args; } | args:r-r-opargs { args.instr.variant += 8; $$ = args; } mov = "mov" ( args:imm-rm-opargs { $$ = args; } | args:r-rm-opargs { args.instr.variant += 8; $$ = args; } ) { $$.instr.kind = ASM_MOV; } movsx = "movs" ( args:mov-extend-opargs { $$ = args; } | 'lq' ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(10, s, d); } | 'lq' ws s:r32 ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } ) { $$.instr.kind = ASM_MOVSX; } movzx = "movz" args:mov-extend-opargs { $$ = args; $$.instr.kind = ASM_MOVZX; } mov-extend-opargs = 'bw' ws s:m ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } | 'bl' ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(1, s, d); } | 'bq' ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } | 'wl' ws s:m ws? ',' ws? d:r32 { $$ = INSTR2(3, s, d); } | 'wq' ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(4, s, d); } | 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = INSTR2(5, s, d); } | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = INSTR2(6, s, d); } | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = INSTR2(7, s, d); } | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = INSTR2(8, s, d); } | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = INSTR2(9, s, d); } xchg = 'xchg' ( 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } | 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = INSTR2(3, s, d); } | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = INSTR2(4, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = INSTR2(5, s, d); } | args:r-rm-opargs { args.instr.variant += 6; $$ = args; } ) { $$.instr.kind = ASM_XCHG; } add = "cmp" a:basic-op-args { a.instr.kind = ASM_CMP; $$ = a; } cmp = "add" a:basic-op-args { a.instr.kind = ASM_ADD; $$ = a; } and = "and" a:basic-op-args { a.instr.kind = ASM_AND; $$ = a; } or = "or" a:basic-op-args { a.instr.kind = ASM_OR; $$ = a; } sub = "sub" a:basic-op-args { a.instr.kind = ASM_SUB; $$ = a; } xor = "xor" a:basic-op-args { a.instr.kind = ASM_XOR; $$ = a; } basic-op-args = 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = INSTR2(0, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR2(2, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR2(3, s, d); } | args:imm-rm-opargs { args.instr.variant += 4; $$ = args; } | args:r-rm-opargs { args.instr.variant += 12; $$ = args; } set = "set" cc:condition-code ( 'b'? ws a:m { $$ = INSTR1(0, a); $$.instr.variant = cc.i64; } | 'b'? ws a:r8 { $$ = INSTR1(0, a); $$.instr.variant = 31 + cc.i64; } ) { $$.instr.kind = ASM_SET } sal = "sal" args:shift-args {$$ = args; $$.instr.kind = ASM_SAL} sar = "sar" args:shift-args {$$ = args; $$.instr.kind = ASM_SAR} shl = "shl" args:shift-args {$$ = args; $$.instr.kind = ASM_SHL} shr = "shr" args:shift-args {$$ = args; $$.instr.kind = ASM_SHR} shift-args = # There are some more specific variants we could add. 'w' ws c:cl ws? ',' ws? d:m { $$ = INSTR2(0, c, d); } | 'l' ws c:cl ws? ',' ws? d:m { $$ = INSTR2(1, c, d); } | 'q' ws c:cl ws? ',' ws? d:m { $$ = INSTR2(2, c, d); } | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = INSTR2(3, c, d); } | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = INSTR2(4, c, d); } | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = INSTR2(5, c, d); } | 'w' ws i:imm8 ws? ',' ws? d:m { $$ = INSTR2(6, i, d); } | 'l' ws i:imm8 ws? ',' ws? d:m { $$ = INSTR2(7, i, d); } | 'q' ws i:imm8 ws? ',' ws? d:m { $$ = INSTR2(8, i, d); } | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = INSTR2(9, i, d); } | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = INSTR2(10, i, d); } | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = INSTR2(11, i, d); } test = "test" ( 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = INSTR2(0, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR2(2, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR2(3, s, d); } | args:imm-rm-opargs { args.instr.variant += 4; $$ = args; } | args:r-m-opargs { args.instr.variant += 12; $$ = args; } | args:r-r-opargs { args.instr.variant += 16; $$ = args; } ) { $$.instr.kind = ASM_TEST; } r64-or-rip = ( r:r64 | r:rip ) { $$ = r; } scale-index-base = '(' ws? b:r64 ws? ',' ws? i:r64 ws? ',' ws? s:number ws? ')' { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = s.i64, .index=i.kind, .base = b.kind, .disp = (Value){ .c = 0, .l = NULL } }; } | '(' ws? b:r64 ws? ',' ws? i:r64 ')' { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 1, .index=i.kind, .base = b.kind, .disp = (Value){ .c = 0, .l = NULL } }; } | '(' ws? b:r64-or-rip ws? ')' { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 0, .index=ASM_NO_REG, .base = b.kind, .disp = (Value){ .c = 0, .l = NULL } }; } m = sib:scale-index-base { $$ = sib; } | d:value ws? sib:scale-index-base { sib.memarg.disp = d.value; $$ = sib; } imm8 = i:imm { i.imm.nbytes = 1; $$ = i; } imm16 = i:imm { i.imm.nbytes = 2; $$ = i; } imm32 = i:imm { i.imm.nbytes = 4; $$ = i; } imm = '$' ws? val:value { $$.imm = (Imm){ .kind = ASM_IMM, .v = val.value, .nbytes = 0}; } al = "%al" { $$ = REG(ASM_AL); } cl = "%cl" { $$ = REG(ASM_CL); } ax = "%ax" { $$ = REG(ASM_AX); } eax = "%eax" { $$ = REG(ASM_EAX); } rax = "%rax" { $$ = REG(ASM_RAX); } rip = "%rip" { $$ = REG(ASM_RIP); } r8 = "%al" { $$ = REG(ASM_AL); } | "%cl" { $$ = REG(ASM_CL); } | "%dl" { $$ = REG(ASM_DL); } | "%bl" { $$ = REG(ASM_BL); } | "%spl" { $$ = REG(ASM_SPL); } | "%bpl" { $$ = REG(ASM_BPL); } | "%sil" { $$ = REG(ASM_SIL); } | "%dil" { $$ = REG(ASM_DIL); } | "%r8b" { $$ = REG(ASM_R8B); } | "%r9b" { $$ = REG(ASM_R9B); } | "%r10b" { $$ = REG(ASM_R10B); } | "%r11b" { $$ = REG(ASM_R11B); } | "%r12b" { $$ = REG(ASM_R12B); } | "%r13b" { $$ = REG(ASM_R13B); } | "%r14b" { $$ = REG(ASM_R14B); } | "%r15b" { $$ = REG(ASM_R15B); } r16 = "%ax" { $$ = REG(ASM_AX); } | "%cx" { $$ = REG(ASM_CX); } | "%dx" { $$ = REG(ASM_DX); } | "%bx" { $$ = REG(ASM_BX); } | "%sp" { $$ = REG(ASM_SP); } | "%bp" { $$ = REG(ASM_BP); } | "%si" { $$ = REG(ASM_SI); } | "%di" { $$ = REG(ASM_DI); } | "%r8w" { $$ = REG(ASM_R8W); } | "%r9w" { $$ = REG(ASM_R9W); } | "%r10w" { $$ = REG(ASM_R10W); } | "%r11w" { $$ = REG(ASM_R11W); } | "%r12w" { $$ = REG(ASM_R12W); } | "%r13w" { $$ = REG(ASM_R13W); } | "%r14w" { $$ = REG(ASM_R14W); } | "%r15w" { $$ = REG(ASM_R15W); } r32 = "%eax" { $$ = REG(ASM_EAX); } | "%ecx" { $$ = REG(ASM_ECX); } | "%edx" { $$ = REG(ASM_EDX); } | "%ebx" { $$ = REG(ASM_EBX); } | "%esp" { $$ = REG(ASM_ESP); } | "%ebp" { $$ = REG(ASM_EBP); } | "%esi" { $$ = REG(ASM_ESI); } | "%edi" { $$ = REG(ASM_EDI); } | "%r8d" { $$ = REG(ASM_R8D); } | "%r9d" { $$ = REG(ASM_R9D); } | "%r10d" { $$ = REG(ASM_R10D); } | "%r11d" { $$ = REG(ASM_R11D); } | "%r12d" { $$ = REG(ASM_R12D); } | "%r13d" { $$ = REG(ASM_R13D); } | "%r14d" { $$ = REG(ASM_R14D); } | "%r15d" { $$ = REG(ASM_R15D); } r64 = "%rax" { $$ = REG(ASM_RAX); } | "%rcx" { $$ = REG(ASM_RCX); } | "%rdx" { $$ = REG(ASM_RDX); } | "%rbx" { $$ = REG(ASM_RBX); } | "%rsp" { $$ = REG(ASM_RSP); } | "%rbp" { $$ = REG(ASM_RBP); } | "%rsi" { $$ = REG(ASM_RSI); } | "%rdi" { $$ = REG(ASM_RDI); } | "%r8" ![lwb] { $$ = REG(ASM_R8); } | "%r9" ![lwb] { $$ = REG(ASM_R9); } | "%r10" ![lwb] { $$ = REG(ASM_R10); } | "%r11" ![lwb] { $$ = REG(ASM_R11); } | "%r12" ![lwb] { $$ = REG(ASM_R12); } | "%r13" ![lwb] { $$ = REG(ASM_R13); } | "%r14" ![lwb] { $$ = REG(ASM_R14); } | "%r15" ![lwb] { $$ = REG(ASM_R15); } xmm = # Reverse order due to peg ordering. "%xmm15" { $$ = REG(ASM_XMM15); } | "%xmm14" { $$ = REG(ASM_XMM14); } | "%xmm13" { $$ = REG(ASM_XMM13); } | "%xmm12" { $$ = REG(ASM_XMM12); } | "%xmm11" { $$ = REG(ASM_XMM11); } | "%xmm10" { $$ = REG(ASM_XMM10); } | "%xmm9" { $$ = REG(ASM_XMM7); } | "%xmm8" { $$ = REG(ASM_XMM7); } | "%xmm7" { $$ = REG(ASM_XMM7); } | "%xmm6" { $$ = REG(ASM_XMM6); } | "%xmm5" { $$ = REG(ASM_XMM5); } | "%xmm4" { $$ = REG(ASM_XMM4); } | "%xmm3" { $$ = REG(ASM_XMM3); } | "%xmm2" { $$ = REG(ASM_XMM2); } | "%xmm1" { $$ = REG(ASM_XMM1); } | "%xmm0" { $$ = REG(ASM_XMM0); } # We disallow newlines in our strings, it is simpler for lineno tracking. string = '"' <(string-escape | ( ! '\n' ! '\\' !'"' .))*> '"' { $$.string = decodestring(yytext); } string-escape = '\\' ( '\\' | '"' | [nrt] | 'x' [0-9A-Fa-f]+ | [0-7][0-7][0-7] ) value = n:number { $$.value = (Value){ .l = NULL, .c = n.i64 }; } | i:ident ws? ( '+' ws? n:number { $$.value = (Value){ .c = n.i64 }; } | &'-' n:number { $$.value = (Value){ .c = n.i64 }; } | { $$.value = (Value){ .c = 0 }; } ) { $$.value.l = i.charptr; } ident = <[._a-zA-Z][._a-zA-Z0-9]*> { $$.charptr = xstrdup(yytext); } number = <'-'? ws? [0-9]+> { $$.i64 = strtoll(yytext, NULL, 10); } | <[0-9]+> { $$.i64 = (int64_t)strtoull(yytext, NULL, 10); }