xref: /plan9-contrib/sys/src/cmd/5a/a.y (revision 375daca8932d0755549a5f8e4d068a24a49927d4)
1 %{
2 #include "a.h"
3 %}
4 %union
5 {
6 	Sym	*sym;
7 	long	lval;
8 	double	dval;
9 	char	sval[8];
10 	Gen	gen;
11 }
12 %left	'|'
13 %left	'^'
14 %left	'&'
15 %left	'<' '>'
16 %left	'+' '-'
17 %left	'*' '/' '%'
18 %token	<lval>	LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
19 %token	<lval>	LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
20 %token	<lval>	LTYPEB LTYPEC LTYPED LTYPEE LTYPEF
21 %token	<lval>	LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
22 %token	<lval>	LTYPEL LTYPEM LTYPEN LTYPEBX
23 %token	<lval>	LCONST LSP LSB LFP LPC
24 %token	<lval>	LTYPEX LR LREG LF LFREG LC LCREG LPSR LFCR
25 %token	<lval>	LCOND LS LAT
26 %token	<dval>	LFCONST
27 %token	<sval>	LSCONST
28 %token	<sym>	LNAME LLAB LVAR
29 %type	<lval>	con expr oexpr pointer offset sreg spreg creg
30 %type	<lval>	rcon cond reglist
31 %type	<gen>	gen rel reg regreg freg shift fcon frcon
32 %type	<gen>	imm ximm name oreg ireg nireg ioreg imsr
33 %%
34 prog:
35 |	prog line
36 
37 line:
38 	LLAB ':'
39 	{
40 		if($1->value != pc)
41 			yyerror("redeclaration of %s", $1->name);
42 		$1->value = pc;
43 	}
44 	line
45 |	LNAME ':'
46 	{
47 		$1->type = LLAB;
48 		$1->value = pc;
49 	}
50 	line
51 |	LNAME '=' expr ';'
52 	{
53 		$1->type = LVAR;
54 		$1->value = $3;
55 	}
56 |	LVAR '=' expr ';'
57 	{
58 		if($1->value != $3)
59 			yyerror("redeclaration of %s", $1->name);
60 		$1->value = $3;
61 	}
62 |	';'
63 |	inst ';'
64 |	error ';'
65 
66 inst:
67 /*
68  * ADD
69  */
70 	LTYPE1 cond imsr ',' spreg ',' reg
71 	{
72 		outcode($1, $2, &$3, $5, &$7);
73 	}
74 |	LTYPE1 cond imsr ',' spreg ','
75 	{
76 		outcode($1, $2, &$3, $5, &nullgen);
77 	}
78 |	LTYPE1 cond imsr ',' reg
79 	{
80 		outcode($1, $2, &$3, NREG, &$5);
81 	}
82 /*
83  * MVN
84  */
85 |	LTYPE2 cond imsr ',' reg
86 	{
87 		outcode($1, $2, &$3, NREG, &$5);
88 	}
89 /*
90  * MOVW
91  */
92 |	LTYPE3 cond gen ',' gen
93 	{
94 		outcode($1, $2, &$3, NREG, &$5);
95 	}
96 /*
97  * B/BL
98  */
99 |	LTYPE4 cond comma rel
100 	{
101 		outcode($1, $2, &nullgen, NREG, &$4);
102 	}
103 |	LTYPE4 cond comma nireg
104 	{
105 		outcode($1, $2, &nullgen, NREG, &$4);
106 	}
107 /*
108  * BX
109  */
110 |	LTYPEBX comma ireg
111 	{
112 		outcode($1, Always, &nullgen, NREG, &$3);
113 	}
114 /*
115  * BEQ
116  */
117 |	LTYPE5 comma rel
118 	{
119 		outcode($1, Always, &nullgen, NREG, &$3);
120 	}
121 /*
122  * SWI
123  */
124 |	LTYPE6 cond comma gen
125 	{
126 		outcode($1, $2, &nullgen, NREG, &$4);
127 	}
128 /*
129  * CMP
130  */
131 |	LTYPE7 cond imsr ',' spreg comma
132 	{
133 		outcode($1, $2, &$3, $5, &nullgen);
134 	}
135 /*
136  * MOVM
137  */
138 |	LTYPE8 cond ioreg ',' '[' reglist ']'
139 	{
140 		Gen g;
141 
142 		g = nullgen;
143 		g.type = D_CONST;
144 		g.offset = $6;
145 		outcode($1, $2, &$3, NREG, &g);
146 	}
147 |	LTYPE8 cond '[' reglist ']' ',' ioreg
148 	{
149 		Gen g;
150 
151 		g = nullgen;
152 		g.type = D_CONST;
153 		g.offset = $4;
154 		outcode($1, $2, &g, NREG, &$7);
155 	}
156 /*
157  * SWAP
158  */
159 |	LTYPE9 cond reg ',' ireg ',' reg
160 	{
161 		outcode($1, $2, &$5, $3.reg, &$7);
162 	}
163 |	LTYPE9 cond reg ',' ireg comma
164 	{
165 		outcode($1, $2, &$5, $3.reg, &$3);
166 	}
167 |	LTYPE9 cond comma ireg ',' reg
168 	{
169 		outcode($1, $2, &$4, $6.reg, &$6);
170 	}
171 /*
172  * RET
173  */
174 |	LTYPEA cond comma
175 	{
176 		outcode($1, $2, &nullgen, NREG, &nullgen);
177 	}
178 /*
179  * TEXT/GLOBL
180  */
181 |	LTYPEB name ',' imm
182 	{
183 		outcode($1, Always, &$2, NREG, &$4);
184 	}
185 |	LTYPEB name ',' con ',' imm
186 	{
187 		outcode($1, Always, &$2, $4, &$6);
188 	}
189 /*
190  * DATA
191  */
192 |	LTYPEC name '/' con ',' ximm
193 	{
194 		outcode($1, Always, &$2, $4, &$6);
195 	}
196 /*
197  * CASE
198  */
199 |	LTYPED cond reg comma
200 	{
201 		outcode($1, $2, &$3, NREG, &nullgen);
202 	}
203 /*
204  * word
205  */
206 |	LTYPEH comma ximm
207 	{
208 		outcode($1, Always, &nullgen, NREG, &$3);
209 	}
210 /*
211  * floating-point coprocessor
212  */
213 |	LTYPEI cond freg ',' freg
214 	{
215 		outcode($1, $2, &$3, NREG, &$5);
216 	}
217 |	LTYPEK cond frcon ',' freg
218 	{
219 		outcode($1, $2, &$3, NREG, &$5);
220 	}
221 |	LTYPEK cond frcon ',' LFREG ',' freg
222 	{
223 		outcode($1, $2, &$3, $5, &$7);
224 	}
225 |	LTYPEL cond freg ',' freg comma
226 	{
227 		outcode($1, $2, &$3, $5.reg, &nullgen);
228 	}
229 /*
230  * MCR MRC
231  */
232 |	LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
233 	{
234 		Gen g;
235 
236 		g = nullgen;
237 		g.type = D_CONST;
238 		g.offset =
239 			(0xe << 24) |		/* opcode */
240 			($1 << 20) |		/* MCR/MRC */
241 			($2 << 28) |		/* scond */
242 			(($3 & 15) << 8) |	/* coprocessor number */
243 			(($5 & 7) << 21) |	/* coprocessor operation */
244 			(($7 & 15) << 12) |	/* arm register */
245 			(($9 & 15) << 16) |	/* Crn */
246 			(($11 & 15) << 0) |	/* Crm */
247 			(($12 & 7) << 5) |	/* coprocessor information */
248 			(1<<4);			/* must be set */
249 		outcode(AWORD, Always, &nullgen, NREG, &g);
250 	}
251 /*
252  * MULL hi,lo,r1,r2
253  */
254 |	LTYPEM cond reg ',' reg ',' regreg
255 	{
256 		outcode($1, $2, &$3, $5.reg, &$7);
257 	}
258 /*
259  * MULA hi,lo,r1,r2
260  */
261 |	LTYPEN cond reg ',' reg ',' reg ',' spreg
262 	{
263 		$7.type = D_REGREG;
264 		$7.offset = $9;
265 		outcode($1, $2, &$3, $5.reg, &$7);
266 	}
267 /*
268  * END
269  */
270 |	LTYPEE comma
271 	{
272 		outcode($1, Always, &nullgen, NREG, &nullgen);
273 	}
274 
275 cond:
276 	{
277 		$$ = Always;
278 	}
279 |	cond LCOND
280 	{
281 		$$ = ($1 & ~C_SCOND) | $2;
282 	}
283 |	cond LS
284 	{
285 		$$ = $1 | $2;
286 	}
287 
288 comma:
289 |	',' comma
290 
291 rel:
292 	con '(' LPC ')'
293 	{
294 		$$ = nullgen;
295 		$$.type = D_BRANCH;
296 		$$.offset = $1 + pc;
297 	}
298 |	LNAME offset
299 	{
300 		$$ = nullgen;
301 		if(pass == 2)
302 			yyerror("undefined label: %s", $1->name);
303 		$$.type = D_BRANCH;
304 		$$.sym = $1;
305 		$$.offset = $2;
306 	}
307 |	LLAB offset
308 	{
309 		$$ = nullgen;
310 		$$.type = D_BRANCH;
311 		$$.sym = $1;
312 		$$.offset = $1->value + $2;
313 	}
314 
315 ximm:	'$' con
316 	{
317 		$$ = nullgen;
318 		$$.type = D_CONST;
319 		$$.offset = $2;
320 	}
321 |	'$' oreg
322 	{
323 		$$ = $2;
324 		$$.type = D_CONST;
325 	}
326 |	'$' '*' '$' oreg
327 	{
328 		$$ = $4;
329 		$$.type = D_OCONST;
330 	}
331 |	'$' LSCONST
332 	{
333 		$$ = nullgen;
334 		$$.type = D_SCONST;
335 		memcpy($$.sval, $2, sizeof($$.sval));
336 	}
337 |	fcon
338 
339 fcon:
340 	'$' LFCONST
341 	{
342 		$$ = nullgen;
343 		$$.type = D_FCONST;
344 		$$.dval = $2;
345 	}
346 |	'$' '-' LFCONST
347 	{
348 		$$ = nullgen;
349 		$$.type = D_FCONST;
350 		$$.dval = -$3;
351 	}
352 
353 reglist:
354 	spreg
355 	{
356 		$$ = 1 << $1;
357 	}
358 |	spreg '-' spreg
359 	{
360 		int i;
361 		$$=0;
362 		for(i=$1; i<=$3; i++)
363 			$$ |= 1<<i;
364 		for(i=$3; i<=$1; i++)
365 			$$ |= 1<<i;
366 	}
367 |	spreg comma reglist
368 	{
369 		$$ = (1<<$1) | $3;
370 	}
371 
372 gen:
373 	reg
374 |	ximm
375 |	shift
376 |	shift '(' spreg ')'
377 	{
378 		$$ = $1;
379 		$$.reg = $3;
380 	}
381 |	LPSR
382 	{
383 		$$ = nullgen;
384 		$$.type = D_PSR;
385 		$$.reg = $1;
386 	}
387 |	LFCR
388 	{
389 		$$ = nullgen;
390 		$$.type = D_FPCR;
391 		$$.reg = $1;
392 	}
393 |	con
394 	{
395 		$$ = nullgen;
396 		$$.type = D_OREG;
397 		$$.offset = $1;
398 	}
399 |	oreg
400 |	freg
401 
402 nireg:
403 	ireg
404 |	name
405 	{
406 		$$ = $1;
407 		if($1.name != D_EXTERN && $1.name != D_STATIC) {
408 		}
409 	}
410 
411 ireg:
412 	'(' spreg ')'
413 	{
414 		$$ = nullgen;
415 		$$.type = D_OREG;
416 		$$.reg = $2;
417 		$$.offset = 0;
418 	}
419 
420 ioreg:
421 	ireg
422 |	con '(' sreg ')'
423 	{
424 		$$ = nullgen;
425 		$$.type = D_OREG;
426 		$$.reg = $3;
427 		$$.offset = $1;
428 	}
429 
430 oreg:
431 	name
432 |	name '(' sreg ')'
433 	{
434 		$$ = $1;
435 		$$.type = D_OREG;
436 		$$.reg = $3;
437 	}
438 |	ioreg
439 
440 imsr:
441 	reg
442 |	imm
443 |	shift
444 
445 imm:	'$' con
446 	{
447 		$$ = nullgen;
448 		$$.type = D_CONST;
449 		$$.offset = $2;
450 	}
451 
452 reg:
453 	spreg
454 	{
455 		$$ = nullgen;
456 		$$.type = D_REG;
457 		$$.reg = $1;
458 	}
459 
460 regreg:
461 	'(' spreg ',' spreg ')'
462 	{
463 		$$ = nullgen;
464 		$$.type = D_REGREG;
465 		$$.reg = $2;
466 		$$.offset = $4;
467 	}
468 
469 shift:
470 	spreg '<' '<' rcon
471 	{
472 		$$ = nullgen;
473 		$$.type = D_SHIFT;
474 		$$.offset = $1 | $4 | (0 << 5);
475 	}
476 |	spreg '>' '>' rcon
477 	{
478 		$$ = nullgen;
479 		$$.type = D_SHIFT;
480 		$$.offset = $1 | $4 | (1 << 5);
481 	}
482 |	spreg '-' '>' rcon
483 	{
484 		$$ = nullgen;
485 		$$.type = D_SHIFT;
486 		$$.offset = $1 | $4 | (2 << 5);
487 	}
488 |	spreg LAT '>' rcon
489 	{
490 		$$ = nullgen;
491 		$$.type = D_SHIFT;
492 		$$.offset = $1 | $4 | (3 << 5);
493 	}
494 
495 rcon:
496 	spreg
497 	{
498 		if($$ < 0 || $$ >= 16)
499 			print("register value out of range\n");
500 		$$ = (($1&15) << 8) | (1 << 4);
501 	}
502 |	con
503 	{
504 		if($$ < 0 || $$ >= 32)
505 			print("shift value out of range\n");
506 		$$ = ($1&31) << 7;
507 	}
508 
509 sreg:
510 	LREG
511 |	LPC
512 	{
513 		$$ = REGPC;
514 	}
515 |	LR '(' expr ')'
516 	{
517 		if($3 < 0 || $3 >= NREG)
518 			print("register value out of range\n");
519 		$$ = $3;
520 	}
521 
522 spreg:
523 	sreg
524 |	LSP
525 	{
526 		$$ = REGSP;
527 	}
528 
529 creg:
530 	LCREG
531 |	LC '(' expr ')'
532 	{
533 		if($3 < 0 || $3 >= NREG)
534 			print("register value out of range\n");
535 		$$ = $3;
536 	}
537 
538 frcon:
539 	freg
540 |	fcon
541 
542 freg:
543 	LFREG
544 	{
545 		$$ = nullgen;
546 		$$.type = D_FREG;
547 		$$.reg = $1;
548 	}
549 |	LF '(' con ')'
550 	{
551 		$$ = nullgen;
552 		$$.type = D_FREG;
553 		$$.reg = $3;
554 	}
555 
556 name:
557 	con '(' pointer ')'
558 	{
559 		$$ = nullgen;
560 		$$.type = D_OREG;
561 		$$.name = $3;
562 		$$.sym = S;
563 		$$.offset = $1;
564 	}
565 |	LNAME offset '(' pointer ')'
566 	{
567 		$$ = nullgen;
568 		$$.type = D_OREG;
569 		$$.name = $4;
570 		$$.sym = $1;
571 		$$.offset = $2;
572 	}
573 |	LNAME '<' '>' offset '(' LSB ')'
574 	{
575 		$$ = nullgen;
576 		$$.type = D_OREG;
577 		$$.name = D_STATIC;
578 		$$.sym = $1;
579 		$$.offset = $4;
580 	}
581 
582 offset:
583 	{
584 		$$ = 0;
585 	}
586 |	'+' con
587 	{
588 		$$ = $2;
589 	}
590 |	'-' con
591 	{
592 		$$ = -$2;
593 	}
594 
595 pointer:
596 	LSB
597 |	LSP
598 |	LFP
599 
600 con:
601 	LCONST
602 |	LVAR
603 	{
604 		$$ = $1->value;
605 	}
606 |	'-' con
607 	{
608 		$$ = -$2;
609 	}
610 |	'+' con
611 	{
612 		$$ = $2;
613 	}
614 |	'~' con
615 	{
616 		$$ = ~$2;
617 	}
618 |	'(' expr ')'
619 	{
620 		$$ = $2;
621 	}
622 
623 oexpr:
624 	{
625 		$$ = 0;
626 	}
627 |	',' expr
628 	{
629 		$$ = $2;
630 	}
631 
632 expr:
633 	con
634 |	expr '+' expr
635 	{
636 		$$ = $1 + $3;
637 	}
638 |	expr '-' expr
639 	{
640 		$$ = $1 - $3;
641 	}
642 |	expr '*' expr
643 	{
644 		$$ = $1 * $3;
645 	}
646 |	expr '/' expr
647 	{
648 		$$ = $1 / $3;
649 	}
650 |	expr '%' expr
651 	{
652 		$$ = $1 % $3;
653 	}
654 |	expr '<' '<' expr
655 	{
656 		$$ = $1 << $4;
657 	}
658 |	expr '>' '>' expr
659 	{
660 		$$ = $1 >> $4;
661 	}
662 |	expr '&' expr
663 	{
664 		$$ = $1 & $3;
665 	}
666 |	expr '^' expr
667 	{
668 		$$ = $1 ^ $3;
669 	}
670 |	expr '|' expr
671 	{
672 		$$ = $1 | $3;
673 	}
674