%{
#include <u.h>
#include <stdio.h>
#include <libc.h>
#include "a.h"
#include "../../pkg/runtime/funcdata.h"
%}
%union
{
Sym *sym;
int32 lval;
double dval;
char sval[8];
Addr addr;
}
%left '|'
%left '^'
%left '&'
%left '<' '>'
%left '+' '-'
%left '*' '/' '%'
%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
%token <lval> LTYPEB LTYPEC LTYPED LTYPEE
%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
%token <lval> LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
%token <lval> LCONST LSP LSB LFP LPC
%token <lval> LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR
%token <lval> LCOND LS LAT
%token <dval> LFCONST
%token <sval> LSCONST
%token <sym> LNAME LLAB LVAR
%type <lval> con expr oexpr pointer offset sreg spreg creg
%type <lval> rcon cond reglist
%type <addr> gen rel reg regreg freg shift fcon frcon
%type <addr> imm ximm name oreg ireg nireg ioreg imsr
%%
prog:
| prog
{
stmtline = lineno;
}
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:
LTYPE1 cond imsr ',' spreg ',' reg
{
outcode($1, $2, &$3, $5, &$7);
}
| LTYPE1 cond imsr ',' spreg ','
{
outcode($1, $2, &$3, $5, &nullgen);
}
| LTYPE1 cond imsr ',' reg
{
outcode($1, $2, &$3, NREG, &$5);
}
| LTYPE2 cond imsr ',' reg
{
outcode($1, $2, &$3, NREG, &$5);
}
| LTYPE3 cond gen ',' gen
{
outcode($1, $2, &$3, NREG, &$5);
}
| LTYPE4 cond comma rel
{
outcode($1, $2, &nullgen, NREG, &$4);
}
| LTYPE4 cond comma nireg
{
outcode($1, $2, &nullgen, NREG, &$4);
}
| LTYPEBX comma ireg
{
outcode($1, Always, &nullgen, NREG, &$3);
}
| LTYPE5 comma rel
{
outcode($1, Always, &nullgen, NREG, &$3);
}
| LTYPE6 cond comma gen
{
outcode($1, $2, &nullgen, NREG, &$4);
}
| LTYPE7 cond imsr ',' spreg comma
{
outcode($1, $2, &$3, $5, &nullgen);
}
| LTYPE8 cond ioreg ',' '[' reglist ']'
{
Addr g;
g = nullgen;
g.type = D_CONST;
g.offset = $6;
outcode($1, $2, &$3, NREG, &g);
}
| LTYPE8 cond '[' reglist ']' ',' ioreg
{
Addr g;
g = nullgen;
g.type = D_CONST;
g.offset = $4;
outcode($1, $2, &g, NREG, &$7);
}
| LTYPE9 cond reg ',' ireg ',' reg
{
outcode($1, $2, &$5, $3.reg, &$7);
}
| LTYPE9 cond reg ',' ireg comma
{
outcode($1, $2, &$5, $3.reg, &$3);
}
| LTYPE9 cond comma ireg ',' reg
{
outcode($1, $2, &$4, $6.reg, &$6);
}
| LTYPEA cond comma
{
outcode($1, $2, &nullgen, NREG, &nullgen);
}
| LTYPEB name ',' imm
{
$4.type = D_CONST2;
$4.offset2 = ArgsSizeUnknown;
outcode($1, Always, &$2, 0, &$4);
}
| LTYPEB name ',' con ',' imm
{
$6.type = D_CONST2;
$6.offset2 = ArgsSizeUnknown;
outcode($1, Always, &$2, $4, &$6);
}
| LTYPEB name ',' con ',' imm '-' con
{
$6.type = D_CONST2;
$6.offset2 = $8;
outcode($1, Always, &$2, $4, &$6);
}
| LTYPEC name '/' con ',' ximm
{
outcode($1, Always, &$2, $4, &$6);
}
| LTYPED cond reg comma
{
outcode($1, $2, &$3, NREG, &nullgen);
}
| LTYPEH comma ximm
{
outcode($1, Always, &nullgen, NREG, &$3);
}
| LTYPEI cond freg ',' freg
{
outcode($1, $2, &$3, NREG, &$5);
}
| LTYPEK cond frcon ',' freg
{
outcode($1, $2, &$3, NREG, &$5);
}
| LTYPEK cond frcon ',' LFREG ',' freg
{
outcode($1, $2, &$3, $5, &$7);
}
| LTYPEL cond freg ',' freg comma
{
outcode($1, $2, &$3, $5.reg, &nullgen);
}
| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
{
Addr g;
g = nullgen;
g.type = D_CONST;
g.offset =
(0xe << 24) |
($1 << 20) |
($2 << 28) |
(($3 & 15) << 8) |
(($5 & 7) << 21) |
(($7 & 15) << 12) |
(($9 & 15) << 16) |
(($11 & 15) << 0) |
(($12 & 7) << 5) |
(1<<4);
outcode(AMRC, Always, &nullgen, NREG, &g);
}
| LTYPEM cond reg ',' reg ',' regreg
{
outcode($1, $2, &$3, $5.reg, &$7);
}
| LTYPEN cond reg ',' reg ',' reg ',' spreg
{
$7.type = D_REGREG2;
$7.offset = $9;
outcode($1, $2, &$3, $5.reg, &$7);
}
| LTYPEPLD oreg
{
outcode($1, Always, &$2, NREG, &nullgen);
}
| LTYPEPC gen ',' gen
{
if($2.type != D_CONST || $4.type != D_CONST)
yyerror("arguments to PCDATA must be integer constants");
outcode($1, Always, &$2, NREG, &$4);
}
| LTYPEF gen ',' gen
{
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, Always, &$2, NREG, &$4);
}
| LTYPEE comma
{
outcode($1, Always, &nullgen, NREG, &nullgen);
}
cond:
{
$$ = Always;
}
| cond LCOND
{
$$ = ($1 & ~C_SCOND) | $2;
}
| cond LS
{
$$ = $1 | $2;
}
comma:
| ',' comma
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;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
$$.offset = $1->value + $2;
}
ximm: '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
| '$' oreg
{
$$ = $2;
$$.type = D_CONST;
}
| '$' '*' '$' oreg
{
$$ = $4;
$$.type = D_OCONST;
}
| '$' LSCONST
{
$$ = nullgen;
$$.type = D_SCONST;
memcpy($$.u.sval, $2, sizeof($$.u.sval));
}
| fcon
fcon:
'$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.u.dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.u.dval = -$3;
}
reglist:
spreg
{
$$ = 1 << $1;
}
| spreg '-' spreg
{
int i;
$$=0;
for(i=$1; i<=$3; i++)
$$ |= 1<<i;
for(i=$3; i<=$1; i++)
$$ |= 1<<i;
}
| spreg comma reglist
{
$$ = (1<<$1) | $3;
}
gen:
reg
| ximm
| shift
| shift '(' spreg ')'
{
$$ = $1;
$$.reg = $3;
}
| LPSR
{
$$ = nullgen;
$$.type = D_PSR;
$$.reg = $1;
}
| LFCR
{
$$ = nullgen;
$$.type = D_FPCR;
$$.reg = $1;
}
| con
{
$$ = nullgen;
$$.type = D_OREG;
$$.offset = $1;
}
| oreg
| freg
nireg:
ireg
| name
{
$$ = $1;
if($1.name != D_EXTERN && $1.name != D_STATIC) {
}
}
ireg:
'(' spreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $2;
$$.offset = 0;
}
ioreg:
ireg
| con '(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $3;
$$.offset = $1;
}
oreg:
name
| name '(' sreg ')'
{
$$ = $1;
$$.type = D_OREG;
$$.reg = $3;
}
| ioreg
imsr:
reg
| imm
| shift
imm: '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
reg:
spreg
{
$$ = nullgen;
$$.type = D_REG;
$$.reg = $1;
}
regreg:
'(' spreg ',' spreg ')'
{
$$ = nullgen;
$$.type = D_REGREG;
$$.reg = $2;
$$.offset = $4;
}
shift:
spreg '<' '<' rcon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = $1 | $4 | (0 << 5);
}
| spreg '>' '>' rcon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = $1 | $4 | (1 << 5);
}
| spreg '-' '>' rcon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = $1 | $4 | (2 << 5);
}
| spreg LAT '>' rcon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = $1 | $4 | (3 << 5);
}
rcon:
spreg
{
if($$ < 0 || $$ >= 16)
print("register value out of range\n");
$$ = (($1&15) << 8) | (1 << 4);
}
| con
{
if($$ < 0 || $$ >= 32)
print("shift value out of range\n");
$$ = ($1&31) << 7;
}
sreg:
LREG
| LPC
{
$$ = REGPC;
}
| LR '(' expr ')'
{
if($3 < 0 || $3 >= NREG)
print("register value out of range\n");
$$ = $3;
}
spreg:
sreg
| LSP
{
$$ = REGSP;
}
creg:
LCREG
| LC '(' expr ')'
{
if($3 < 0 || $3 >= NREG)
print("register value out of range\n");
$$ = $3;
}
frcon:
freg
| fcon
freg:
LFREG
{
$$ = nullgen;
$$.type = D_FREG;
$$.reg = $1;
}
| LF '(' con ')'
{
$$ = nullgen;
$$.type = D_FREG;
$$.reg = $3;
}
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, 1);
$$.offset = $4;
}
offset:
{
$$ = 0;
}
| '+' con
{
$$ = $2;
}
| '-' con
{
$$ = -$2;
}
pointer:
LSB
| LSP
| LFP
con:
LCONST
| LVAR
{
$$ = $1->value;
}
| '-' con
{
$$ = -$2;
}
| '+' con
{
$$ = $2;
}
| '~' con
{
$$ = ~$2;
}
| '(' expr ')'
{
$$ = $2;
}
oexpr:
{
$$ = 0;
}
| ',' 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;
}