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

541 lines
6.6 KiB
Plaintext

%{
#include "a.h"
%}
%union {
Sym *sym;
long lval;
double dval;
char sval[8];
Addr addr;
Gen gen;
Gen2 gen2;
}
%left '|'
%left '^'
%left '&'
%left '<' '>'
%left '+' '-'
%left '*' '/' '%'
%token <lval> LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
%token <lval> LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA LTYPEB
%token <lval> LCONST LSP LSB LFP LPC LTOS LAREG LDREG LFREG LWID
%token <dval> LFCONST
%token <sval> LSCONST
%token <sym> LNAME LLAB LVAR
%type <lval> con expr scale type pointer reg offset
%type <addr> name areg xreg
%type <gen> gen rel
%type <gen2> noaddr gengen dstgen spec1 spec2 spec3 srcgen dstrel genrel
%%
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;
}
| LTYPE1 gengen { outcode($1, &$2); }
| LTYPE2 noaddr { outcode($1, &$2); }
| LTYPE3 dstgen { outcode($1, &$2); }
| LTYPE4 spec1 { outcode($1, &$2); }
| LTYPE5 srcgen { outcode($1, &$2); }
| LTYPE6 dstrel { outcode($1, &$2); }
| LTYPE7 genrel { outcode($1, &$2); }
| LTYPE8 dstgen { outcode($1, &$2); }
| LTYPE8 gengen { outcode($1, &$2); }
| LTYPE9 noaddr { outcode($1, &$2); }
| LTYPE9 dstgen { outcode($1, &$2); }
| LTYPEA spec2 { outcode($1, &$2); }
| LTYPEB spec3 { outcode($1, &$2); }
noaddr:
{
$$.from = nullgen;
$$.to = nullgen;
}
| ','
{
$$.from = nullgen;
$$.to = nullgen;
}
srcgen:
gen
{
$$.from = $1;
$$.to = nullgen;
}
| gen ','
{
$$.from = $1;
$$.to = nullgen;
}
dstgen:
gen
{
$$.from = nullgen;
$$.to = $1;
}
| ',' gen
{
$$.from = nullgen;
$$.to = $2;
}
gengen:
gen ',' gen
{
$$.from = $1;
$$.to = $3;
}
dstrel:
rel
{
$$.from = nullgen;
$$.to = $1;
}
| ',' rel
{
$$.from = nullgen;
$$.to = $2;
}
genrel:
gen ',' rel
{
$$.from = $1;
$$.to = $3;
}
spec1: /* DATA opcode */
gen '/' con ',' gen
{
$1.displace = $3;
$$.from = $1;
$$.to = $5;
}
spec2: /* bit field opcodes */
gen ',' gen ',' con ',' con
{
$1.field = $7;
$3.field = $5;
$$.from = $1;
$$.to = $3;
}
spec3: /* TEXT opcode */
gengen
| gen ',' con ',' gen
{
$1.displace = $3;
$$.from = $1;
$$.to = $5;
}
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;
}
gen:
type
{
$$ = nullgen;
$$.type = $1;
}
| '$' con
{
$$ = nullgen;
$$.type = D_CONST;
$$.offset = $2;
}
| '$' name
{
$$ = nullgen;
{
Addr *a;
a = &$$;
*a = $2;
}
if($2.type == D_AUTO || $2.type == D_PARAM)
yyerror("constant cannot be automatic: %s",
$2.sym->name);
$$.type = $2.type | I_ADDR;
}
| '$' LSCONST
{
$$ = nullgen;
$$.type = D_SCONST;
memcpy($$.sval, $2, sizeof($$.sval));
}
| '$' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = $2;
}
| '$' '-' LFCONST
{
$$ = nullgen;
$$.type = D_FCONST;
$$.dval = -$3;
}
| LTOS '+' con
{
$$ = nullgen;
$$.type = D_STACK;
$$.offset = $3;
}
| LTOS '-' con
{
$$ = nullgen;
$$.type = D_STACK;
$$.offset = -$3;
}
| con
{
$$ = nullgen;
$$.type = D_CONST | I_INDIR;
$$.offset = $1;
}
| '-' '(' LAREG ')'
{
$$ = nullgen;
$$.type = $3 | I_INDDEC;
}
| '(' LAREG ')' '+'
{
$$ = nullgen;
$$.type = $2 | I_INDINC;
}
| areg
{
$$ = nullgen;
$$.type = $1.type;
{
Addr *a;
a = &$$;
*a = $1;
}
if(($$.type & D_MASK) == D_NONE) {
$$.index = D_NONE | I_INDEX1;
$$.scale = 0;
$$.displace = 0;
}
}
| areg xreg
{
$$ = nullgen;
$$.type = $1.type;
{
Addr *a;
a = &$$;
*a = $1;
}
$$.index = $2.type | I_INDEX1;
$$.scale = $2.offset;
}
| '(' areg ')' xreg
{
$$ = nullgen;
$$.type = $2.type;
{
Addr *a;
a = &$$;
*a = $2;
}
$$.index = $4.type | I_INDEX2;
$$.scale = $4.offset;
$$.displace = 0;
}
| con '(' areg ')' xreg
{
$$ = nullgen;
$$.type = $3.type;
{
Addr *a;
a = &$$;
*a = $3;
}
$$.index = $5.type | I_INDEX2;
$$.scale = $5.offset;
$$.displace = $1;
}
| '(' areg ')'
{
$$ = nullgen;
$$.type = $2.type;
{
Addr *a;
a = &$$;
*a = $2;
}
$$.index = D_NONE | I_INDEX3;
$$.scale = 0;
$$.displace = 0;
}
| con '(' areg ')'
{
$$ = nullgen;
$$.type = $3.type;
{
Addr *a;
a = &$$;
*a = $3;
}
$$.index = D_NONE | I_INDEX3;
$$.scale = 0;
$$.displace = $1;
}
| '(' areg xreg ')'
{
$$ = nullgen;
$$.type = $2.type;
{
Addr *a;
a = &$$;
*a = $2;
}
$$.index = $3.type | I_INDEX3;
$$.scale = $3.offset;
$$.displace = 0;
}
| con '(' areg xreg ')'
{
$$ = nullgen;
$$.type = $3.type;
{
Addr *a;
a = &$$;
*a = $3;
}
$$.index = $4.type | I_INDEX3;
$$.scale = $4.offset;
$$.displace = $1;
}
type:
reg
| LFREG
xreg:
/*
* .W*1 0
* .W*2 1
* .W*4 2
* .W*8 3
* .L*1 4
* .L*2 5
* .L*4 6
* .L*8 7
*/
'(' reg LWID scale ')'
{
$$.type = $2;
$$.offset = $3+$4;
$$.sym = S;
}
reg:
LAREG
| LDREG
| LTOS
scale:
'*' con
{
switch($2) {
case 1:
$$ = 0;
break;
case 2:
$$ = 1;
break;
default:
yyerror("bad scale: %ld", $2);
case 4:
$$ = 2;
break;
case 8:
$$ = 3;
break;
}
}
areg:
'(' LAREG ')'
{
$$.type = $2 | I_INDIR;
$$.sym = S;
$$.offset = 0;
}
| con '(' LAREG ')'
{
$$.type = $3 | I_INDIR;
$$.sym = S;
$$.offset = $1;
}
| '(' ')'
{
$$.type = D_NONE | I_INDIR;
$$.sym = S;
$$.offset = 0;
}
| con '(' ')'
{
$$.type = D_NONE | I_INDIR;
$$.sym = S;
$$.offset = $1;
}
| name
name:
LNAME offset '(' pointer ')'
{
$$.type = $4;
$$.sym = $1;
$$.offset = $2;
}
| LNAME '<' '>' offset '(' LSB ')'
{
$$.type = 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;
}