xref: /plan9-contrib/sys/src/cmd/qa/a.y (revision 6891d8578618fb7ccda4a131c122d4d0e6580c4b)
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>	LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP
19 %token	<lval>	LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW
20 %token	<lval>	LNOP LEND LRETT LWORD LTEXT LDATA LRETRN
21 %token	<lval>	LCONST LSP LSB LFP LPC LCREG LFLUSH
22 %token	<lval>	LREG LFREG LR LCR LF LFPSCR
23 %token	<lval>	LLR LCTR LSPR LSPREG LSEG LMSR LDCR
24 %token	<lval>	LSCHED LXLD LXST LXOP LXMV
25 %token	<lval>	LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA LFMOVX
26 %token	<dval>	LFCONST
27 %token	<sval>	LSCONST
28 %token	<sym>	LNAME LLAB LVAR
29 %type	<lval>	con expr pointer offset sreg
30 %type	<gen>	addr rreg regaddr name creg freg xlreg lr ctr
31 %type	<gen>	imm ximm fimm rel psr lcr cbit fpscr fpscrf seg msr mask
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  * load ints and bytes
72  */
73 	LMOVW rreg ',' rreg
74 	{
75 		outcode($1, &$2, NREG, &$4);
76 	}
77 |	LMOVW addr ',' rreg
78 	{
79 		outcode($1, &$2, NREG, &$4);
80 	}
81 |	LMOVW regaddr ',' rreg
82 	{
83 		outcode($1, &$2, NREG, &$4);
84 	}
85 |	LMOVB rreg ',' rreg
86 	{
87 		outcode($1, &$2, NREG, &$4);
88 	}
89 |	LMOVB addr ',' rreg
90 	{
91 		outcode($1, &$2, NREG, &$4);
92 	}
93 |	LMOVB regaddr ',' rreg
94 	{
95 		outcode($1, &$2, NREG, &$4);
96 	}
97 /*
98  * load and store floats
99  */
100 |	LFMOV addr ',' freg
101 	{
102 		outcode($1, &$2, NREG, &$4);
103 	}
104 |	LFMOV regaddr ',' freg
105 	{
106 		outcode($1, &$2, NREG, &$4);
107 	}
108 |	LFMOV fimm ',' freg
109 	{
110 		outcode($1, &$2, NREG, &$4);
111 	}
112 |	LFMOV freg ',' freg
113 	{
114 		outcode($1, &$2, NREG, &$4);
115 	}
116 |	LFMOV freg ',' addr
117 	{
118 		outcode($1, &$2, NREG, &$4);
119 	}
120 |	LFMOV freg ',' regaddr
121 	{
122 		outcode($1, &$2, NREG, &$4);
123 	}
124 /*
125  * load and store floats, indexed only
126  */
127 |	LFMOVX regaddr ',' freg
128 	{
129 		outcode($1, &$2, NREG, &$4);
130 	}
131 |	LFMOVX freg ',' regaddr
132 	{
133 		outcode($1, &$2, NREG, &$4);
134 	}
135 /*
136  * store ints and bytes
137  */
138 |	LMOVW rreg ',' addr
139 	{
140 		outcode($1, &$2, NREG, &$4);
141 	}
142 |	LMOVW rreg ',' regaddr
143 	{
144 		outcode($1, &$2, NREG, &$4);
145 	}
146 |	LMOVB rreg ',' addr
147 	{
148 		outcode($1, &$2, NREG, &$4);
149 	}
150 |	LMOVB rreg ',' regaddr
151 	{
152 		outcode($1, &$2, NREG, &$4);
153 	}
154 /*
155  * store floats
156  */
157 |	LMOVW freg ',' addr
158 	{
159 		outcode($1, &$2, NREG, &$4);
160 	}
161 |	LMOVW freg ',' regaddr
162 	{
163 		outcode($1, &$2, NREG, &$4);
164 	}
165 /*
166  * floating point status
167  */
168 |	LMOVW fpscr ',' freg
169 	{
170 		outcode($1, &$2, NREG, &$4);
171 	}
172 |	LMOVW freg ','  fpscr
173 	{
174 		outcode($1, &$2, NREG, &$4);
175 	}
176 |	LMOVW freg ',' imm ',' fpscr
177 	{
178 		outgcode($1, &$2, NREG, &$4, &$6);
179 	}
180 |	LMOVW fpscr ',' creg
181 	{
182 		outcode($1, &$2, NREG, &$4);
183 	}
184 |	LMOVW imm ',' fpscrf
185 	{
186 		outcode($1, &$2, NREG, &$4);
187 	}
188 |	LMTFSB imm ',' con
189 	{
190 		outcode($1, &$2, $4, &nullgen);
191 	}
192 /*
193  * field moves (mtcrf)
194  */
195 |	LMOVW rreg ',' imm ',' lcr
196 	{
197 		outgcode($1, &$2, NREG, &$4, &$6);
198 	}
199 |	LMOVW rreg ',' creg
200 	{
201 		outcode($1, &$2, NREG, &$4);
202 	}
203 |	LMOVW rreg ',' lcr
204 	{
205 		outcode($1, &$2, NREG, &$4);
206 	}
207 /*
208  * integer operations
209  * logical instructions
210  * shift instructions
211  * unary instructions
212  */
213 |	LADDW rreg ',' sreg ',' rreg
214 	{
215 		outcode($1, &$2, $4, &$6);
216 	}
217 |	LADDW imm ',' sreg ',' rreg
218 	{
219 		outcode($1, &$2, $4, &$6);
220 	}
221 |	LADDW rreg ',' imm ',' rreg
222 	{
223 		outgcode($1, &$2, NREG, &$4, &$6);
224 	}
225 |	LADDW rreg ',' rreg
226 	{
227 		outcode($1, &$2, NREG, &$4);
228 	}
229 |	LADDW imm ',' rreg
230 	{
231 		outcode($1, &$2, NREG, &$4);
232 	}
233 |	LLOGW rreg ',' sreg ',' rreg
234 	{
235 		outcode($1, &$2, $4, &$6);
236 	}
237 |	LLOGW rreg ',' rreg
238 	{
239 		outcode($1, &$2, NREG, &$4);
240 	}
241 |	LSHW rreg ',' sreg ',' rreg
242 	{
243 		outcode($1, &$2, $4, &$6);
244 	}
245 |	LSHW rreg ',' rreg
246 	{
247 		outcode($1, &$2, NREG, &$4);
248 	}
249 |	LSHW imm ',' sreg ',' rreg
250 	{
251 		outcode($1, &$2, $4, &$6);
252 	}
253 |	LSHW imm ',' rreg
254 	{
255 		outcode($1, &$2, NREG, &$4);
256 	}
257 |	LABS rreg ',' rreg
258 	{
259 		outcode($1, &$2, NREG, &$4);
260 	}
261 |	LABS rreg
262 	{
263 		outcode($1, &$2, NREG, &$2);
264 	}
265 /*
266  * multiply-accumulate
267  */
268 |	LMA rreg ',' sreg ',' rreg
269 	{
270 		outcode($1, &$2, $4, &$6);
271 	}
272 /*
273  * move immediate: macro for cau+or, addi, addis, and other combinations
274  */
275 |	LMOVW imm ',' rreg
276 	{
277 		outcode($1, &$2, NREG, &$4);
278 	}
279 |	LMOVW ximm ',' rreg
280 	{
281 		outcode($1, &$2, NREG, &$4);
282 	}
283 /*
284  * condition register operations
285  */
286 |	LCROP cbit ',' cbit
287 	{
288 		outcode($1, &$2, $4.reg, &$4);
289 	}
290 |	LCROP cbit ',' con ',' cbit
291 	{
292 		outcode($1, &$2, $4, &$6);
293 	}
294 /*
295  * condition register moves
296  * move from machine state register
297  */
298 |	LMOVW creg ',' creg
299 	{
300 		outcode($1, &$2, NREG, &$4);
301 	}
302 |	LMOVW psr ',' creg
303 	{
304 		outcode($1, &$2, NREG, &$4);
305 	}
306 |	LMOVW lcr ',' rreg
307 	{
308 		outcode($1, &$2, NREG, &$4);
309 	}
310 |	LMOVW psr ',' rreg
311 	{
312 		outcode($1, &$2, NREG, &$4);
313 	}
314 |	LMOVW seg ',' rreg
315 	{
316 		int r;
317 		r = $2.offset;
318 		$2.offset = 0;
319 		outcode($1, &$2, r, &$4);
320 	}
321 |	LMOVW rreg ',' seg
322 	{
323 		int r;
324 		r = $4.offset;
325 		$4.offset = 0;
326 		outcode($1, &$2, r, &$4);
327 	}
328 |	LMOVW xlreg ',' rreg
329 	{
330 		outcode($1, &$2, NREG, &$4);
331 	}
332 |	LMOVW rreg ',' xlreg
333 	{
334 		outcode($1, &$2, NREG, &$4);
335 	}
336 |	LMOVW creg ',' psr
337 	{
338 		outcode($1, &$2, NREG, &$4);
339 	}
340 |	LMOVW rreg ',' psr
341 	{
342 		outcode($1, &$2, NREG, &$4);
343 	}
344 /*
345  * branch, branch conditional
346  * branch conditional register
347  * branch conditional to count register
348  */
349 |	LBRA rel
350 	{
351 		outcode($1, &nullgen, NREG, &$2);
352 	}
353 |	LBRA addr
354 	{
355 		outcode($1, &nullgen, NREG, &$2);
356 	}
357 |	LBRA '(' xlreg ')'
358 	{
359 		outcode($1, &nullgen, NREG, &$3);
360 	}
361 |	LBRA ',' rel
362 	{
363 		outcode($1, &nullgen, NREG, &$3);
364 	}
365 |	LBRA ',' addr
366 	{
367 		outcode($1, &nullgen, NREG, &$3);
368 	}
369 |	LBRA ',' '(' xlreg ')'
370 	{
371 		outcode($1, &nullgen, NREG, &$4);
372 	}
373 |	LBRA creg ',' rel
374 	{
375 		outcode($1, &$2, NREG, &$4);
376 	}
377 |	LBRA creg ',' addr
378 	{
379 		outcode($1, &$2, NREG, &$4);
380 	}
381 |	LBRA creg ',' '(' xlreg ')'
382 	{
383 		outcode($1, &$2, NREG, &$5);
384 	}
385 |	LBRA con ',' rel
386 	{
387 		outcode($1, &nullgen, $2, &$4);
388 	}
389 |	LBRA con ',' addr
390 	{
391 		outcode($1, &nullgen, $2, &$4);
392 	}
393 |	LBRA con ',' '(' xlreg ')'
394 	{
395 		outcode($1, &nullgen, $2, &$5);
396 	}
397 |	LBRA con ',' con ',' rel
398 	{
399 		Gen g;
400 		g = nullgen;
401 		g.type = D_CONST;
402 		g.offset = $2;
403 		outcode($1, &g, $4, &$6);
404 	}
405 |	LBRA con ',' con ',' addr
406 	{
407 		Gen g;
408 		g = nullgen;
409 		g.type = D_CONST;
410 		g.offset = $2;
411 		outcode($1, &g, $4, &$6);
412 	}
413 |	LBRA con ',' con ',' '(' xlreg ')'
414 	{
415 		Gen g;
416 		g = nullgen;
417 		g.type = D_CONST;
418 		g.offset = $2;
419 		outcode($1, &g, $4, &$7);
420 	}
421 /*
422  * conditional trap
423  */
424 |	LTRAP rreg ',' sreg
425 	{
426 		outcode($1, &$2, $4, &nullgen);
427 	}
428 |	LTRAP imm ',' sreg
429 	{
430 		outcode($1, &$2, $4, &nullgen);
431 	}
432 |	LTRAP rreg comma
433 	{
434 		outcode($1, &$2, NREG, &nullgen);
435 	}
436 |	LTRAP comma
437 	{
438 		outcode($1, &nullgen, NREG, &nullgen);
439 	}
440 /*
441  * floating point operate
442  */
443 |	LFCONV freg ',' freg
444 	{
445 		outcode($1, &$2, NREG, &$4);
446 	}
447 |	LFADD freg ',' freg
448 	{
449 		outcode($1, &$2, NREG, &$4);
450 	}
451 |	LFADD freg ',' freg ',' freg
452 	{
453 		outcode($1, &$2, $4.reg, &$6);
454 	}
455 |	LFMA freg ',' freg ',' freg ',' freg
456 	{
457 		outgcode($1, &$2, $4.reg, &$6, &$8);
458 	}
459 |	LFCMP freg ',' freg
460 	{
461 		outcode($1, &$2, NREG, &$4);
462 	}
463 |	LFCMP freg ',' freg ',' creg
464 	{
465 		outcode($1, &$2, $6.reg, &$4);
466 	}
467 /*
468  * CMP
469  */
470 |	LCMP rreg ',' rreg
471 	{
472 		outcode($1, &$2, NREG, &$4);
473 	}
474 |	LCMP rreg ',' imm
475 	{
476 		outcode($1, &$2, NREG, &$4);
477 	}
478 |	LCMP rreg ',' rreg ',' creg
479 	{
480 		outcode($1, &$2, $6.reg, &$4);
481 	}
482 |	LCMP rreg ',' imm ',' creg
483 	{
484 		outcode($1, &$2, $6.reg, &$4);
485 	}
486 /*
487  * rotate and mask
488  */
489 |	LRLWM  imm ',' rreg ',' imm ',' rreg
490 	{
491 		outgcode($1, &$2, $4.reg, &$6, &$8);
492 	}
493 |	LRLWM  imm ',' rreg ',' mask ',' rreg
494 	{
495 		outgcode($1, &$2, $4.reg, &$6, &$8);
496 	}
497 |	LRLWM  rreg ',' rreg ',' imm ',' rreg
498 	{
499 		outgcode($1, &$2, $4.reg, &$6, &$8);
500 	}
501 |	LRLWM  rreg ',' rreg ',' mask ',' rreg
502 	{
503 		outgcode($1, &$2, $4.reg, &$6, &$8);
504 	}
505 /*
506  * load/store multiple
507  */
508 |	LMOVMW addr ',' rreg
509 	{
510 		outcode($1, &$2, NREG, &$4);
511 	}
512 |	LMOVMW rreg ',' addr
513 	{
514 		outcode($1, &$2, NREG, &$4);
515 	}
516 /*
517  * various indexed load/store
518  * indexed unary (eg, cache clear)
519  */
520 |	LXLD regaddr ',' rreg
521 	{
522 		outcode($1, &$2, NREG, &$4);
523 	}
524 |	LXLD regaddr ',' imm ',' rreg
525 	{
526 		outgcode($1, &$2, NREG, &$4, &$6);
527 	}
528 |	LXST rreg ',' regaddr
529 	{
530 		outcode($1, &$2, NREG, &$4);
531 	}
532 |	LXST rreg ',' imm ',' regaddr
533 	{
534 		outgcode($1, &$2, NREG, &$4, &$6);
535 	}
536 |	LXMV regaddr ',' rreg
537 	{
538 		outcode($1, &$2, NREG, &$4);
539 	}
540 |	LXMV rreg ',' regaddr
541 	{
542 		outcode($1, &$2, NREG, &$4);
543 	}
544 |	LXOP regaddr
545 	{
546 		outcode($1, &$2, NREG, &nullgen);
547 	}
548 /*
549  * NOP
550  */
551 |	LNOP comma
552 	{
553 		outcode($1, &nullgen, NREG, &nullgen);
554 	}
555 |	LNOP rreg comma
556 	{
557 		outcode($1, &$2, NREG, &nullgen);
558 	}
559 |	LNOP freg comma
560 	{
561 		outcode($1, &$2, NREG, &nullgen);
562 	}
563 |	LNOP ',' rreg
564 	{
565 		outcode($1, &nullgen, NREG, &$3);
566 	}
567 |	LNOP ',' freg
568 	{
569 		outcode($1, &nullgen, NREG, &$3);
570 	}
571 /*
572  * word
573  */
574 |	LWORD imm comma
575 	{
576 		outcode($1, &$2, NREG, &nullgen);
577 	}
578 |	LWORD ximm comma
579 	{
580 		outcode($1, &$2, NREG, &nullgen);
581 	}
582 /*
583  * END
584  */
585 |	LEND comma
586 	{
587 		outcode($1, &nullgen, NREG, &nullgen);
588 	}
589 /*
590  * TEXT/GLOBL
591  */
592 |	LTEXT name ',' imm
593 	{
594 		outcode($1, &$2, NREG, &$4);
595 	}
596 |	LTEXT name ',' con ',' imm
597 	{
598 		outcode($1, &$2, $4, &$6);
599 	}
600 |	LTEXT name ',' imm ':' imm
601 	{
602 		outgcode($1, &$2, NREG, &$6, &$4);
603 	}
604 |	LTEXT name ',' con ',' imm ':' imm
605 	{
606 		outgcode($1, &$2, $4, &$8, &$6);
607 	}
608 /*
609  * DATA
610  */
611 |	LDATA name '/' con ',' imm
612 	{
613 		outcode($1, &$2, $4, &$6);
614 	}
615 |	LDATA name '/' con ',' ximm
616 	{
617 		outcode($1, &$2, $4, &$6);
618 	}
619 |	LDATA name '/' con ',' fimm
620 	{
621 		outcode($1, &$2, $4, &$6);
622 	}
623 /*
624  * RETURN
625  */
626 |	LRETRN	comma
627 	{
628 		outcode($1, &nullgen, NREG, &nullgen);
629 	}
630 
631 rel:
632 	con '(' LPC ')'
633 	{
634 		$$ = nullgen;
635 		$$.type = D_BRANCH;
636 		$$.offset = $1 + pc;
637 	}
638 |	LNAME offset
639 	{
640 		$$ = nullgen;
641 		if(pass == 2)
642 			yyerror("undefined label: %s", $1->name);
643 		$$.type = D_BRANCH;
644 		$$.sym = $1;
645 		$$.offset = $2;
646 	}
647 |	LLAB offset
648 	{
649 		$$ = nullgen;
650 		$$.type = D_BRANCH;
651 		$$.sym = $1;
652 		$$.offset = $1->value + $2;
653 	}
654 
655 rreg:
656 	sreg
657 	{
658 		$$ = nullgen;
659 		$$.type = D_REG;
660 		$$.reg = $1;
661 	}
662 
663 xlreg:
664 	lr
665 |	ctr
666 
667 lr:
668 	LLR
669 	{
670 		$$ = nullgen;
671 		$$.type = D_SPR;
672 		$$.offset = $1;
673 	}
674 
675 lcr:
676 	LCR
677 	{
678 		$$ = nullgen;
679 		$$.type = D_CREG;
680 		$$.reg = NREG;	/* whole register */
681 	}
682 
683 ctr:
684 	LCTR
685 	{
686 		$$ = nullgen;
687 		$$.type = D_SPR;
688 		$$.offset = $1;
689 	}
690 
691 msr:
692 	LMSR
693 	{
694 		$$ = nullgen;
695 		$$.type = D_MSR;
696 	}
697 
698 psr:
699 	LSPREG
700 	{
701 		$$ = nullgen;
702 		$$.type = D_SPR;
703 		$$.offset = $1;
704 	}
705 |	LSPR '(' con ')'
706 	{
707 		$$ = nullgen;
708 		$$.type = $1;
709 		$$.offset = $3;
710 	}
711 |	LDCR '(' con ')'
712 	{
713 		$$ = nullgen;
714 		$$.type = $1;
715 		$$.offset = $3;
716 	}
717 |	LDCR '(' sreg ')'
718 	{
719 		$$ = nullgen;
720 		$$.type = $1;
721 		$$.reg = $3;
722 		$$.offset = 0;
723 	}
724 |	msr
725 
726 seg:
727 	LSEG '(' con ')'
728 	{
729 		if($3 < 0 || $3 > 15)
730 			yyerror("segment register number out of range");
731 		$$ = nullgen;
732 		$$.type = D_SREG;
733 		$$.reg = $3;
734 		$$.offset = NREG;
735 	}
736 |	LSEG '(' sreg ')'
737 	{
738 		$$ = nullgen;
739 		$$.type = D_SREG;
740 		$$.reg = NREG;
741 		$$.offset = $3;
742 	}
743 
744 fpscr:
745 	LFPSCR
746 	{
747 		$$ = nullgen;
748 		$$.type = D_FPSCR;
749 		$$.reg = NREG;
750 	}
751 
752 fpscrf:
753 	LFPSCR '(' con ')'
754 	{
755 		$$ = nullgen;
756 		$$.type = D_FPSCR;
757 		$$.reg = $3;
758 	}
759 
760 freg:
761 	LFREG
762 	{
763 		$$ = nullgen;
764 		$$.type = D_FREG;
765 		$$.reg = $1;
766 	}
767 |	LF '(' con ')'
768 	{
769 		$$ = nullgen;
770 		$$.type = D_FREG;
771 		$$.reg = $3;
772 	}
773 
774 creg:
775 	LCREG
776 	{
777 		$$ = nullgen;
778 		$$.type = D_CREG;
779 		$$.reg = $1;
780 	}
781 |	LCR '(' con ')'
782 	{
783 		$$ = nullgen;
784 		$$.type = D_CREG;
785 		$$.reg = $3;
786 	}
787 
788 
789 cbit:	con
790 	{
791 		$$ = nullgen;
792 		$$.type = D_REG;
793 		$$.reg = $1;
794 	}
795 
796 mask:
797 	con ',' con
798 	{
799 		int mb, me;
800 		ulong v;
801 
802 		$$ = nullgen;
803 		$$.type = D_CONST;
804 		mb = $1;
805 		me = $3;
806 		if(mb < 0 || mb > 31 || me < 0 || me > 31){
807 			yyerror("illegal mask start/end value(s)");
808 			mb = me = 0;
809 		}
810 		if(mb <= me)
811 			v = ((ulong)~0L>>mb) & (~0L<<(31-me));
812 		else
813 			v = ~(((ulong)~0L>>(me+1)) & (~0L<<(31-(mb-1))));
814 		$$.offset = v;
815 	}
816 
817 ximm:
818 	'$' addr
819 	{
820 		$$ = $2;
821 		$$.type = D_CONST;
822 	}
823 |	'$' LSCONST
824 	{
825 		$$ = nullgen;
826 		$$.type = D_SCONST;
827 		memcpy($$.sval, $2, sizeof($$.sval));
828 	}
829 
830 fimm:
831 	'$' LFCONST
832 	{
833 		$$ = nullgen;
834 		$$.type = D_FCONST;
835 		$$.dval = $2;
836 	}
837 |	'$' '-' LFCONST
838 	{
839 		$$ = nullgen;
840 		$$.type = D_FCONST;
841 		$$.dval = -$3;
842 	}
843 
844 imm:	'$' con
845 	{
846 		$$ = nullgen;
847 		$$.type = D_CONST;
848 		$$.offset = $2;
849 	}
850 
851 sreg:
852 	LREG
853 |	LR '(' con ')'
854 	{
855 		if($$ < 0 || $$ >= NREG)
856 			print("register value out of range\n");
857 		$$ = $3;
858 	}
859 
860 regaddr:
861 	'(' sreg ')'
862 	{
863 		$$ = nullgen;
864 		$$.type = D_OREG;
865 		$$.reg = $2;
866 		$$.offset = 0;
867 	}
868 |	'(' sreg '+' sreg ')'
869 	{
870 		$$ = nullgen;
871 		$$.type = D_OREG;
872 		$$.reg = $2;
873 		$$.xreg = $4;
874 		$$.offset = 0;
875 	}
876 
877 addr:
878 	name
879 |	con '(' sreg ')'
880 	{
881 		$$ = nullgen;
882 		$$.type = D_OREG;
883 		$$.reg = $3;
884 		$$.offset = $1;
885 	}
886 
887 name:
888 	con '(' pointer ')'
889 	{
890 		$$ = nullgen;
891 		$$.type = D_OREG;
892 		$$.name = $3;
893 		$$.sym = S;
894 		$$.offset = $1;
895 	}
896 |	LNAME offset '(' pointer ')'
897 	{
898 		$$ = nullgen;
899 		$$.type = D_OREG;
900 		$$.name = $4;
901 		$$.sym = $1;
902 		$$.offset = $2;
903 	}
904 |	LNAME '<' '>' offset '(' LSB ')'
905 	{
906 		$$ = nullgen;
907 		$$.type = D_OREG;
908 		$$.name = D_STATIC;
909 		$$.sym = $1;
910 		$$.offset = $4;
911 	}
912 
913 comma:
914 |	','
915 
916 offset:
917 	{
918 		$$ = 0;
919 	}
920 |	'+' con
921 	{
922 		$$ = $2;
923 	}
924 |	'-' con
925 	{
926 		$$ = -$2;
927 	}
928 
929 pointer:
930 	LSB
931 |	LSP
932 |	LFP
933 
934 con:
935 	LCONST
936 |	LVAR
937 	{
938 		$$ = $1->value;
939 	}
940 |	'-' con
941 	{
942 		$$ = -$2;
943 	}
944 |	'+' con
945 	{
946 		$$ = $2;
947 	}
948 |	'~' con
949 	{
950 		$$ = ~$2;
951 	}
952 |	'(' expr ')'
953 	{
954 		$$ = $2;
955 	}
956 
957 expr:
958 	con
959 |	expr '+' expr
960 	{
961 		$$ = $1 + $3;
962 	}
963 |	expr '-' expr
964 	{
965 		$$ = $1 - $3;
966 	}
967 |	expr '*' expr
968 	{
969 		$$ = $1 * $3;
970 	}
971 |	expr '/' expr
972 	{
973 		$$ = $1 / $3;
974 	}
975 |	expr '%' expr
976 	{
977 		$$ = $1 % $3;
978 	}
979 |	expr '<' '<' expr
980 	{
981 		$$ = $1 << $4;
982 	}
983 |	expr '>' '>' expr
984 	{
985 		$$ = $1 >> $4;
986 	}
987 |	expr '&' expr
988 	{
989 		$$ = $1 & $3;
990 	}
991 |	expr '^' expr
992 	{
993 		$$ = $1 ^ $3;
994 	}
995 |	expr '|' expr
996 	{
997 		$$ = $1 | $3;
998 	}
999