%{ #ifndef NORCSID static char rcsid[]="$Header$"; #endif /* * (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 #include #include #include #include #include #define extern #include "booth.h" #undef extern %} %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 list1,structlistel %type structlist,structdecl %type expr optexpr %type optcost cost optcommacost %type optboolexpr optnocoerc mnem emargno tokargno optprop %type optcommabool optstack subreg tokenexpressionno optregvar %type tokeninstanceno code stackreplacement optslashnumber %type tokenexpression %type tokeninstance %type optformat %token IDENT TYPENAME %token RIDENT,PIDENT,TIDENT,EIDENT %token LSTRING,STRING %token NUMBER %token 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 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;irmembers[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;irprop[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 i; for(i=0;ii_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 i; if (($$.set_size=$1.set_size)==0) $$.set_size = $3.set_size; for (i=0;i1) 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;ic2_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 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 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 : { $$ = 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 i; if ($4!=0) chkregexp(pattokexp[$3]); $$.in_which = IN_COPY; $$.in_info[0] = $3; $$.in_info[1] = $4; for (i=2;ii_i.i_regno; for (i=1;i= 'a'+nallreg) yyerror("Bad letter in %[x] construct"); $$.in_which = IN_ALLOC; $$.in_info[0] = $3-'a'; $$.in_info[1] = $4; for (i=2;ii_i.i_tokno; for(i=0;ii_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;ii_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; } ; %%