plan9fox/sys/src/cmd/va/a.y
2011-03-30 19:35:09 +03:00

589 lines
7 KiB
Plaintext

%{
#include "a.h"
%}
%union
{
Sym *sym;
long lval;
double dval;
char sval[8];
Gen gen;
}
%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 LTYPEF
%token <lval> LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
%token <lval> LCONST LSP LSB LFP LPC LHI LLO LMREG
%token <lval> LTYPEX LREG LFREG LFCREG LR LM LF
%token <lval> LFCR LSCHED
%token <dval> LFCONST
%token <sval> LSCONST
%token <sym> LNAME LLAB LVAR
%type <lval> con expr pointer offset sreg
%type <gen> gen vgen lgen vlgen rel reg freg mreg fcreg
%type <gen> imm ximm ireg name oreg imr nireg fgen
%%
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;
}
| LSCHED ';'
{
nosched = $1;
}
| ';'
| inst ';'
| error ';'
inst:
/*
* Immed-type
*/
LTYPE1 imr ',' sreg ',' reg
{
outcode($1, &$2, $4, &$6);
}
| LTYPE1 imr ',' reg
{
outcode($1, &$2, NREG, &$4);
}
/*
* NOR
*/
| LTYPE2 imr ',' sreg ',' imr
{
outcode($1, &$2, $4, &$6);
}
| LTYPE2 imr ',' imr
{
outcode($1, &$2, NREG, &$4);
}
/*
* LOAD/STORE, but not MOVW
*/
| LTYPE3 lgen ',' gen
{
if(!isreg(&$2) && !isreg(&$4))
print("one side must be register\n");
outcode($1, &$2, NREG, &$4);
}
/*
* SPECIAL
*/
| LTYPE4 comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
/*
* MOVW
*/
| LTYPE5 vlgen ',' vgen
{
if(!isreg(&$2) && !isreg(&$4))
print("one side must be register\n");
outcode($1, &$2, NREG, &$4);
}
/*
* MUL/DIV
*/
| LTYPE6 reg ',' sreg comma
{
outcode($1, &$2, $4, &nullgen);
}
| LTYPE6 reg ',' sreg ',' reg
{
outcode($1, &$2, $4, &$6);
}
/*
* JMP/JAL
*/
| LTYPE7 comma rel
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPE7 comma nireg
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPE8 comma rel
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPE8 comma nireg
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPE8 sreg ',' nireg
{
outcode($1, &nullgen, $2, &$4);
}
/*
* BEQ/BNE
*/
| LTYPE9 gen ',' rel
{
if(!isreg(&$2))
print("left side must be register\n");
outcode($1, &$2, NREG, &$4);
}
| LTYPE9 gen ',' sreg ',' rel
{
if(!isreg(&$2))
print("left side must be register\n");
outcode($1, &$2, $4, &$6);
}
/*
* B-other
*/
| LTYPEA gen ',' rel
{
if(!isreg(&$2))
print("left side must be register\n");
outcode($1, &$2, NREG, &$4);
}
/*
* TEXT/GLOBL
*/
| LTYPEB name ',' imm
{
outcode($1, &$2, NREG, &$4);
}
| LTYPEB name ',' con ',' imm
{
outcode($1, &$2, $4, &$6);
}
/*
* DATA
*/
| LTYPEC name '/' con ',' ximm
{
outcode($1, &$2, $4, &$6);
}
/*
* floating-type
*/
| LTYPED freg ',' freg
{
outcode($1, &$2, NREG, &$4);
}
| LTYPEE freg ',' freg
{
outcode($1, &$2, NREG, &$4);
}
| LTYPEE freg ',' LFREG ',' freg
{
outcode($1, &$2, $4, &$6);
}
| LTYPEF freg ',' LFREG comma
{
outcode($1, &$2, $4, &nullgen);
}
/*
* coprocessor branch
*/
| LTYPEG comma rel
{
outcode($1, &nullgen, NREG, &$3);
}
/*
* word
*/
| LTYPEH comma ximm
{
outcode($1, &nullgen, NREG, &$3);
}
/*
* NOP
*/
| LTYPEI comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
| LTYPEI ',' vgen
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPEI vgen comma
{
outcode($1, &$2, NREG, &nullgen);
}
/*
* BREAK -- overloaded with CACHE opcode
*/
| LTYPEJ comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
| LTYPEJ vgen ',' vgen
{
outcode($1, &$2, NREG, &$4);
}
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;
$$.sym = $1;
$$.offset = $2;
}
| LLAB offset
{
$$ = nullgen;
$$.type = D_BRANCH;
$$.sym = $1;
$$.offset = $1->value + $2;
}
vlgen:
lgen
| fgen
| mreg
| fcreg
| LHI
{
$$ = nullgen;
$$.type = D_HI;
}
| LLO
{
$$ = nullgen;
$$.type = D_LO;
}
vgen:
gen
| fgen
| mreg
| fcreg
| LHI
{
$$ = nullgen;
$$.type = D_HI;
}
| LLO
{
$$ = nullgen;
$$.type = D_LO;
}
lgen:
gen
| ximm
fgen:
freg
mreg:
LMREG
{
$$ = nullgen;
$$.type = D_MREG;
$$.reg = $1;
}
| LM '(' con ')'
{
$$ = nullgen;
$$.type = D_MREG;
$$.reg = $3;
}
fcreg:
LFCREG
{
$$ = nullgen;
$$.type = D_FCREG;
$$.reg = $1;
}
| LFCR '(' con ')'
{
$$ = nullgen;
$$.type = D_FCREG;
$$.reg = $3;
}
freg:
LFREG
{
$$ = nullgen;
$$.type = D_FREG;
$$.reg = $1;
}
| LF '(' con ')'
{
$$ = nullgen;
$$.type = D_FREG;
$$.reg = $3;
}
ximm: '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
| '$' oreg
{
$$ = $2;
$$.type = D_CONST;
}
| '$' '*' '$' oreg
{
$$ = $4;
$$.type = D_OCONST;
}
| '$' LSCONST
{
$$ = nullgen;
$$.type = D_SCONST;
memcpy($$.sval, $2, sizeof($$.sval));
}
| '$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = -$3;
}
nireg:
ireg
| con ireg
{
if($1 != 0)
yyerror("offset must be zero");
$$ = $2;
}
| name
{
$$ = $1;
if($1.name != D_EXTERN && $1.name != D_STATIC) {
}
}
ireg:
'(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $2;
$$.offset = 0;
}
gen:
reg
| con
{
$$ = nullgen;
$$.type = D_OREG;
$$.offset = $1;
}
| oreg
oreg:
name
| name '(' sreg ')'
{
$$ = $1;
$$.type = D_OREG;
$$.reg = $3;
}
| '(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $2;
$$.offset = 0;
}
| con '(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $3;
$$.offset = $1;
}
imr:
reg
| imm
imm: '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
reg:
sreg
{
$$ = nullgen;
$$.type = D_REG;
$$.reg = $1;
}
sreg:
LREG
| LR '(' con ')'
{
if($$ < 0 || $$ >= NREG)
print("register value out of range\n");
$$ = $3;
}
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
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;
}