xref: /plan9-contrib/sys/src/cmd/4a/a.y (revision f8bc6aaf8056e137bcdfb6117a990ac3eff62cc9)
1 %{
2 #include "a.h"
3 %}
4 %union
5 {
6 	Sym	*sym;
7 	vlong	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>	LCONST LSP LSB LFP LPC LHI LLO LMREG
23 %token	<lval>	LTYPEX LREG LFREG LFCREG LR LM LF
24 %token	<lval>	LFCR LSCHED
25 %token	<dval>	LFCONST
26 %token	<sval>	LSCONST
27 %token	<lval>	LVCONST
28 %token	<sym>	LNAME LLAB LVAR
29 %type	<lval>	con expr pointer offset sreg
30 %type	<gen>	gen vgen lgen vlgen rel reg freg mreg fcreg
31 %type	<gen>	imm ximm ireg name oreg imr nireg fgen
32 %%
33 prog:
34 |	prog line
35 
36 line:
37 	LLAB ':'
38 	{
39 		if($1->value != pc)
40 			yyerror("redeclaration of %s", $1->name);
41 		$1->value = pc;
42 	}
43 	line
44 |	LNAME ':'
45 	{
46 		$1->type = LLAB;
47 		$1->value = pc;
48 	}
49 	line
50 |	LNAME '=' expr ';'
51 	{
52 		$1->type = LVAR;
53 		$1->value = $3;
54 	}
55 |	LVAR '=' expr ';'
56 	{
57 		if($1->value != $3)
58 			yyerror("redeclaration of %s", $1->name);
59 		$1->value = $3;
60 	}
61 |	LSCHED ';'
62 	{
63 		nosched = $1;
64 	}
65 |	';'
66 |	inst ';'
67 |	error ';'
68 
69 inst:
70 /*
71  * Immed-type
72  */
73 	LTYPE1 imr ',' sreg ',' reg
74 	{
75 		outcode($1, &$2, $4, &$6);
76 	}
77 |	LTYPE1 imr ',' reg
78 	{
79 		outcode($1, &$2, NREG, &$4);
80 	}
81 /*
82  * NOR
83  */
84 |	LTYPE2 imr ',' sreg ',' imr
85 	{
86 		outcode($1, &$2, $4, &$6);
87 	}
88 |	LTYPE2 imr ',' imr
89 	{
90 		outcode($1, &$2, NREG, &$4);
91 	}
92 /*
93  * LOAD/STORE, but not MOVW
94  */
95 |	LTYPE3 lgen ',' gen
96 	{
97 		if(!isreg(&$2) && !isreg(&$4))
98 			print("one side must be register\n");
99 		outcode($1, &$2, NREG, &$4);
100 	}
101 /*
102  * SPECIAL
103  */
104 |	LTYPE4 comma
105 	{
106 		outcode($1, &nullgen, NREG, &nullgen);
107 	}
108 /*
109  * MOVW
110  */
111 |	LTYPE5 vlgen ',' vgen
112 	{
113 		if(!isreg(&$2) && !isreg(&$4))
114 			print("one side must be register\n");
115 		outcode($1, &$2, NREG, &$4);
116 	}
117 /*
118  * MUL/DIV
119  */
120 |	LTYPE6 reg ',' sreg comma
121 	{
122 		outcode($1, &$2, $4, &nullgen);
123 	}
124 |	LTYPE6 reg ',' sreg ',' reg
125 	{
126 		outcode($1, &$2, $4, &$6);
127 	}
128 /*
129  * JMP/JAL
130  */
131 |	LTYPE7 comma rel
132 	{
133 		outcode($1, &nullgen, NREG, &$3);
134 	}
135 |	LTYPE7 comma nireg
136 	{
137 		outcode($1, &nullgen, NREG, &$3);
138 	}
139 |	LTYPE8 comma rel
140 	{
141 		outcode($1, &nullgen, NREG, &$3);
142 	}
143 |	LTYPE8 comma nireg
144 	{
145 		outcode($1, &nullgen, NREG, &$3);
146 	}
147 |	LTYPE8 sreg ',' nireg
148 	{
149 		outcode($1, &nullgen, $2, &$4);
150 	}
151 /*
152  * BEQ/BNE
153  */
154 |	LTYPE9 gen ',' rel
155 	{
156 		if(!isreg(&$2))
157 			print("left side must be register\n");
158 		outcode($1, &$2, NREG, &$4);
159 	}
160 |	LTYPE9 gen ',' sreg ',' rel
161 	{
162 		if(!isreg(&$2))
163 			print("left side must be register\n");
164 		outcode($1, &$2, $4, &$6);
165 	}
166 /*
167  * B-other
168  */
169 |	LTYPEA gen ',' rel
170 	{
171 		if(!isreg(&$2))
172 			print("left side must be register\n");
173 		outcode($1, &$2, NREG, &$4);
174 	}
175 /*
176  * TEXT/GLOBL
177  */
178 |	LTYPEB name ',' imm
179 	{
180 		outcode($1, &$2, NREG, &$4);
181 	}
182 |	LTYPEB name ',' con ',' imm
183 	{
184 		outcode($1, &$2, $4, &$6);
185 	}
186 /*
187  * DATA
188  */
189 |	LTYPEC name '/' con ',' ximm
190 	{
191 		outcode($1, &$2, $4, &$6);
192 	}
193 /*
194  * floating-type
195  */
196 |	LTYPED freg ',' freg
197 	{
198 		outcode($1, &$2, NREG, &$4);
199 	}
200 |	LTYPEE freg ',' freg
201 	{
202 		outcode($1, &$2, NREG, &$4);
203 	}
204 |	LTYPEE freg ',' LFREG ',' freg
205 	{
206 		outcode($1, &$2, $4, &$6);
207 	}
208 |	LTYPEF freg ',' LFREG comma
209 	{
210 		outcode($1, &$2, $4, &nullgen);
211 	}
212 /*
213  * coprocessor branch
214  */
215 |	LTYPEG comma rel
216 	{
217 		outcode($1, &nullgen, NREG, &$3);
218 	}
219 /*
220  * word
221  */
222 |	LTYPEH comma ximm
223 	{
224 		outcode($1, &nullgen, NREG, &$3);
225 	}
226 /*
227  * NOP
228  */
229 |	LTYPEI comma
230 	{
231 		outcode($1, &nullgen, NREG, &nullgen);
232 	}
233 |	LTYPEI ',' vgen
234 	{
235 		outcode($1, &nullgen, NREG, &$3);
236 	}
237 |	LTYPEI vgen comma
238 	{
239 		outcode($1, &$2, NREG, &nullgen);
240 	}
241 /*
242  * BREAK -- overloaded with CACHE opcode
243  */
244 |	LTYPEJ comma
245 	{
246 		outcode($1, &nullgen, NREG, &nullgen);
247 	}
248 |	LTYPEJ vgen ',' vgen
249 	{
250 		outcode($1, &$2, NREG, &$4);
251 	}
252 
253 comma:
254 |	','
255 
256 rel:
257 	con '(' LPC ')'
258 	{
259 		$$ = nullgen;
260 		$$.type = D_BRANCH;
261 		$$.offset = $1 + pc;
262 	}
263 |	LNAME offset
264 	{
265 		$$ = nullgen;
266 		if(pass == 2)
267 			yyerror("undefined label: %s", $1->name);
268 		$$.type = D_BRANCH;
269 		$$.sym = $1;
270 		$$.offset = $2;
271 	}
272 |	LLAB offset
273 	{
274 		$$ = nullgen;
275 		$$.type = D_BRANCH;
276 		$$.sym = $1;
277 		$$.offset = $1->value + $2;
278 	}
279 
280 vlgen:
281 	lgen
282 |	fgen
283 |	mreg
284 |	fcreg
285 |	LHI
286 	{
287 		$$ = nullgen;
288 		$$.type = D_HI;
289 	}
290 |	LLO
291 	{
292 		$$ = nullgen;
293 		$$.type = D_LO;
294 	}
295 
296 vgen:
297 	gen
298 |	fgen
299 |	mreg
300 |	fcreg
301 |	LHI
302 	{
303 		$$ = nullgen;
304 		$$.type = D_HI;
305 	}
306 |	LLO
307 	{
308 		$$ = nullgen;
309 		$$.type = D_LO;
310 	}
311 
312 lgen:
313 	gen
314 |	ximm
315 
316 fgen:
317 	freg
318 
319 mreg:
320 	LMREG
321 	{
322 		$$ = nullgen;
323 		$$.type = D_MREG;
324 		$$.reg = $1;
325 	}
326 |	LM '(' con ')'
327 	{
328 		$$ = nullgen;
329 		$$.type = D_MREG;
330 		$$.reg = $3;
331 	}
332 
333 fcreg:
334 	LFCREG
335 	{
336 		$$ = nullgen;
337 		$$.type = D_FCREG;
338 		$$.reg = $1;
339 	}
340 |	LFCR '(' con ')'
341 	{
342 		$$ = nullgen;
343 		$$.type = D_FCREG;
344 		$$.reg = $3;
345 	}
346 
347 freg:
348 	LFREG
349 	{
350 		$$ = nullgen;
351 		$$.type = D_FREG;
352 		$$.reg = $1;
353 	}
354 |	LF '(' con ')'
355 	{
356 		$$ = nullgen;
357 		$$.type = D_FREG;
358 		$$.reg = $3;
359 	}
360 
361 ximm:	'$' con
362 	{
363 		$$ = nullgen;
364 		if(isvconst($2))
365 			$$.type = D_VCONST;
366 		else
367 			$$.type = D_CONST;
368 		$$.offset = $2;
369 	}
370 |	'$' oreg
371 	{
372 		$$ = $2;
373 		$$.type = D_CONST;
374 	}
375 |	'$' '*' '$' oreg
376 	{
377 		$$ = $4;
378 		$$.type = D_OCONST;
379 	}
380 |	'$' LSCONST
381 	{
382 		$$ = nullgen;
383 		$$.type = D_SCONST;
384 		memcpy($$.sval, $2, sizeof($$.sval));
385 	}
386 |	'$' LFCONST
387 	{
388 		$$ = nullgen;
389 		$$.type = D_FCONST;
390 		$$.dval = $2;
391 	}
392 |	'$' '-' LFCONST
393 	{
394 		$$ = nullgen;
395 		$$.type = D_FCONST;
396 		$$.dval = -$3;
397 	}
398 
399 nireg:
400 	ireg
401 |	con ireg
402 	{
403 		if($1 != 0)
404 			yyerror("offset must be zero");
405 		$$ = $2;
406 	}
407 |	name
408 	{
409 		$$ = $1;
410 		if($1.name != D_EXTERN && $1.name != D_STATIC) {
411 		}
412 	}
413 
414 ireg:
415 	'(' sreg ')'
416 	{
417 		$$ = nullgen;
418 		$$.type = D_OREG;
419 		$$.reg = $2;
420 		$$.offset = 0;
421 	}
422 
423 gen:
424 	reg
425 |	con
426 	{
427 		$$ = nullgen;
428 		$$.type = D_OREG;
429 		$$.offset = $1;
430 	}
431 |	oreg
432 
433 oreg:
434 	name
435 |	name '(' sreg ')'
436 	{
437 		$$ = $1;
438 		$$.type = D_OREG;
439 		$$.reg = $3;
440 	}
441 |	'(' sreg ')'
442 	{
443 		$$ = nullgen;
444 		$$.type = D_OREG;
445 		$$.reg = $2;
446 		$$.offset = 0;
447 	}
448 |	con '(' sreg ')'
449 	{
450 		$$ = nullgen;
451 		$$.type = D_OREG;
452 		$$.reg = $3;
453 		$$.offset = $1;
454 	}
455 
456 imr:
457 	reg
458 |	imm
459 
460 imm:	'$' con
461 	{
462 		$$ = nullgen;
463 		if(isvconst($2))
464 			$$.type = D_VCONST;
465 		else
466 			$$.type = D_CONST;
467 		$$.offset = $2;
468 	}
469 
470 reg:
471 	sreg
472 	{
473 		$$ = nullgen;
474 		$$.type = D_REG;
475 		$$.reg = $1;
476 	}
477 
478 sreg:
479 	LREG
480 |	LR '(' con ')'
481 	{
482 		if($$ < 0 || $$ >= NREG)
483 			print("register value out of range\n");
484 		$$ = $3;
485 	}
486 
487 name:
488 	con '(' pointer ')'
489 	{
490 		$$ = nullgen;
491 		$$.type = D_OREG;
492 		$$.name = $3;
493 		$$.sym = S;
494 		$$.offset = $1;
495 	}
496 |	LNAME offset '(' pointer ')'
497 	{
498 		$$ = nullgen;
499 		$$.type = D_OREG;
500 		$$.name = $4;
501 		$$.sym = $1;
502 		$$.offset = $2;
503 	}
504 |	LNAME '<' '>' offset '(' LSB ')'
505 	{
506 		$$ = nullgen;
507 		$$.type = D_OREG;
508 		$$.name = D_STATIC;
509 		$$.sym = $1;
510 		$$.offset = $4;
511 	}
512 
513 offset:
514 	{
515 		$$ = 0;
516 	}
517 |	'+' con
518 	{
519 		$$ = $2;
520 	}
521 |	'-' con
522 	{
523 		$$ = -$2;
524 	}
525 
526 pointer:
527 	LSB
528 |	LSP
529 |	LFP
530 
531 con:
532 	LCONST
533 |	LVAR
534 	{
535 		$$ = $1->value;
536 	}
537 |	'-' con
538 	{
539 		$$ = -$2;
540 	}
541 |	'+' con
542 	{
543 		$$ = $2;
544 	}
545 |	'~' con
546 	{
547 		$$ = ~$2;
548 	}
549 |	'(' expr ')'
550 	{
551 		$$ = $2;
552 	}
553 
554 expr:
555 	con
556 |	expr '+' expr
557 	{
558 		$$ = $1 + $3;
559 	}
560 |	expr '-' expr
561 	{
562 		$$ = $1 - $3;
563 	}
564 |	expr '*' expr
565 	{
566 		$$ = $1 * $3;
567 	}
568 |	expr '/' expr
569 	{
570 		$$ = $1 / $3;
571 	}
572 |	expr '%' expr
573 	{
574 		$$ = $1 % $3;
575 	}
576 |	expr '<' '<' expr
577 	{
578 		$$ = $1 << $4;
579 	}
580 |	expr '>' '>' expr
581 	{
582 		$$ = $1 >> $4;
583 	}
584 |	expr '&' expr
585 	{
586 		$$ = $1 & $3;
587 	}
588 |	expr '^' expr
589 	{
590 		$$ = $1 ^ $3;
591 	}
592 |	expr '|' expr
593 	{
594 		$$ = $1 | $3;
595 	}
596 %%
597 
598 int
599 isvconst(vlong con)
600 {
601 	long l;
602 
603 	l = con;
604 	return (vlong)l != con;
605 }
606