ack/util/cgg/bootgram.y
2019-05-11 01:13:43 +08:00

1128 lines
23 KiB
Plaintext

%{
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*
* Author: Hans van Staveren
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "em_spec.h"
#include "em_flag.h"
#include "em_reg.h"
#define INIT_VAR
#define EXTERN
#include "booth.h"
#undef INIT_VAR
#undef EXTERN
extern int yylex(void);
%}
%union {
int yy_int;
int *yy_intp;
string yy_string;
list1 yy_list1;
list2 yy_list2;
expr_t yy_expr;
cost_t yy_cost;
set_t yy_set;
ident_p yy_ident;
char yy_char;
inst_t yy_instance;
}
%type <yy_list1> list1 structlistel
%type <yy_list2> structlist structdecl
%type <yy_expr> expr optexpr
%type <yy_cost> optcost cost optcommacost
%type <yy_int> optboolexpr optnocoerc mnem emargno tokargno optprop
%type <yy_int> optcommabool optstack subreg tokenexpressionno optregvar
%type <yy_int> tokeninstanceno code stackreplacement optslashnumber
%type <yy_set> tokenexpression
%type <yy_instance> tokeninstance
%type <yy_string> optformat
%token <yy_string> IDENT TYPENAME
%token <yy_ident> RIDENT PIDENT TIDENT EIDENT
%token <yy_string> LSTRING STRING
%token <yy_int> NUMBER
%token <yy_intp> CIDENT
%token REGISTERHEAD TOKENHEAD EXPRESSIONHEAD CODEHEAD MOVEHEAD TESTHEAD STACKHEAD
%token REGVAR INREG LOOP POINTER FLOAT
%token TIMEFAC SIZEFAC FORMAT RETURN
%token MOVE ERASE ALLOCATE ELLIPS COST REMOVE STACK
%token SEP SAMESIGN SFIT UFIT ROM DEFINED TOSTRING LOWW HIGHW
%token NOCC SETCC SAMECC TEST NOCOERC
%token <yy_char> LCASELETTER
%start machinespec
%left OR2
%left AND2
%left CMPEQ CMPNE
%left CMPLT CMPLE CMPGT CMPGE
%left RSHIFT LSHIFT
%left '+' '-'
%left '*' '/' '%'
%nonassoc NOT COMP UMINUS
%nonassoc '$'
%%
machinespec
: rcsid constants registersection tokensection
{ inbetween(); }
expressionsection codesection movesection testsection stacksection
;
rcsid
: /* empty */
| STRING
{ strlookup($1); }
;
constants
: /* empty */
| constants CIDENT '=' NUMBER
{ *$2 = $4; }
| constants SIZEFAC '=' NUMBER optslashnumber
{ cc1 = $4; cc2 = $5; }
| constants TIMEFAC '=' NUMBER optslashnumber
{ cc3 = $4; cc4 = $5; }
| constants FORMAT '=' STRING
{ fmt = $4; }
;
optslashnumber
: /* empty */
{ $$ = 1; }
| '/' NUMBER
{ $$ = $2; }
;
registersection
: REGISTERHEAD registerdefs
;
registerdefs
: /* empty */
| registerdefs registerdef
;
registerdef
: IDENT '=' '(' STRING ',' NUMBER list1 ')' optregvar list1 '.'
{ register ident_p ip;
register list1 l;
register reginfo r;
int i;
r=(reginfo) myalloc(sizeof(struct reginfo));
r->rname = $1;
r->rrepr = $4;
r->rsize = $6;
if($9>=0 && $7!=0)
yyerror("No subregisters allowed in regvar");
for (i=0;i<MAXMEMBERS;i++)
r->rmembers[i] = 0;
i=0;
for (l=$7;l!=0;l=l->l1next) {
ip=ilookup(l->l1name,LOOKUP);
if (ip->i_type != IREG)
yyerror("Bad member of set");
chktabsiz(i,MAXMEMBERS,"Member of register");
r->rmembers[i++] = ip->i_i.i_regno;
}
maxmembers=max(maxmembers,i);
r->rregvar=$9;
if ($9>=0) {
rvused=1;
chktabsiz(nregvar[$9],MAXREGVARS,"Regvar");
rvnumbers[$9][nregvar[$9]++] = nmachregs;
}
for(i=0;i<PROPSETSIZE;i++)
r->rprop[i] = 0;
ip=ilookup($1,ENTER);
ip->i_type=IREG;
ip->i_i.i_regno=nmachregs;
for (l = $10; l!= 0; l=l->l1next) {
ip = ilookup(l->l1name,HALFWAY);
if (ip->i_type) {
if (ip->i_type != IPRP)
yyerror("Multiple defined symbol");
else if(machprops[ip->i_i.i_prpno].propset.set_size != r->rsize)
yyerror("property has more than 1 size");
} else {
chktabsiz(nprops,MAXPROPS,"Property");
ip->i_type = IPRP;
ip->i_i.i_prpno = nprops;
machprops[nprops].propname = ip;
machprops[nprops++].propset.set_size = r->rsize;
}
r->rprop[ip->i_i.i_prpno>>4] |= (1<<(ip->i_i.i_prpno&017));
}
chktabsiz(nmachregs,MAXREGS,"Register table");
machregs[nmachregs++] = r;
}
| error '.'
;
optregvar
: /* nothing */
{ $$ = -1; }
| REGVAR
{ $$ = reg_any; }
| REGVAR '(' LOOP ')'
{ $$ = reg_loop; }
| REGVAR '(' POINTER ')'
{ $$ = reg_pointer; }
| REGVAR '(' FLOAT ')'
{ $$ = reg_float; }
;
tokensection
: TOKENHEAD tkdefs
;
tkdefs
: /* empty */
| tkdefs tkdef
;
tkdef
: IDENT '=' structdecl NUMBER optcost optformat
{ register token_p tp;
register ident_p ip;
chktabsiz(nmachtokens,MAXTOKENS,"Token table");
tp = &machtokens[nmachtokens];
tp->t_name = $1;
tp->t_struct = $3;
tp->t_size = $4;
tp->t_cost = $5;
ip = ilookup($1,ENTER);
ip->i_type = ITOK;
ip->i_i.i_tokno = nmachtokens++;
maxtokensize=max(maxtokensize,structsize($3));
setfields(tp,$6);
}
| error
;
structdecl
: '{' structlist '}'
{ $$ = lookstruct($2); }
;
structlist
: /* empty */
{ $$=0; }
| structlistel structlist
{ $$=(list2) myalloc(sizeof(struct list2str));
$$->l2next = $2;
$$->l2list = $1;
}
;
structlistel
: TYPENAME list1 ';'
{ $$=(list1) myalloc(sizeof(struct list1str));
$$->l1next = $2;
$$->l1name = $1;
}
;
optcost : /* empty */
{ $$.c_size = $$.c_time = 0; }
| COST '=' '(' expr ',' expr ')'
{ MUST2BEINT($4,$6);
$$.c_size = exp1;
$$.c_time = exp2;
}
;
optformat
: /* empty */
{ $$ = 0; }
| STRING
;
expressionsection
: /* empty */
| EXPRESSIONHEAD tokenexpressions
;
tokenexpressions
: tokenexpressionline
| tokenexpressionline tokenexpressions
;
tokenexpressionline
: IDENT '=' tokenexpression
{
{ register ident_p ip;
chktabsiz(nmachsets,MAXSETS,"Expression table");
machsets[nmachsets] = $3;
ip=ilookup($1,ENTER);
ip->i_type = IEXP;
ip->i_i.i_expno = nmachsets++;
}
}
| error
;
tokenexpression
: PIDENT
{ $$ = machprops[$1->i_i.i_prpno].propset; }
| TIDENT
{ register int i;
for(i=0;i<SETSIZE;i++) $$.set_val[i]=0;
$$.set_val[($1->i_i.i_tokno+nmachregs+1)>>4] |=
01<<(($1->i_i.i_tokno+nmachregs+1)&017);
$$.set_size = machtokens[$1->i_i.i_tokno].t_size;
}
| EIDENT
{ $$=machsets[$1->i_i.i_expno]; }
| tokenexpression '*' tokenexpression
{ register int i;
if (($$.set_size=$1.set_size)==0)
$$.set_size = $3.set_size;
for (i=0;i<SETSIZE;i++)
$$.set_val[i] = $1.set_val[i] & $3.set_val[i];
}
| tokenexpression '+' tokenexpression
{ register int i;
if ($1.set_size == -1)
$$.set_size = $3.set_size;
else if ($3.set_size == -1)
$$.set_size = $1.set_size;
else if ($1.set_size == $3.set_size)
$$.set_size = $1.set_size;
else
$$.set_size = 0;
for (i=0;i<SETSIZE;i++)
$$.set_val[i] = $1.set_val[i] | $3.set_val[i];
}
| tokenexpression '-' tokenexpression
{ register int i;
if ($1.set_size == -1)
$$.set_size = $3.set_size;
else if ($3.set_size == -1)
$$.set_size = $1.set_size;
else if ($1.set_size == $3.set_size)
$$.set_size = $1.set_size;
else
$$.set_size = 0;
for (i=0;i<SETSIZE;i++)
$$.set_val[i] = $1.set_val[i] & ~ $3.set_val[i];
}
| '(' tokenexpression ')'
{ $$ = $2; }
;
codesection
: CODEHEAD coderules
;
coderules
: coderule
| coderules coderule
;
coderule
: { nallreg=emrepllen=tokrepllen=0; }
empattern SEP stackpattern SEP code SEP stackreplacement SEP
emreplacement SEP cost
{ int i;
if (emrepllen) {
outbyte(DO_EMREPLACE+(emrepllen<<5));
for (i=0;i<emrepllen;i++) {
out(replmnem[i]);
out(replexpr[i]);
}
}
if ($8==0) {
outbyte(DO_TOKREPLACE+(tokrepllen<<5));
for(i=0;i<tokrepllen;i++)
out(replinst[i]);
} else {
static int warncount=0;
if (!warncount++)
fprintf(stderr,
"WARNING: convert to stacksection, will disappear soon");
outbyte(DO_TOKREPLACE);
}
if ($12.c_size!=0 || $12.c_time!=0) {
outbyte(DO_COST);
out($12.c_size);
out($12.c_time);
}
outbyte(empatlen==0? DO_RETURN : DO_NEXTEM);
fprintf(cfile,"\n");
ncoderules++;
maxallreg=max(maxallreg,nallreg);
if (empatlen==0) { /* coercion */
if (tokrepllen<1 && $8==0)
yyerror("No replacement in coercion");
if (tokpatlen>1)
yyerror("Token pattern too long");
if ($8!=0) { /* stacking */
c1_p cp;
chktabsiz(nc1,MAXC1,"Coerc table 1");
cp = &c1coercs[nc1++];
cp->c1_texpno = pattokexp[1];
cp->c1_prop = -1;
cp->c1_codep = $6;
} else if (tokrepllen>1) { /* splitting */
c2_p cp;
chktabsiz(nc2,MAXC2,"Coerc table 2");
cp= &c2coercs[nc2++];
cp->c2_texpno = pattokexp[1];
cp->c2_nsplit = tokrepllen;
maxsplit=max(maxsplit,tokrepllen);
for (i=0;i<tokrepllen;i++)
cp->c2_repl[i] = replinst[i];
cp->c2_codep = $6;
if (nallreg>0)
yyerror("No allocates allowed here");
} else { /* one to one coercion */
c3_p cp;
chktabsiz(nc3,MAXC3,"Coerc table 3");
cp= &c3coercs[nc3++];
if (tokpatlen)
cp->c3_texpno = pattokexp[1];
else
cp->c3_texpno = 0;
if (nallreg>1)
yyerror("Too many allocates in coercion");
cp->c3_prop = nallreg==0 ? 0 : allreg[0];
cp->c3_repl = replinst[0];
cp->c3_codep = $6;
}
}
}
| error
;
empattern
: /* empty */
{ empatlen=0; }
| mnemlist optboolexpr
{ register int i;
empatexpr = $2;
patbyte(0);
patshort(prevind);
prevind = npatbytes - 3;
maxempatlen = max(empatlen,maxempatlen);
pat(empatlen);
for(i=1;i<=empatlen;i++)
patbyte(patmnem[i]);
pat(empatexpr);
rulecount = npatbytes;
patbyte(1); /* number of different rules with this pattern */
pat(codebytes); /* first rule */
}
| ELLIPS
{ pattern[rulecount]++;
maxrule= max(maxrule,pattern[rulecount]);
pat(codebytes);
}
;
mnemlist
: mnem
{ empatlen = 1; patmnem[empatlen] = $1; }
| mnemlist mnem
{ chktabsiz(empatlen+1,MAXEMPATLEN,"EM pattern");
patmnem[++empatlen] = $2;
}
;
mnem : IDENT
{ if(strlen($1)!=3 || ($$=mlookup($1))==0)
yyerror("not an EM-mnemonic");
}
;
stackpattern
: optnocoerc tokenexpressionlist optstack
{ register int i;
if (tokpatlen != 0) {
outbyte(($1 ? ( $3 ? DO_XXMATCH: DO_XMATCH ) : DO_MATCH)+(tokpatlen<<5));
for(i=1;i<=tokpatlen;i++) {
out(pattokexp[i]);
}
}
if ($3 && tokpatlen==0 && empatlen==0) {
outbyte(DO_COERC);
}
if ($3 && !$1 && empatlen!=0) {
outbyte(DO_REMOVE);
out(allexpno);
}
}
;
optnocoerc
: /* empty */
{ $$ = 0; }
| NOCOERC ':'
{ $$ = 1; }
;
tokenexpressionlist
: /* empty */
{ tokpatlen = 0; }
| tokenexpressionlist tokenexpressionno
{ chktabsiz(tokpatlen+1,MAXPATLEN,"Token pattern");
pattokexp[++tokpatlen] = $2;
if (machsets[$2].set_size==0)
yyerror("Various sized set in tokenpattern");
}
;
tokenexpressionno
: tokenexpression
{ $$ = exprlookup($1); }
;
optstack
: /* empty */
{ $$ = 0; }
| STACK
{ $$ = 1; }
;
code :
{ $<yy_int>$ = codebytes; cchandled=ccspoiled=0; }
initcode restcode
{ if (cchandled==0 && ccspoiled!=0) {
outbyte(DO_ERASE);
out(ccregexpr);
}
}
;
initcode
: /* empty */
| initcode remove
| initcode allocate
;
remove
: REMOVE '(' tokenexpressionno
{ curtokexp = $3; }
optcommabool ')'
{ outbyte(DO_REMOVE+ ($5!=0 ? 32 : 0));
out($3);
if ($5!=0) out($5);
}
| REMOVE '(' expr ')'
{ if ($3.expr_typ != TYPREG)
yyerror("Expression must be register");
outbyte(DO_RREMOVE);
out($3.expr_index);
}
;
optcommabool
: /* empty */
{ $$ = 0; }
| ',' expr
{ MUST1BEBOOL($2);
$$ = exp1;
}
;
restcode: /* empty */
| restcode LSTRING expr
{ outbyte(DO_LOUTPUT);
out(stringno($2));
free($2);
out($3.expr_index);
ccspoiled++;
}
| restcode stringlist
{ int i;
for(i=0;nstr>0;i++,nstr--) {
if (i%8==0) outbyte(DO_ROUTPUT+(nstr>7 ? 7 : nstr-1)*32);
out(strar[i]);
}
ccspoiled++;
}
| restcode RETURN
{ outbyte(DO_PRETURN); }
| restcode move
| restcode erase
| restcode NOCC
{ outbyte(DO_ERASE);
out(ccregexpr);
cchandled++;
}
| restcode SAMECC
{ cchandled++; }
| restcode SETCC '(' tokeninstanceno ')'
{ outbyte(DO_MOVE);
out(ccinstanceno);
out($4);
cchandled++;
}
| restcode TEST '(' tokeninstanceno ')'
{ outbyte(DO_MOVE);
out($4);
out(ccinstanceno);
ccspoiled=0;
}
;
stringlist
: STRING
{ nstr=1;
strar[0]=stringno($1);
free($1);
}
| stringlist STRING
{ chktabsiz(nstr,MAXNSTR,"Consecutiv strings");
strar[nstr++] = stringno($2);
free($2);
}
;
move
: MOVE '(' tokeninstanceno ',' tokeninstanceno ')'
{ outbyte(DO_MOVE);
out($3);
out($5);
}
;
erase
: ERASE '(' expr ')'
{ outbyte(DO_ERASE);
out($3.expr_index);
if($3.expr_typ != TYPREG)
yyerror("Bad argument of erase");
}
;
allocate
: ALLOCATE { dealflag=0; } '(' alloclist ')'
{ if (dealflag)
outbyte(DO_REALLOCATE);
}
;
alloclist
: allocel
| alloclist optcomma allocel
;
allocel
: tokeninstanceno /* deallocate */
{ outbyte(DO_DEALLOCATE);
out($1);
dealflag++;
}
| PIDENT
{ allreg[nallreg++] = $1->i_i.i_prpno;
outbyte(DO_ALLOCATE);
out($1->i_i.i_prpno);
}
| PIDENT '=' tokeninstanceno
{ allreg[nallreg++] = $1->i_i.i_prpno;
outbyte(DO_ALLOCATE+32);
out($1->i_i.i_prpno);
out($3);
}
;
stackreplacement
: /* empty */
{ $$=0; }
| STACK
{ $$=1; }
| '{' STACK '}'
{ $$=1; }
| stackrepllist
{ $$=0; }
;
stackrepllist
: tokeninstanceno
{ tokrepllen=1; replinst[0] = $1; }
| stackrepllist tokeninstanceno
{ chktabsiz(tokrepllen+1,MAXPATLEN,"Stack replacement");
replinst[tokrepllen++] = $2;
}
;
emreplacement
: /* empty, normal case */
| emrepllist
;
emrepllist
: mnem optexpr
{ emrepllen=1;
replmnem[0]=$1;
replexpr[0]=$2.expr_index;
}
| emrepllist mnem optexpr
{ chktabsiz(emrepllen+1,MAXEMPATLEN,"EM replacement");
replmnem[emrepllen]=$2;
replexpr[emrepllen]=$3.expr_index;
emrepllen++;
}
;
cost : /* empty */
{ $$.c_size = $$.c_time = 0;
}
| '(' expr ',' expr ')'
{ MUST2BEINT($2,$4);
$$.c_size = exp1;
$$.c_time = exp2;
}
| cost '+' '%' '[' tokargno ']'
{ $$.c_size = lookup(1,EX_PLUS,$1.c_size,
lookup(0,EX_COST,$5,0));
$$.c_time = lookup(1,EX_PLUS,$1.c_time,
lookup(0,EX_COST,$5,1));
}
;
movesection
: MOVEHEAD movedefs
;
movedefs
: movedef
| movedefs movedef
;
movedef
: '(' tokenexpressionno
{ curtokexp = $2; }
optboolexpr ',' tokenexpressionno
{ curtokexp = $6;
pattokexp[1] = $2;
pattokexp[2] = $6;
tokpatlen=2;
}
optboolexpr ',' code optcommacost ')'
{ register move_p mp;
outbyte(DO_RETURN);
fprintf(cfile,"\n");
chktabsiz(nmoves,NMOVES,"Move definition table");
mp = &machmoves[nmoves++];
mp->m_set1 = $2;
mp->m_expr1= $4;
mp->m_set2 = $6;
mp->m_expr2= $8;
mp->m_cindex=$10;
mp->m_cost = $11;
}
| error
;
testsection
: /* empty */
| TESTHEAD testdefs
;
testdefs: testdef
| testdefs testdef
;
testdef : '(' tokenexpressionno
{ curtokexp = $2;
pattokexp[1] = $2;
pattokexp[2] = cocosetno;
tokpatlen=2;
}
optboolexpr ',' code optcommacost ')'
{ register move_p mp;
outbyte(DO_RETURN);
fprintf(cfile,"\n");
chktabsiz(nmoves,NMOVES,"Move definition table(tests)");
mp = &machmoves[nmoves++];
mp->m_set1 = $2;
mp->m_expr1 = $4;
mp->m_set2 = cocosetno;
mp->m_expr2 = 0;
mp->m_cindex = $6;
mp->m_cost = $7;
}
;
stacksection
: STACKHEAD stackdefs
| /* empty */
;
stackdefs
: stackdef
| stackdefs stackdef
;
stackdef
: '(' tokenexpressionno
{ curtokexp = $2;
pattokexp[1] = $2;
tokpatlen=1;
}
optboolexpr ',' optprop ',' code optcommacost ')'
{ register c1_p cp;
outbyte(DO_TOKREPLACE);
outbyte(DO_RETURN);
fprintf(cfile,"\n");
chktabsiz(nc1,MAXC1,"Stacking table");
cp = &c1coercs[nc1++];
cp->c1_texpno = $2;
cp->c1_expr = $4;
cp->c1_prop = $6;
cp->c1_codep = $8;
cp->c1_cost = $9;
}
;
optprop
: /* empty */
{ $$ = -1; }
| PIDENT
{ $$ = $1->i_i.i_prpno; }
;
optcommacost
: /* empty */
{ $$.c_size = 0; $$.c_time = 0;}
| ',' cost
{ $$ = $2; }
;
list1 : /* empty */
{ $$ = 0; }
| optcomma IDENT list1
{ $$=(list1) myalloc(sizeof(struct list1str));
$$->l1next = $3;
$$->l1name = $2;
}
;
optcomma: /* nothing */
| ','
;
emargno : NUMBER
{ if ($1<1 || $1>empatlen)
yyerror("Number after $ out of range");
$$ = $1;
}
;
tokargno
: NUMBER
{ if ($1<1 || $1>tokpatlen)
yyerror("Number within %[] out of range");
$$ = $1;
}
;
expr : '$' emargno
{ $$.expr_index = lookup(0,EX_ARG,$2,0); $$.expr_typ = argtyp(patmnem[$2]);
}
| NUMBER
{ $$.expr_index = lookup(0,EX_CON,(int)($1&0177777),(int)($1>>16));
$$.expr_typ = TYPINT;
}
| STRING
{ $$.expr_index = lookup(0,EX_STRING,strlookup($1),0);
$$.expr_typ = TYPSTR;
}
| RIDENT
{ $$.expr_index = lookup(0,EX_REG,$1->i_i.i_regno,0);
$$.expr_typ = TYPREG;
}
| '%' '[' tokargno '.' IDENT ']'
{ $$.expr_index = lookup(0,EX_TOKFIELD,$3,
findstructel(pattokexp[$3],$5,&$$.expr_typ));
}
| '%' '[' tokargno subreg ']'
{ chkregexp(pattokexp[$3]);
$$.expr_index = lookup(0,EX_SUBREG,$3,$4);
$$.expr_typ = TYPREG;
}
| '%' '[' LCASELETTER subreg ']'
{ if ($3 >= 'a'+nallreg)
yyerror("Bad letter in %[x] construct");
$$.expr_index = lookup(0,EX_ALLREG,$3-'a'+1,$4);
$$.expr_typ = TYPREG;
}
| '%' '[' IDENT ']'
{ $$.expr_index = lookup(0,EX_TOKFIELD,0,
findstructel(curtokexp,$3,&$$.expr_typ));
}
| TOSTRING '(' expr ')'
{ MUST1BEINT($3);
$$.expr_index = lookup(0,EX_TOSTRING,exp1,0);
$$.expr_typ = TYPSTR;
}
| DEFINED '(' expr ')'
{ $$.expr_index = lookup(0,EX_DEFINED,$3.expr_index,0);
$$.expr_typ = TYPBOOL;
}
| SAMESIGN '(' expr ',' expr ')'
{ MUST2BEINT($3,$5);
$$.expr_index = lookup(1,EX_SAMESIGN,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| SFIT '(' expr ',' expr ')'
{ MUST2BEINT($3,$5);
$$.expr_index = lookup(0,EX_SFIT,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| UFIT '(' expr ',' expr ')'
{ MUST2BEINT($3,$5);
$$.expr_index = lookup(0,EX_UFIT,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| ROM '(' emargno ',' NUMBER ')'
{ if ($5<1 || $5>3)
yyerror("Second argument of rom must be >=1 and <=3");
$$.expr_index = lookup(0,EX_ROM,$3-1,$5-1);
$$.expr_typ = TYPINT;
}
| LOWW '(' emargno ')'
{
$$.expr_index = lookup(0,EX_LOWW,$3-1,0);
$$.expr_typ = TYPINT;
}
| HIGHW '(' emargno ')'
{
$$.expr_index = lookup(0,EX_HIGHW,$3-1,0);
$$.expr_typ = TYPINT;
}
| '(' expr ')'
{ $$ = $2; }
| expr CMPEQ expr
{ switch(commontype($1,$3)) {
case TYPINT:
$$.expr_index = lookup(1,EX_NCPEQ,$1.expr_index,$3.expr_index);
break;
case TYPSTR:
$$.expr_index = lookup(1,EX_SCPEQ,$1.expr_index,$3.expr_index);
break;
case TYPREG:
$$.expr_index = lookup(1,EX_RCPEQ,$1.expr_index,$3.expr_index);
break;
}
$$.expr_typ = TYPBOOL;
}
| expr CMPNE expr
{ switch(commontype($1,$3)) {
case TYPINT:
$$.expr_index = lookup(1,EX_NCPNE,$1.expr_index,$3.expr_index);
break;
case TYPSTR:
$$.expr_index = lookup(1,EX_SCPNE,$1.expr_index,$3.expr_index);
break;
case TYPREG:
$$.expr_index = lookup(1,EX_RCPNE,$1.expr_index,$3.expr_index);
break;
}
$$.expr_typ = TYPBOOL;
}
| expr CMPGT expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_NCPGT,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| expr CMPGE expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_NCPGE,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| expr CMPLT expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_NCPLT,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| expr CMPLE expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_NCPLE,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| expr OR2 expr
{ MUST2BEBOOL($1,$3);
$$.expr_index = lookup(0,EX_OR2,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| expr AND2 expr
{ MUST2BEBOOL($1,$3);
$$.expr_index = lookup(0,EX_AND2,exp1,exp2);
$$.expr_typ = TYPBOOL;
}
| expr '+' expr
{ switch(commontype($1,$3)) {
case TYPINT:
$$.expr_index = lookup(1,EX_PLUS,$1.expr_index,$3.expr_index);
break;
case TYPSTR:
$$.expr_index = lookup(0,EX_CAT,$1.expr_index,$3.expr_index);
break;
default:
yyerror("Bad types");
}
$$.expr_typ = $1.expr_typ;
}
| expr '-' expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_MINUS,exp1,exp2);
$$.expr_typ = TYPINT;
}
| expr '*' expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(1,EX_TIMES,exp1,exp2);
$$.expr_typ = TYPINT;
}
| expr '/' expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_DIVIDE,exp1,exp2);
$$.expr_typ = TYPINT;
}
| expr '%' expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_MOD,exp1,exp2);
$$.expr_typ = TYPINT;
}
| expr LSHIFT expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_LSHIFT,exp1,exp2);
$$.expr_typ = TYPINT;
}
| expr RSHIFT expr
{ MUST2BEINT($1,$3);
$$.expr_index = lookup(0,EX_RSHIFT,exp1,exp2);
$$.expr_typ = TYPINT;
}
| NOT expr
{ MUST1BEBOOL($2);
$$.expr_index = lookup(0,EX_NOT,exp1,0);
$$.expr_typ = TYPBOOL;
}
| COMP expr
{ MUST1BEINT($2);
$$.expr_index = lookup(0,EX_COMP,exp1,0);
$$.expr_typ = TYPINT;
}
| INREG '(' expr ')'
{ MUST1BEINT($3);
$$.expr_index = lookup(0,EX_INREG,exp1,0);
$$.expr_typ = TYPINT;
}
| REGVAR '(' expr ')'
{ MUST1BEINT($3);
$$.expr_index = lookup(0,EX_REGVAR,exp1,0);
$$.expr_typ = TYPREG;
}
/*
| '-' expr %prec UMINUS
{ MUST1BEINT($2);
$$.expr_index = lookup(0,EX_UMINUS,exp1,0);
$$.expr_typ = TYPINT;
}
*/
;
subreg : /* empty */
{ $$=0; }
| '.' NUMBER
{ $$=$2; }
;
optboolexpr
: /* empty */
{ $$ = 0; }
| expr
{ MUST1BEBOOL($1);
$$=exp1;
}
;
optexpr
: /* empty */
{ $$.expr_typ=0;
$$.expr_index=0;
}
| expr
;
tokeninstanceno
: tokeninstance
{ $$ = instno($1); }
;
tokeninstance
: '%' '[' tokargno subreg ']'
{ register int i;
if ($4!=0)
chkregexp(pattokexp[$3]);
$$.in_which = IN_COPY;
$$.in_info[0] = $3;
$$.in_info[1] = $4;
for (i=2;i<TOKENSIZE;i++)
$$.in_info[i] = 0;
}
| '%' '[' tokargno '.' IDENT ']'
{ int typ;
register int i;
$$.in_which = IN_COPY;
$$.in_info[0] = $3;
$$.in_info[1] = findstructel(pattokexp[$3],$5,&typ);
if (typ != TYPREG)
yyerror("Must be register");
for (i=2;i<TOKENSIZE;i++)
$$.in_info[i] = 0;
}
| RIDENT
{ register int i;
$$.in_which = IN_RIDENT;
$$.in_info[0] = $1->i_i.i_regno;
for (i=1;i<TOKENSIZE;i++)
$$.in_info[i] = 0;
}
| REGVAR '(' expr ')'
{ register int i;
MUST1BEINT($3);
$$.in_which = IN_REGVAR;
$$.in_info[0] = exp1;
for (i=1;i<TOKENSIZE;i++)
$$.in_info[i] = 0;
}
| '%' '[' LCASELETTER subreg ']'
{ register int i;
if ($3 >= 'a'+nallreg)
yyerror("Bad letter in %[x] construct");
$$.in_which = IN_ALLOC;
$$.in_info[0] = $3-'a';
$$.in_info[1] = $4;
for (i=2;i<TOKENSIZE;i++)
$$.in_info[i] = 0;
}
| '{' TIDENT attlist '}'
{ register int i;
$$.in_which = IN_DESCR;
$$.in_info[0] = $2->i_i.i_tokno;
for(i=0;i<narexp;i++) {
if (arexp[i].expr_typ !=
machtokens[$2->i_i.i_tokno].t_fields[i].t_type)
yyerror("Attribute %d has wrong type",i+1);
$$.in_info[i+1] = arexp[i].expr_index;
}
for (i=narexp+1;i<TOKENSIZE;i++) {
if (machtokens[$2->i_i.i_tokno].t_fields[i-1].t_type!=0)
yyerror("Too few attributes");
$$.in_info[i] = 0;
}
}
;
attlist
: /* empty */
{ narexp = 0; }
| attlist ',' expr
{ arexp[narexp++] = $3; }
;
%%