1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
line =
ws? s:stmt eol { yy->v = s; }
| eol { yy->v.kind = ASM_BLANK; }
| . { yy->v.kind = ASM_SYNTAX_ERROR; }
ws = [ \t]+
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.ident.name }; }
| ".data"
{ $$.kind = ASM_DIR_DATA; }
| ".text"
{ $$.kind = ASM_DIR_TEXT; }
| ".balign" ws n:number
{ $$.balign = (Balign){.kind = ASM_DIR_BALIGN, .align = n.number.v }; }
| ".byte" ws n:number
{ $$.byte = (Byte){.kind = ASM_DIR_BYTE, .b = (uint8_t)n.number.v }; }
label =
i:ident ':'
{ $$.label = (Label){.kind = ASM_LABEL, .name = i.ident.name}; }
instr =
"nop" { $$.kind = ASM_NOP; }
| "leave" { $$.kind = ASM_LEAVE; }
| "ret" { $$.kind = ASM_RET; }
| i:xchg { $$ = i; }
| i:add { $$ = i; }
| i:and { $$ = i; }
| i:lea { $$ = i; }
| i:or { $$ = i; }
| i:sub { $$ = i; }
| i:xor { $$ = i; }
lea =
'lea' (
'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR(0, s, d); }
| 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR(1, s, d); }
| 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR(2, s, d); }
) { $$.instr.kind = ASM_LEA; }
xchg =
'xchg' (
'w'? ws s:ax ws? ',' ws? d:r16 { $$ = INSTR(0, s, d); }
| 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = INSTR(1, s, d); }
| 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = INSTR(2, s, d); }
| 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = INSTR(3, s, d); }
| 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = INSTR(4, s, d); }
| 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = INSTR(5, s, d); }
| 'b'? ws s:r-m8 ws? ',' ws? d:r8 { $$ = INSTR(6, s, d); }
| 'b'? ws s:r8 ws? ',' ws? d:r-m8 { $$ = INSTR(7, s, d); }
| 'w'? ws s:r16 ws? ',' ws? d:r-m16 { $$ = INSTR(8, s, d); }
| 'w'? ws s:r-m16 ws? ',' ws? d:r16 { $$ = INSTR(9, s, d); }
| 'l'? ws s:r32 ws? ',' ws? d:r-m32 { $$ = INSTR(10, s, d); }
| 'l'? ws s:r-m32 ws? ',' ws? d:r32 { $$ = INSTR(11, s, d); }
| 'q'? ws s:r64 ws? ',' ws? d:r-m64 { $$ = INSTR(12, s, d); }
| 'q'? ws s:r-m64 ws? ',' ws? d:r64 { $$ = INSTR(13, s, d); }
) { $$.instr.kind = ASM_XCHG; }
add = "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 { $$ = INSTR(0, s, d); }
| 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR(1, s, d); }
| 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR(2, s, d); }
| 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR(3, s, d); }
| 'b' ws s:imm8 ws? ',' ws? d:m { $$ = INSTR(4, s, d); }
| 'w' ws s:imm16 ws? ',' ws? d:m { $$ = INSTR(5, s, d); }
| 'l' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR(6, s, d); }
| 'q' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR(7, s, d); }
| 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR(8, s, d); }
| 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR(9, s, d); }
| 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR(10, s, d); }
| 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR(11, s, d); }
| 'b'? ws s:m ws? ',' ws? d:r8 { $$ = INSTR(12, s, d); }
| 'w'? ws s:m ws? ',' ws? d:r16 { $$ = INSTR(13, s, d); }
| 'l'? ws s:m ws? ',' ws? d:r32 { $$ = INSTR(14, s, d); }
| 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR(15, s, d); }
| 'b'? ws s:r8 ws? ',' ws? d:m { $$ = INSTR(16, s, d); }
| 'w'? ws s:r16 ws? ',' ws? d:m { $$ = INSTR(17, s, d); }
| 'l'? ws s:r32 ws? ',' ws? d:m { $$ = INSTR(18, s, d); }
| 'q'? ws s:r64 ws? ',' ws? d:m { $$ = INSTR(19, s, d); }
| 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR(20, s, d); }
| 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR(21, s, d); }
| 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR(22, s, d); }
| 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR(23, s, d); }
r-m8 =
r:r8 { $$ = r; }
| m:m { $$ = m; }
r-m16 =
r:r16 { $$ = r; }
| m:m { $$ = m; }
r-m32 =
r:r32 { $$ = r; }
| m:m { $$ = m; }
r-m64 =
r:r64 { $$ = r; }
| m:m { $$ = m; }
m =
'(' ws? r:r64 ws? ')'
{ $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = NULL, .reg = r.kind }; }
| <'-'?[0-9]+> ws? '(' ws? r:r64 ws? ')'
{ $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = strtoll(yytext, NULL, 10), .l = NULL, .reg = r.kind }; }
| i:ident ws? '(' ws? r:r64 ws? ')'
{ $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = i.ident.name, .reg = r.kind }; }
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? <'-'?[0-9]+>
{ $$.imm = (Imm){ .kind = ASM_IMM, .c = strtoll(yytext, NULL, 10), .l = NULL, .nbytes = 0}; }
al = "%al" { $$ = REG(ASM_AL); }
ax = "%ax" { $$ = REG(ASM_AX); }
eax = "%eax" { $$ = REG(ASM_EAX); }
rax = "%rax" { $$ = REG(ASM_RAX); }
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); }
ident =
<[_a-zA-Z][_a-zA-Z0-9]*>
{ $$.ident = (Ident){ .kind = ASM_IDENT, .name = xstrdup(yytext) }; }
number =
<'-'?[0-9]+>
{ $$.number = (Number){ .kind = ASM_NUMBER, .v = strtoll(yytext, NULL, 10) }; }
|