aboutsummaryrefslogtreecommitdiff
path: root/asm.peg
blob: 76918fd391b5f92e2d9f108972c363fffa9ccc23 (plain)
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) }; }