ack/util/ncgg/cgg.y
George Koehler 307a8b996e Add regvar_w() and regvar_d() for use with reglap.
If the ncg table uses reglap, then regvar($1, reg_float) would have
two sizes of registers.  An error from ncgg would happen if regvar()
was in a token that allows only one size.  Now one can pick a size
with regvar_w() for word size or regvar_d() for double-word size.

Add regvar_d and regvar_w as keywords in ncgg.  Modify EX_REGVAR to
include the register size.  In ncg, add some checks for the register
size.  In tables without reglap, regvar() works as before, and ncg
ignores the register size in EX_REGVAR.
2017-10-17 12:05:41 -04:00

1104 lines
22 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".
*/
%{
#ifndef NORCSID
static char rcsid[]= "$Id$";
#endif
#include "param.h"
#include "varinfo.h"
#include "lookup.h"
#include "set.h"
#include "iocc.h"
#include "instruct.h"
#include "expr.h"
#include "extern.h"
#include <cgg_cg.h>
#include <em_reg.h>
extern int lineno;
int instline,saveline;
int startline;
int npatterns;
int att_type;
int patindex[MAXPATTERNS];
extern set_t l_sets[];
int emhere=0; /* lexical analyzer flag */
int optexact=0; /* Inside "with exact" rule */
int optstack=0; /* Inside with <blah> STACK rule */
int saferulefound=0;
int maxrule=0;
int in_em_repl=0; /* set when in EM replacement part */
struct varinfo *defcost;
int Xstackflag=0; /* set in coercions, moves, and tests. %1 means something
different then.
*/
struct varinfo *gen_inst(),*gen_move(),*gen_test(),*gen_preturn(),*gen_tlab();
struct varinfo *gen_label(), *make_erase();
expr_t make_expr(),ident_expr(),subreg_expr(),tokm_expr(),all_expr();
expr_t perc_ident_expr(),sum_expr(),regvar_expr();
set_t ident_to_set(),setproduct(),setsum(),setdiff();
iocc_t subr_iocc(),tokm_iocc(),ident_iocc(),all_iocc(),percident_iocc(), descr_iocc();
extern int narexpr;
extern expr_t arexp[];
int niops;
iocc_t iops[20];
%}
%union {
int yy_int;
char * yy_str;
varinfo * yy_varinfo;
set_t yy_set;
operand *yy_oplist;
expr_t yy_expr;
iocc_t yy_iocc;
}
%token PROPERTIES
%token REGISTERS
%token TOKENS
%token SETS
%token MOVES
%token TESTS
%token STACKINGRULES COERCIONS
%token INSTRUCTIONS
%token TOPELTSIZE FALLTHROUGH LABELDEF
%token PROC CALL EXAMPLE
%token FROM TO
%token TEST MOVE STACK RETURN
%token PATTERNS PAT WITH EXACT KILLS USES REUSING GEN YIELDS LEAVING
%token DEFINED SAMESIGN SFIT UFIT ROM LOWW HIGHW ISROM
%token CMPEQ CMPNE CMPLT CMPGT CMPLE CMPGE OR2 AND2 LSHIFT RSHIFT NOT COMP
%token INREG REGVAR REGVAR_W REGVAR_D
%token REG_ANY REG_FLOAT REG_LOOP REG_POINTER
%token <yy_int> ADORNACCESS
%token <yy_int> ADORNCC
%token INT
%token ADDR
%token <yy_int> EMMNEM
%token <yy_int> NUMBER
%token <yy_int> DOLLAR PERCENT ALLREG
%token <yy_str> IDENT PERC_IDENT
%token <yy_str> STRING
%token TIMEFACTOR SIZEFACTOR
%token COST
%type <yy_varinfo> prop_list property ident_list ident_list_el
%type <yy_varinfo> att_list att_list_el att_list_el_list att_ident structdecl optcost optformat
%type <yy_varinfo> kills allocates yields leaving
%type <yy_varinfo> generates kill_list kill_list_el uselist uselist_el genlist yieldlist
%type <yy_varinfo> leavelist leavelist_el gen_instruction
%type <yy_varinfo> opt_erase_list erase_list erase_list_el
%type <yy_str> opt_par_string optstring
%type <yy_int> register propno att_list_el_type tokenset_no
%type <yy_int> adornlist optstar optuses optregvar regvartype optregvartype
%type <yy_int> emarg tokarg subreg allreg
%type <yy_expr> expr regvarexpr
%type <yy_iocc> tokeninstance
%type <yy_int> optexpr optexact optstack
%type <yy_set> tokenset
%type <yy_oplist> oplist oplist_el
%left OR2
%left AND2
%left '|'
%left '^'
%left '&'
%left CMPEQ CMPNE
%left CMPLT CMPLE CMPGT CMPGE
%left RSHIFT LSHIFT
%left '+' '-'
%left '*' '/' '%'
%nonassoc NOT COMP UMINUS
%start machtable
%%
/*
* The machine table consists of a number of sections, with their
* own associated parsers.
*/
machtable
: constants
properties
registers
tokens
{ make_std_sets(); }
sets
instructions
moves
tests
stacks
coercs
code
;
/*
* Constants are parsed as name=value pairs
*/
constants
: constdeflist
;
constdeflist
: /* empty */
| constdeflist constdef
;
constdef
: IDENT'=' NUMBER
{ n_const($1,$3); free($1); }
| IDENT '=' STRING
{ n_sconst($1,$3); free($1); free($3); }
| TIMEFACTOR '=' NUMBER '/' NUMBER
{ fc1 = $3; fc2 = $5; }
| SIZEFACTOR '=' NUMBER '/' NUMBER
{ fc3 = $3; fc4 = $5; }
| error
;
/*
* Properties are parsed as a list of names optionally followed by their size
*/
properties
: PROPERTIES { make_const(); } prdef_list
;
prdef_list
: prdef_list_el
| prdef_list optcomma prdef_list_el
;
prdef_list_el
: IDENT
{ n_prop($1,wordsize); free($1); }
| IDENT '(' NUMBER ')'
{ n_prop($1,$3); free($1); }
;
/*
* Registers are rows of reglist:proplist pairs
*/
registers
: REGISTERS regdef_list
;
regdef_list
: regdef_list_el
| regdef_list regdef_list_el
;
regdef_list_el
: ident_list ':' prop_list optregvar '.'
{ regline($1,$3,$4); free((char *) $1); free((char *) $3); }
| error '.'
;
optregvar
: /* empty */
{ $$ = -1; }
| REGVAR
{ $$ = reg_any; }
| REGVAR '(' regvartype ')'
{ $$ = $3; }
;
regvartype
: REG_ANY
{ $$ = reg_any;}
| REG_FLOAT
{ $$ = reg_float;}
| REG_LOOP
{ $$ = reg_loop;}
| REG_POINTER
{ $$ = reg_pointer;}
;
ident_list
: ident_list_el
| ident_list optcomma ident_list_el
{ $3->vi_next = $1; $$ = $3; }
;
ident_list_el
: IDENT opt_par_string
{ NEW($$,struct varinfo);
$$->vi_next = 0;
$$->vi_int[0] = n_reg($1,$2,0,0,0);
free($1); if($2!=0) free($2);
}
| IDENT opt_par_string '=' register
{ NEW($$,struct varinfo);
$$->vi_next = 0;
$$->vi_int[0] = n_reg($1,$2,1,$4,0);
free($1); if($2!=0) free($2);
}
| IDENT opt_par_string '=' register '+' register
{ NEW($$,struct varinfo);
$$->vi_next = 0;
$$->vi_int[0] = n_reg($1,$2,2,$4,$6);
free($1); if($2!=0) free($2);
}
;
opt_par_string
: /* empty */
{ $$ = 0; }
| '(' STRING ')'
{ $$ = $2; }
;
register
: IDENT
{ register symbol *sy_p;
sy_p = lookup($1,symreg,mustexist);
$$ = sy_p->sy_value.syv_regno;
free($1);
}
;
prop_list
: property
| prop_list optcomma property
{ $3->vi_next = $1; $$ = $3; }
;
property
: IDENT
{ register symbol *sy_p;
sy_p = lookup($1,symprop,mustexist);
NEW($$,struct varinfo);
$$->vi_next=0;
$$->vi_int[0]=sy_p->sy_value.syv_propno;
free($1);
}
;
propno
: IDENT
{ register symbol *sy_p;
sy_p = lookup($1,symprop,mustexist);
$$ = sy_p->sy_value.syv_propno;
free($1);
}
;
/* tokens are parsed as struct definitions
* types in the struct can be register properties, ADDR or INT
*/
tokens
: TOKENS tokdeflist
;
tokdeflist
: tokdeflist_el
| tokdeflist tokdeflist_el
;
tokdeflist_el
: IDENT '=' structdecl NUMBER optcost optformat '.'
{ n_tok($1,$3,$4,$5,$6);
free($1);
freevi($3);
freevi($5);
freevi($6);
}
| error '.'
;
structdecl
: '{' att_list '}'
{ $$ = $2; }
;
att_list
: /* empty */
{ $$ = 0; }
| att_list_el att_list
{ $$ = $1; while ($$->vi_next) $$ = $$->vi_next;
$$->vi_next = $2; $$ = $1;
}
;
att_list_el
: att_list_el_type
{ att_type = $1; }
att_list_el_list
';'
{ $$ = $3; }
;
att_list_el_list
: att_ident
| att_ident ',' att_list_el_list
{ $1->vi_next = $3; $$ = $1; }
;
att_ident
: IDENT
{ NEW($$, struct varinfo);
$$->vi_next = 0;
$$->vi_int[0] = att_type;
$$->vi_str[0] = $1;
}
;
att_list_el_type
: INT
{ $$ = -1; }
| ADDR
{ $$ = -2; }
| propno
;
optcost
:
{ if (defcost==VI_NULL)
$$=VI_NULL;
else {
NEW($$,struct varinfo);
*$$ = *defcost;
}
}
| COST '(' NUMBER ',' NUMBER ')'
{ NEW ($$,struct varinfo);
$$->vi_int[0] = $3;
$$->vi_int[1] = $5;
}
;
optformat
:
{ $$ = 0; }
| STRING optformat
{ NEW($$,struct varinfo);
$$->vi_next = $2;
$$->vi_int[0] = 0;
$$->vi_str[0] = $1;
}
| IDENT optformat
{ NEW($$,struct varinfo);
$$->vi_next = $2;
$$->vi_int[0] = 1;
$$->vi_str[0] = $1;
}
;
optcomma
: ','
| /* empty */
;
/* sets are parsed as ident = expression */
sets
: SETS setdeflist
;
setdeflist
: setdeflist_el
| setdeflist setdeflist_el
;
setdeflist_el
: IDENT '=' tokenset_no '.'
{ n_set($1,$3); free($1); }
| error '.'
;
tokenset_no
: tokenset
{ $$ = setlookup($1); }
;
tokenset
: IDENT
{ $$ = ident_to_set($1); free($1); }
| tokenset '*' tokenset
{ $$ = setproduct($1,$3); }
| tokenset '+' tokenset
{ $$ = setsum($1,$3); }
| tokenset '-' tokenset
{ $$ = setdiff($1,$3); }
| '(' tokenset ')'
{ $$ = $2; }
;
instructions
: INSTRUCTIONS optcost instdef_list
{ defcost = $2; }
;
instdef_list
: instdef_list_el
| instdef_list instdef_list_el
;
instdef_list_el
: IDENT optstring oplist opt_erase_list optcost '.'
{ n_instr($1,$2,$3,$4,$5); freevi($5); }
| error '.'
;
oplist
: /* empty */
{ $$ = 0; }
| oplist_el
| oplist_el ',' oplist
{ $$ = $1; $$->o_next = $3; }
;
oplist_el
: tokenset_no adornlist
{ NEW($$,struct operand);
$$->o_next = 0 ;
$$->o_setno = $1;
$$->o_adorn = $2;
checkprintformat($1);
}
;
adornlist
: /* empty */
{ $$ = 0; }
| ADORNACCESS adornlist
{ if ($2&AD_RWMASK)
error("Only one of :ro,:wo,:rw allowed");
$$ = $1 | $2;
}
| ADORNCC adornlist
{ $$ = $1|$2; }
;
opt_erase_list
: /* empty */
{ $$ = VI_NULL;}
| KILLS erase_list
{ $$ = $2; }
;
erase_list
: erase_list_el
{ $$ = $1; }
| erase_list_el erase_list
{ $1->vi_next = $2; $$ = $1; }
;
erase_list_el
: IDENT
{ $$ = make_erase($1); }
| ADORNCC
{ NEW($$, struct varinfo);
$$->vi_int[0] = -1;
$$->vi_next = VI_NULL;
}
;
/* Now the moves */
moves
: MOVES
movedeflist
| /* empty */
;
movedeflist
: movedeflist_el
| movedeflist movedeflist_el
;
movedeflist_el
: FROM
{startline = lineno; }
tokenset_no
{ Xstackflag = 1;
cursetno = $3;
}
optexpr
{ Xstackflag = 0;
cursetno = -1;
}
TO tokenset_no
{ cursetno = $8;
tokpatlen=2;
tokpatset[0] = $3;
tokpatset[1] = $8;
tokpatro[0] = 1;
Xstackflag = 1;
}
optexpr
{ Xstackflag = 0;
cursetno = -1;
}
GEN genlist
{ tokpatlen=0;
tokpatro[0]=0;
n_move($3,$5,$8,$10,$13);
freevi($13);
}
| error
;
/* Now the test part */
tests
: TESTS
{ Xstackflag = 1; }
testdeflist
{ Xstackflag = 0; }
| /* empty */
;
testdeflist
: testdeflist_el
| testdeflist testdeflist_el
;
testdeflist_el
: TO
{ startline = lineno;}
TEST tokenset_no
{ cursetno = $4;
tokpatlen=1;
tokpatset[0]=$4;
tokpatro[0] = 1;
}
optexpr GEN genlist
{ tokpatlen=0;
tokpatro[0] = 0;
n_test($4,$6,$8);
freevi($8);
cursetno = -1;
}
| error
;
/* Now the stacks */
stacks
: STACKINGRULES
{ Xstackflag = 1; }
stackdeflist
{ Xstackflag = 0; }
;
stackdeflist
: stackdeflist_el
| stackdeflist stackdeflist_el
;
stackdeflist_el
: FROM
{startline = lineno;}
tokenset_no
{ cursetno = $3;
tokpatlen=1;
tokpatset[0] = $3;
tokpatro[0] = 1;
}
optexpr TO STACK optuses GEN genlist
{ tokpatro[0] = 0;
n_stack($3,$5,$8,$10);
freevi($10);
cursetno = -1;
}
;
optuses
: /* empty */
{ $$ = -1; nallreg=0;}
| USES propno
{ $$ = $2; nallreg = 1; allreg[0] = $2; }
;
/* Now the one-to-one coercion rules */
coercs
: COERCIONS
{ Xstackflag = 1; }
coercdeflist
{ Xstackflag = 0; }
;
coercdeflist
: coercdeflist_el
| coercdeflist coercdeflist_el
;
coercdeflist_el
: FROM
{startline = lineno; tokpatlen=0; inithall();}
STACK allocates generates YIELDS tokeninstance
{ checkhall();
n_coerc(0,0,$4,$5,(struct varinfo *) 0,$7);
freevi($4);
freevi($5);
}
| FROM
{startline = lineno;}
tokenset_no
{ cursetno = $3;
tokpatlen=1;
tokpatset[0]=$3;
tokpatro[0] = 1;
inithall();
}
optexpr allocates generates yields
{ tokpatro[0] = 0;
checkhall();
n_coerc($3,$5,$6,$7,$8);
freevi($6);
freevi($7);
cursetno = -1;
}
;
/* Now the code part */
code
: PATTERNS coderules
;
coderules
: coderule
| coderules coderule
;
coderule
: PAT {emhere=1;} empattern {emhere=0;} optexpr
{ empatexpr = $5;
npatterns = 0;
saferulefound=0;
if (empatlen>maxempatlen)
maxempatlen=empatlen;
}
patterns
{ if (!saferulefound)
error("Previous rule impossible on empty stack");
outpatterns();
}
| PROC IDENT example
{ npatterns = 0; saferulefound=0; inproc=1; n_proc($2); }
patterns
{ if (!saferulefound)
error("Previous rule impossible on empty stack");
outpatterns(); inproc=0;
}
| error
{ skipupto(PAT,"pat"); yyerrok; yyclearin; }
;
example
: /* empty */
{ empatlen = 0; }
| EXAMPLE {emhere=1;} empattern {emhere=0;}
;
empattern
: EMMNEM
{ empatlen = 1; emmnem[0] = $1; }
| empattern EMMNEM
{ NEXT(empatlen,EMPATMAX,"Em pattern");
emmnem[empatlen-1] = $2;
}
;
patterns
: onepattern
{ saferulefound=1;
callproc=0;
}
| morepatterns
{ callproc=0;
if (npatterns>maxrule)
maxrule=npatterns;
}
| CALL IDENT '(' stringlist ')'
{ register symbol *sy_p;
saferulefound=1;
sy_p=lookup($2,symproc,mustexist);
callproc=sy_p->sy_value.syv_procoff;
free($2);
if (nprocargs > maxprocargs) maxprocargs = nprocargs;
}
;
stringlist
: STRING
{ nprocargs = 1; procarg[0] = strlookup($1); free($1); }
| stringlist ',' STRING
{ NEXT(nprocargs, MAXPROCARG, "Procedure argument list");
procarg[nprocargs-1] = strlookup($3); free($3);
}
;
onepattern
: { inithall(); startline=lineno;
tokpatlen=0; optexact=0; optstack=0;
}
kills allocates generates yields leaving
{
patindex[npatterns++]=codeindex;
checkhall();
dopattern(0,$2,$3,$4,$5,$6);
freevi($2);
freevi($3);
freevi($4);
freevi($5);
freevi($6);
}
;
morepatterns
: { inithall(); } pattern
| morepatterns { inithall(); } pattern
;
pattern
: stackpattern kills allocates generates yields leaving
{ patindex[NEXT(npatterns,MAXPATTERNS,"Patterns")]=codeindex;
if (hall() && !optexact) saferulefound=1;
dopattern(0,$2,$3,$4,$5,$6);
freevi($2);
freevi($3);
freevi($4);
freevi($5);
freevi($6);
}
;
stackpattern
: WITH optexact
{ startline = lineno; }
setlist optstack
{ if (tokpatlen > maxtokpatlen) maxtokpatlen = tokpatlen; }
;
optexact
: /* empty */
{ $$ = optexact = 0; }
| EXACT
{ $$ = optexact = 1; }
;
optstack
: /* empty */
{ $$ = optstack = 0; }
| STACK
{ $$ = optstack = 1; }
;
setlist
: /* empty */
{ tokpatlen = 0; }
| setlist tokenset_no
{ NEXT(tokpatlen,TOKPATMAX,"Stack pattern");
tokpatset[tokpatlen-1] = $2;
checkunstacking($2);
if (l_sets[$2].set_size == 0) {
error("Tokenset is empty or has elements with different sizes");
}
}
;
kills
: /* empty */
{ $$ = 0; }
| KILLS kill_list
{ $$ = $2;
}
;
kill_list
: kill_list_el
| kill_list_el ',' kill_list
{ $$=$1; $$->vi_next = $3; }
;
kill_list_el
: tokenset_no { cursetno=$1; } optexpr
{ NEW($$,struct varinfo);
$$->vi_next = 0;
$$->vi_int[0]=$1;
$$->vi_int[1]=$3;
cursetno = -1;
}
| regvarexpr
{ NEW($$,struct varinfo);
$$->vi_next = 0;
$$->vi_int[0] = -($1.ex_index + 1);
$$->vi_int[1] = 0;
}
;
allocates
: /* empty */
{ $$ = 0; nallreg=0;}
| USES uselist
{ $$ = $2; setallreg($2); }
;
uselist
: uselist_el
{ prophall($1->vi_int[0]); }
| uselist_el ',' uselist
{ prophall($1->vi_int[0]); $$=$1; $$->vi_next=$3; }
;
uselist_el
: property
{ $$=$1; $$->vi_int[1] = 0; }
| property '=' tokeninstance
{ if (!existalmove($3,$$->vi_int[0]))
error("No such move defined");
$$=$1; $$->vi_int[1] = $3.in_index;
}
| REUSING tokeninstance
{ NEW($$,struct varinfo);
$$->vi_next = 0;
$$->vi_int[0] = -1;
$$->vi_int[1] = $2.in_index;
}
;
generates
: /* empty */
{ $$ = 0; }
| GEN genlist
{ $$ = $2; }
;
genlist
: /* empty */
{ $$ = 0; }
| gen_instruction genlist
{ if ($1!=0) {
register struct varinfo *tvip;
$$=tvip=$1;
while (tvip->vi_next!=VI_NULL)
tvip=tvip->vi_next;
tvip->vi_next = $2;
} else {
$$ = $2;
}
}
;
gen_instruction
: {instline = lineno; } IDENT optstar gen_oplist
{ saveline =lineno; lineno=instline;
$$ = gen_inst($2,$3); free($2);
lineno = saveline;
}
| NUMBER ':'
{ $$ = gen_tlab($1); }
| MOVE tokeninstance ',' tokeninstance
{ $$ = gen_move($2,$4); }
| TEST tokeninstance
{ $$ = gen_test($2);}
| LABELDEF emarg
{ $$ = gen_label($2-1); use_tes++; }
| RETURN
{ $$ = gen_preturn(); }
;
optstar
: /* empty */
{ $$=0; }
| '*'
{ $$=1; }
| '[' NUMBER ']'
{ $$=$2; }
;
gen_oplist
: '.' /* empty gives conflicts */
{ niops=0; }
| tokeninstance
{ niops=1;iops[0]=$1; }
| gen_oplist ',' tokeninstance
{ iops[niops++] = $3; }
;
yields
: /* empty */
{ $$ = 0; }
| YIELDS { tokrepllen = 0; } yieldlist
{ $$ = $3; if (tokrepllen > maxtokrepllen) maxtokrepllen = tokrepllen; }
;
yieldlist
: /* empty */
{ $$ = 0; }
| tokeninstance yieldlist
{ checkstacking($1.in_set);
NEW($$,struct varinfo);
$$->vi_next = $2;
$$->vi_int[0] = $1.in_index;
tokrepllen++;
}
;
leaving
: /* empty */
{ $$ = 0; }
| LEAVING {emhere=1; in_em_repl=1; emrepllen = 0; } leavelist
{ emhere=0; in_em_repl=0; $$ = $3;
if (emrepllen > maxemrepllen) maxemrepllen = emrepllen;
}
;
leavelist
: leavelist_el
| leavelist_el leavelist
{ $$=$1; $$->vi_next=$2; }
;
leavelist_el
: EMMNEM optexpr
{ NEW($$,struct varinfo);
$$->vi_next=0;
$$->vi_int[0] = $1;
$$->vi_int[1] = $2;
emrepllen++;
}
;
optstring
: /* empty */
{ $$ = 0; }
| STRING
;
optexpr
: /* empty */
{ $$ = 0; }
| expr
{ $$ = $1.ex_index; } /* type checking ? */
;
tokeninstance
: tokarg subreg
{ $$ = subr_iocc($1,$2); }
| tokarg '.' IDENT
{ $$ = tokm_iocc($1,$3); free($3); }
| IDENT
{ $$ = ident_iocc($1); free($1);}
| allreg subreg
{ $$ = all_iocc($1,$2); }
| PERC_IDENT
{ if (cursetno < 0) {
error("%%<ident> not allowed here");
}
$$ = percident_iocc($1);
free($1);
}
| '{' IDENT attlist '}'
{ $$ = descr_iocc($2); free($2); }
;
attlist
: /* empty */
{ narexpr = 0; }
| attlist ',' expr
{ arexp[narexpr++] = $3; }
;
emarg
: DOLLAR
{ if ($1<1 || $1>empatlen)
error("Only %d instructions in pattern",empatlen);
$$ = $1;
}
;
tokarg
: PERCENT
{ $$ = $1;
if (in_em_repl)
error("No token references allowed in EM replacement part");
if ($1<1 || $1>tokpatlen) {
error("Only %d tokens in stackpattern",tokpatlen);
$$ =1;
}
if (Xstackflag) $$ = 0;
}
;
subreg
: /* empty */
{ $$ = 0; }
| '.' NUMBER
{ if ($2<1 || $2>2) {
error("Only 2 subregisters allowed");
$$ = 1;
} else {
$$ = $2;
}
}
;
allreg
: ALLREG
{ if ($1>=nallreg)
fatal("Only %d registers allocated",nallreg);
$$ = $1;
}
;
expr
: NUMBER
{ $$ = make_expr(TYPINT,EX_CON, (int) ($1 & 0xFFFF), (int) ($1>>16));
}
| emarg
{ $$ = make_expr(argtyp(emmnem[$1-1]),EX_ARG,$1,0); }
| STRING
{ $$ = make_expr(TYPADDR,EX_STRING,strlookup($1),0); free($1); }
| IDENT
{ $$ = ident_expr($1); free($1); }
| tokarg subreg
{ $$ = subreg_expr($1,$2); }
| tokarg '.' IDENT
{ $$ = tokm_expr($1,$3); free($3); }
| allreg subreg
{ $$ = all_expr($1,$2); }
| PERC_IDENT
{ if (cursetno < 0) {
error("%%<ident> not allowed here");
}
$$ = perc_ident_expr($1);
free($1);
}
| DEFINED '(' expr ')'
{ $$ = make_expr(TYPBOOL,EX_DEFINED,i_expr($3),0); }
| SAMESIGN '(' expr ',' expr ')'
{ $$ = make_expr(TYPBOOL,EX_SAMESIGN,i_expr($3),i_expr($5)); }
| TOPELTSIZE '(' emarg ')'
{ $$ = make_expr(TYPINT,EX_TOPELTSIZE,$3-1,0); }
| FALLTHROUGH '(' emarg ')'
{ $$ = make_expr(TYPBOOL,EX_FALLTHROUGH,$3-1,0); }
| SFIT '(' expr ',' expr ')'
{ $$ = make_expr(TYPBOOL,EX_SFIT,i_expr($3),i_expr($5)); }
| UFIT '(' expr ',' expr ')'
{ $$ = make_expr(TYPBOOL,EX_UFIT,i_expr($3),i_expr($5)); }
| ROM '(' emarg ',' NUMBER ')'
{ $$ = make_expr(TYPINT,EX_ROM,$3-1,chkincl($5,1,3)-1); }
| ISROM '(' emarg ')'
{ $$ = make_expr(TYPBOOL,EX_ISROM,$3-1,0); }
| LOWW '(' emarg ')'
{ $$ = make_expr(TYPINT,EX_LOWW,$3-1,0); }
| HIGHW '(' emarg ')'
{ $$ = make_expr(TYPINT,EX_HIGHW,$3-1,0); }
/* Excluded, because it causes a shift-reduce conflict
(problems with a tokenset_no followed by an optexpr)
| '-' expr %prec UMINUS
{ $$ = make_expr(TYPINT,EX_CON, 0, 0);
$$ = make_expr(TYPINT,EX_MINUS,i_expr($$),i_expr($2));
}
*/
| '(' expr ')'
{ $$ = $2; }
| expr CMPEQ expr
{ $$ = make_expr(TYPBOOL,eq2expr($1,$3),$1.ex_index,$3.ex_index); }
| expr CMPNE expr
{ $$ = make_expr(TYPBOOL,ne2expr($1,$3),$1.ex_index,$3.ex_index); }
| expr CMPLT expr
{ $$ = make_expr(TYPBOOL,EX_NCPLT,i_expr($1),i_expr($3)); }
| expr CMPGT expr
{ $$ = make_expr(TYPBOOL,EX_NCPGT,i_expr($1),i_expr($3)); }
| expr CMPLE expr
{ $$ = make_expr(TYPBOOL,EX_NCPLE,i_expr($1),i_expr($3)); }
| expr CMPGE expr
{ $$ = make_expr(TYPBOOL,EX_NCPGE,i_expr($1),i_expr($3)); }
| expr OR2 expr
{ $$ = make_expr(TYPBOOL,EX_OR2,b_expr($1),b_expr($3)); }
| expr AND2 expr
{ $$ = make_expr(TYPBOOL,EX_AND2,b_expr($1),b_expr($3)); }
| expr '|' expr
{ $$ = make_expr(TYPINT,EX_OR,i_expr($1),i_expr($3)); }
| expr '^' expr
{ $$ = make_expr(TYPINT,EX_XOR,i_expr($1),i_expr($3)); }
| expr '&' expr
{ $$ = make_expr(TYPINT,EX_AND,i_expr($1),i_expr($3)); }
| expr '+' expr
{ $$ = sum_expr($1,$3); }
| expr '-' expr
{ $$ = make_expr(TYPINT,EX_MINUS,i_expr($1),i_expr($3)); }
| expr '*' expr
{ $$ = make_expr(TYPINT,EX_TIMES,i_expr($1),i_expr($3)); }
| expr '/' expr
{ $$ = make_expr(TYPINT,EX_DIVIDE,i_expr($1),i_expr($3)); }
| expr '%' expr
{ $$ = make_expr(TYPINT,EX_MOD,i_expr($1),i_expr($3)); }
| expr LSHIFT expr
{ $$ = make_expr(TYPINT,EX_LSHIFT,i_expr($1),i_expr($3)); }
| expr RSHIFT expr
{ $$ = make_expr(TYPINT,EX_RSHIFT,i_expr($1),i_expr($3)); }
| NOT expr
{ $$ = make_expr(TYPBOOL,EX_NOT,b_expr($2),0); }
| COMP expr
{ $$ = make_expr(TYPINT,EX_COMP,i_expr($2),0); }
| INREG '(' expr ')'
{ $$ = make_expr(TYPINT,EX_INREG,i_expr($3),0); }
| regvartype
{ $$ = make_expr(TYPINT,EX_CON, $1+1, 0); }
| regvarexpr
;
regvarexpr
: REGVAR '(' expr optregvartype ')'
{ $$ = regvar_expr($3,$4,-1); }
| REGVAR_W '(' expr optregvartype ')'
{ $$ = regvar_expr($3,$4,wordsize); }
| REGVAR_D '(' expr optregvartype ')'
{ $$ = regvar_expr($3,$4,2*wordsize); }
;
optregvartype
: /* empty */
{ $$ = reg_any; }
| ',' regvartype
{ $$ = $2; }
;
%%