#ifndef NORCSID
static char rcsid[] = "$Id$";
#endif

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "param.h"
#include "tables.h"
#include "types.h"
#include <cgg_cg.h>
#include "data.h"
#include "result.h"
#include "state.h"
#include "equiv.h"
#include "extern.h"
#ifdef REGVARS
#include "regvar.h" /* regreturn */
#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
 */

#define ALLOW_NEXTEM /* code generator is allowed new try of NEXTEM \
            in exceptional cases */

byte startupcode[] = { DO_NEXTEM };

#ifdef NDEBUG
#define DEBUG(string)
#else
#include <stdio.h>
#define DEBUG(string)                                              \
	{                                                              \
		if (Debug)                                                 \
			fprintf(stderr, "%-*d%s\n", 4 * level, level, string); \
	}
#endif

#define BROKE()                                    \
	{                                              \
		assert(origcp != startupcode || !paniced); \
		DEBUG("BROKE");                            \
		totalcost = INFINITY;                      \
		goto doreturn;                             \
	}
#define CHKCOST()                   \
	{                               \
		if (totalcost >= costlimit) \
			BROKE();                \
	}

#ifdef TABLEDEBUG
int tablelines[MAXTDBUG];
int ntableline;
int set_fd, set_size;
short* set_val;
char* set_flag;
#endif

unsigned codegen(byte* codep, int ply, int toplevel, unsigned costlimit, int forced)
{
#ifndef NDEBUG
	byte* origcp = codep;
	static int level = 0;
#endif
	unsigned totalcost = 0;
	int inscoerc = 0;
	int procarg[MAXPROCARG + 1] = {};
#ifdef ALLOW_NEXTEM
	static int paniced;
	char* savebp = 0;
#endif
	state_t state;
#define SAVEST savestatus(&state)
#define RESTST restorestatus(&state)
#define FREEST /* nothing */
#ifdef TABLEDEBUG
	extern char* tablename;
#endif

#ifndef NDEBUG
	assert(costlimit <= INFINITY);
	level++;
	DEBUG("Entering codegen");
	if (Debug > 1)
		fprintf(stderr, "toplevel = %d\n", toplevel);
#endif
	for (;;)
	{
		switch ((*codep++) & 037)
		{
			default:
				assert(FALSE);
/* NOTREACHED */
#ifdef TABLEDEBUG
			case DO_DLINE:
			{
				int n;

				getint(n, codep);
				tablelines[ntableline++] = n;
				if (ntableline >= MAXTDBUG)
					ntableline -= MAXTDBUG;
				if (set_fd)
					set_val[n >> 4] &= ~(1 << (n & 017));
#ifndef NDEBUG
				if (Debug)
					fprintf(stderr, "code from \"%s\", line %d\n", tablename, n);
#endif
				break;
			}
#endif
			case DO_NEXTEM:
			{
				byte* bp;
				int n;
				unsigned mindistance, dist;
				int i;
				int cindex;
				int npos, pos[MAXRULE];
				unsigned mincost, t;

				DEBUG("NEXTEM");
				tokpatlen = 0;
				nallreg = 0;
				if (toplevel)
				{
					garbage_collect();
					totalcost = 0;
				}
				else
				{
					if (--ply <= 0)
						goto doreturn;
				}
				if (stackheight > MAXFSTACK - 7)
				{
#ifndef NDEBUG
					if (Debug)
						fprintf(stderr, "Fakestack overflow threatens(%d), action ...\n", stackheight);
#endif
					totalcost += stackupto(&fakestack[6], ply, toplevel);
				}
#ifndef ALLOW_NEXTEM
				bp = nextem(toplevel);
#else
				if (toplevel)
					paniced = 0;
				savebp = nextem(toplevel);
			panic:
				if (toplevel)
					totalcost = 0;
				bp = savebp;
#endif
				if (bp == 0)
				{
					/*
		 * No pattern found, can be pseudo or error
		 * in table.
		 */
					if (toplevel)
					{
						codep--;
						DEBUG("pseudo");
						dopseudo();
					}
					else
						goto doreturn;
				}
				else
				{
#ifndef NDEBUG
					chkregs();
#endif
					if (!toplevel)
					{
						ply -= emp - saveemp + 1;
						if (ply <= 0)
							ply = 1;
					}
					n = *bp++;
					if (n == 0)
					{ /* "procedure" */
						int j, nargs;
						getint(i, bp);
						getint(nargs, bp);
						assert(nargs <= MAXPROCARG);
						for (j = 0; j < nargs; j++)
						{
							getint(procarg[j], bp);
						}
						bp = &pattern[i];
						n = *bp++;
						DEBUG("PROC_CALL");
					}
					assert(n > 0 && n <= MAXRULE);
					if (n > 1)
					{
						mindistance = MAXINT;
						npos = 0;
						for (i = 0; i < n; i++)
						{
							getint(cindex, bp);
							dist = distance(cindex);
#ifndef NDEBUG
							if (Debug)
								fprintf(stderr, "distance of pos %d is %u\n", i, dist);
#endif
							if (dist <= mindistance
#ifdef ALLOW_NEXTEM
							    || paniced
#endif
							    )
							{
								if (dist < mindistance)
								{
									if (dist == 0)
										goto gotit;
									npos = 0;
									mindistance = dist;
								}
#ifdef ALLOW_NEXTEM
								if (dist < MAXINT)
#endif
									pos[npos++] = cindex;
							}
						}
						assert(mindistance < MAXINT);
						if (npos > 1)
						{
							/*
				 * More than 1 tokenpattern is a candidate.
				 * Decision has to be made by lookahead.
				 */
							SAVEST;
							mincost = costlimit - totalcost + 1;
							assert(mincost <= INFINITY);
							for (i = 0; i < npos; i++)
							{
								t = codegen(&coderules[pos[i]], ply, FALSE,
								    costlimit < MAXINT ? mincost : MAXINT, 0);
#ifndef NDEBUG
								if (Debug)
									fprintf(stderr, "mincost %u,cost %u,pos %d\n", mincost, t, i);
#endif
								if (t < mincost)
								{
									mincost = t;
									cindex = pos[i];
								}
								RESTST;
							}
							FREEST;
							if (totalcost + mincost > costlimit)
							{
								BROKE();
							}
						}
						else
						{
							cindex = pos[0];
						}
					}
					else
					{
						getint(cindex, bp);
					}

				gotit:
					/*
		 * Now cindex contains the code-index of the best candidate
		 * so proceed to use it.
		 */
					codep = &coderules[cindex];
				}
				break;
			}
			case DO_COERC:
			{
				DEBUG("COERC");
				tokpatlen = 1;
				inscoerc = 1;
				break;
			}
			case DO_XXMATCH:
				DEBUG("XXMATCH");
			case DO_XMATCH:
			{
				int i, temp;

				DEBUG("XMATCH");
				tokpatlen = (codep[-1] >> 5) & 07;
				for (i = 0; i < tokpatlen; i++)
					getint(temp, codep);
				break; /* match already checked by distance() */
			}
			case DO_MATCH:
			{
				int i, j;
				unsigned mincost, t;
				token_p tp;
				int size, lsize;
				int tokexp[MAXPATLEN];
				int nregneeded;
				token_p regtp[MAXCREG];
				c3_p regcp[MAXCREG];
				rl_p regls[MAXCREG];
				c3_p cp, findcoerc();
#ifdef MAXSPLIT
				int sret;
#endif
				int stackpad = 0;
				struct perm *tup, *ntup, *besttup, *tuples();

				DEBUG("MATCH");
				tokpatlen = (codep[-1] >> 5) & 07;
				for (i = 0; i < tokpatlen; i++)
					getint(tokexp[i], codep);
				tp = &fakestack[stackheight - 1];
				i = 0;
				while (i < tokpatlen && tp >= fakestack)
				{
					size = tsize(tp);
					while (i < tokpatlen && (lsize = ssize(tokexp[i])) <= size)
					{
						size -= lsize;
						i++;
					}
					if (i < tokpatlen && size != 0)
					{
						totalcost += stackupto(tp, ply, toplevel);
						CHKCOST();
						break;
					}
					tp--;
				}
				tp = &fakestack[stackheight - 1];
				i = 0;
				while (i < tokpatlen && tp >= fakestack)
				{
					size = tsize(tp);
					lsize = ssize(tokexp[i]);
					if (size != lsize)
					{ /* find coercion */
#ifdef MAXSPLIT
						sret = split(tp, &tokexp[i], ply, toplevel);
						if (sret == 0)
						{
#endif /* MAXSPLIT */
							totalcost += stackupto(tp, ply, toplevel);
							CHKCOST();
							break;
#ifdef MAXSPLIT
						}
						i += sret;
#endif /* MAXSPLIT */
					}
					else
						i += 1;
					tp--;
				}
			nextmatch:
				tp = &fakestack[stackheight - 1];
				i = 0;
				nregneeded = 0;
				while (i < tokpatlen && tp >= fakestack)
				{
					if (!match(tp, &machsets[tokexp[i]], 0))
					{
						cp = findcoerc(tp, &machsets[tokexp[i]]);
#ifndef NDEBUG
						if (Debug > 1)
							fprintf(stderr, "findcoerc returns %p at position %d\n", cp, i);
#endif
						if (cp == 0)
						{
							for (j = 0; j < nregneeded; j++)
								regtp[j] -= (tp - fakestack + 1);
							totalcost += stackupto(tp, ply, toplevel);
							CHKCOST();
							break;
						}
						else
						{
							if (cp->c3_prop < 0)
							{
								totalcost += docoerc(tp, cp, ply, toplevel, 0);
								CHKCOST();
							}
							else
							{
#ifndef NDEBUG
								if (Debug > 1)
									fprintf(stderr, "Register of type %d needed, remembering...\n", cp->c3_prop);
#endif
								assert(nregneeded < MAXCREG);
								regtp[nregneeded] = tp;
								regcp[nregneeded] = cp;
								regls[nregneeded] = curreglist;
								nregneeded++;
							}
						}
					}
					i++;
					tp--;
				}
				if (tokpatlen > stackheight)
				{
#ifndef NDEBUG
					if (Debug > 1)
						fprintf(stderr, "Pattern too long, %d with only %d items on stack\n",
						    tokpatlen, stackheight);
#endif
					stackpad = tokpatlen - stackheight;
					for (j = stackheight - 1; j >= 0; j--)
						fakestack[j + stackpad] = fakestack[j];
					for (j = 0; j < stackpad; j++)
						fakestack[j].t_token = 0;
					stackheight += stackpad;
					for (j = 0; j < nregneeded; j++)
						regtp[j] += stackpad;
					for (tp = &fakestack[stackpad - 1]; i < tokpatlen && tp >= fakestack; i++, tp--)
					{
						cp = findcoerc((token_p)0, &machsets[tokexp[i]]);
						if (cp == 0)
						{
							for (j = 0; j < nregneeded; j++)
								myfree((string)(regls[j]));
#ifndef ALLOW_NEXTEM
							assert(!toplevel);
							BROKE();
#else
							assert(!(toplevel && paniced));
							if (paniced)
								goto normalfailed;
							totalcost = INFINITY;
							for (i = 0; i < stackheight - stackpad; i++)
								fakestack[i] = fakestack[i + stackpad];
							stackheight -= stackpad;
							goto doreturn;
#endif
						}
						if (cp->c3_prop < 0)
						{
							totalcost += docoerc(tp, cp, ply, toplevel, 0);
							CHKCOST();
						}
						else
						{
							assert(nregneeded < MAXCREG);
							regtp[nregneeded] = tp;
							regcp[nregneeded] = cp;
							regls[nregneeded] = curreglist;
							nregneeded++;
						}
					}
				}
				else
					stackpad = 0;
				assert(i == tokpatlen);
				if (nregneeded == 0)
					break;
				SAVEST;
				mincost = costlimit - totalcost + 1;
				tup = tuples(regls, nregneeded);
				besttup = 0;
				for (; tup != 0; tup = ntup)
				{
#ifndef NDEBUG
					if (Debug > 1)
					{
						fprintf(stderr, "Next tuple %d,%d,%d,%d\n",
						    tup->p_rar[0],
						    tup->p_rar[1],
						    tup->p_rar[2],
						    tup->p_rar[3]);
						fprintf(stderr, "totalcost = %u, costlimit = %u, mincost = %u\n",
						    totalcost, costlimit, mincost);
					}
#endif
					ntup = tup->p_next;
					for (i = 0, t = 0; i < nregneeded && t < mincost; i++)
						t += docoerc(regtp[i], regcp[i], ply, FALSE, tup->p_rar[i]);
#ifndef NDEBUG
					if (Debug > 1)
						fprintf(stderr, "cost after coercions: %u\n", t);
#endif
					if (t < mincost && tokpatlen <= stackheight)
					{
#ifndef NDEBUG
						if (Debug > 2)
							fprintf(stderr, "Continuing match after coercions\n");
#endif
						t += codegen(codep, ply, FALSE, mincost < MAXINT ? mincost - t : MAXINT, 0);
					}
					if (t < mincost && tokpatlen <= stackheight)
					{
						mincost = t;
						besttup = tup;
					}
					else
						myfree((string)tup);
					RESTST;
				}
				FREEST;
				for (i = 0; i < nregneeded; i++)
					myfree((string)(regls[i]));
				if (totalcost + mincost > costlimit)
				{
					if (besttup)
						myfree((string)besttup);
				normalfailed:
					if (stackpad != tokpatlen)
					{
						if (stackpad)
						{
							for (i = 0; i < stackheight - stackpad; i++)
								fakestack[i] = fakestack[i + stackpad];
							stackheight -= stackpad;
							if (costlimit < MAXINT)
								BROKE();
							totalcost += stackupto(&fakestack[stackheight - 1], ply, toplevel);
						}
						else
							totalcost += stackupto(fakestack, ply, toplevel);
						CHKCOST();
						goto nextmatch;
					}
					totalcost += mincost;
					for (i = 0; i < stackheight - stackpad; i++)
						fakestack[i] = fakestack[i + stackpad];
					stackheight -= stackpad;
					BROKE();
				}
				for (i = 0; i < nregneeded; i++)
					totalcost += docoerc(regtp[i], regcp[i], ply, toplevel, besttup->p_rar[i]);
				assert(totalcost <= costlimit);
				myfree((string)besttup);
				break;
			}
			case DO_TOSTACK:
			case DO_REMOVE:
			{
				int texpno, nodeno;
				token_p tp;
				struct reginfo* rp;
				int doremove = (codep[-1] & 037) == DO_REMOVE;
				extern int allsetno;

				DEBUG(doremove ? "REMOVE" : "TOSTACK");
				if (codep[-1] & 32)
				{
					getint(texpno, codep);
					getint(nodeno, codep);
				}
				else
				{
					getint(texpno, codep);
					nodeno = 0;
				}
				if (texpno == allsetno)
				{
					totalcost += stackupto(&fakestack[stackheight - tokpatlen - 1], ply, toplevel);
					CHKCOST();
					if (doremove)
						for (rp = machregs; rp < machregs + NREGS; rp++)
							rp->r_contents.t_token = 0;
					break;
				}
				for (tp = &fakestack[stackheight - tokpatlen - 1]; tp >= &fakestack[0]; tp--)
					if (match(tp, &machsets[texpno], nodeno))
					{
						/* investigate possible coercion to register */
						totalcost += stackupto(tp, ply, toplevel);
						CHKCOST();
						break;
					}
				if (doremove)
					for (rp = machregs; rp < machregs + NREGS; rp++)
					{
						if (rp->r_contents.t_token != 0 && match(&rp->r_contents, &machsets[texpno], nodeno))
						{
#ifndef NDEBUG
							if (Debug > 1)
								fprintf(stderr, "killing reg %ld (%s)\n", (long)(rp - machregs), rp->r_repr ? codestrings[rp->r_repr] : "cc");
#endif
							rp->r_contents.t_token = 0;
						}
					}
				break;
			}
			case DO_KILLREG:
			case DO_RREMOVE:
			{ /* register remove */
				int i, nodeno;
				token_p tp;
				tkdef_p tdp;
				result_t result;
				int dokill = (codep[-1] & 037) == DO_KILLREG;

				DEBUG(dokill ? "KILLREG" : "RREMOVE");
				getint(nodeno, codep);
				compute(&enodes[nodeno], &result);
				if (result.e_typ != EV_REG)
					break;
				if (in_stack(result.e_v.e_reg))
					BROKE(); /* Check aside-stack */
				if (dokill)
				{
					/* kill register, and kill condition codes if they are set to
		   this register
		*/
					machregs[result.e_v.e_reg].r_contents.t_token = 0;
					if (machregs[0].r_contents.t_token == -1 && machregs[0].r_contents.t_att[0].ar == result.e_v.e_reg)
					{
						machregs[0].r_contents.t_token = 0;
					}
				}
				for (tp = &fakestack[stackheight - tokpatlen - 1]; tp >= &fakestack[0]; tp--)
					if (tp->t_token == -1)
					{
						if (tp->t_att[0].ar == result.e_v.e_reg)
							goto gotone;
					}
					else
					{
						tdp = &tokens[tp->t_token];
						for (i = 0; i < TOKENSIZE; i++)
							if (tdp->t_type[i] == EV_REG && tp->t_att[i].ar == result.e_v.e_reg)
								goto gotone;
					}
				break;
			gotone:
				/* investigate possible coercion to register */
				totalcost += stackupto(tp, ply, toplevel);
				CHKCOST();
				break;
			}
			case DO_DEALLOCATE:
			{
				int i;
				tkdef_p tdp;
				int tinstno;
				token_t token;

				DEBUG("DEALLOCATE");
				getint(tinstno, codep);
				instance(tinstno, &token);
				if (token.t_token == -1)
					chrefcount(token.t_att[0].ar, -1, TRUE);
				else
				{
					tdp = &tokens[token.t_token];
					for (i = 0; i < TOKENSIZE; i++)
						if (tdp->t_type[i] == EV_REG)
							chrefcount(token.t_att[i].ar, -1, TRUE);
				}
				break;
			}
			case DO_REALLOCATE:
			{
				struct reginfo* rp;

				DEBUG("REALLOCATE");
				for (rp = machregs + 1; rp < machregs + NREGS; rp++)
					if (rp->r_tcount)
					{
						rp->r_refcount -= rp->r_tcount;
						rp->r_tcount = 0;
					}
				break;
			}
			case DO_ALLOCATE:
			{
				int i, j;
				int tinstno;
				int npos, npos2, pos[NREGS], pos2[NREGS];
				unsigned mincost, t;
				struct reginfo *rp, **rpp;
				token_t token, token2;
				int propno;
				int exactmatch;
				int decision;

				if (codep[-1] & 32)
				{
					getint(propno, codep);
					getint(tinstno, codep);
					DEBUG("ALLOCATE,INIT");
				}
				else
				{
					getint(propno, codep);
					tinstno = 0;
					DEBUG("ALLOCATE,EMPTY");
				}
				instance(tinstno, &token);
				if (!forced)
				{
					do
					{
						npos = exactmatch = 0;
						for (rpp = reglist[propno]; (rp = *rpp) != NULL; rpp++)
							if (getrefcount((int)(rp - machregs), FALSE) == 0)
							{
								pos[npos++] = rp - machregs;
								if (eqtoken(&rp->r_contents, &token))
									pos2[exactmatch++] = rp - machregs;
							}
						/*
			 * Now pos[] contains all free registers with desired
			 * property. If none then some stacking has to take place.
			 */
						if (npos == 0)
						{
							if (stackheight <= tokpatlen)
							{
								if (!toplevel)
								{
									BROKE();
								}
								else
								{
									if (paniced)
										fatal("No regs available");
									totalcost += stackupto(&fakestack[0], ply, toplevel);
									goto panic;
								}
							}
							totalcost += stackupto(&fakestack[0], ply, toplevel);
							CHKCOST();
						}
					} while (npos == 0);

					if (!exactmatch && tinstno != 0)
					{
						/*
			 * No exact match, but we were looking for a particular
			 * token. Now try to find registers of which no
			 * known contents is available (the others might still
			 * be useful).
			 */
						for (i = 0; i < npos; i++)
							if (machregs[pos[i]].r_contents.t_token == 0)
							{
								pos2[exactmatch++] = pos[i];
							}
					}

					if (!exactmatch)
					{
						npos2 = npos;
						for (i = 0; i < npos; i++)
							pos2[i] = pos[i];
					}
					else
					{
						/*
			 * Now we are reducing the number of possible registers.
			 * We take only one equally likely register out of every
			 * equivalence class as given by set of properties.
			 */
						npos2 = 0;
						for (i = 0; i < exactmatch; i++)
						{
							pos2[npos2++] = pos2[i];
							for (j = 0; j < npos2 - 1; j++)
								if (eqregclass(pos2[j], pos2[i]))
								{
									npos2--;
									break;
								}
						}
					}
					/*
		 * Now pos2[] contains all possibilities to try, if more than
		 * one, lookahead is necessary.
		 */
					token2.t_token = -1;
					for (i = 1; i < TOKENSIZE; i++)
						token2.t_att[i].aw = 0;
					decision = pos2[0];
					if (npos2 != 1)
					{
						SAVEST;
						mincost = costlimit - totalcost + 1;
						for (j = 0; j < npos2; j++)
						{
							chrefcount(pos2[j], 1, FALSE);
							token2.t_att[0].ar = pos2[j];
							allreg[nallreg++] = pos2[j];
							if (token.t_token != 0)
								t = move(&token, &token2, ply, FALSE, mincost);
							else
							{
								t = 0;
								erasereg(pos2[j]);
							}
							if (t < mincost)
								t += codegen(codep, ply, FALSE, mincost < MAXINT ? mincost - t : MAXINT, 0);
							if (t < mincost)
							{
								mincost = t;
								decision = pos2[j];
							}
							RESTST;
						}
						FREEST;
						if (totalcost + mincost > costlimit)
							BROKE();
					}
				}
				else
				{
					decision = forced;
					if (getrefcount(decision, FALSE) != 0)
						BROKE();
					token2.t_token = -1;
				}
				chrefcount(decision, 1, FALSE);
				token2.t_att[0].ar = decision;
				if (token.t_token != 0)
				{
					totalcost += move(&token, &token2, ply, toplevel, MAXINT);
					CHKCOST();
				}
				else
					erasereg(decision);
				allreg[nallreg++] = decision;
				break;
			}
			case DO_INSTR:
			{
				int i, n;
				int tinstno;
				token_t token;
				int stringno;

				DEBUG("INSTR");
				n = ((codep[-1] >> 5) & 07);
				getint(stringno, codep);
				if (toplevel)
				{
					swtxt();
					if (stringno > 10000)
					{
						assert(stringno < 10001 + MAXPROCARG);
						genstr(procarg[stringno - 10001]);
					}
					else
						genstr(stringno);
				}
				for (i = 0; i < n; i++)
				{
					getint(tinstno, codep);
					instance(tinstno, &token);
					if (toplevel)
						prtoken(&token, i == 0 ? ' ' : ',');
					if (token.t_token > 0)
						totalcost += tokens[token.t_token].t_cost.ct_space;
				}
				if (toplevel)
					gennl();
				CHKCOST();
				break;
			}
			case DO_MOVE:
			{
				int tinstno;
				token_t token, token2;

				DEBUG("MOVE");
				getint(tinstno, codep);
				instance(tinstno, &token);
				getint(tinstno, codep);
				instance(tinstno, &token2);
				totalcost += move(&token, &token2, ply, toplevel, costlimit - totalcost + 1);
				CHKCOST();
				break;
			}
			case DO_TEST:
			{
				int tinstno;
				token_t token;

				DEBUG("TEST");
				getint(tinstno, codep);
				instance(tinstno, &token);
				totalcost += test(&token, ply, toplevel, costlimit - totalcost + 1);
				CHKCOST();
				break;
			}
			case DO_SETCC:
			{
				int tinstno;
				token_t token;

				DEBUG("SETCC");
				getint(tinstno, codep);
				instance(tinstno, &token);
				setcc(&token);
				break;
			}
			case DO_ERASE:
			{
				int nodeno;
				result_t result;

				DEBUG("ERASE");
				getint(nodeno, codep);
				compute(&enodes[nodeno], &result);
				assert(result.e_typ != EV_INT && result.e_typ != EV_ADDR);
				if (result.e_typ == EV_REG)
				{
					int regno = result.e_v.e_reg;
					erasereg(regno);
				}
				break;
			}
			case DO_TOKREPLACE:
			{
				int i;
				int tinstno;
				int repllen;
				token_t reptoken[MAXREPLLEN];

				DEBUG("TOKREPLACE");
				assert(stackheight >= tokpatlen);
				repllen = (codep[-1] >> 5) & 07;
#ifndef NDEBUG
				if (Debug > 2)
					fprintf(stderr, "Stackheight=%d, tokpatlen=%d, repllen=%d %s\n",
					    stackheight, tokpatlen, repllen, inscoerc ? "(inscoerc)" : "");
#endif
				for (i = 0; i < repllen; i++)
				{
					getint(tinstno, codep);
					instance(tinstno, &reptoken[i]);
					tref(&reptoken[i], 1);
				}
				for (i = 0; i < tokpatlen; i++)
				{
					if (!inscoerc)
						tref(&fakestack[stackheight - 1], -1);
					stackheight--;
				}
				for (i = 0; i < repllen; i++)
				{
					assert(stackheight < MAXFSTACK);
					fakestack[stackheight++] = reptoken[i];
				}
				for (i = 0; i < nallreg; i++)
					chrefcount(allreg[i], -1, FALSE);
				break;
			}
			case DO_EMREPLACE:
			{
				int i, j;
				int nodeno;
				result_t result[MAXEMREPLLEN];
				int emrepllen, eminstr;

				DEBUG("EMREPLACE");
				emrepllen = (codep[-1] >> 5) & 07;
				j = emp - emlines;
				if (emrepllen > j)
				{
					assert(nemlines + emrepllen - j < MAXEMLINES);
					for (i = nemlines; i >= 0; i--)
						emlines[i + emrepllen - j] = emlines[i];
					nemlines += emrepllen - j;
					emp += emrepllen - j;
				}
				emp -= emrepllen;
				for (i = 0; i < emrepllen; i++)
				{
					getint(eminstr, codep);
					getint(nodeno, codep);
					emp[i].em_instr = eminstr;
					compute(&enodes[nodeno], &result[i]);
				}
				for (i = 0; i < emrepllen; i++)
				{
					switch (result[i].e_typ)
					{
						default:
							assert(FALSE);
						case 0:
							emp[i].em_optyp = OPNO;
							emp[i].em_soper = 0;
							break;
						case EV_INT:
							emp[i].em_optyp = OPINT;
							emp[i].em_soper = tostring(result[i].e_v.e_con);
							emp[i].em_u.em_ioper = result[i].e_v.e_con;
							break;
						case EV_ADDR:
							emp[i].em_optyp = OPSYMBOL;
							emp[i].em_soper = ad2str(result[i].e_v.e_addr);
							break;
					}
				}
				if (!toplevel)
				{
					ply += emrepllen;
#ifndef NDEBUG
					if (Debug > 4)
						fprintf(stderr, "ply becomes %d\n", ply);
#endif
				}
				break;
			}
			case DO_COST:
			{
				cost_t cost;

				DEBUG("COST");
				getint(cost.ct_space, codep);
				getint(cost.ct_time, codep);
				totalcost += costcalc(cost);
				CHKCOST();
				break;
			}
#ifdef REGVARS
			case DO_PRETURN:
			{
				if (toplevel)
				{
					swtxt();
					regreturn(); /* in mach.c */
				}
				break;
			}
#endif
			case DO_RETURN:
				DEBUG("RETURN");
				assert(origcp != startupcode);
#ifndef NDEBUG
				level--;
#endif
				return (totalcost);
#ifdef USE_TES
			case DO_LABDEF:
			{
				int index;

				DEBUG("LABDEF");
				getint(index, codep);
				if (toplevel)
				{
					swtxt();
					printlabel(index);
				}

				break;
			}
#endif
		}
	}
doreturn:
#ifdef ALLOW_NEXTEM
	if (toplevel && totalcost == INFINITY && !paniced)
	{
		DEBUG("PANIC!");
		totalcost += stackupto(&fakestack[stackheight - 1], ply, toplevel);
#ifndef NDEBUG
		if (Debug > 2)
			fprintf(stderr, "Stackheight = %d\n", stackheight);
#endif
		paniced = 1;
		tokpatlen = 0;
		goto panic;
	}
#endif
#ifndef NDEBUG
	level--;
#endif
	return (totalcost);
}

void readcodebytes(void)
{
#ifndef CODEINC
	int fd;
	extern int ncodebytes;

	if ((fd = open("code", 0)) < 0)
	{
		error("Can't open code");
	}
	if (read(fd, coderules, ncodebytes) != ncodebytes)
	{
		error("Short read from code");
	}
	close(fd);
#endif /* CODEINC */
}

#ifdef TABLEDEBUG
void initlset(char *f)
{

	set_flag = f;
	if ((set_fd = open(f + 1, 2)) < 0)
		error("Can't open %s rw", f + 1);
	read(set_fd, &set_size, sizeof(int));
	set_val = (short*)myalloc(set_size);
	read(set_fd, set_val, set_size);
}

void termlset(void)
{

	if (set_fd)
	{
		lseek(set_fd, (long)sizeof(int), 0);
		write(set_fd, set_val, set_size);
		close(set_fd);
		if (set_flag[0] == 'u')
		{
			int i;

			fprintf(stderr, "Unused code rules:\n\n");
			for (i = 0; i < 8 * set_size; i++)
				if (set_val[i >> 4] & (1 << (i & 017)))
					fprintf(stderr, "\"%s\", line %d\n", tablename, i);
		}
	}
}
#endif /* TABLEDEBUG */
