| // Inferno utils/6a/a.y |
| // http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y |
| // |
| // 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-2007 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-2007 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 <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */ |
| #include "a.h" |
| %} |
| %union { |
| Sym *sym; |
| vlong lval; |
| double dval; |
| char sval[8]; |
| Gen gen; |
| Gen2 gen2; |
| } |
| %left '|' |
| %left '^' |
| %left '&' |
| %left '<' '>' |
| %left '+' '-' |
| %left '*' '/' '%' |
| %token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 |
| %token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG |
| %token <lval> LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT |
| %token <lval> LCONST LFP LPC LSB |
| %token <lval> LBREG LLREG LSREG LFREG LMREG LXREG |
| %token <dval> LFCONST |
| %token <sval> LSCONST LSP |
| %token <sym> LNAME LLAB LVAR |
| %type <lval> con con2 expr pointer offset |
| %type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem |
| %type <gen2> nonnon nonrel nonrem rimnon rimrem remrim spec10 spec11 |
| %type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 |
| %% |
| prog: |
| | prog line |
| |
| line: |
| LLAB ':' |
| { |
| if($1->value != pc) |
| yyerror("redeclaration of %s", $1->name); |
| $1->value = pc; |
| } |
| line |
| | LNAME ':' |
| { |
| $1->type = LLAB; |
| $1->value = pc; |
| } |
| line |
| | ';' |
| | inst ';' |
| | error ';' |
| |
| inst: |
| LNAME '=' expr |
| { |
| $1->type = LVAR; |
| $1->value = $3; |
| } |
| | LVAR '=' expr |
| { |
| if($1->value != $3) |
| yyerror("redeclaration of %s", $1->name); |
| $1->value = $3; |
| } |
| | LTYPE0 nonnon { outcode($1, &$2); } |
| | LTYPE1 nonrem { outcode($1, &$2); } |
| | LTYPE2 rimnon { outcode($1, &$2); } |
| | LTYPE3 rimrem { outcode($1, &$2); } |
| | LTYPE4 remrim { outcode($1, &$2); } |
| | LTYPER nonrel { outcode($1, &$2); } |
| | LTYPED spec1 { outcode($1, &$2); } |
| | LTYPET spec2 { outcode($1, &$2); } |
| | LTYPEC spec3 { outcode($1, &$2); } |
| | LTYPEN spec4 { outcode($1, &$2); } |
| | LTYPES spec5 { outcode($1, &$2); } |
| | LTYPEM spec6 { outcode($1, &$2); } |
| | LTYPEI spec7 { outcode($1, &$2); } |
| | LTYPEXC spec8 { outcode($1, &$2); } |
| | LTYPEX spec9 { outcode($1, &$2); } |
| | LTYPERT spec10 { outcode($1, &$2); } |
| | LTYPEG spec11 { outcode($1, &$2); } |
| |
| nonnon: |
| { |
| $$.from = nullgen; |
| $$.to = nullgen; |
| } |
| | ',' |
| { |
| $$.from = nullgen; |
| $$.to = nullgen; |
| } |
| |
| rimrem: |
| rim ',' rem |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| |
| remrim: |
| rem ',' rim |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| |
| rimnon: |
| rim ',' |
| { |
| $$.from = $1; |
| $$.to = nullgen; |
| } |
| | rim |
| { |
| $$.from = $1; |
| $$.to = nullgen; |
| } |
| |
| nonrem: |
| ',' rem |
| { |
| $$.from = nullgen; |
| $$.to = $2; |
| } |
| | rem |
| { |
| $$.from = nullgen; |
| $$.to = $1; |
| } |
| |
| nonrel: |
| ',' rel |
| { |
| $$.from = nullgen; |
| $$.to = $2; |
| } |
| | rel |
| { |
| $$.from = nullgen; |
| $$.to = $1; |
| } |
| |
| spec1: /* DATA */ |
| nam '/' con ',' imm |
| { |
| $$.from = $1; |
| $$.from.scale = $3; |
| $$.to = $5; |
| } |
| |
| spec2: /* TEXT */ |
| mem ',' imm2 |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| | mem ',' con ',' imm2 |
| { |
| $$.from = $1; |
| $$.from.scale = $3; |
| $$.to = $5; |
| } |
| |
| spec3: /* JMP/CALL */ |
| ',' rom |
| { |
| $$.from = nullgen; |
| $$.to = $2; |
| } |
| | rom |
| { |
| $$.from = nullgen; |
| $$.to = $1; |
| } |
| |
| spec4: /* NOP */ |
| nonnon |
| | nonrem |
| |
| spec5: /* SHL/SHR */ |
| rim ',' rem |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| | rim ',' rem ':' LLREG |
| { |
| $$.from = $1; |
| $$.to = $3; |
| if($$.from.index != D_NONE) |
| yyerror("dp shift with lhs index"); |
| $$.from.index = $5; |
| } |
| |
| spec6: /* MOVW/MOVL */ |
| rim ',' rem |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| | rim ',' rem ':' LSREG |
| { |
| $$.from = $1; |
| $$.to = $3; |
| if($$.to.index != D_NONE) |
| yyerror("dp move with lhs index"); |
| $$.to.index = $5; |
| } |
| |
| spec7: |
| rim ',' |
| { |
| $$.from = $1; |
| $$.to = nullgen; |
| } |
| | rim |
| { |
| $$.from = $1; |
| $$.to = nullgen; |
| } |
| | rim ',' rem |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| |
| spec8: /* CMPPS/CMPPD */ |
| reg ',' rem ',' con |
| { |
| $$.from = $1; |
| $$.to = $3; |
| $$.to.offset = $5; |
| } |
| |
| spec9: /* shufl */ |
| imm ',' rem ',' reg |
| { |
| $$.from = $3; |
| $$.to = $5; |
| if($1.type != D_CONST) |
| yyerror("illegal constant"); |
| $$.to.offset = $1.offset; |
| } |
| |
| spec10: /* RET/RETF */ |
| { |
| $$.from = nullgen; |
| $$.to = nullgen; |
| } |
| | imm |
| { |
| $$.from = $1; |
| $$.to = nullgen; |
| } |
| |
| spec11: /* GLOBL */ |
| mem ',' imm |
| { |
| $$.from = $1; |
| $$.to = $3; |
| } |
| | mem ',' con ',' imm |
| { |
| $$.from = $1; |
| $$.from.scale = $3; |
| $$.to = $5; |
| } |
| |
| rem: |
| reg |
| | mem |
| |
| rom: |
| rel |
| | nmem |
| | '*' reg |
| { |
| $$ = $2; |
| } |
| | '*' omem |
| { |
| $$ = $2; |
| } |
| | reg |
| | omem |
| |
| rim: |
| rem |
| | imm |
| |
| rel: |
| con '(' LPC ')' |
| { |
| $$ = nullgen; |
| $$.type = D_BRANCH; |
| $$.offset = $1 + pc; |
| } |
| | LNAME offset |
| { |
| $$ = nullgen; |
| if(pass == 2) |
| yyerror("undefined label: %s", $1->name); |
| $$.type = D_BRANCH; |
| $$.sym = $1; |
| $$.offset = $2; |
| } |
| | LLAB offset |
| { |
| $$ = nullgen; |
| $$.type = D_BRANCH; |
| $$.sym = $1; |
| $$.offset = $1->value + $2; |
| } |
| |
| reg: |
| LBREG |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| } |
| | LFREG |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| } |
| | LLREG |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| } |
| | LMREG |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| } |
| | LSP |
| { |
| $$ = nullgen; |
| $$.type = D_SP; |
| } |
| | LSREG |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| } |
| | LXREG |
| { |
| $$ = nullgen; |
| $$.type = $1; |
| } |
| imm2: |
| '$' con2 |
| { |
| $$ = nullgen; |
| $$.type = D_CONST; |
| $$.offset = $2; |
| } |
| |
| imm: |
| '$' con |
| { |
| $$ = nullgen; |
| $$.type = D_CONST; |
| $$.offset = $2; |
| } |
| | '$' nam |
| { |
| $$ = $2; |
| $$.index = $2.type; |
| $$.type = D_ADDR; |
| /* |
| if($2.type == D_AUTO || $2.type == D_PARAM) |
| yyerror("constant cannot be automatic: %s", |
| $2.sym->name); |
| */ |
| } |
| | '$' LSCONST |
| { |
| $$ = nullgen; |
| $$.type = D_SCONST; |
| memcpy($$.sval, $2, sizeof($$.sval)); |
| } |
| | '$' LFCONST |
| { |
| $$ = nullgen; |
| $$.type = D_FCONST; |
| $$.dval = $2; |
| } |
| | '$' '(' LFCONST ')' |
| { |
| $$ = nullgen; |
| $$.type = D_FCONST; |
| $$.dval = $3; |
| } |
| | '$' '-' LFCONST |
| { |
| $$ = nullgen; |
| $$.type = D_FCONST; |
| $$.dval = -$3; |
| } |
| |
| mem: |
| omem |
| | nmem |
| |
| omem: |
| con |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+D_NONE; |
| $$.offset = $1; |
| } |
| | con '(' LLREG ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+$3; |
| $$.offset = $1; |
| } |
| | con '(' LSP ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+D_SP; |
| $$.offset = $1; |
| } |
| | con '(' LLREG '*' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+D_NONE; |
| $$.offset = $1; |
| $$.index = $3; |
| $$.scale = $5; |
| checkscale($$.scale); |
| } |
| | con '(' LLREG ')' '(' LLREG '*' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+$3; |
| $$.offset = $1; |
| $$.index = $6; |
| $$.scale = $8; |
| checkscale($$.scale); |
| } |
| | '(' LLREG ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+$2; |
| } |
| | '(' LSP ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+D_SP; |
| } |
| | '(' LLREG '*' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+D_NONE; |
| $$.index = $2; |
| $$.scale = $4; |
| checkscale($$.scale); |
| } |
| | '(' LLREG ')' '(' LLREG '*' con ')' |
| { |
| $$ = nullgen; |
| $$.type = D_INDIR+$2; |
| $$.index = $5; |
| $$.scale = $7; |
| checkscale($$.scale); |
| } |
| |
| nmem: |
| nam |
| { |
| $$ = $1; |
| } |
| | nam '(' LLREG '*' con ')' |
| { |
| $$ = $1; |
| $$.index = $3; |
| $$.scale = $5; |
| checkscale($$.scale); |
| } |
| |
| nam: |
| LNAME offset '(' pointer ')' |
| { |
| $$ = nullgen; |
| $$.type = $4; |
| $$.sym = $1; |
| $$.offset = $2; |
| } |
| | LNAME '<' '>' offset '(' LSB ')' |
| { |
| $$ = nullgen; |
| $$.type = D_STATIC; |
| $$.sym = $1; |
| $$.offset = $4; |
| } |
| |
| offset: |
| { |
| $$ = 0; |
| } |
| | '+' con |
| { |
| $$ = $2; |
| } |
| | '-' con |
| { |
| $$ = -$2; |
| } |
| |
| pointer: |
| LSB |
| | LSP |
| { |
| $$ = D_AUTO; |
| } |
| | LFP |
| |
| con: |
| LCONST |
| | LVAR |
| { |
| $$ = $1->value; |
| } |
| | '-' con |
| { |
| $$ = -$2; |
| } |
| | '+' con |
| { |
| $$ = $2; |
| } |
| | '~' con |
| { |
| $$ = ~$2; |
| } |
| | '(' expr ')' |
| { |
| $$ = $2; |
| } |
| |
| con2: |
| LCONST |
| { |
| $$ = $1 & 0xffffffffLL; |
| } |
| | '-' LCONST |
| { |
| $$ = -$2 & 0xffffffffLL; |
| } |
| | LCONST '-' LCONST |
| { |
| $$ = ($1 & 0xffffffffLL) + |
| (($3 & 0xffffLL) << 32); |
| } |
| | '-' LCONST '-' LCONST |
| { |
| $$ = (-$2 & 0xffffffffLL) + |
| (($4 & 0xffffLL) << 32); |
| } |
| |
| 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; |
| } |