%{

#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 <local.h>

#if BIGMACHINE
#define BORS(x,y) x
#else
#define BORS(x,y) y
#endif
/* Tunable constants */

#define MAXALLREG 5             /* Maximum number of allocates per rule */
#define MAXREGS BORS(36,32)     /* Total number of registers */
#define MAXREGVARS 8		/* Maximum regvars per type */
#define MAXPROPS 16             /* Total number of register properties */
#define MAXTOKENS BORS(75,32)   /* Different kind of tokens */
#define MAXSETS BORS(100,80)    /* Number of tokenexpressions definable */
#define MAXEMPATLEN 25		/* Maximum length of EM-pattern/replacement */
#define TOKENSIZE 5             /* Maximum number of fields in token struct */
#define MAXINSTANCE BORS(250,120) /* Maximum number of different tokeninstances */
#define MAXSTRINGS BORS(800,400)/* Maximum number of different codestrings */
#define MAXPATTERN BORS(8000,6000) /* Maximum number of bytes in pattern[] */
#define MAXNODES BORS(500,400)  /* Maximum number of expression nodes */
#define MAXMEMBERS 2            /* Maximum number of subregisters per reg */
#define NMOVES BORS(50,30)      /* Maximum number of move definitions */
#define MAXC1   20              /* Maximum of coercions type 1 */
#define MAXC2   20              /* Maximum of coercions type 2 */
#define MAXC3   20              /* Maximum of coercions type 3 */
#define MAXSPLIT 4              /* Maximum degree of split */
#define MAXNSTR 40		/* Maximum consecutive strings in coderule */

char *hname="tables.h";
char *cname="tables.c";
char *iname=0;			/* stdin */

/* Derived constants */

#define SETSIZE ((MAXREGS+1+MAXTOKENS+15)>>4)
#define PROPSETSIZE ((MAXPROPS+15)>>4)

#define BMASK 0377
#define BSHIFT 8

#define TRUE    1
#define FALSE   0

#define MAXPATLEN 7             /* Maximum length of tokenpatterns */

typedef char byte;
typedef char * string;

char *malloc(),*myalloc();

#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <em_spec.h>
#include <em_flag.h>
#include <em_reg.h>
#include <cg_pattern.h>

typedef struct list1str {
	struct list1str *l1next;
	string l1name;
} *list1;
typedef struct list2str {
	struct list2str *l2next;
	list1 l2list;
} *list2;
typedef struct list3str {
	struct list3str *l3next;
	list2 l3list;
} *list3;

typedef struct reginfo {
	string rname;
	string rrepr;
	int rsize;
	int rmembers[MAXMEMBERS];
	int rregvar;
	short rprop[PROPSETSIZE];
} *reginfo;

typedef struct tokeninfo {
	string t_name;
	list2 t_struct;
	struct {
		int t_type;
		string t_sname;
	} t_fields[TOKENSIZE-1];
	int t_size;
	cost_t t_cost;
	int t_format;
} token_t,*token_p;

typedef struct ident {
	struct ident *i_next;
	string i_name;
	int i_type;
#               define IREG 1
#               define IPRP 2
#               define ITOK 3
#               define IEXP 4
	union {
		int i_regno;
		int i_prpno;
		int i_tokno;
		int i_expno;
	} i_i;
} ident_t,*ident_p;

#define ITABSIZE 32
ident_p identtab[ITABSIZE];

#define LOOKUP          0
#define HALFWAY         1
#define ENTER           2
#define JUSTLOOKING     3


typedef struct expr {
	int expr_typ;
#               define TYPINT  1
#               define TYPREG  2
#               define TYPSTR  3
#               define TYPBOOL 4
	int expr_index;
} expr_t,*expr_p;

unsigned cc1=1,cc2=1,cc3=1,cc4=1;

node_t  nodes[MAXNODES];
node_p  lastnode=nodes+1;

string codestrings[MAXSTRINGS];
int ncodestrings;

int strar[MAXNSTR];
int nstr;

int pathash[256];

reginfo machregs[MAXREGS];
char stregclass[MAXREGS];
int nmachregs=1;
int nregclasses=1;
int maxmembers;
struct {
	ident_p propname;
	set_t	propset;
} machprops[MAXPROPS];
int nprops=0;
token_t machtokens[MAXTOKENS];
int nmachtokens=1;
set_t machsets[MAXSETS];
int nmachsets=0;
int patmnem[MAXEMPATLEN];
int empatlen;
int maxempatlen;
int empatexpr;
int maxrule=1;
int pattokexp[MAXPATLEN];
int tokpatlen;
int lookident=0;        /* lexical analyzer flag */
list3 structpool=0;
int nallreg;
int allreg[MAXALLREG];
int maxallreg;
int lino=0;
int nerrors=0;
int curtokexp;
expr_t arexp[TOKENSIZE];
int narexp;
inst_t arinstance[MAXINSTANCE];
int narinstance=1;
move_t machmoves[NMOVES];
int nmoves=0;
byte pattern[MAXPATTERN];
int npatbytes=0;
int prevind;
int rulecount;                  /* Temporary index for ... construct */
int ncoderules=0;
int codebytes=0;
FILE *cfile;
FILE *hfile;
int maxtokensize=0;
int dealflag;
int emrepllen;
int replmnem[MAXEMPATLEN];
int tokrepllen;
int replinst[MAXPATLEN];
int replexpr[MAXPATLEN];
c1_t c1coercs[MAXC1];
c2_t c2coercs[MAXC2];
c3_t c3coercs[MAXC3];
int nc1=0,nc2=0,nc3=0;
int maxsplit=0;
int wsize= -1;
int psize= -1;
int bsize= -1;
char *fmt=0;

int cchandled;
int ccspoiled;
int ccregexpr;
int ccinstanceno;
int cocopropno;
int cocosetno;
int allexpno;

int rvused;	/* regvars used */
int nregvar[4];	/* # of register variables of all kinds */
int rvnumbers[4][MAXREGVARS];	/* The register numbers */

#define chktabsiz(size,maxsize,which) if(size>=maxsize) tabovf(which)

#define MUST1BEINT(e) int exp1=e.expr_index;tstint(e)
#define MUST2BEINT(e1,e2) int exp1=e1.expr_index,exp2=e2.expr_index;tstint(e1);tstint(e2)
#define MUST1BEBOOL(e) int exp1=e.expr_index;tstbool(e)
#define MUST2BEBOOL(e1,e2) int exp1=e1.expr_index,exp2=e2.expr_index;tstbool(e1);tstbool(e2)

%}

%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 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 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 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 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 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;i<TOKENSIZE;i++)
			$$.in_info[i] = 0;
		}
	| '%' '[' tokargno '.' IDENT ']'
		{ int typ;
		  register 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 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 i;
		  MUST1BEINT($3);
		  $$.in_which = IN_REGVAR;
		  $$.in_info[0] = exp1;
		  for (i=1;i<TOKENSIZE;i++)
			$$.in_info[i] = 0;
		}
	| '%' '[' LCASELETTER subreg ']'
		{ register 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 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; }
	;

%%

char * myalloc(n) {
	register char *p;

	p= (char*) malloc(n);
	if (p==0) {
		yyerror("Out of core");
		exit(1);
	}
	return(p);
}

tstint(e) expr_t e; {

	if(e.expr_typ != TYPINT)
		yyerror("Must be integer expression");
}

tstbool(e) expr_t e; {

	if(e.expr_typ != TYPBOOL)
		yyerror("Must be boolean expression");
}

structsize(s) register list2 s; {
	register list1 l;
	register sum;

	sum = 0;
	while ( s != 0 ) {
		l = s->l2list->l1next;
		while ( l != 0 ) {
			sum++;
			l = l->l1next;
		}
		s = s->l2next;
	}
	return(sum);
}

list2 lookstruct(ll) list2 ll; {
	list3 l3;
	list2 l21,l22;
	list1 l11,l12;

	for (l3=structpool;l3 != 0;l3=l3->l3next) {
		for (l21=l3->l3list,l22=ll;l21!=0 && l22!=0;
		     l21=l21->l2next,l22=l22->l2next) {
			for(l11=l21->l2list,l12=l22->l2list;
			    l11!=0 && l12!=0 && strcmp(l11->l1name,l12->l1name)==0;
			    l11=l11->l1next,l12=l12->l1next)
				;
			if (l11!=0 || l12!=0)
				goto contin;
		}
		if(l21==0 && l22==0)
			return(l3->l3list);
		contin:;
	}
	l3 = (list3) myalloc(sizeof(struct list3str));
	l3->l3next=structpool;
	l3->l3list=ll;
	structpool=l3;
	return(ll);
}

instno(inst) inst_t inst; {
	register i,j;

	for(i=1;i<narinstance;i++) {
		if (arinstance[i].in_which != inst.in_which)
			continue;
		for(j=0;j<TOKENSIZE;j++)
			if(arinstance[i].in_info[j] != inst.in_info[j])
				goto cont;
		return(i);
	cont:;
	}
	chktabsiz(narinstance,MAXINSTANCE,"Instance table");
	arinstance[narinstance] = inst;
	return(narinstance++);
}

string scopy(s) string s; {
	register string t;

	t = (char *) myalloc(strlen(s)+1);
	strcpy(t,s);
	return(t);
}

strlookup(s) string s; {
	register i;

	for(i=0;i<ncodestrings;i++)
		if(strcmp(s,codestrings[i])==0)
			return(i);
	chktabsiz(ncodestrings,MAXSTRINGS,"string table");
	codestrings[ncodestrings] = scopy(s);
	return(ncodestrings++);
}

stringno(s) register string s; {
	char buf[256];
	register char *p=buf;

	while(*s != 0) switch(*s) {
	default:
		*p++ = *s++;
		continue;
	case '$':
		s++;
		switch(*s) {
		default:
			yyerror("Bad character after $ in codestring");
		case '$':
			*p++ = *s++;
			continue;
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			*p++ = argtyp(patmnem[*s-'0']) == TYPINT ?
				PR_EMINT : PR_EMSTR;
			*p++ = *s++ -'0';
			continue;
		}
	case '%':
		s++;
		if (*s != '[') {
			if(*s == '%') {
				*p++ = *s++;
				continue;
			} else
				yyerror("Bad character following %% in codestring");
		} else
			s++;
		if(isdigit(*s)) {
			int num;
			num = *s++ - '0';
			if (num<1 || num>tokpatlen)
				yyerror("Number within %[] out of range");
			if (*s == ']') {
				s++;
				*p++ = PR_TOK;
				*p++ = num;
			} else if (*s++ != '.')
				yyerror("Bad character following %%[digit in codestring");
			else {
				char field[256];
				register char *f=field;
				int type,offset;

				while( *s != ']' && *s != 0)
					*f++ = *s++;
				*f++ = 0;
				if (*s != ']')
					yyerror("Unterminated %[] construction in codestring");
				else
					s++;
				if (isdigit(field[0])) {
					chkregexp(pattokexp[num]);
					*p++ = PR_SUBREG;
					*p++ = num;
					*p++ = atoi(field);
				} else {
					offset = findstructel(pattokexp[num],field,&type);
					*p++ = PR_TOKFLD;
					*p++ = num;
					*p++ = offset;
				}
			}
		} else if (*s >= 'a' && *s < 'a'+nallreg) {
			int reg,subreg;
			reg = *s++ -'a'+1;
			if(*s == ']')
				subreg = 255;
			else {
				if (*s != '.')
					yyerror("Bad character following %%[x in codestring");
				s++;
				if(!isdigit(*s))
					yyerror("Bad character following %%[x. in codestring");
				subreg = *s - '0';
				s++;
				if(*s != ']')
					yyerror("Bad character following %%[x.y in codestring");
			}
			s++;
			*p++ = PR_ALLREG;
			*p++ = reg;
			*p++ = subreg;
		} else
			yyerror("Bad character following %%[ in codestring");
	}
	*p++ = 0;
	return(strlookup(buf));
}

tabovf(tablename) string tablename; {
	char buf[256];

	sprintf(buf,"%s overflow",tablename);
	yyerror(buf);
	exit(-1);
}

main(argc,argv) char *argv[]; {

	while (--argc) {
		++argv;
		if (argv[0][0]=='-') {
			switch (argv[0][1]) {
			case 'h':
				hname= &argv[0][2];
				break;
			case 'c':
				cname= &argv[0][2];
				break;
			default:
				fprintf(stderr,"Bad flag %s\n",argv[0]);
				break;
			}
		} else {
			iname= argv[0];
		}
	}
	inithash();
	initio();
	inittables();
	yyparse();
	if (nerrors==0) {
		compueq();
		hashpatterns();
		finishio();
		verbose();
	}
	debug();
	exit(nerrors);
}

lookup(comm,operator,lnode,rnode) {
	register node_p p;

	for (p=nodes+1;p<lastnode;p++) {
		if (p->ex_operator != operator)
			continue;
		if (!(p->ex_lnode == lnode && p->ex_rnode == rnode ||
		    comm && p->ex_lnode == rnode && p->ex_rnode == lnode))
			continue;
		return(p-nodes);
	}
	if (lastnode >= &nodes[MAXNODES])
		yyerror("node table overflow");
	lastnode++;
	p->ex_operator = operator;
	p->ex_lnode = lnode;
	p->ex_rnode = rnode;
	return(p-nodes);
}

compueq() {
	register i,j;

	for (i=1;i<nmachregs;i++) {
		for (j=1;j<i;j++)
			if (eqregclass(i,j)) {
				stregclass[i] = stregclass[j];
				break;
			}
		if (j==i)
			stregclass[i] = nregclasses++;
	}
}

eqregclass(r1,r2) {
	register reginfo rp1,rp2;
	register i;
	short regbits[(MAXREGS+15)>>4];
	int member;

	rp1 = machregs[r1]; rp2 = machregs[r2];
	for (i=0;i<((nprops+15)>>4);i++)
		if (rp1->rprop[i] != rp2->rprop[i])
			return(0);
	for (i=0;i<((MAXREGS+15)>>4);i++)
		regbits[i] = 0;
	for (i=0;i<maxmembers;i++) {
		if (member = rp1->rmembers[i])
			regbits[member>>4] |= (1<<(member&017));
	}
	for (i=0;i<maxmembers;i++) {
		member = rp2->rmembers[i];
		if (regbits[member>>4]&(1<<(member&017)))
			return(0);
	}
	return(1);
}

unsigned hash(name) register string name; {
	register unsigned sum;
	register i;

	for (sum=i=0;*name;i+=3)
		sum ^= (*name++)<<(i&07);
	return(sum);
}

ident_p ilookup(name,enterf) string name; int enterf; {
	register ident_p p,*pp;

	pp = &identtab[hash(name)%ITABSIZE];
	while (*pp != 0) {
		if (strcmp((*pp)->i_name,name)==0)
			if (enterf != ENTER)
				return(*pp);
			else
				yyerror("Multiply defined symbol");
		pp = &(*pp)->i_next;
	}
	if (enterf == LOOKUP)
		yyerror("Undefined symbol");
	if (enterf == JUSTLOOKING)
		return(0);
	p = *pp = (ident_p) myalloc(sizeof(ident_t));
	p->i_name = name;
	p->i_next = 0;
	p->i_type = 0;
	return(p);
}

initio() {

	if (iname!=0 && freopen(iname,"r",stdin)==NULL) {
		fprintf(stderr,"Can't open %s\n",iname);
		exit(-1);
	}
	if ((cfile=fopen(cname,"w"))==NULL) {
		fprintf(stderr,"Can't create %s\n",cname);
		exit(-1);
	}
	if ((hfile=fopen(hname,"w"))==NULL) {
		fprintf(stderr,"Can't create %s\n",hname);
		exit(-1);
	}
	fprintf(cfile,"#include \"param.h\"\n");
	fprintf(cfile,"#include \"tables.h\"\n");
	fprintf(cfile,"#include \"types.h\"\n");
	fprintf(cfile,"#include <cg_pattern.h>\n");
	fprintf(cfile,"#include \"data.h\"\n");
	fprintf(cfile,"\nbyte coderules[] = {\n");
	patbyte(0);
}

exprlookup(sett) set_t sett; {
	register i,j,ok;

	for(i=0;i<nmachsets;i++) {
		ok= (sett.set_size == machsets[i].set_size);
		for(j=0;j<SETSIZE;j++) {
			if (sett.set_val[j] == machsets[i].set_val[j])
				continue;
			ok=0;
			break;
		}
		if (ok)
			return(i);
	}
	chktabsiz(nmachsets,MAXSETS,"Expression table");
	machsets[nmachsets] = sett;
	return(nmachsets++);
}

inittables() {
	register reginfo r;
	register i;
	inst_t inst;
	set_t sett;

	nodes[0].ex_operator=EX_CON;
	nodes[0].ex_lnode=0;
	nodes[0].ex_rnode=0;
	cocopropno=nprops++;
	r=(reginfo)myalloc(sizeof(struct reginfo));
	r->rname = "cc reg";
	r->rrepr = "CC";
	r->rsize = -1;
	r->rregvar= -1;
	for(i=0;i<MAXMEMBERS;i++)
		r->rmembers[i] = 0;
	for(i=0;i<PROPSETSIZE;i++)
		r->rprop[i] = 0;
	r->rprop[cocopropno>>4] |= (1<<(cocopropno&017));
	chktabsiz(nmachregs,MAXREGS,"Register table");
	machregs[nmachregs++]  = r;
	inst.in_which = IN_RIDENT;
	inst.in_info[0] = nmachregs-1;
	for(i=1;i<TOKENSIZE;i++)
		inst.in_info[i]=0;
	ccinstanceno=instno(inst);
	ccregexpr=lookup(0,EX_REG,nmachregs-1,0);
	sett.set_size=0;
	for (i=0;i<SETSIZE;i++)
		sett.set_val[i]=0;
	sett.set_val[nmachregs>>4] |= (01<<(nmachregs&017));
	cocosetno=exprlookup(sett);
}

outregs() {
	register i,j,k;
	static short rset[(MAXREGS+15)>>4];
	int t,ready;

	fprintf(cfile,"char stregclass[] = {\n");
	for (i=0;i<nmachregs;i++)
		fprintf(cfile,"\t%d,\n",stregclass[i]);
	fprintf(cfile,"};\n\nstruct reginfo machregs[] = {\n{0},\n");
	for (i=1;i<nmachregs;i++) {
		fprintf(cfile,"{%d,%d",strlookup(machregs[i]->rrepr),
			machregs[i]->rsize);
		if (maxmembers!=0) {
			fprintf(cfile,",{");
			for(j=0;j<maxmembers;j++)
				fprintf(cfile,"%d,",machregs[i]->rmembers[j]);
			/* now compute and print set of registers
			 * that clashes with this register.
			 * A register clashes with al its children (and theirs)
			 * and with all their parents.
			 */
			for (j=0;j<((MAXREGS+15)>>4);j++)
				rset[j]=0;
			rset[i>>4] |= (1<<(i&017));
			do {
			    ready=1;
			    for (j=1;j<nmachregs;j++)
				if (rset[j>>4]&(1<<(j&017)))
				    for (k=0;k<maxmembers;k++)
					if ((t=machregs[j]->rmembers[k])!=0) {
					    if ((rset[t>>4]&(1<<(t&017)))==0)
						ready=0;
					    rset[t>>4] |= (1<<(t&017));
					}
			} while (!ready);
			do {
			    ready=1;
			    for (j=1;j<nmachregs;j++)
				for (k=0;k<maxmembers;k++)
				    if ((t=machregs[j]->rmembers[k])!=0)
					if (rset[t>>4]&(1<<(t&017))) {
						if (rset[j>>4]&(1<<(j&017))==0)
						    ready=0;
						rset[j>>4] |= (1<<(j&017));
					}
			} while (!ready);
			fprintf(cfile,"},{");
			for (j=0;j<((nmachregs+15)>>4);j++)
				fprintf(cfile,"%d,",rset[j]);
			fprintf(cfile,"}");
		}
		if (machregs[i]->rregvar>=0)
			fprintf(cfile,",1");
		fprintf(cfile,"},\n");
	}
	fprintf(cfile,"};\n\n");
}

finishio() {
	register i;
	register node_p np;
	int j;
	int setsize;
	register move_p mp;

	fprintf(cfile,"};\n\n");
	if (wsize>0)
		fprintf(hfile,"#define TEM_WSIZE %d\n",wsize);
	else
		yyerror("Wordsize undefined");
	if (psize>0)
		fprintf(hfile,"#define TEM_PSIZE %d\n",psize);
	else
		yyerror("Pointersize undefined");
	if (bsize>=0)
		fprintf(hfile,"#define TEM_BSIZE %d\n",bsize);
	else
		yyerror("EM_BSIZE undefined");
	if (fmt!=0)
		fprintf(hfile,"#define WRD_FMT \"%s\"\n",fmt);
	fprintf(hfile,"#define MAXALLREG %d\n",maxallreg);
	setsize = (nmachregs+1 + nmachtokens + 15)>>4;
	fprintf(hfile,"#define SETSIZE %d\n",setsize);
	fprintf(hfile,"#define NPROPS %d\n",nprops);
	fprintf(hfile,"#define NREGS %d\n",nmachregs);
	fprintf(hfile,"#define REGSETSIZE %d\n",(nmachregs+15)>>4);
	fprintf(hfile,"#define TOKENSIZE %d\n",maxtokensize);
	fprintf(hfile,"#define MAXMEMBERS %d\n",maxmembers);
	fprintf(hfile,"#define LONGESTPATTERN %d\n",maxempatlen);
	fprintf(hfile,"#define MAXRULE %d\n",maxrule);
	fprintf(hfile,"#define NMOVES %d\n",nmoves);
	fprintf(hfile,"#define NC1 %d\n",nc1);
	if (nc2) {
		assert(maxsplit!=0);
		fprintf(hfile,"#define NC2 %d\n",nc2);
		fprintf(hfile,"#define MAXSPLIT %d\n",maxsplit);
	}
	fprintf(hfile,"#define NC3 %d\n",nc3);
	outregs();
	fprintf(cfile,"tkdef_t tokens[] = {\n");
	for(i=0;i<nmachtokens;i++) {
		fprintf(cfile,"{%d,{%d,%d},{",machtokens[i].t_size,
				machtokens[i].t_cost.c_size,
				machtokens[i].t_cost.c_time);
		for(j=0;j<maxtokensize;j++)
			fprintf(cfile,"%d,",machtokens[i].t_fields[j].t_type);
		fprintf(cfile,"},%d},\n",machtokens[i].t_format);
	}
	fprintf(cfile,"};\n\nnode_t enodes[] = {\n");
	for(np=nodes;np<lastnode;np++)
		fprintf(cfile,"{%d,%d,%d},\n",np->ex_operator,np->ex_lnode,
				np->ex_rnode);
	fprintf(cfile,"};\n\nstring codestrings[] = {\n");
	for(i=0;i<ncodestrings;i++) {
		register char *p;
		p=codestrings[i];
		fprintf(cfile,"\t\"");
		while (*p) {
			register int c = (*p) & BMASK;
			if (! isascii(c) || iscntrl(c)) {
				fprintf(cfile,"\\%c%c%c",((c>>6) &03)+'0',
					((c>>3)&07)+'0',(c&07)+'0');
			}
			else	putc(c, cfile);
			p++;
		}
		fprintf(cfile,"\",\n");
	}
	fprintf(cfile,"};\n\nset_t machsets[] = {\n");
	for(i=0;i<nmachsets;i++) {
		fprintf(cfile,"{%d,{",machsets[i].set_size);
		for(j=0;j<setsize;j++)
			fprintf(cfile,"0%o,",machsets[i].set_val[j]);
		fprintf(cfile,"}},\n");
	}
	fprintf(cfile,"};\n\ninst_t tokeninstances[] = {\n");
	for(i=0;i<narinstance;i++) {
		fprintf(cfile,"{ %d, {",arinstance[i].in_which);
		for(j=0;j<=maxtokensize;j++)
			fprintf(cfile,"%d,",arinstance[i].in_info[j]);
		fprintf(cfile,"}},\n");
	}
	fprintf(cfile,"};\n\nmove_t moves[] = {\n");
	for (i=0;i<nmoves;i++) {
		mp = &machmoves[i];
		fprintf(cfile,"{%d,%d,%d,%d,%d,{%d,%d}},\n",
			mp->m_set1, mp->m_expr1,
			mp->m_set2, mp->m_expr2,
			mp->m_cindex,
			mp->m_cost.c_size,mp->m_cost.c_time);
	}
	fprintf(cfile,"};\n\nbyte pattern[] = {\n");
	for (i=0;i<npatbytes;i++) {
		fprintf(cfile,"%3d,",pattern[i]&BMASK);
		if ((i%10)==9)
			fprintf(cfile,"\n");
	}
	fprintf(cfile,"\n};\n\nint pathash[256] = {\n");
	for(i=0;i<256;i++) {
		fprintf(cfile,"%6d,",pathash[i]);
		if((i&07)==07)
			fprintf(cfile,"\n");
	}
	fprintf(cfile,"};\n\nc1_t c1coercs[] = {\n");
	for (i=0;i<nc1;i++)
		fprintf(cfile,"{%d,%d,%d,%d,{%d,%d}},\n",
			c1coercs[i].c1_texpno,
			c1coercs[i].c1_expr,
			c1coercs[i].c1_prop,
			c1coercs[i].c1_codep,
			c1coercs[i].c1_cost.c_size,
			c1coercs[i].c1_cost.c_time);
	if (nc2)
		fprintf(cfile,"};\n\nc2_t c2coercs[] = {\n");
	for (i=0;i<nc2;i++) {
		fprintf(cfile,"{%d,%d,{",
			c2coercs[i].c2_texpno,
			c2coercs[i].c2_nsplit);
		for (j=0;j<maxsplit;j++)
			fprintf(cfile,"%d,",c2coercs[i].c2_repl[j]);
		fprintf(cfile,"},%d},\n",c2coercs[i].c2_codep);
	}
	fprintf(cfile,"};\n\nc3_t c3coercs[] = {\n");
	for (i=0;i<nc3;i++)
		fprintf(cfile,"{%d,%d,%d,%d},\n",
			c3coercs[i].c3_texpno,
			c3coercs[i].c3_prop,
			c3coercs[i].c3_repl,
			c3coercs[i].c3_codep);
	fprintf(cfile,"};\n\n");
	for (i=0;i<nprops;i++) {
		fprintf(cfile,"struct reginfo *rlist%d[] = {\n",i);
		for (j=2;j<=nmachregs;j++) {
			if (machregs[j-1]->rregvar<0 && 
			    (machprops[i].propset.set_val[j>>4]&(1<<(j&017))))
				fprintf(cfile,"\t&machregs[%d],\n",j-1);
		}
		fprintf(cfile,"\t0\n};\n");
	}
	fprintf(cfile,"struct reginfo **reglist[] = {\n");
	for (i=0;i<nprops;i++) {
		fprintf(cfile,"\trlist%d,\n",i);
	}
	fprintf(cfile,"};\n");
	fprintf(cfile,"unsigned cc1 = %u;\n",cc1);
	fprintf(cfile,"unsigned cc2 = %u;\n",cc2);
	fprintf(cfile,"unsigned cc3 = %u;\n",cc3);
	fprintf(cfile,"unsigned cc4 = %u;\n",cc4);
	if (rvused)
		outregvar();
}

outregvar() {
	register i,j;

	fprintf(hfile,"#define REGVARS\n");
	fprintf(cfile,"#include \"regvar.h\"\n");
	fprintf(cfile,"int nregvar[4] = { ");
	for (i=0;i<4;i++) fprintf(cfile,"%d, ",nregvar[i]);
	fprintf(cfile,"};\n");
	for (i=0;i<4;i++)
		if (nregvar[i]>0)
			fprintf(cfile,"struct regassigned ratar%d[%d];\n",
					i,nregvar[i]);
	for (i=0;i<4;i++) if (nregvar[i]>0) {
		fprintf(cfile,"int rvtar%d[] = {",i);
		for (j=0;j<nregvar[i];j++)
			fprintf(cfile,"%d,",rvnumbers[i][j]);
		fprintf(cfile,"};\n");
	}
	fprintf(cfile,"\nint *rvnumbers[] = {\n");
	for (i=0;i<4;i++)
		if (nregvar[i]>0)
			fprintf(cfile,"\trvtar%d,\n",i);
		else
			fprintf(cfile,"\t0,\n");
	fprintf(cfile,"};\n\nstruct regassigned *regassigned[] = {\n");
	for (i=0;i<4;i++)
		if (nregvar[i]>0)
			fprintf(cfile,"\tratar%d,\n",i);
		else
			fprintf(cfile,"\t0,\n");
	fprintf(cfile,"};\n");
}

verbose() {

	fprintf(stderr,"Codebytes %d\n",codebytes);
	fprintf(stderr,"Registers %d(%d)\n",nmachregs,MAXREGS);
	fprintf(stderr,"Properties %d(%d)\n",nprops,MAXPROPS);
	fprintf(stderr,"Tokens %d(%d)\n",nmachtokens,MAXTOKENS);
	fprintf(stderr,"Sets %d(%d)\n",nmachsets,MAXSETS);
	fprintf(stderr,"Tokeninstances %d(%d)\n",narinstance,MAXINSTANCE);
	fprintf(stderr,"Strings %d(%d)\n",ncodestrings,MAXSTRINGS);
	fprintf(stderr,"Enodes %d(%d)\n",lastnode-nodes,MAXNODES);
	fprintf(stderr,"Patbytes %d(%d)\n",npatbytes,MAXPATTERN);
}

inbetween() {
	register ident_p ip;
	register i,j;
	register move_p mp;

	lookident=1;    /* for lexical analysis */

	chktabsiz(nmachsets+1,MAXSETS,"Expressiontable");
	for (i=0;i<SETSIZE;i++)
		machsets[nmachsets].set_val[i] = 0xFFFF;
	machsets[nmachsets].set_val[0] &= ~1;
	machsets[nmachsets].set_size = 0;
	ip=ilookup("SCRATCH",ENTER);
	ip->i_type=IEXP;
	ip->i_i.i_expno = nmachsets++;

	for (i=0;i<SETSIZE;i++)
		machsets[nmachsets].set_val[i] = 0xFFFF;
	machsets[nmachsets].set_size = 0;
	ip=ilookup("ALL",ENTER);
	ip->i_type=IEXP;
	allexpno = ip->i_i.i_expno = nmachsets++;
	mp = &machmoves[nmoves++];
	mp->m_set1 = cocosetno;
	mp->m_expr1 = 0;
	mp->m_set2 = nmachsets-1;
	mp->m_expr2 = 0;
	mp->m_cindex = 0;
	mp->m_cost.c_size = 0;
	mp->m_cost.c_time = 0;

	/*
	 * Create sets of registers per property
	 */

	for (i=0;i<nprops;i++) {
		short *sp = machprops[i].propset.set_val;

		sp[0] |= 1;
		for (j=2;j<=nmachregs;j++)
			if (machregs[j-1]->rprop[i>>4]&(1<<(i&017)))
				sp[j>>4] |= (1<<(j&017));
	}
}

formconversion(p,tp) register char *p; register token_p tp; {
	char buf[256];
	register char *q=buf;
	char field[256];
	register char *f;
	int i;

	if (p==0)
		return(0);
	while (*p) switch(*p) {
	default: *q++ = *p++; continue;
	case '%':
		p++;
		if(*p == '%') {
			*q++ = *p++;
			continue;
		}
		if (*p == '[')
			p++;
		else
			yyerror("Bad character after % in format");
		f=field;
		while (*p != 0 && *p != ']')
			*f++ = *p++;
		*f++ = 0;
		if (*p == ']')
			p++;
		else
			yyerror("Unterminated %[] construct in format");
		for (i=0;i<TOKENSIZE-1;i++)
			if (strcmp(field,tp->t_fields[i].t_sname)==0)
				break;
		if (i==TOKENSIZE-1)
			yyerror("Unknown field in %[] construct in format");
		*q++ = i+1;
	}
	*q++ = 0;
	return(strlookup(buf));
}

setfields(tp,format) register token_p tp; string format; {
	register i;
	list2 ll;
	register list1 l;
	int type;

	for(i=0;i<TOKENSIZE-1;i++)
		tp->t_fields[i].t_type = 0;
	i=0;
	for(ll=tp->t_struct;ll!=0;ll=ll->l2next) {
		l=ll->l2list;
		if(strcmp(l->l1name,"REGISTER")==0)
			type = TYPREG;
		else if (strcmp(l->l1name,"INT")==0)
			type = TYPINT;
		else    type = TYPSTR;
		for(l=l->l1next;l!=0;l=l->l1next) {
			tp->t_fields[i].t_type = type;
			tp->t_fields[i].t_sname = l->l1name;
			i++;
		}
	}
	if (format != 0)
		tp->t_format = formconversion(format,tp);
	else
		tp->t_format = -1;
}

chkregexp(number) {
	register i;

	for(i=nmachregs+1;i<nmachregs+1+nmachtokens;i++)
		if(machsets[number].set_val[i>>4]&(01<<(i&017)))
			yyerror("No tokens allowed in this set");
}

findstructel(number,name,t) string name; int *t; {
	register i;
	register token_p tp;
	register list2 structdecl;
	int offset;

	for(i=1;i<=nmachregs;i++)
		if (machsets[number].set_val[i>>4]&(01<<(i&017)))
			yyerror("No registers allowed in this set");
	structdecl = 0;
	for (i=nmachregs+1;i<nmachregs+1+nmachtokens;i++) {
		if (machsets[number].set_val[i>>4]&(01<<(i&017))) {
			if (structdecl == 0) {
				structdecl = machtokens[i-(nmachregs+1)].t_struct;
				tp = &machtokens[i-(nmachregs+1)];
			} else if(structdecl != machtokens[i-(nmachregs+1)].t_struct)
					yyerror("Multiple structs in this set");
		}
	}
	if (structdecl == 0) {
		yyerror("No structs in this set");
		return(0);
	}
	for(offset=0;offset<TOKENSIZE-1;offset++)
		if(tp->t_fields[offset].t_type != 0 &&
		   strcmp(tp->t_fields[offset].t_sname,name)==0) {
			*t = tp->t_fields[offset].t_type;
			return(offset+1);
		}
	yyerror("No such field in this struct");
	return(0);
}

extern char em_flag[];

argtyp(mn) {

	switch(em_flag[mn-sp_fmnem]&EM_PAR) {
	case PAR_W:
	case PAR_S:
	case PAR_Z:
	case PAR_O:
	case PAR_N:
	case PAR_L:
	case PAR_F:
	case PAR_R:
	case PAR_C:
		return(TYPINT);
	default:
		return(TYPSTR);
	}
}

commontype(e1,e2) expr_t e1,e2; {

	if(e1.expr_typ != e2.expr_typ)
		yyerror("Type incompatibility");
	return(e1.expr_typ);
}

extern char em_mnem[][4];

#define HASHSIZE        (2*(sp_lmnem-sp_fmnem))

struct hashmnem {
	char h_name[3];
	byte h_value;
} hashmnem[HASHSIZE];

inithash() {
	register i;

	for(i=0;i<=sp_lmnem-sp_fmnem;i++)
		enter(em_mnem[i],i+sp_fmnem);
}

enter(name,value) char *name; {
	register unsigned h;

	h=hash(name)%HASHSIZE;
	while (hashmnem[h].h_name[0] != 0)
		h = (h+1)%HASHSIZE;
	strncpy(hashmnem[h].h_name,name,3);
	hashmnem[h].h_value = value;
}

int mlookup(name) char *name; {
	register unsigned h;

	h = hash(name)%HASHSIZE;
	while (strncmp(hashmnem[h].h_name,name,3) != 0 &&
	       hashmnem[h].h_name[0] != 0)
		h = (h+1)%HASHSIZE;
	return(hashmnem[h].h_value&BMASK);      /* 0 if not found */
}

hashpatterns() {
	short index;
	register byte *bp,*tp;
	register short i;
	unsigned short hashvalue;
	int patlen;

	index = prevind;
	while (index != 0) {
		bp = &pattern[index];
		tp = &bp[PO_MATCH];
		i = *tp++&BMASK;
		if (i==BMASK) {
			i = *tp++&BMASK;
			i |= (*tp++&BMASK)<<BSHIFT;
		}
		patlen = i;
		hashvalue = 0;
		switch(patlen) {
		default:        /* 3 or more */
			hashvalue = (hashvalue<<4)^(*tp++&BMASK);
		case 2:
			hashvalue = (hashvalue<<4)^(*tp++&BMASK);
		case 1:
			hashvalue = (hashvalue<<4)^(*tp++&BMASK);
		}
		assert(hashvalue!= ILLHASH);
		i=index;
		index = (bp[PO_NEXT]&BMASK)|(bp[PO_NEXT+1]<<BSHIFT);
		bp[PO_HASH] = hashvalue>>BSHIFT;
		hashvalue &= BMASK;
		bp[PO_NEXT] = pathash[hashvalue]&BMASK;
		bp[PO_NEXT+1] = pathash[hashvalue]>>BSHIFT;
		pathash[hashvalue] = i;
	}
}

debug() {
	register i,j;

	for(i=0;i<ITABSIZE;i++) {
		register ident_p ip;
		for(ip=identtab[i];ip!=0;ip=ip->i_next)
			printf("%-14s %1d %3d\n",ip->i_name,
				ip->i_type,ip->i_i.i_regno);
	}

	for(i=2;i<nmachregs;i++) {
		register reginfo rp;

		rp=machregs[i];
		printf("%s = (\"%s\", %d",rp->rname,rp->rrepr,rp->rsize);
		for(j=0;j<MAXMEMBERS;j++)
			if(rp->rmembers[j] != 0)
				printf(", %s",machregs[rp->rmembers[j]]->rname);
		printf(")");
		for(j=0;j<nprops;j++)
			if(rp->rprop[j>>4]&(1<<(j&017)))
				printf(", %s",machprops[j].propname->i_name);
		printf(".\n");
	}
}

out(n) {

	assert(n>=0);
	if (n<128)
		outbyte(n);
	else {
		outbyte(n/256+128);
		outbyte(n%256);
	}
}

outbyte(n) {

	fprintf(cfile,"%d, ",n&BMASK);
	codebytes++;
}

pat(n) {

	assert(n>=0);
	if (n<128)
		patbyte(n);
	else {
		patbyte(n/256+128);
		patbyte(n%256);
	}
}

patshort(n) {

	patbyte(n&BMASK);
	patbyte(n>>BSHIFT);
}

patbyte(n) {

	chktabsiz(npatbytes,MAXPATTERN,"Pattern table");
	pattern[npatbytes++] = n;
}

max(a,b) {

	if (a>b)
		return(a);
	return(b);
}

#include "bootlex.c"