%{
#include "a.h"
%}
%union
{
Sym *sym;
vlong lval;
double dval;
char sval[NSNAME];
Gen gen;
}
%left '|'
%left '^'
%left '&'
%left '<' '>'
%left '+' '-'
%left '*' '/' '%'
%token <lval> LTYPE0 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> LTYPEL LTYPEM LTYPEN LTYPEO LTYPEP LTYPEQ
%token <lval> LTYPER LTYPES LTYPET LTYPEU LTYPEV LTYPEW LTYPEX LTYPEY LTYPEZ
%token <lval> LMOVK LDMB LSTXR
%token <lval> LCONST LSP LSB LFP LPC
%token <lval> LR LREG LF LFREG LV LVREG LC LCREG LFCR LFCSEL
%token <lval> LCOND LS LAT LEXT LSPR LSPREG LVTYPE
%token <dval> LFCONST
%token <sval> LSCONST
%token <sym> LNAME LLAB LVAR
%type <lval> con expr pointer offset sreg spreg
%type <lval> scon indexreg vset vreglist
%type <gen> gen rel reg freg vreg shift fcon frcon extreg vlane vgen
%type <gen> imm ximm name oreg nireg ioreg imsr spr cond sysarg
%%
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:
/*
* ERET
*/
LTYPE0 comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
/*
* ADD
*/
| LTYPE1 imsr ',' spreg ',' reg
{
outcode($1, &$2, $4, &$6);
}
| LTYPE1 imsr ',' spreg ','
{
outcode($1, &$2, $4, &nullgen);
}
| LTYPE1 imsr ',' reg
{
outcode($1, &$2, NREG, &$4);
}
/*
* CLS
*/
| LTYPE2 imsr ',' reg
{
outcode($1, &$2, NREG, &$4);
}
/*
* MOV
*/
| LTYPE3 gen ',' gen
{
outcode($1, &$2, NREG, &$4);
}
/*
* MOVK
*/
| LMOVK imm ',' reg
{
outcode($1, &$2, NREG, &$4);
}
| LMOVK imm '<' '<' con ',' reg
{
Gen g;
g = nullgen;
g.type = D_CONST;
g.offset = $5;
outcode4($1, &$2, NREG, &g, &$7);
}
/*
* B/BL
*/
| LTYPE4 comma rel
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPE4 comma nireg
{
outcode($1, &nullgen, NREG, &$3);
}
/*
* BEQ
*/
| LTYPE5 comma rel
{
outcode($1, &nullgen, NREG, &$3);
}
/*
* SVC
*/
| LTYPE6 comma gen
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPE6
{
outcode($1, &nullgen, NREG, &nullgen);
}
/*
* CMP
*/
| LTYPE7 imsr ',' spreg comma
{
outcode($1, &$2, $4, &nullgen);
}
/*
* CBZ
*/
| LTYPE8 reg ',' rel
{
outcode($1, &$2, NREG, &$4);
}
/*
* CSET
*/
| LTYPER cond ',' reg
{
outcode($1, &$2, NREG, &$4);
}
/*
* CSEL/CINC/CNEG/CINV
*/
| LTYPES cond ',' reg ',' reg ',' reg
{
outcode4($1, &$2, $6.reg, &$4, &$8);
}
| LTYPES cond ',' reg ',' reg
{
outcode($1, &$2, $4.reg, &$6);
}
/*
* TBZ
*/
| LTYPET imm ',' reg ',' rel
{
outcode($1, &$2, $4.reg, &$6);
}
/*
* CCMN
*/
| LTYPEU cond ',' imsr ',' reg ',' imm comma
{
outcode4($1, &$2, $6.reg, &$4, &$8);
}
/*
* ADR
*/
| LTYPEV rel ',' reg
{
outcode($1, &$2, NREG, &$4);
}
| LTYPEV '$' name ',' reg
{
outcode($1, &$3, NREG, &$5);
}
/*
* BFM/BFI
*/
| LTYPEY imm ',' imm ',' spreg ',' reg
{
outcode4($1, &$2, $6, &$4, &$8);
}
/*
* EXTR
*/
| LTYPEP imm ',' reg ',' spreg ',' reg
{
outcode4($1, &$2, $6, &$4, &$8);
}
/*
* RET/RETURN
*/
| LTYPEA comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
| LTYPEA reg
{
outcode($1, &nullgen, NREG, &$2);
}
/*
* NOP
*/
| LTYPEQ comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
| LTYPEQ reg comma
{
outcode($1, &$2, NREG, &nullgen);
}
| LTYPEQ freg comma
{
outcode($1, &$2, NREG, &nullgen);
}
| LTYPEQ ',' reg
{
outcode($1, &nullgen, NREG, &$3);
}
| LTYPEQ ',' freg
{
outcode($1, &nullgen, NREG, &$3);
}
/*
* 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);
}
/*
* CASE
*/
| LTYPED reg ',' reg
{
outcode($1, &$2, NREG, &$4);
}
/*
* word
*/
| LTYPEH comma ximm
{
outcode($1, &nullgen, NREG, &$3);
}
/*
* floating-point
*/
| LTYPEI freg ',' freg
{
outcode($1, &$2, NREG, &$4);
}
/*
* FADDD
*/
| LTYPEK frcon ',' freg
{
outcode($1, &$2, NREG, &$4);
}
| LTYPEK frcon ',' freg ',' freg
{
outcode($1, &$2, $4.reg, &$6);
}
/*
* FCMP
*/
| LTYPEL frcon ',' freg comma
{
outcode($1, &$2, $4.reg, &nullgen);
}
/*
* FCCMP
*/
| LTYPEF cond ',' freg ',' freg ',' imm comma
{
outcode4($1, &$2, $6.reg, &$4, &$8);
}
/*
* FMULA
*/
| LTYPE9 freg ',' freg ', ' freg ',' freg comma
{
outcode4($1, &$2, $4.reg, &$6, &$8);
}
/*
* FCSEL
*/
| LFCSEL cond ',' freg ',' freg ',' freg
{
outcode4($1, &$2, $6.reg, &$4, &$8);
}
/*
* SIMD
*/
| LTYPEW vgen ',' vgen
{
outcode($1, &$2, NREG, &$4);
}
| LTYPEW vgen ',' vgen ',' vgen
{
outcode($1, &$2, $4.reg, &$6);
}
/*
* MOVP/MOVNP
*/
| LTYPEJ gen ',' sreg ',' gen
{
outcode($1, &$2, $4, &$6);
}
/*
* MADD Rn,Rm,Ra,Rd
*/
| LTYPEM reg ',' reg ',' sreg ',' reg
{
outcode4($1, &$2, $6, &$4, &$8);
}
/*
* SYS/SYSL
*/
| LTYPEN sysarg
{
outcode($1, &$2, NREG, &nullgen);
}
| LTYPEN reg ',' sysarg
{
outcode($1, &$4, $2.reg, &nullgen);
}
| LTYPEO sysarg ',' reg
{
outcode($1, &$2, NREG, &$4);
}
/*
* DMB, HINT
*/
| LDMB imm
{
outcode($1, &$2, NREG, &nullgen);
}
/*
* STXR
*/
| LSTXR reg ',' gen ',' sreg
{
outcode($1, &$2, $6, &$4);
}
/*
* END
*/
| LTYPEE comma
{
outcode($1, &nullgen, NREG, &nullgen);
}
cond:
LCOND
{
$$ = nullgen;
$$.type = D_COND;
$$.reg = $1;
}
comma:
| ',' comma
sysarg:
con ',' con ',' con ',' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = SYSARG4($1, $3, $5, $7);
}
| 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;
}
ximm: '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
| '$' oreg
{
$$ = $2;
$$.type = D_CONST;
}
| '$' '*' '$' oreg
{
$$ = $4;
$$.type = D_OCONST;
}
| '$' LSCONST
{
$$ = nullgen;
$$.type = D_SCONST;
memmove($$.sval, $2, sizeof($$.sval));
}
| fcon
fcon:
'$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = -$3;
}
gen:
reg
| ximm
| LFCR
{
$$ = nullgen;
$$.type = D_SPR;
$$.offset = $1;
}
| con
{
$$ = nullgen;
$$.type = D_OREG;
$$.offset = $1;
}
| oreg
| freg
| vreg
| spr
nireg:
'(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $2;
$$.offset = 0;
}
| name
{
$$ = $1;
if($1.name != D_EXTERN && $1.name != D_STATIC) {
}
}
oreg:
name
| name '(' sreg ')'
{
$$ = $1;
$$.type = D_OREG;
$$.reg = $3;
}
| ioreg
ioreg:
'(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $2;
$$.offset = 0;
}
| con '(' sreg ')'
{
$$ = nullgen;
$$.type = D_OREG;
$$.reg = $3;
$$.offset = $1;
}
| con '(' sreg ')' '!'
{
$$ = nullgen;
$$.type = D_XPRE;
$$.reg = $3;
$$.offset = $1;
}
| '(' sreg ')' con '!'
{
$$ = nullgen;
$$.type = D_XPOST;
$$.reg = $2;
$$.offset = $4;
}
| '(' sreg ')' '(' indexreg ')'
{
$$ = nullgen;
$$.type = D_ROFF;
$$.reg = $2;
$$.xreg = $5 & 0x1f;
$$.offset = $5;
}
| '(' sreg ')' '[' indexreg ']'
{
$$ = nullgen;
$$.type = D_ROFF;
$$.reg = $2;
$$.xreg = $5 & 0x1f;
$$.offset = $5 | (1<<16);
}
imsr:
imm
| shift
| extreg
imm: '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
reg:
sreg
{
$$ = nullgen;
$$.type = D_REG;
$$.reg = $1;
}
| LSP
{
$$ = nullgen;
$$.type = D_SP;
$$.reg = REGSP;
}
shift:
sreg '<' '<' scon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = ($1 << 16) | ($4 << 10) | (0 << 22);
}
| sreg '>' '>' scon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = (($1&0x1F) << 16) | ($4 << 10) | (1 << 22);
}
| sreg '-' '>' scon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = ($1 << 16) | ($4 << 10) | (2 << 22);
}
| sreg LAT '>' scon
{
$$ = nullgen;
$$.type = D_SHIFT;
$$.offset = ($1 << 16) | ($4 << 10) | (3 << 22);
}
extreg:
sreg
{
$$ = nullgen;
$$.type = D_REG;
$$.reg = $1;
}
| sreg LEXT
{
$$ = nullgen;
$$.type = D_EXTREG;
$$.reg = $1;
$$.offset = ($1 << 16) | ($2 << 13);
}
| sreg LEXT '<' '<' con
{
if($5 < 0 || $5 > 4)
yyerror("shift value out of range");
$$ = nullgen;
$$.type = D_EXTREG;
$$.reg = $1;
$$.offset = ($1 << 16) | ($2 << 13) | ($5 << 10);
}
indexreg:
sreg
{
$$ = (3 << 8) | $1;
}
| sreg LEXT
{
$$ = ($2 << 8) | $1;
}
scon:
con
{
if($$ < 0 || $$ >= 64)
yyerror("shift value out of range");
$$ = $1&0x3F;
}
sreg:
LREG
| LR '(' expr ')'
{
if($3 < 0 || $3 >= NREG)
print("register value out of range\n");
$$ = $3;
}
spreg:
sreg
| LSP
{
$$ = REGSP;
}
spr:
LSPREG
{
$$ = nullgen;
$$.type = D_SPR;
$$.offset = $1;
}
| LSPR '(' con ')'
{
$$ = nullgen;
$$.type = $1;
$$.offset = $3;
}
frcon:
freg
| fcon
freg:
LFREG
{
$$ = nullgen;
$$.type = D_FREG;
$$.reg = $1;
}
| LF '(' con ')'
{
$$ = nullgen;
$$.type = D_FREG;
$$.reg = $3;
}
vgen:
oreg
| vreg
| vlane
| vset
{
$$ = nullgen;
$$.type = D_VSET;
$$.offset = $1;
}
vlane:
vreg '[' con ']'
{
$$.type = D_VLANE;
$$.offset = $3;
}
| vset '[' con ']'
{
$$.type = D_VLANE;
$$.offset = $3;
}
vset:
'{' vreglist '}'
{
$$ = $2;
}
vreglist:
vreg
{
$$ = 1 << $1.reg;
}
| vreg '-' vreg
{
int i;
$$=0;
for(i=$1.reg; i<=$3.reg; i++)
$$ |= 1<<i;
for(i=$3.reg; i<=$1.reg; i++)
$$ |= 1<<i;
}
| vreg comma vreglist
{
$$ = (1<<$1.reg) | $3;
}
vreg:
LVREG
{
$$ = nullgen;
$$.type = D_VREG;
$$.reg = $1;
/* TO DO: slice */
}
| LV '(' con ')'
{
$$ = nullgen;
$$.type = D_VREG;
$$.reg = $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;
}