9db305b338
Upon enabling the check, mach/powerpc/ncg/table fails to build as ncgg
gives many errors of "Previous rule impossible on empty stack". David
Given reported this problem in 2013:
https://sourceforge.net/p/tack/mailman/message/30814694/
Commit c93cb69
commented out the error in util/ncgg/cgg.y to disable
the Hall check. This commit enables it again. In ncgg, the Hall
check is checking that a rule is possible with an empty fake stack.
It would be possible if ncg can coerce the values from the real stack
to the fake stack. The powerpc table defined coercions from STACK to
{FS, %a} and {FD, %a}, but the Hall check didn't understand the
coercions and rejected each rule "with FS" or "with FD".
This commit removes the FS and FD tokens and adds a new group of FSREG
registers for single-precision floats, while keeping FREG registers
for double precision. The registers overlap, with each FSREG
containing one FREG, because it is the same register in PowerPC
hardware. FS tokens become FSREG registers and FD tokens become FREG
registers. The Hall check understands the coercions from STACK to
FSREG and FREG. The idea to define separate but overlapping registers
comes from the PDP-11 table (mach/pdp/ncg/table).
This commit also removes F0 from the FREG group. This is my attempt
to keep F0 off the fake stack, because one of the stacking rules uses
F0 as a scratch register (FSCRATCH).
1103 lines
22 KiB
Plaintext
1103 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(), *gen_stackadjust(), *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 STACKADJUST
|
|
%token PATTERNS PAT WITH EXACT KILLS USES REUSING GEN YIELDS LEAVING
|
|
%token DEFINED SAMESIGN SFIT UFIT ROM LOWW HIGHW ISROM STACKOFFSET
|
|
%token CMPEQ CMPNE CMPLT CMPGT CMPLE CMPGE OR2 AND2 LSHIFT RSHIFT NOT COMP
|
|
%token INREG REGVAR 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(); }
|
|
| STACKADJUST expr
|
|
{ $$ = gen_stackadjust($2.ex_index); use_noframepointer++; }
|
|
;
|
|
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); }
|
|
| STACKOFFSET '(' ')'
|
|
{ $$ = make_expr(TYPINT,EX_STACKOFFSET, 0, 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); }
|
|
;
|
|
|
|
optregvartype
|
|
: /* empty */
|
|
{ $$ = reg_any; }
|
|
| ',' regvartype
|
|
{ $$ = $2; }
|
|
;
|
|
%%
|