ref: f88a55e79b5bf656e7f9578d1318a955b9a4963a
dir: /sys/src/cmd/ja/a.y/
%{ #include "a.h" %} %union { Sym *sym; vlong lval; double dval; char sval[8]; Gen gen; } %left '|' %left '^' %left '&' %left '<' '>' %left '+' '-' %left '*' '/' '%' %token <lval> LADD LMUL LBEQ LBR LBRET LCALL LFLT2 LFLT3 %token <lval> LMOVB LMOVBU LMOVW LMOVF LLUI LSYS LSYS0 LCSR LSWAP LAMO %token <lval> LCONST LSP LSB LFP LPC LREG LFREG LR FR LCTL %token <lval> LDATA LTEXT LWORD %token <sval> LSCONST %token <dval> LFCONST %token <sym> LNAME LLAB LVAR %type <lval> con expr pointer offset sreg freg oprrr %type <gen> rreg dreg ctlreg drreg %type <gen> addr name oreg rel imm ximm fimm %% 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 | LNAME '=' expr ';' { $1->type = LVAR; $1->value = $3; } | LVAR '=' expr ';' { if($1->value != $3) yyerror("redeclaration of %s", $1->name); $1->value = $3; } | ';' | inst ';' | error ';' inst: LADD imm ',' rreg { outcode($1, &$2, NREG, &$4); } | oprrr rreg ',' rreg { outcode($1, &$2, NREG, &$4); } | LADD imm ',' sreg ',' rreg { outcode($1, &$2, $4, &$6); } | oprrr rreg ',' sreg ',' rreg { outcode($1, &$2, $4, &$6); } | LFLT2 drreg ',' drreg { outcode($1, &$2, NREG, &$4); } | LFLT3 drreg ',' freg ',' drreg { outcode($1, &$2, $4, &$6); } | LBEQ rreg ',' sreg ',' rel { outcode($1, &$2, $4, &$6); } | LBEQ rreg ',' rel { Gen regzero; regzero = nullgen; regzero.type = D_REG; regzero.reg = 0; outcode($1, ®zero, $2.reg, &$4); } | LBR rel { outcode($1, &nullgen, NREG, &$2); } | LBR oreg { outcode($1, &nullgen, NREG, &$2); } | LBRET { outcode($1, &nullgen, NREG, &nullgen); } | LCALL sreg ',' addr { outcode($1, &nullgen, $2, &$4); } | LCALL sreg ',' rel { outcode($1, &nullgen, $2, &$4); } | LMOVB addr ',' rreg { outcode($1, &$2, NREG, &$4); } | LMOVBU addr ',' rreg { outcode($1, &$2, NREG, &$4); } | LMOVB rreg ',' addr { outcode($1, &$2, NREG, &$4); } | LMOVF addr ',' dreg { outcode($1, &$2, NREG, &$4); } | LMOVF dreg ',' addr { outcode($1, &$2, NREG, &$4); } | LMOVF dreg ',' dreg { outcode($1, &$2, NREG, &$4); } | LMOVW imm ',' rreg { outcode($1, &$2, NREG, &$4); } | LMOVW ximm ',' rreg { outcode($1, &$2, NREG, &$4); } | LMOVW rreg ',' rreg { outcode($1, &$2, NREG, &$4); } | LMOVW addr ',' rreg { outcode($1, &$2, NREG, &$4); } | LMOVW rreg ',' addr { outcode($1, &$2, NREG, &$4); } | LMOVW rreg ',' ctlreg { Gen regzero; regzero = nullgen; regzero.type = D_REG; regzero.reg = 0; outcode(ACSRRW, &$4, $2.reg, ®zero); } | LMOVW imm ',' ctlreg { Gen regzero; int r = $2.offset; if(r < 0 || r >= NREG) yyerror("immediate value out of range"); regzero = nullgen; regzero.type = D_REG; regzero.reg = 0; outcode(ACSRRWI, &$4, r, ®zero); } | LMOVW ctlreg ',' rreg { outcode(ACSRRS, &$2, REGZERO, &$4); } | LLUI name ',' rreg { outcode($1, &$2, NREG, &$4); } | LLUI imm ',' rreg { outcode($1, &$2, NREG, &$4); } | LSYS imm { outcode($1, &nullgen, NREG, &$2); } | LSYS0 { Gen syscon; syscon = nullgen; syscon.type = D_CONST; syscon.offset = $1; outcode(ASYS, &nullgen, NREG, &syscon); } | LCSR ctlreg ',' sreg ',' rreg { outcode($1, &$2, $4, &$6); } | LCSR ctlreg ',' '$' con ',' rreg { if($5 < 0 || $5 >= NREG) yyerror("immediate value out of range"); outcode($1 + (ACSRRWI-ACSRRW), &$2, $5, &$7); } | LSWAP rreg ',' sreg ',' rreg { outcode($1, &$2, $4, &$6); } | LAMO con ',' rreg ',' sreg ',' rreg { outcode($1, &$4, ($2<<16)|$6, &$8); } | LTEXT name ',' imm { outcode($1, &$2, NREG, &$4); } | LTEXT name ',' con ',' imm { outcode($1, &$2, $4, &$6); } | 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); } | LWORD imm { outcode($1, &nullgen, NREG, &$2); } 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; } oprrr: LADD | LMUL addr: oreg | name oreg: '(' sreg ')' { $$ = nullgen; $$.type = D_OREG; $$.reg = $2; $$.offset = 0; } | con '(' sreg ')' { $$ = nullgen; $$.type = D_OREG; $$.reg = $3; $$.offset = $1; } name: con '(' pointer ')' { $$ = nullgen; $$.type = D_OREG; $$.name = $3; $$.sym = S; $$.offset = $1; } | LNAME offset '(' pointer ')' { $$ = nullgen; $$.type = D_OREG; $$.name = $4; $$.sym = $1; $$.offset = $2; } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; $$.type = D_OREG; $$.name = D_STATIC; $$.sym = $1; $$.offset = $4; } offset: { $$ = 0; } | '+' con { $$ = $2; } | '-' con { $$ = -$2; } pointer: LSB | LSP | LFP rreg: sreg { $$ = nullgen; $$.type = D_REG; $$.reg = $1; } dreg: freg { $$ = nullgen; $$.type = D_FREG; $$.reg = $1; } drreg: dreg | rreg sreg: LREG | LR '(' expr ')' { if($3 < 0 || $3 >= NREG) yyerror("register value out of range"); $$ = $3; } freg: LFREG | FR '(' expr ')' { if($3 < 0 || $3 >= NREG) yyerror("register value out of range"); $$ = $3; } ctlreg: LCTL '(' expr ')' { if($3 < 0 || $3 >= 0xFFF) yyerror("CSR value out of range"); $$ = nullgen; $$.type = D_CTLREG; $$.offset = $3; } ximm: '$' addr { $$ = $2; $$.type = D_CONST; } | '$' LSCONST { $$ = nullgen; $$.type = D_SCONST; memcpy($$.sval, $2, sizeof($$.sval)); } fimm: '$' LFCONST { $$ = nullgen; $$.type = D_FCONST; $$.dval = $2; } | '$' '-' LFCONST { $$ = nullgen; $$.type = D_FCONST; $$.dval = -$3; } imm: '$' con { $$ = nullgen; $$.type = D_CONST; $$.offset = $2; if(thechar == 'j' && (vlong)$$.offset != $2){ $$.type = D_VCONST; $$.vval = $2; } } 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; }