| // cmd/9a/a.y from Vita Nuova. |
| // |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
| // Portions Copyright © 1997-1999 Vita Nuova Limited |
| // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) |
| // Portions Copyright © 2004,2006 Bruce Ellis |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
| // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| %{ |
| #include <u.h> |
| #include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */ |
| #include <libc.h> |
| #include "a.h" |
| #include "../../runtime/funcdata.h" |
| %} |
| %union |
| { |
| Sym *sym; |
| vlong lval; |
| double dval; |
| char sval[8]; |
| Addr addr; |
| } |
| %left '|' |
| %left '^' |
| %left '&' |
| %left '<' '>' |
| %left '+' '-' |
| %left '*' '/' '%' |
| %token <lval> LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP |
| %token <lval> LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW |
| %token <lval> LNOP LEND LRETT LWORD LTEXT LDATA LRETRN |
| %token <lval> LCONST LSP LSB LFP LPC LCREG LFLUSH |
| %token <lval> LREG LFREG LR LCR LF LFPSCR |
| %token <lval> LLR LCTR LSPR LSPREG LSEG LMSR |
| %token <lval> LPCDAT LFUNCDAT LSCHED LXLD LXST LXOP LXMV |
| %token <lval> LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA |
| %token <dval> LFCONST |
| %token <sval> LSCONST |
| %token <sym> LNAME LLAB LVAR |
| %type <lval> con expr pointer offset sreg |
| %type <addr> addr rreg regaddr name creg freg xlreg lr ctr |
| %type <addr> imm ximm fimm rel psr lcr cbit fpscr fpscrf msr mask |
| %% |
| prog: |
| | prog line |
| |
| line: |
| LNAME ':' |
| { |
| $1 = labellookup($1); |
| if($1->type == LLAB && $1->value != pc) |
| yyerror("redeclaration of %s", $1->labelname); |
| $1->type = LLAB; |
| $1->value = pc; |
| } |
| line |
| | LNAME '=' expr ';' |
| { |
| $1->type = LVAR; |
| $1->value = $3; |
| } |
| | LVAR '=' expr ';' |
| { |
| if($1->value != $3) |
| yyerror("redeclaration of %s", $1->name); |
| $1->value = $3; |
| } |
| | LSCHED ';' |
| { |
| nosched = $1; |
| } |
| | ';' |
| | inst ';' |
| | error ';' |
| |
| inst: |
| /* |
| * load ints and bytes |
| */ |
| LMOVW rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW addr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW regaddr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVB rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVB addr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVB regaddr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * load floats |
| */ |
| | LFMOV addr ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFMOV regaddr ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFMOV fimm ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFMOV freg ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFMOV freg ',' addr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFMOV freg ',' regaddr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * store ints and bytes |
| */ |
| | LMOVW rreg ',' addr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW rreg ',' regaddr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVB rreg ',' addr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVB rreg ',' regaddr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * store floats |
| */ |
| | LMOVW freg ',' addr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW freg ',' regaddr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * floating point status |
| */ |
| | LMOVW fpscr ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW freg ',' fpscr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW freg ',' imm ',' fpscr |
| { |
| outgcode($1, &$2, NREG, &$4, &$6); |
| } |
| | LMOVW fpscr ',' creg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW imm ',' fpscrf |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMTFSB imm ',' con |
| { |
| outcode($1, &$2, $4, &nullgen); |
| } |
| /* |
| * field moves (mtcrf) |
| */ |
| | LMOVW rreg ',' imm ',' lcr |
| { |
| outgcode($1, &$2, NREG, &$4, &$6); |
| } |
| | LMOVW rreg ',' creg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW rreg ',' lcr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * integer operations |
| * logical instructions |
| * shift instructions |
| * unary instructions |
| */ |
| | LADDW rreg ',' sreg ',' rreg |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LADDW imm ',' sreg ',' rreg |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LADDW rreg ',' imm ',' rreg |
| { |
| outgcode($1, &$2, NREG, &$4, &$6); |
| } |
| | LADDW rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LADDW imm ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LLOGW rreg ',' sreg ',' rreg |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LLOGW rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LSHW rreg ',' sreg ',' rreg |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LSHW rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LSHW imm ',' sreg ',' rreg |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LSHW imm ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LABS rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LABS rreg |
| { |
| outcode($1, &$2, NREG, &$2); |
| } |
| /* |
| * multiply-accumulate |
| */ |
| | LMA rreg ',' sreg ',' rreg |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| /* |
| * move immediate: macro for cau+or, addi, addis, and other combinations |
| */ |
| | LMOVW imm ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW ximm ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * condition register operations |
| */ |
| | LCROP cbit ',' cbit |
| { |
| outcode($1, &$2, $4.reg, &$4); |
| } |
| | LCROP cbit ',' con ',' cbit |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| /* |
| * condition register moves |
| * move from machine state register |
| */ |
| | LMOVW creg ',' creg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW psr ',' creg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW lcr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW psr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW xlreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW rreg ',' xlreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW creg ',' psr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVW rreg ',' psr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * branch, branch conditional |
| * branch conditional register |
| * branch conditional to count register |
| */ |
| | LBRA rel |
| { |
| outcode($1, &nullgen, NREG, &$2); |
| } |
| | LBRA addr |
| { |
| outcode($1, &nullgen, NREG, &$2); |
| } |
| | LBRA '(' xlreg ')' |
| { |
| outcode($1, &nullgen, NREG, &$3); |
| } |
| | LBRA ',' rel |
| { |
| outcode($1, &nullgen, NREG, &$3); |
| } |
| | LBRA ',' addr |
| { |
| outcode($1, &nullgen, NREG, &$3); |
| } |
| | LBRA ',' '(' xlreg ')' |
| { |
| outcode($1, &nullgen, NREG, &$4); |
| } |
| | LBRA creg ',' rel |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LBRA creg ',' addr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LBRA creg ',' '(' xlreg ')' |
| { |
| outcode($1, &$2, NREG, &$5); |
| } |
| | LBRA con ',' rel |
| { |
| outcode($1, &nullgen, $2, &$4); |
| } |
| | LBRA con ',' addr |
| { |
| outcode($1, &nullgen, $2, &$4); |
| } |
| | LBRA con ',' '(' xlreg ')' |
| { |
| outcode($1, &nullgen, $2, &$5); |
| } |
| | LBRA con ',' con ',' rel |
| { |
| Addr g; |
| g = nullgen; |
| g.type = D_CONST; |
| g.offset = $2; |
| outcode($1, &g, $4, &$6); |
| } |
| | LBRA con ',' con ',' addr |
| { |
| Addr g; |
| g = nullgen; |
| g.type = D_CONST; |
| g.offset = $2; |
| outcode($1, &g, $4, &$6); |
| } |
| | LBRA con ',' con ',' '(' xlreg ')' |
| { |
| Addr g; |
| g = nullgen; |
| g.type = D_CONST; |
| g.offset = $2; |
| outcode($1, &g, $4, &$7); |
| } |
| /* |
| * conditional trap |
| */ |
| | LTRAP rreg ',' sreg |
| { |
| outcode($1, &$2, $4, &nullgen); |
| } |
| | LTRAP imm ',' sreg |
| { |
| outcode($1, &$2, $4, &nullgen); |
| } |
| | LTRAP rreg comma |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| | LTRAP comma |
| { |
| outcode($1, &nullgen, NREG, &nullgen); |
| } |
| /* |
| * floating point operate |
| */ |
| | LFCONV freg ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFADD freg ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFADD freg ',' freg ',' freg |
| { |
| outcode($1, &$2, $4.reg, &$6); |
| } |
| | LFMA freg ',' freg ',' freg ',' freg |
| { |
| outgcode($1, &$2, $4.reg, &$6, &$8); |
| } |
| | LFCMP freg ',' freg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LFCMP freg ',' freg ',' creg |
| { |
| outcode($1, &$2, $6.reg, &$4); |
| } |
| /* |
| * CMP |
| */ |
| | LCMP rreg ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LCMP rreg ',' imm |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LCMP rreg ',' rreg ',' creg |
| { |
| outcode($1, &$2, $6.reg, &$4); |
| } |
| | LCMP rreg ',' imm ',' creg |
| { |
| outcode($1, &$2, $6.reg, &$4); |
| } |
| /* |
| * rotate and mask |
| */ |
| | LRLWM imm ',' rreg ',' imm ',' rreg |
| { |
| outgcode($1, &$2, $4.reg, &$6, &$8); |
| } |
| | LRLWM imm ',' rreg ',' mask ',' rreg |
| { |
| outgcode($1, &$2, $4.reg, &$6, &$8); |
| } |
| | LRLWM rreg ',' rreg ',' imm ',' rreg |
| { |
| outgcode($1, &$2, $4.reg, &$6, &$8); |
| } |
| | LRLWM rreg ',' rreg ',' mask ',' rreg |
| { |
| outgcode($1, &$2, $4.reg, &$6, &$8); |
| } |
| /* |
| * load/store multiple |
| */ |
| | LMOVMW addr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LMOVMW rreg ',' addr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * various indexed load/store |
| * indexed unary (eg, cache clear) |
| */ |
| | LXLD regaddr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LXLD regaddr ',' imm ',' rreg |
| { |
| outgcode($1, &$2, NREG, &$4, &$6); |
| } |
| | LXST rreg ',' regaddr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LXST rreg ',' imm ',' regaddr |
| { |
| outgcode($1, &$2, NREG, &$4, &$6); |
| } |
| | LXMV regaddr ',' rreg |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LXMV rreg ',' regaddr |
| { |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LXOP regaddr |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| /* |
| * NOP |
| */ |
| | LNOP comma |
| { |
| outcode($1, &nullgen, NREG, &nullgen); |
| } |
| | LNOP rreg comma |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| | LNOP freg comma |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| | LNOP ',' rreg |
| { |
| outcode($1, &nullgen, NREG, &$3); |
| } |
| | LNOP ',' freg |
| { |
| outcode($1, &nullgen, NREG, &$3); |
| } |
| | LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */ |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| /* |
| * word |
| */ |
| | LWORD imm comma |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| | LWORD ximm comma |
| { |
| outcode($1, &$2, NREG, &nullgen); |
| } |
| /* |
| * PCDATA |
| */ |
| | LPCDAT imm ',' imm |
| { |
| if($2.type != D_CONST || $4.type != D_CONST) |
| yyerror("arguments to PCDATA must be integer constants"); |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * FUNCDATA |
| */ |
| | LFUNCDAT imm ',' addr |
| { |
| if($2.type != D_CONST) |
| yyerror("index for FUNCDATA must be integer constant"); |
| if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG) |
| yyerror("value for FUNCDATA must be symbol reference"); |
| outcode($1, &$2, NREG, &$4); |
| } |
| /* |
| * END |
| */ |
| | LEND comma |
| { |
| outcode($1, &nullgen, NREG, &nullgen); |
| } |
| /* |
| * TEXT/GLOBL |
| */ |
| | LTEXT name ',' imm |
| { |
| settext($2.sym); |
| outcode($1, &$2, NREG, &$4); |
| } |
| | LTEXT name ',' con ',' imm |
| { |
| settext($2.sym); |
| $6.offset &= 0xffffffffull; |
| $6.offset |= (vlong)ArgsSizeUnknown << 32; |
| outcode($1, &$2, $4, &$6); |
| } |
| | LTEXT name ',' con ',' imm '-' con |
| { |
| settext($2.sym); |
| $6.offset &= 0xffffffffull; |
| $6.offset |= ($8 & 0xffffffffull) << 32; |
| outcode($1, &$2, $4, &$6); |
| } |
| /* |
| * DATA |
| */ |
| | LDATA name '/' con ',' imm |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LDATA name '/' con ',' ximm |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| | LDATA name '/' con ',' fimm |
| { |
| outcode($1, &$2, $4, &$6); |
| } |
| /* |
| * RETURN |
| */ |
| | LRETRN comma |
| { |
| outcode($1, &nullgen, NREG, &nullgen); |
| } |
| |
| rel: |
| con '(' LPC ')' |
| { |
| $$ = nullgen; |
| $$.type = D_BRANCH; |
| $$.offset = $1 + pc; |
| } |
| | LNAME offset |
| { |
| $1 = labellookup($1); |
| $$ = nullgen; |
| if(pass == 2 && $1->type != LLAB) |
| yyerror("undefined label: %s", $1->labelname); |
| $$.type = D_BRANCH; |
| $$.offset = $1->value + $2; |
| } |
| |
| rreg: |
| sreg |
| { |
| $$ = nullgen; |
| $$.type = D_REG; |
| $$.reg = $1; |
| } |
| |
| xlreg: |
| lr |
| | ctr |
| |
| lr: |
| LLR |
| { |
| $$ = nullgen; |
| $$.type = D_SPR; |
| $$.offset = $1; |
| } |
| |
| lcr: |
| LCR |
| { |
| $$ = nullgen; |
| $$.type = D_CREG; |
| $$.reg = NREG; /* whole register */ |
| } |
| |
| ctr: |
| LCTR |
| { |
| $$ = nullgen; |
| $$.type = D_SPR; |
| $$.offset = $1; |
| } |
| |
| msr: |
| LMSR |
| { |
| $$ = nullgen; |
| $$.type = D_MSR; |
| } |
| |
| psr: |
| LSPREG |
| { |
| $$ = nullgen; |
| $$.type = D_SPR; |
| $$.offset = $1; |
| } |
| | LSPR '(' con ')' |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| $$.offset = $3; |
| } |
| | msr |
| |
| fpscr: |
| LFPSCR |
| { |
| $$ = nullgen; |
| $$.type = D_FPSCR; |
| $$.reg = NREG; |
| } |
| |
| fpscrf: |
| LFPSCR '(' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_FPSCR; |
| $$.reg = $3; |
| } |
| |
| freg: |
| LFREG |
| { |
| $$ = nullgen; |
| $$.type = D_FREG; |
| $$.reg = $1; |
| } |
| | LF '(' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_FREG; |
| $$.reg = $3; |
| } |
| |
| creg: |
| LCREG |
| { |
| $$ = nullgen; |
| $$.type = D_CREG; |
| $$.reg = $1; |
| } |
| | LCR '(' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_CREG; |
| $$.reg = $3; |
| } |
| |
| |
| cbit: con |
| { |
| $$ = nullgen; |
| $$.type = D_REG; |
| $$.reg = $1; |
| } |
| |
| mask: |
| con ',' con |
| { |
| int mb, me; |
| uint32 v; |
| |
| $$ = nullgen; |
| $$.type = D_CONST; |
| mb = $1; |
| me = $3; |
| if(mb < 0 || mb > 31 || me < 0 || me > 31){ |
| yyerror("illegal mask start/end value(s)"); |
| mb = me = 0; |
| } |
| if(mb <= me) |
| v = ((uint32)~0L>>mb) & (~0L<<(31-me)); |
| else |
| v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1)))); |
| $$.offset = v; |
| } |
| |
| ximm: |
| '$' addr |
| { |
| $$ = $2; |
| $$.type = D_CONST; |
| } |
| | '$' LSCONST |
| { |
| $$ = nullgen; |
| $$.type = D_SCONST; |
| memcpy($$.u.sval, $2, sizeof($$.u.sval)); |
| } |
| |
| fimm: |
| '$' LFCONST |
| { |
| $$ = nullgen; |
| $$.type = D_FCONST; |
| $$.u.dval = $2; |
| } |
| | '$' '-' LFCONST |
| { |
| $$ = nullgen; |
| $$.type = D_FCONST; |
| $$.u.dval = -$3; |
| } |
| |
| imm: '$' con |
| { |
| $$ = nullgen; |
| $$.type = D_CONST; |
| $$.offset = $2; |
| } |
| |
| sreg: |
| LREG |
| | LR '(' con ')' |
| { |
| if($$ < 0 || $$ >= NREG) |
| print("register value out of range\n"); |
| $$ = $3; |
| } |
| |
| regaddr: |
| '(' sreg ')' |
| { |
| $$ = nullgen; |
| $$.type = D_OREG; |
| $$.reg = $2; |
| $$.offset = 0; |
| } |
| | '(' sreg '+' sreg ')' |
| { |
| $$ = nullgen; |
| $$.type = D_OREG; |
| $$.reg = $2; |
| $$.scale = $4; |
| $$.offset = 0; |
| } |
| |
| addr: |
| name |
| | con '(' sreg ')' |
| { |
| $$ = nullgen; |
| $$.type = D_OREG; |
| $$.reg = $3; |
| $$.offset = $1; |
| } |
| |
| name: |
| con '(' pointer ')' |
| { |
| $$ = nullgen; |
| $$.type = D_OREG; |
| $$.name = $3; |
| $$.sym = nil; |
| $$.offset = $1; |
| } |
| | LNAME offset '(' pointer ')' |
| { |
| $$ = nullgen; |
| $$.type = D_OREG; |
| $$.name = $4; |
| $$.sym = linklookup(ctxt, $1->name, 0); |
| $$.offset = $2; |
| } |
| | LNAME '<' '>' offset '(' LSB ')' |
| { |
| $$ = nullgen; |
| $$.type = D_OREG; |
| $$.name = D_STATIC; |
| $$.sym = linklookup(ctxt, $1->name, 0); |
| $$.offset = $4; |
| } |
| |
| comma: |
| | ',' |
| |
| offset: |
| { |
| $$ = 0; |
| } |
| | '+' con |
| { |
| $$ = $2; |
| } |
| | '-' con |
| { |
| $$ = -$2; |
| } |
| |
| pointer: |
| LSB |
| | LSP |
| | LFP |
| |
| con: |
| LCONST |
| | LVAR |
| { |
| $$ = $1->value; |
| } |
| | '-' con |
| { |
| $$ = -$2; |
| } |
| | '+' con |
| { |
| $$ = $2; |
| } |
| | '~' con |
| { |
| $$ = ~$2; |
| } |
| | '(' expr ')' |
| { |
| $$ = $2; |
| } |
| |
| expr: |
| con |
| | expr '+' expr |
| { |
| $$ = $1 + $3; |
| } |
| | expr '-' expr |
| { |
| $$ = $1 - $3; |
| } |
| | expr '*' expr |
| { |
| $$ = $1 * $3; |
| } |
| | expr '/' expr |
| { |
| $$ = $1 / $3; |
| } |
| | expr '%' expr |
| { |
| $$ = $1 % $3; |
| } |
| | expr '<' '<' expr |
| { |
| $$ = $1 << $4; |
| } |
| | expr '>' '>' expr |
| { |
| $$ = $1 >> $4; |
| } |
| | expr '&' expr |
| { |
| $$ = $1 & $3; |
| } |
| | expr '^' expr |
| { |
| $$ = $1 ^ $3; |
| } |
| | expr '|' expr |
| { |
| $$ = $1 | $3; |
| } |