xref: /plan9-contrib/sys/src/cmd/6a/a.y (revision 272efad760864ee41cfe633b56aea9b4f5cf3ae7)
1 %{
2 #include "a.h"
3 %}
4 %union	{
5 	Sym	*sym;
6 	vlong	lval;
7 	double	dval;
8 	char	sval[8];
9 	Gen	gen;
10 	Gen2	gen2;
11 }
12 %left	'|'
13 %left	'^'
14 %left	'&'
15 %left	'<' '>'
16 %left	'+' '-'
17 %left	'*' '/' '%'
18 %token	<lval>	LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
19 %token	<lval>	LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG LTYPEXC LTYPEX LTYPEY LTYPERT
20 %token	<lval>	LCONST LFP LPC LSB
21 %token	<lval>	LBREG LLREG LSREG LFREG LMREG LXREG LYREG
22 %token	<dval>	LFCONST
23 %token	<sval>	LSCONST LSP
24 %token	<sym>	LNAME LLAB LVAR
25 %type	<lval>	con expr pointer offset
26 %type	<gen>	mem imm reg nam rel rem rim rom omem nmem
27 %type	<gen2>	nonnon nonrel nonrem rimnon rimrem remrim
28 %type	<gen2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12
29 %%
30 prog:
31 |	prog line
32 
33 line:
34 	LLAB ':'
35 	{
36 		if($1->value != pc)
37 			yyerror("redeclaration of %s", $1->name);
38 		$1->value = pc;
39 	}
40 	line
41 |	LNAME ':'
42 	{
43 		$1->type = LLAB;
44 		$1->value = pc;
45 	}
46 	line
47 |	';'
48 |	inst ';'
49 |	error ';'
50 
51 inst:
52 	LNAME '=' expr
53 	{
54 		$1->type = LVAR;
55 		$1->value = $3;
56 	}
57 |	LVAR '=' expr
58 	{
59 		if($1->value != $3)
60 			yyerror("redeclaration of %s", $1->name);
61 		$1->value = $3;
62 	}
63 |	LTYPE0 nonnon	{ outcode($1, &$2); }
64 |	LTYPE1 nonrem	{ outcode($1, &$2); }
65 |	LTYPE2 rimnon	{ outcode($1, &$2); }
66 |	LTYPE3 rimrem	{ outcode($1, &$2); }
67 |	LTYPE4 remrim	{ outcode($1, &$2); }
68 |	LTYPER nonrel	{ outcode($1, &$2); }
69 |	LTYPED spec1	{ outcode($1, &$2); }
70 |	LTYPET spec2	{ outcode($1, &$2); }
71 |	LTYPEC spec3	{ outcode($1, &$2); }
72 |	LTYPEN spec4	{ outcode($1, &$2); }
73 |	LTYPES spec5	{ outcode($1, &$2); }
74 |	LTYPEM spec6	{ outcode($1, &$2); }
75 |	LTYPEI spec7	{ outcode($1, &$2); }
76 |	LTYPEXC spec8	{ outcode($1, &$2); }
77 |	LTYPEX spec9	{ outcode($1, &$2); }
78 |	LTYPEG spec10	{ outcode($1, &$2); }
79 |	LTYPEY spec11	{ outcode($1, &$2); }
80 |	LTYPERT spec12	{ outcode($1, &$2); }
81 
82 nonnon:
83 	{
84 		$$.from = nullgen;
85 		$$.to = nullgen;
86 	}
87 |	','
88 	{
89 		$$.from = nullgen;
90 		$$.to = nullgen;
91 	}
92 
93 rimrem:
94 	rim ',' rem
95 	{
96 		$$.from = $1;
97 		$$.to = $3;
98 	}
99 
100 remrim:
101 	rem ',' rim
102 	{
103 		$$.from = $1;
104 		$$.to = $3;
105 	}
106 
107 rimnon:
108 	rim ','
109 	{
110 		$$.from = $1;
111 		$$.to = nullgen;
112 	}
113 |	rim
114 	{
115 		$$.from = $1;
116 		$$.to = nullgen;
117 	}
118 
119 nonrem:
120 	',' rem
121 	{
122 		$$.from = nullgen;
123 		$$.to = $2;
124 	}
125 |	rem
126 	{
127 		$$.from = nullgen;
128 		$$.to = $1;
129 	}
130 
131 nonrel:
132 	',' rel
133 	{
134 		$$.from = nullgen;
135 		$$.to = $2;
136 	}
137 |	rel
138 	{
139 		$$.from = nullgen;
140 		$$.to = $1;
141 	}
142 
143 spec1:	/* DATA */
144 	nam '/' con ',' imm
145 	{
146 		$$.from = $1;
147 		$$.from.scale = $3;
148 		$$.to = $5;
149 	}
150 
151 spec2:	/* TEXT */
152 	mem ',' imm
153 	{
154 		$$.from = $1;
155 		$$.to = $3;
156 	}
157 |	mem ',' con ',' imm
158 	{
159 		$$.from = $1;
160 		$$.from.scale = $3;
161 		$$.to = $5;
162 	}
163 
164 spec3:	/* JMP/CALL */
165 	',' rom
166 	{
167 		$$.from = nullgen;
168 		$$.to = $2;
169 	}
170 |	rom
171 	{
172 		$$.from = nullgen;
173 		$$.to = $1;
174 	}
175 
176 spec4:	/* NOP */
177 	nonnon
178 |	nonrem
179 
180 spec5:	/* SHL/SHR */
181 	rim ',' rem
182 	{
183 		$$.from = $1;
184 		$$.to = $3;
185 	}
186 |	rim ',' rem ':' LLREG
187 	{
188 		$$.from = $1;
189 		$$.to = $3;
190 		if($$.from.index != D_NONE)
191 			yyerror("dp shift with lhs index");
192 		$$.from.index = $5;
193 	}
194 
195 spec6:	/* MOVW/MOVL */
196 	rim ',' rem
197 	{
198 		$$.from = $1;
199 		$$.to = $3;
200 	}
201 |	rim ',' rem ':' LSREG
202 	{
203 		$$.from = $1;
204 		$$.to = $3;
205 		if($$.to.index != D_NONE)
206 			yyerror("dp move with lhs index");
207 		$$.to.index = $5;
208 	}
209 
210 spec7:
211 	rim ','
212 	{
213 		$$.from = $1;
214 		$$.to = nullgen;
215 	}
216 |	rim
217 	{
218 		$$.from = $1;
219 		$$.to = nullgen;
220 	}
221 |	rim ',' rem
222 	{
223 		$$.from = $1;
224 		$$.to = $3;
225 	}
226 
227 spec8:	/* CMPPS/CMPPD */
228 	reg ',' rem ',' con
229 	{
230 		$$.from = $1;
231 		$$.to = $3;
232 		$$.from.offset = $5;
233 	}
234 |	reg ',' reg ',' rem ',' con	/* VCMPPS/VCMPPD */
235 	{
236 		$$.from = $1;
237 		if(!isxyreg($3.type))
238 			yyerror("second source operand must be X/Y register");
239 		$$.from.index = $3.type;
240 		$$.to = $5;
241 		$$.from.offset = $7;
242 	}
243 
244 spec9:	/* SHUFL */
245 	imm ',' rem ',' reg
246 	{
247 		$$.from = $3;
248 		$$.to = $5;
249 		if($1.type != D_CONST)
250 			yyerror("illegal constant");
251 		$$.to.offset = $1.offset;
252 	}
253 |	imm ',' rem ',' reg ',' reg
254 	{
255 		$$.from = $3;
256 		$$.to = $7;
257 		if($1.type != D_CONST)
258 			yyerror("illegal constant");
259 		$$.to.offset = $1.offset;
260 		if(!isxyreg($5.type))
261 			yyerror("second source operand must be X/Y register");
262 		$$.to.index = $5.type;
263 	}
264 
265 spec10:	/* GLOBL */
266 	mem ',' imm
267 	{
268 		$$.from = $1;
269 		$$.to = $3;
270 	}
271 |	mem ',' con ',' imm
272 	{
273 		$$.from = $1;
274 		$$.from.scale = $3;
275 		$$.to = $5;
276 	}
277 
278 spec11:
279 	rimrem
280 |	rim ',' reg ',' rem
281 	{
282 		$$.from = $1;
283 		$$.to = $5;
284 		if(isxyreg($3.type)) {
285 			if(isxyreg($1.type))
286 				$$.from.index = $3.type;
287 			else if(isxyreg($5.type))
288 				$$.to.index = $3.type;
289 		} else
290 			yyerror("second source operand must be X or Y register");
291 	}
292 
293 spec12:	/* RET/RETF */
294 	{
295 		$$.from = nullgen;
296 		$$.to = nullgen;
297 	}
298 |	imm
299 	{
300 		$$.from = $1;
301 		$$.to = nullgen;
302 	}
303 
304 rem:
305 	reg
306 |	mem
307 
308 rom:
309 	rel
310 |	nmem
311 |	'*' reg
312 	{
313 		$$ = $2;
314 	}
315 |	'*' omem
316 	{
317 		$$ = $2;
318 	}
319 |	reg
320 |	omem
321 |	imm
322 
323 rim:
324 	rem
325 |	imm
326 
327 rel:
328 	con '(' LPC ')'
329 	{
330 		$$ = nullgen;
331 		$$.type = D_BRANCH;
332 		$$.offset = $1 + pc;
333 	}
334 |	LNAME offset
335 	{
336 		$$ = nullgen;
337 		if(pass == 2)
338 			yyerror("undefined label: %s", $1->name);
339 		$$.type = D_BRANCH;
340 		$$.sym = $1;
341 		$$.offset = $2;
342 	}
343 |	LLAB offset
344 	{
345 		$$ = nullgen;
346 		$$.type = D_BRANCH;
347 		$$.sym = $1;
348 		$$.offset = $1->value + $2;
349 	}
350 
351 reg:
352 	LBREG
353 	{
354 		$$ = nullgen;
355 		$$.type = $1;
356 	}
357 |	LFREG
358 	{
359 		$$ = nullgen;
360 		$$.type = $1;
361 	}
362 |	LLREG
363 	{
364 		$$ = nullgen;
365 		$$.type = $1;
366 	}
367 |	LMREG
368 	{
369 		$$ = nullgen;
370 		$$.type = $1;
371 	}
372 |	LSP
373 	{
374 		$$ = nullgen;
375 		$$.type = D_SP;
376 	}
377 |	LSREG
378 	{
379 		$$ = nullgen;
380 		$$.type = $1;
381 	}
382 |	LXREG
383 	{
384 		$$ = nullgen;
385 		$$.type = $1;
386 	}
387 |	LYREG
388 	{
389 		$$ = nullgen;
390 		$$.type = $1;
391 	}
392 
393 imm:
394 	'$' con
395 	{
396 		$$ = nullgen;
397 		$$.type = D_CONST;
398 		$$.offset = $2;
399 	}
400 |	'$' nam
401 	{
402 		$$ = $2;
403 		$$.index = $2.type;
404 		$$.type = D_ADDR;
405 		/*
406 		if($2.type == D_AUTO || $2.type == D_PARAM)
407 			yyerror("constant cannot be automatic: %s",
408 				$2.sym->name);
409 		 */
410 	}
411 |	'$' LSCONST
412 	{
413 		$$ = nullgen;
414 		$$.type = D_SCONST;
415 		memcpy($$.sval, $2, sizeof($$.sval));
416 	}
417 |	'$' LFCONST
418 	{
419 		$$ = nullgen;
420 		$$.type = D_FCONST;
421 		$$.dval = $2;
422 	}
423 |	'$' '(' LFCONST ')'
424 	{
425 		$$ = nullgen;
426 		$$.type = D_FCONST;
427 		$$.dval = $3;
428 	}
429 |	'$' '-' LFCONST
430 	{
431 		$$ = nullgen;
432 		$$.type = D_FCONST;
433 		$$.dval = -$3;
434 	}
435 
436 mem:
437 	omem
438 |	nmem
439 
440 omem:
441 	con
442 	{
443 		$$ = nullgen;
444 		$$.type = D_INDIR+D_NONE;
445 		$$.offset = $1;
446 	}
447 |	con '(' LLREG ')'
448 	{
449 		$$ = nullgen;
450 		$$.type = D_INDIR+$3;
451 		$$.offset = $1;
452 	}
453 |	con '(' LSP ')'
454 	{
455 		$$ = nullgen;
456 		$$.type = D_INDIR+D_SP;
457 		$$.offset = $1;
458 	}
459 |	con '(' LLREG '*' con ')'
460 	{
461 		$$ = nullgen;
462 		$$.type = D_INDIR+D_NONE;
463 		$$.offset = $1;
464 		$$.index = $3;
465 		$$.scale = $5;
466 		checkscale($$.scale);
467 	}
468 |	con '(' LLREG ')' '(' LLREG '*' con ')'
469 	{
470 		$$ = nullgen;
471 		$$.type = D_INDIR+$3;
472 		$$.offset = $1;
473 		$$.index = $6;
474 		$$.scale = $8;
475 		checkscale($$.scale);
476 	}
477 |	'(' LLREG ')'
478 	{
479 		$$ = nullgen;
480 		$$.type = D_INDIR+$2;
481 	}
482 |	'(' LSP ')'
483 	{
484 		$$ = nullgen;
485 		$$.type = D_INDIR+D_SP;
486 	}
487 |	con '(' LSREG ')'
488 	{
489 		$$ = nullgen;
490 		$$.type = D_INDIR+$3;
491 		$$.offset = $1;
492 	}
493 |	'(' LLREG '*' con ')'
494 	{
495 		$$ = nullgen;
496 		$$.type = D_INDIR+D_NONE;
497 		$$.index = $2;
498 		$$.scale = $4;
499 		checkscale($$.scale);
500 	}
501 |	'(' LLREG ')' '(' LLREG '*' con ')'
502 	{
503 		$$ = nullgen;
504 		$$.type = D_INDIR+$2;
505 		$$.index = $5;
506 		$$.scale = $7;
507 		checkscale($$.scale);
508 	}
509 
510 nmem:
511 	nam
512 	{
513 		$$ = $1;
514 	}
515 |	nam '(' LLREG '*' con ')'
516 	{
517 		$$ = $1;
518 		$$.index = $3;
519 		$$.scale = $5;
520 		checkscale($$.scale);
521 	}
522 
523 nam:
524 	LNAME offset '(' pointer ')'
525 	{
526 		$$ = nullgen;
527 		$$.type = $4;
528 		$$.sym = $1;
529 		$$.offset = $2;
530 	}
531 |	LNAME '<' '>' offset '(' LSB ')'
532 	{
533 		$$ = nullgen;
534 		$$.type = D_STATIC;
535 		$$.sym = $1;
536 		$$.offset = $4;
537 	}
538 
539 offset:
540 	{
541 		$$ = 0;
542 	}
543 |	'+' con
544 	{
545 		$$ = $2;
546 	}
547 |	'-' con
548 	{
549 		$$ = -$2;
550 	}
551 
552 pointer:
553 	LSB
554 |	LSP
555 	{
556 		$$ = D_AUTO;
557 	}
558 |	LFP
559 
560 con:
561 	LCONST
562 |	LVAR
563 	{
564 		$$ = $1->value;
565 	}
566 |	'-' con
567 	{
568 		$$ = -$2;
569 	}
570 |	'+' con
571 	{
572 		$$ = $2;
573 	}
574 |	'~' con
575 	{
576 		$$ = ~$2;
577 	}
578 |	'(' expr ')'
579 	{
580 		$$ = $2;
581 	}
582 
583 expr:
584 	con
585 |	expr '+' expr
586 	{
587 		$$ = $1 + $3;
588 	}
589 |	expr '-' expr
590 	{
591 		$$ = $1 - $3;
592 	}
593 |	expr '*' expr
594 	{
595 		$$ = $1 * $3;
596 	}
597 |	expr '/' expr
598 	{
599 		$$ = $1 / $3;
600 	}
601 |	expr '%' expr
602 	{
603 		$$ = $1 % $3;
604 	}
605 |	expr '<' '<' expr
606 	{
607 		$$ = $1 << $4;
608 	}
609 |	expr '>' '>' expr
610 	{
611 		$$ = $1 >> $4;
612 	}
613 |	expr '&' expr
614 	{
615 		$$ = $1 & $3;
616 	}
617 |	expr '^' expr
618 	{
619 		$$ = $1 ^ $3;
620 	}
621 |	expr '|' expr
622 	{
623 		$$ = $1 | $3;
624 	}
625