1422 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1422 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "b.h"
 | 
						|
 | 
						|
void extdef(void);
 | 
						|
struct hshtab * lookup(void);
 | 
						|
void blkhed(void);
 | 
						|
void blkend(void);
 | 
						|
void statement(int d);
 | 
						|
struct tnode * tree(void);
 | 
						|
void errflush(int o);
 | 
						|
 | 
						|
int	line = 1;
 | 
						|
int	peeksym = -1, peeksym2 = -1;;
 | 
						|
int	contlab = -1;
 | 
						|
int	brklab = -1;
 | 
						|
 | 
						|
int wordsize = 4;
 | 
						|
const char* modulename = "bmodule_main";
 | 
						|
int bsymb_part;
 | 
						|
int code_part;
 | 
						|
int string_part;
 | 
						|
 | 
						|
int paramsize;
 | 
						|
struct	hshtab hshtab[HSHSIZ];
 | 
						|
int	hshused;
 | 
						|
int	eof;
 | 
						|
int	peekc;
 | 
						|
const char* ctab;
 | 
						|
struct	hshtab *bsym;
 | 
						|
struct	hshtab *paraml, *parame;
 | 
						|
int	cval;
 | 
						|
int	isn;
 | 
						|
char	symbuf[NCPS+1];
 | 
						|
FILE	*sbufp;
 | 
						|
int	stack;
 | 
						|
struct	tnode **cp;
 | 
						|
int	*space;
 | 
						|
int	ospace[OSSIZ];
 | 
						|
int	retlab;
 | 
						|
int	nerror;
 | 
						|
struct	swtab swtab[SWSIZ];
 | 
						|
struct	swtab *swp;
 | 
						|
int	deflab;
 | 
						|
int	contlab;
 | 
						|
int	brklab;
 | 
						|
 | 
						|
int opdope[];
 | 
						|
int line;
 | 
						|
int peeksym, peeksym2;
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
init(char *s, int val)
 | 
						|
{
 | 
						|
	char *sp;
 | 
						|
	struct hshtab *np;
 | 
						|
 | 
						|
	sp = symbuf;
 | 
						|
	while (sp < symbuf+NCPS+1)
 | 
						|
		if ((*sp++ = *s++) == '\0')
 | 
						|
			s--;
 | 
						|
	np = lookup();
 | 
						|
	np->class = KEYWF;
 | 
						|
	np->offset = val;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
usage(void)
 | 
						|
{
 | 
						|
	error("Usage: em_b [-w wordsize] [-B modulename] [-i inputfile] [-o outputfile]");
 | 
						|
	exit(1);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main(int argc, char *argv[])
 | 
						|
{
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		int opt = getopt(argc, argv, "w:B:i:o:");
 | 
						|
		if (opt == -1)
 | 
						|
			break;
 | 
						|
 | 
						|
		switch (opt) {
 | 
						|
			case 'w':
 | 
						|
				wordsize = atoi(optarg);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'B':
 | 
						|
				modulename = aprintf("bmodule_%s", optarg);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'i':
 | 
						|
				if (freopen(optarg, "r", stdin) == NULL) {
 | 
						|
					error("Can't find %s", optarg);
 | 
						|
					exit(1);
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			case 'o':
 | 
						|
				if (freopen(optarg, "w", stdout) == NULL) {
 | 
						|
					error("Can't create %s", optarg);
 | 
						|
					exit(1);
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				usage();
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (optind < argc)
 | 
						|
		usage();
 | 
						|
 | 
						|
	init("auto", AUTO);
 | 
						|
	init("extrn", EXTERN);
 | 
						|
	init("case", CASE);
 | 
						|
	init("if", IF);
 | 
						|
	init("else", ELSE);
 | 
						|
	init("while", WHILE);
 | 
						|
	init("switch", SWITCH);
 | 
						|
	init("goto", GOTO);
 | 
						|
	init("return", RETURN);
 | 
						|
	init("default", DEFAULT);
 | 
						|
	init("break", BREAK);
 | 
						|
 | 
						|
	C_init(wordsize, wordsize);
 | 
						|
	C_open(NULL);
 | 
						|
	C_magic();
 | 
						|
	C_ms_emx(wordsize, wordsize);
 | 
						|
	bsymb_part = 0;
 | 
						|
	string_part = 0;
 | 
						|
	code_part = C_getid();
 | 
						|
	C_beginpart(code_part);
 | 
						|
	while (!eof) {
 | 
						|
		extdef();
 | 
						|
		blkend();
 | 
						|
	}
 | 
						|
	C_endpart(code_part);
 | 
						|
	C_insertpart(code_part);
 | 
						|
 | 
						|
	if (string_part)
 | 
						|
		C_insertpart(string_part);
 | 
						|
 | 
						|
	C_exa_dnam((char*) modulename);
 | 
						|
	C_df_dnam((char*) modulename);
 | 
						|
	if (bsymb_part)
 | 
						|
		C_insertpart(bsymb_part);
 | 
						|
	C_rom_cst(0);
 | 
						|
 | 
						|
	C_close();
 | 
						|
 | 
						|
	return nerror != 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Lexer
 | 
						|
 */
 | 
						|
 | 
						|
int
 | 
						|
spnextchar(void)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
 | 
						|
	if ((c = peekc) == 0)
 | 
						|
		c = getchar();
 | 
						|
	if (c == '\t')
 | 
						|
		c = ' ';
 | 
						|
	else if (c == '\n') {
 | 
						|
		c = ' ';
 | 
						|
		line++;
 | 
						|
	}
 | 
						|
	peekc = c;
 | 
						|
	return c;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
nextchar(void)
 | 
						|
{
 | 
						|
	while (spnextchar() == ' ')
 | 
						|
		peekc = 0;
 | 
						|
	return peekc;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
subseq(int c, int a, int b)
 | 
						|
{
 | 
						|
	if (spnextchar() != c)
 | 
						|
		return a;
 | 
						|
	peekc = 0;
 | 
						|
	return b;
 | 
						|
}
 | 
						|
 | 
						|
/* Only decimal and octal bases, could extend */
 | 
						|
int
 | 
						|
getnum(void)
 | 
						|
{
 | 
						|
	int base;
 | 
						|
	int c;
 | 
						|
 | 
						|
	base = 10;
 | 
						|
	cval = 0;
 | 
						|
	if ((c=spnextchar()) == '0')
 | 
						|
		base = 8;
 | 
						|
	for (; ctab[c] == DIGIT; c = getchar())
 | 
						|
		cval = cval*base + c-'0';
 | 
						|
	peekc = c;
 | 
						|
	return CON;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
mapch(char c)
 | 
						|
{
 | 
						|
	int a;
 | 
						|
 | 
						|
	if ((a=getchar()) == c)
 | 
						|
		return -1;
 | 
						|
	switch (a) {
 | 
						|
 | 
						|
	case '\n':
 | 
						|
	case '\0':
 | 
						|
		error("Nonterminated string");
 | 
						|
		peekc = a;
 | 
						|
		return -1;
 | 
						|
 | 
						|
	case '*':
 | 
						|
		switch (a=getchar()) {
 | 
						|
 | 
						|
		case 't':
 | 
						|
			return('\t');
 | 
						|
 | 
						|
		case 'n':
 | 
						|
			return('\n');
 | 
						|
 | 
						|
		case '0':
 | 
						|
			return('\0');
 | 
						|
 | 
						|
		case '(':
 | 
						|
			return('{');
 | 
						|
 | 
						|
		case ')':
 | 
						|
			return('}');
 | 
						|
 | 
						|
		case 'e':
 | 
						|
			return(EOS);
 | 
						|
 | 
						|
		case '\n':
 | 
						|
			line++;
 | 
						|
			return('\n');
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return a;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
getcc(void)
 | 
						|
{
 | 
						|
	char *cp;
 | 
						|
	int c, cc;
 | 
						|
 | 
						|
	cval = 0;
 | 
						|
	cc = 0;
 | 
						|
	cp = (char*) &cval;
 | 
						|
	while ((c = mapch('\'')) >= 0)
 | 
						|
		if (cc++ < wordsize)
 | 
						|
			*cp++ = c;
 | 
						|
	if (cc > wordsize)
 | 
						|
		error("Long character constant");
 | 
						|
	return CON;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
getstr(void)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	int i;
 | 
						|
	char b;
 | 
						|
	int partid;
 | 
						|
 | 
						|
	partid = C_getid();
 | 
						|
	C_beginpart(partid);
 | 
						|
	if (string_part)
 | 
						|
		C_insertpart(string_part);
 | 
						|
 | 
						|
	cval = isn++;
 | 
						|
	C_df_dlb(cval);
 | 
						|
	for (i = 1; (c = mapch('"')) >= 0; i++) {
 | 
						|
		b = c;
 | 
						|
		C_con_scon(&b, 1);
 | 
						|
	}
 | 
						|
 | 
						|
	b = 04;
 | 
						|
	C_con_scon(&b, 1);
 | 
						|
 | 
						|
	b = 0;
 | 
						|
	while ((i++%4) != 0)
 | 
						|
		C_con_scon(&b, 1);
 | 
						|
 | 
						|
	C_endpart(partid);
 | 
						|
	string_part = partid;
 | 
						|
 | 
						|
	return STRING;
 | 
						|
}
 | 
						|
 | 
						|
struct hshtab *
 | 
						|
lookup(void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
	char *sp, *np;
 | 
						|
	struct hshtab *rp;
 | 
						|
 | 
						|
	i = 0;
 | 
						|
	sp = symbuf;
 | 
						|
	while (sp < symbuf+NCPS)
 | 
						|
		i += *sp++&0177;
 | 
						|
	rp = &hshtab[i%HSHSIZ];
 | 
						|
	while (*(np = rp->name)) {
 | 
						|
		for (sp=symbuf; sp < symbuf+NCPS;)
 | 
						|
			if (*np++ != *sp++)
 | 
						|
				goto no;
 | 
						|
		return rp;
 | 
						|
	no:
 | 
						|
		if (++rp >= &hshtab[HSHSIZ])
 | 
						|
			rp = hshtab;
 | 
						|
	}
 | 
						|
	if (++hshused > HSHSIZ) {
 | 
						|
		error("Symbol table overflow");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	rp->class = 0;
 | 
						|
	rp->offset = 0;
 | 
						|
	rp->dim = 0;
 | 
						|
	sp = symbuf;
 | 
						|
	for (np = rp->name; sp < symbuf+NCPS+1;)
 | 
						|
		*np++ = *sp++;
 | 
						|
	return rp;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Symbol peeking with one peeksym doesn't work if an ASSIGN is only peeked,
 | 
						|
 * since it itself peeks a symbol, which is then overwritten.
 | 
						|
 */
 | 
						|
 | 
						|
/* Note: does not push bsyms !! */
 | 
						|
int
 | 
						|
pushsym(int sym)
 | 
						|
{
 | 
						|
	if (peeksym < 0)
 | 
						|
		peeksym = sym;
 | 
						|
	else if (peeksym2 < 0) {
 | 
						|
		peeksym2 = peeksym;
 | 
						|
		peeksym = sym;
 | 
						|
	} else
 | 
						|
		error("Cannot push more than two symbols\n");
 | 
						|
	return sym;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
symbol(void)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	char *sp;
 | 
						|
 | 
						|
	if (peeksym >= 0) {
 | 
						|
		c = peeksym;
 | 
						|
		peeksym = peeksym2;
 | 
						|
		peeksym2 = -1;
 | 
						|
		return c;
 | 
						|
	}
 | 
						|
	if (peekc) {
 | 
						|
		c = peekc;
 | 
						|
		peekc = 0;
 | 
						|
	} else
 | 
						|
		if (eof)
 | 
						|
			return EOFC;
 | 
						|
		else
 | 
						|
			c = getchar();
 | 
						|
	if (c==EOF) {
 | 
						|
		eof++;
 | 
						|
		return(EOFC);
 | 
						|
	}
 | 
						|
 | 
						|
loop:
 | 
						|
	switch (ctab[c]) {
 | 
						|
 | 
						|
	case NEWLN:
 | 
						|
		line++;
 | 
						|
		/* fall through */
 | 
						|
	case SPACE:
 | 
						|
		c = getchar();
 | 
						|
		goto loop;
 | 
						|
 | 
						|
	case HASH:
 | 
						|
		/* # is invalid in B; but we handle it out of convenience so that we can read
 | 
						|
		 * in input files that have been run through the C preprocessor. Ideally we
 | 
						|
		 * should only recognise it when it's the first character in a line, but as
 | 
						|
		 * it's not used anywhere else we can get away with recognising it anywhere.
 | 
						|
		 */
 | 
						|
 | 
						|
		while ((c = getchar()) == ' ')
 | 
						|
			;
 | 
						|
 | 
						|
		peekc = c;
 | 
						|
		getnum();
 | 
						|
		line = cval;
 | 
						|
 | 
						|
		while ((c = getchar()) != '\n')
 | 
						|
			;
 | 
						|
 | 
						|
		goto loop;
 | 
						|
 | 
						|
	case PLUS:
 | 
						|
		return subseq(c,PLUS,INCBEF);
 | 
						|
 | 
						|
	case MINUS:
 | 
						|
		return subseq(c,MINUS,DECBEF);
 | 
						|
 | 
						|
	case LESS:
 | 
						|
		if (subseq(c,0,1))
 | 
						|
			return LSHIFT;
 | 
						|
		return subseq('=', LESS, LESSEQ);
 | 
						|
 | 
						|
	case GREAT:
 | 
						|
		if (subseq(c,0,1))
 | 
						|
			return RSHIFT;
 | 
						|
		return subseq('=', GREAT, GREATEQ);
 | 
						|
 | 
						|
	case ASSIGN:
 | 
						|
		if (subseq(' ',0,1))
 | 
						|
			return ASSIGN;
 | 
						|
		/* avoid peeking a name, which could overwrite
 | 
						|
		 * an already set bsym. */
 | 
						|
		if (ctab[peekc = spnextchar()] == LETTER)
 | 
						|
			return ASSIGN;
 | 
						|
		c = symbol();
 | 
						|
		if (PLUS <= c && c <= EOR)
 | 
						|
			return c + ASPLUS-PLUS;
 | 
						|
		if (c == ASSIGN)
 | 
						|
			return EQUAL;
 | 
						|
		pushsym(c);
 | 
						|
		return ASSIGN;
 | 
						|
 | 
						|
	case EXCLA:
 | 
						|
		return subseq('=',EXCLA,NEQUAL);
 | 
						|
 | 
						|
	case DIVIDE:
 | 
						|
		if (subseq('*',1,0))
 | 
						|
			return DIVIDE;
 | 
						|
		while ((c = spnextchar()) != EOFC) {
 | 
						|
			peekc = 0;
 | 
						|
			if (c == '*') {
 | 
						|
				if (spnextchar() == '/') {
 | 
						|
					peekc = 0;
 | 
						|
					c = getchar();
 | 
						|
					goto loop;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		eof++;
 | 
						|
		error("Nonterminated comment");
 | 
						|
		return EOFC;
 | 
						|
 | 
						|
	case DIGIT:
 | 
						|
		peekc = c;
 | 
						|
		return getnum();
 | 
						|
 | 
						|
	case SQUOTE:
 | 
						|
		return(getcc());
 | 
						|
 | 
						|
	case DQUOTE:
 | 
						|
		return(getstr());
 | 
						|
 | 
						|
	case LETTER:
 | 
						|
		sp = symbuf;
 | 
						|
		while (ctab[c] == LETTER || ctab[c] == DIGIT) {
 | 
						|
			if (sp < symbuf+NCPS)
 | 
						|
				*sp++ = c;
 | 
						|
			c = getchar();
 | 
						|
		}
 | 
						|
		while (sp < symbuf+NCPS+1)
 | 
						|
			*sp++ = '\0';
 | 
						|
		peekc = c;
 | 
						|
		bsym = lookup();
 | 
						|
		if (bsym->class == KEYWF) {
 | 
						|
			cval = bsym->offset;
 | 
						|
			return KEYW;
 | 
						|
		}
 | 
						|
		return NAME;
 | 
						|
 | 
						|
	case UNKN:
 | 
						|
		error("Unknown character");
 | 
						|
		c = getchar();
 | 
						|
		goto loop;
 | 
						|
	}
 | 
						|
	return (ctab[c]);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Declarations and Definitions
 | 
						|
 */
 | 
						|
 | 
						|
/* Declares a list of names to be of storage class "kw". */
 | 
						|
void
 | 
						|
declare(int kw)
 | 
						|
{
 | 
						|
	int o;
 | 
						|
 | 
						|
	while ((o = symbol()) == NAME) {
 | 
						|
		if (bsym->class)
 | 
						|
			error("%s redeclared", bsym->name);
 | 
						|
		bsym->class = kw;
 | 
						|
		while ((o = symbol()) == LBRACK) {
 | 
						|
			if ((o = symbol()) == CON) {
 | 
						|
				if (bsym->dim)
 | 
						|
					error("Bad vector");
 | 
						|
				bsym->dim = cval + 1;
 | 
						|
				o = symbol();
 | 
						|
			}
 | 
						|
			if (o != RBRACK)
 | 
						|
				goto syntax;
 | 
						|
		}
 | 
						|
		if (kw == ARG) {
 | 
						|
			bsym->next = NULL;
 | 
						|
			if (!paraml)
 | 
						|
				paraml = bsym;
 | 
						|
			else
 | 
						|
				parame->next = bsym;
 | 
						|
			parame = bsym;
 | 
						|
		}
 | 
						|
		if (o != COMMA)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if ((o == SEMI && kw != ARG) || (o == RPARN && kw == ARG))
 | 
						|
		return;
 | 
						|
syntax:
 | 
						|
	error("Declaration syntax");
 | 
						|
	errflush(o);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
declist(void)
 | 
						|
{
 | 
						|
	int o;
 | 
						|
 | 
						|
	while ((o = symbol()) == KEYW && (cval == AUTO || cval == EXTERN))
 | 
						|
		declare(cval);
 | 
						|
	pushsym(o);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
function(void)
 | 
						|
{
 | 
						|
	declare(ARG);
 | 
						|
	statement(1);
 | 
						|
	C_ret(0);
 | 
						|
	C_end(paramsize);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
global(char *s)
 | 
						|
{
 | 
						|
	C_exa_dnam(manglename(s, 'b'));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
bsymb(char *s)
 | 
						|
{
 | 
						|
	int newpart = C_getid();
 | 
						|
	C_beginpart(newpart);
 | 
						|
	if (bsymb_part != 0)
 | 
						|
		C_insertpart(bsymb_part);
 | 
						|
	C_rom_dlb(isn, 0);
 | 
						|
	C_endpart(newpart);
 | 
						|
 | 
						|
	bsymb_part = newpart;
 | 
						|
	C_df_dlb(isn++);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
extdef(void)
 | 
						|
{
 | 
						|
	int o, dim, i;
 | 
						|
	char *bs;
 | 
						|
	char *ms;
 | 
						|
	int neg;
 | 
						|
 | 
						|
	if ((o = symbol()) == EOFC || o == SEMI)
 | 
						|
		return;
 | 
						|
	if (o != NAME)
 | 
						|
		goto syntax;
 | 
						|
	bs = bsym->name;
 | 
						|
	i = dim = 0;
 | 
						|
	neg = 0;
 | 
						|
	switch(o = symbol()) {
 | 
						|
 | 
						|
	case SEMI:
 | 
						|
		global(bs);
 | 
						|
		C_df_dnam(manglename(bs, 'b'));
 | 
						|
		C_bss_cst(wordsize, 0, 1);
 | 
						|
		goto done;
 | 
						|
 | 
						|
	/* init */
 | 
						|
	case CON:
 | 
						|
	case STRING:
 | 
						|
	case MINUS:
 | 
						|
		global(bs);
 | 
						|
		if (o == STRING)
 | 
						|
			bsymb(bs);
 | 
						|
		else if (o == MINUS) {
 | 
						|
			o = symbol();
 | 
						|
			if (o != CON)
 | 
						|
				goto syntax;
 | 
						|
			cval = -cval;
 | 
						|
		}
 | 
						|
		C_df_dnam(manglename(bs, 'b'));
 | 
						|
		pushsym(o);
 | 
						|
		goto init;
 | 
						|
 | 
						|
	/* vector */
 | 
						|
	case LBRACK:
 | 
						|
		if ((o=symbol()) == CON) {
 | 
						|
			dim = cval + 1;
 | 
						|
			o=symbol();
 | 
						|
		}
 | 
						|
		if (o != RBRACK)
 | 
						|
			goto syntax;
 | 
						|
		global(bs);
 | 
						|
		if ((o=symbol()) == SEMI) {
 | 
						|
			bsymb(bs);
 | 
						|
			C_df_dnam(manglename(bs, 'b'));
 | 
						|
			C_con_dlb(isn, 0);
 | 
						|
			C_df_dlb(isn++);
 | 
						|
			C_bss_cst(wordsize*dim, 0, 1); 
 | 
						|
			goto done;
 | 
						|
		}
 | 
						|
		bsymb(bs);
 | 
						|
		C_df_dnam(manglename(bs, 'b'));
 | 
						|
		C_con_dlb(isn, 0);
 | 
						|
		C_df_dlb(isn++);
 | 
						|
		pushsym(o);
 | 
						|
 | 
						|
	init:
 | 
						|
		do {
 | 
						|
			if ((o=symbol()) != CON && o != STRING && o != NAME)
 | 
						|
				goto syntax;
 | 
						|
			if (o == NAME) {
 | 
						|
				bsymb(NULL);
 | 
						|
				C_con_dnam(manglename(bsym->name, 'b'), 0);
 | 
						|
			} else {
 | 
						|
				if (o == STRING) {
 | 
						|
					bsymb(NULL);
 | 
						|
					C_con_dlb(cval, 0);
 | 
						|
				} else
 | 
						|
					C_con_cst(cval);
 | 
						|
			}
 | 
						|
			i++;
 | 
						|
		} while ((o=symbol()) == COMMA);
 | 
						|
		dim = (i > dim) ? i : dim;
 | 
						|
		if (i == 0)
 | 
						|
			C_bss_cst((dim-i)*wordsize, 0, 1);
 | 
						|
		else {
 | 
						|
			while (dim -i) {
 | 
						|
				C_con_cst(0);
 | 
						|
				i++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (o == SEMI)
 | 
						|
			goto done;
 | 
						|
		goto syntax;
 | 
						|
 | 
						|
	/* function */
 | 
						|
	case LPARN:
 | 
						|
		global(bs);
 | 
						|
		ms = manglename(bs, 'b');
 | 
						|
		bsymb(ms);
 | 
						|
		C_df_dnam(ms);
 | 
						|
		ms = manglename(bs, 'i');
 | 
						|
		C_con_pnam(ms);
 | 
						|
		C_inp(ms);
 | 
						|
		C_pro_narg(ms);
 | 
						|
		function();
 | 
						|
	done:
 | 
						|
		return;
 | 
						|
 | 
						|
	case EOFC:
 | 
						|
		return;
 | 
						|
	}
 | 
						|
syntax:
 | 
						|
	error("External definition syntax");
 | 
						|
	printtoken(o, stderr);
 | 
						|
	errflush(o);
 | 
						|
	statement(0);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
blkhed(void)
 | 
						|
{
 | 
						|
	int al, pl;
 | 
						|
	struct hshtab *bs;
 | 
						|
 | 
						|
	declist();
 | 
						|
	stack = al = -wordsize;
 | 
						|
	pl = 0; /* EM parameters start at offset 0. */
 | 
						|
	while (paraml) {
 | 
						|
		paraml = (bs = paraml)->next;
 | 
						|
		bs->offset = pl;
 | 
						|
		pl += wordsize;
 | 
						|
	}
 | 
						|
	for (bs = hshtab; bs < &hshtab[HSHSIZ]; bs++)
 | 
						|
		if (bs->name[0]) {
 | 
						|
			if (bs->class == AUTO) {
 | 
						|
				bs->offset = al;
 | 
						|
				if (bs->dim) {
 | 
						|
					al -= bs->dim*wordsize;
 | 
						|
					C_lal(al);
 | 
						|
					al -= wordsize;
 | 
						|
					fromnativeaddr();
 | 
						|
					C_stl(al);
 | 
						|
					bs->offset = al;
 | 
						|
				}
 | 
						|
				al -= wordsize;
 | 
						|
			} else if (bs->class == ARG)
 | 
						|
				bs->class = AUTO;
 | 
						|
		}
 | 
						|
	paramsize = -al - wordsize;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
blkend(void)
 | 
						|
{
 | 
						|
	struct hshtab *np;
 | 
						|
 | 
						|
	for (np = hshtab; np < &hshtab[HSHSIZ]; np++)
 | 
						|
		if (np->class != KEYWF) {
 | 
						|
			np->name[0] = '\0';
 | 
						|
			hshused--;
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Statements and Expressions
 | 
						|
 */
 | 
						|
 | 
						|
struct tnode *
 | 
						|
pexpr(void)
 | 
						|
{
 | 
						|
	struct tnode *t;
 | 
						|
	int o;
 | 
						|
 | 
						|
	if ((o = symbol()) != LPARN)
 | 
						|
		goto syntax;
 | 
						|
	t = tree();
 | 
						|
	if ((o = symbol()) != RPARN)
 | 
						|
		goto syntax;
 | 
						|
	return t;
 | 
						|
syntax:
 | 
						|
	error("Statement syntax");
 | 
						|
	errflush(o);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
fnlabel(int l)
 | 
						|
{
 | 
						|
	C_ilb(l);
 | 
						|
}
 | 
						|
 | 
						|
/* Jump to "lab", if the expression "t" evaluated to 0. */
 | 
						|
void
 | 
						|
cbranch(struct tnode *t, int lab)
 | 
						|
{
 | 
						|
	rcexpr(t);
 | 
						|
	C_zeq(lab);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
jump(int lab)
 | 
						|
{
 | 
						|
	C_bra(lab);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
pswitch(void)
 | 
						|
{
 | 
						|
	struct swtab *sswp;
 | 
						|
	int dl, swlab;
 | 
						|
 | 
						|
	if (swp == NULL)
 | 
						|
		swp = swtab;
 | 
						|
	sswp = swp;
 | 
						|
	swlab = isn++;
 | 
						|
	C_lae_dlb(swlab, 0);
 | 
						|
	C_csb(wordsize);
 | 
						|
 | 
						|
	dl = deflab;
 | 
						|
	deflab = 0;
 | 
						|
	statement(0);
 | 
						|
	if (!deflab)
 | 
						|
		deflab = brklab;
 | 
						|
 | 
						|
	C_df_dlb(swlab);
 | 
						|
	C_rom_ilb(deflab);
 | 
						|
	C_rom_cst(swp - sswp);
 | 
						|
 | 
						|
	while (swp > sswp && swp > swtab) {
 | 
						|
		--swp;
 | 
						|
		C_rom_cst(swp->swval);
 | 
						|
		C_rom_ilb(swp->swlab);
 | 
						|
	}
 | 
						|
 | 
						|
	C_df_ilb(brklab);
 | 
						|
 | 
						|
	deflab = dl;
 | 
						|
	swp = sswp;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
statement(int d)
 | 
						|
{
 | 
						|
	int o, o1, o2;
 | 
						|
 | 
						|
stmt:
 | 
						|
	if ((o = symbol()) == LBRACE) {
 | 
						|
		if (d)
 | 
						|
			blkhed();
 | 
						|
		while (!eof) {
 | 
						|
			if ((o = symbol()) == RBRACE)
 | 
						|
				goto bend;
 | 
						|
			pushsym(o);
 | 
						|
			statement(0);
 | 
						|
		}
 | 
						|
		error("Missing '}'");
 | 
						|
	bend:
 | 
						|
		return;
 | 
						|
	} else {
 | 
						|
		pushsym(o);
 | 
						|
		if (d)
 | 
						|
			blkhed();
 | 
						|
	}
 | 
						|
 | 
						|
	switch (o = symbol()) {
 | 
						|
 | 
						|
	case EOFC:
 | 
						|
		error("Unexpected EOF");
 | 
						|
 | 
						|
	case SEMI:
 | 
						|
	case RBRACE:
 | 
						|
		return;
 | 
						|
 | 
						|
	case KEYW:
 | 
						|
		switch (cval) {
 | 
						|
		case GOTO:
 | 
						|
			if ((o = symbol()) != NAME)
 | 
						|
				goto syntax;
 | 
						|
			if (bsym->offset == 0)
 | 
						|
				bsym->offset = isn++;
 | 
						|
			jump(bsym->offset);
 | 
						|
			goto semi;
 | 
						|
 | 
						|
		case RETURN:
 | 
						|
			if (pushsym(symbol()) == LPARN) {
 | 
						|
				rcexpr(pexpr());
 | 
						|
				C_ret(wordsize);
 | 
						|
			} else {
 | 
						|
				C_ret(0);
 | 
						|
			}
 | 
						|
			goto semi;
 | 
						|
 | 
						|
		case IF:
 | 
						|
			cbranch(pexpr(), o1=isn++);
 | 
						|
			statement(0);
 | 
						|
			if ((o = symbol()) == KEYW && cval == ELSE) {
 | 
						|
				jump(o2 = isn++);
 | 
						|
				fnlabel(o1);
 | 
						|
				statement(0);
 | 
						|
				fnlabel(o2);
 | 
						|
				return;
 | 
						|
			}
 | 
						|
			pushsym(o);
 | 
						|
			fnlabel(o1);
 | 
						|
			return;
 | 
						|
 | 
						|
		case WHILE:
 | 
						|
			o1 = contlab;
 | 
						|
			o2 = brklab;
 | 
						|
			fnlabel(contlab = isn++);
 | 
						|
			cbranch(pexpr(), brklab=isn++);
 | 
						|
			statement(0);
 | 
						|
			jump(contlab);
 | 
						|
			fnlabel(brklab);
 | 
						|
			contlab = o1;
 | 
						|
			brklab = o2;
 | 
						|
			return;
 | 
						|
 | 
						|
		case BREAK:
 | 
						|
			if (brklab < 0)
 | 
						|
				error("Nothing to break from");
 | 
						|
			jump(brklab);
 | 
						|
			goto semi;
 | 
						|
 | 
						|
		/* Not part of B, but very easy to implement */
 | 
						|
/*
 | 
						|
		case CONTINUE:
 | 
						|
			if (contlab < 0)
 | 
						|
				error("Nothing to continue");
 | 
						|
			jump(contlab);
 | 
						|
			goto semi;
 | 
						|
*/
 | 
						|
 | 
						|
		case SWITCH:
 | 
						|
			o1 = brklab;
 | 
						|
			brklab = isn++;
 | 
						|
			rcexpr(pexpr());
 | 
						|
/*			rcexpr(tree()); */
 | 
						|
			pswitch();
 | 
						|
			brklab = o1;
 | 
						|
			return;
 | 
						|
 | 
						|
		case CASE:
 | 
						|
			if ((o = symbol()) != CON)
 | 
						|
				goto syntax;
 | 
						|
			if ((o = symbol()) != COLON)
 | 
						|
				goto syntax;
 | 
						|
			if (swp == NULL) {
 | 
						|
				error("Case not in switch");
 | 
						|
				goto stmt;
 | 
						|
			}
 | 
						|
			if (swp >= swtab+SWSIZ)
 | 
						|
				error("Switch table overflow");
 | 
						|
			else {
 | 
						|
				swp->swlab = isn;
 | 
						|
				(swp++)->swval = cval;
 | 
						|
				fnlabel(isn++);
 | 
						|
			}
 | 
						|
			goto stmt;
 | 
						|
 | 
						|
		case DEFAULT:
 | 
						|
			if (swp == NULL)
 | 
						|
				error("Default not in switch");
 | 
						|
			if ((o = symbol()) != COLON)
 | 
						|
				goto syntax;
 | 
						|
			deflab = isn++;
 | 
						|
			fnlabel(deflab);
 | 
						|
			goto stmt;
 | 
						|
		}
 | 
						|
 | 
						|
		error("Unknown keyword");
 | 
						|
		goto syntax;
 | 
						|
 | 
						|
	case NAME:
 | 
						|
		if (peekc == ':') {
 | 
						|
			peekc = 0;
 | 
						|
			if (bsym->class) {
 | 
						|
				error("Redefinition");
 | 
						|
				goto stmt;
 | 
						|
			}
 | 
						|
			bsym->class = INTERN;
 | 
						|
			if (bsym->offset == 0)
 | 
						|
				bsym->offset = isn++;
 | 
						|
			fnlabel(bsym->offset);
 | 
						|
			goto stmt;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	pushsym(o);
 | 
						|
	rcexpr(tree());
 | 
						|
	C_asp(wordsize);
 | 
						|
	goto semi;
 | 
						|
 | 
						|
semi:
 | 
						|
	if ((o = symbol()) != SEMI)
 | 
						|
		goto syntax;
 | 
						|
	return;
 | 
						|
 | 
						|
syntax:
 | 
						|
	error("Statement syntax");
 | 
						|
	errflush(o);
 | 
						|
	goto stmt;
 | 
						|
}
 | 
						|
 | 
						|
struct tnode *
 | 
						|
block(int op, int value, struct tnode *tr1, struct tnode *tr2)
 | 
						|
{
 | 
						|
	struct tnode t;
 | 
						|
	int n;
 | 
						|
	int *p, *ap;
 | 
						|
 | 
						|
	p = space;
 | 
						|
	t.op = op;
 | 
						|
	t.value = value;
 | 
						|
	t.tr1 = tr1;
 | 
						|
	t.tr2 = tr2;
 | 
						|
	ap = (int*) &t;
 | 
						|
	n = (sizeof(struct tnode)+sizeof(int)-1) & ~sizeof(int);
 | 
						|
	if (space+n >= &ospace[OSSIZ]) {
 | 
						|
		error("Expression overflow 1");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	while (n--)
 | 
						|
		*space++ = *ap++;
 | 
						|
	return (struct tnode *) p;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
chklval(struct tnode *p)
 | 
						|
{
 | 
						|
	if (p->op != NAME && p->op != STAR)
 | 
						|
		error("Lvalue required");
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
build(int op)
 | 
						|
{
 | 
						|
	struct tnode *p1, *p2;
 | 
						|
	int dope;
 | 
						|
 | 
						|
	/* a[i] -> *(a+i) */
 | 
						|
	if (op == LBRACK) {
 | 
						|
		build(PLUS);
 | 
						|
		op = STAR;
 | 
						|
	}
 | 
						|
	dope = opdope[op];
 | 
						|
	if (dope&01)
 | 
						|
		p2 = *--cp;
 | 
						|
	p1 = *--cp;
 | 
						|
	switch (op) {
 | 
						|
	case QUEST:
 | 
						|
		if (p2->op != COLON)
 | 
						|
			error("Illegal conditional");
 | 
						|
		break;
 | 
						|
 | 
						|
	case AMPER:
 | 
						|
		if (p1->op == STAR) {
 | 
						|
			*cp++ = p1->tr1;
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		if (p1->op == NAME) {
 | 
						|
			*cp++ = block(op,0,p1,NULL);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		error("Illegal lvalue");
 | 
						|
	}
 | 
						|
	if (dope&02)
 | 
						|
		chklval(p1);
 | 
						|
	if (dope&01)
 | 
						|
		*cp++ = block(op,0,p1,p2);
 | 
						|
	else
 | 
						|
		*cp++ = block(op,0,p1,NULL);
 | 
						|
}
 | 
						|
 | 
						|
struct tnode *
 | 
						|
tree(void)
 | 
						|
{
 | 
						|
	struct tnode *cmst[CMSIZ];
 | 
						|
	int opst[SSIZE], prst[SSIZE];
 | 
						|
	int *op, *pp;
 | 
						|
	int andflg;
 | 
						|
	int o, os;
 | 
						|
	int p, ps;
 | 
						|
 | 
						|
	space = ospace;
 | 
						|
	op = opst;
 | 
						|
	pp = prst;
 | 
						|
	cp = cmst;
 | 
						|
	*op = SEOF;
 | 
						|
	*pp = 06;
 | 
						|
	andflg = 0;
 | 
						|
 | 
						|
advanc:
 | 
						|
	switch (o=symbol()) {
 | 
						|
	case NAME:
 | 
						|
		if (pushsym(symbol()) == LPARN) {	/* function */
 | 
						|
			if (bsym->class == 0)
 | 
						|
				bsym->class = EXTERN;
 | 
						|
		} else if (bsym->class == 0) {
 | 
						|
			error("%s undefined", bsym->name);
 | 
						|
			bsym->class = EXTERN;
 | 
						|
		}
 | 
						|
		*cp++ = block(NAME,0,(struct tnode *)bsym,NULL);
 | 
						|
		goto tand;
 | 
						|
 | 
						|
	case STRING:
 | 
						|
		*cp++ = block(STRING,cval,NULL,NULL);
 | 
						|
		goto tand;
 | 
						|
 | 
						|
	case CON:
 | 
						|
	caseCON:
 | 
						|
		*cp++ = block(CON,cval,NULL,NULL);
 | 
						|
		goto tand;
 | 
						|
 | 
						|
tand:
 | 
						|
		if (cp >= &cmst[CMSIZ]) {
 | 
						|
			error("Expression overflow 2");
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
		if (andflg)
 | 
						|
			goto syntax;
 | 
						|
		andflg = 1;
 | 
						|
		goto advanc;
 | 
						|
 | 
						|
	case DECBEF:
 | 
						|
	case INCBEF:
 | 
						|
		if (andflg)
 | 
						|
			o += 2;
 | 
						|
		goto oponst;
 | 
						|
 | 
						|
	case EXCLA:
 | 
						|
	case NOT:
 | 
						|
		if (andflg)
 | 
						|
			goto syntax;
 | 
						|
		goto oponst;
 | 
						|
 | 
						|
	case MINUS:
 | 
						|
		if (!andflg) {
 | 
						|
			if (pushsym(symbol()) == CON) {
 | 
						|
				symbol();
 | 
						|
				cval = -cval;
 | 
						|
				goto caseCON;
 | 
						|
			}
 | 
						|
			o = NEG;
 | 
						|
		}
 | 
						|
		andflg = 0;
 | 
						|
		goto oponst;
 | 
						|
 | 
						|
	case AND:
 | 
						|
	case TIMES:
 | 
						|
		if (andflg)
 | 
						|
			andflg = 0;
 | 
						|
		else
 | 
						|
			if (o == AND)
 | 
						|
				o = AMPER;
 | 
						|
			else
 | 
						|
				o = STAR;
 | 
						|
		goto oponst;
 | 
						|
 | 
						|
	case LPARN:
 | 
						|
		if (andflg) {
 | 
						|
			o = symbol();
 | 
						|
			if (o == RPARN)
 | 
						|
				o = MCALL;
 | 
						|
			else {
 | 
						|
				pushsym(o);
 | 
						|
				o = CALL;
 | 
						|
				andflg = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		goto oponst;
 | 
						|
 | 
						|
	case RPARN:
 | 
						|
	case RBRACK:
 | 
						|
		if (!andflg)
 | 
						|
			goto syntax;
 | 
						|
		goto oponst;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!andflg)
 | 
						|
		goto syntax;
 | 
						|
	andflg = 0;
 | 
						|
 | 
						|
oponst:
 | 
						|
	p = (opdope[o]>>9) & 077;
 | 
						|
opon1:
 | 
						|
	ps = *pp;
 | 
						|
	if (p > ps || (p == ps && (opdope[o]&0200))) {	/* right-assoc */
 | 
						|
		switch (o) {
 | 
						|
		case LPARN:
 | 
						|
		case LBRACK:
 | 
						|
		case CALL:
 | 
						|
			p = 04;
 | 
						|
		}
 | 
						|
		if (op >= &opst[SSIZE]) {
 | 
						|
			error("Expression overflow 3");
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
		*++op = o;
 | 
						|
		*++pp = p;
 | 
						|
		goto advanc;
 | 
						|
	}
 | 
						|
	--pp;
 | 
						|
	switch (os = *op--) {
 | 
						|
	case SEOF:
 | 
						|
		pushsym(o);
 | 
						|
		return(*--cp);
 | 
						|
 | 
						|
	case CALL:
 | 
						|
		if (o != RPARN)
 | 
						|
			goto syntax;
 | 
						|
		build(os);
 | 
						|
		goto advanc;
 | 
						|
 | 
						|
	case MCALL:
 | 
						|
		*cp++ = NULL;
 | 
						|
		os = CALL;
 | 
						|
		goto fbuild;
 | 
						|
 | 
						|
	case LPARN:
 | 
						|
		if (o != RPARN)
 | 
						|
			goto syntax;
 | 
						|
		goto advanc;
 | 
						|
 | 
						|
	case LBRACK:
 | 
						|
		if (o != RBRACK)
 | 
						|
			goto syntax;
 | 
						|
		build(LBRACK);
 | 
						|
		goto advanc;
 | 
						|
 | 
						|
	}
 | 
						|
fbuild:
 | 
						|
	build(os);
 | 
						|
	goto opon1;
 | 
						|
syntax:
 | 
						|
	error("Expression syntax");
 | 
						|
	errflush(o);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
error(char *s, ...)
 | 
						|
{
 | 
						|
	va_list args;
 | 
						|
 | 
						|
	va_start(args, s);
 | 
						|
	nerror++;
 | 
						|
	fprintf(stderr, "%d: ", line);
 | 
						|
	vfprintf(stderr, s, args);
 | 
						|
	putc('\n', stderr);
 | 
						|
	va_end(args);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
errflush(int o)
 | 
						|
{
 | 
						|
	while (o > RBRACE)	/* ; { } */
 | 
						|
		o = symbol();
 | 
						|
	pushsym(o);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	000001	binary
 | 
						|
 *	000002	need lvalue
 | 
						|
 *	000004	relational
 | 
						|
 *	000010	assignment
 | 
						|
 *	000100	commutative
 | 
						|
 *	000200	right-assoc
 | 
						|
 *	0XX000	precedence
 | 
						|
 */
 | 
						|
int opdope[] = {
 | 
						|
	000000,	/* EOFC */
 | 
						|
	000000,	/* ; */
 | 
						|
	000000,	/* { */
 | 
						|
	000000,	/* } */
 | 
						|
	036000,	/* [ */
 | 
						|
	002000,	/* ] */
 | 
						|
	036000,	/* ( */
 | 
						|
	002000,	/* ) */
 | 
						|
	014201,	/* : */
 | 
						|
	007001,	/* , */
 | 
						|
	000000,	/* 10 */
 | 
						|
	000000,	/* 11 */
 | 
						|
	000000,	/* 12 */
 | 
						|
	000000,	/* 13 */
 | 
						|
	000000,	/* 14 */
 | 
						|
	036001,	/* mcall */
 | 
						|
	036001,	/* call */
 | 
						|
	034202,	/* ++a */
 | 
						|
	034202,	/* a++ */
 | 
						|
	034202,	/* --a */
 | 
						|
	034202,	/* a-- */
 | 
						|
	034200,	/* !un */
 | 
						|
	034200,	/* -un */
 | 
						|
	034200,	/* &un */
 | 
						|
	034200,	/* *un */
 | 
						|
	014201,	/* ? */
 | 
						|
	034200, /* ~un */
 | 
						|
	000000,	/* 27 */
 | 
						|
	000000,	/* 28 */
 | 
						|
	000000,	/* 29 */
 | 
						|
	030101,	/* + */
 | 
						|
	030001,	/* - */
 | 
						|
	032001,	/* % */
 | 
						|
	032101,	/* * */
 | 
						|
	032001,	/* / */
 | 
						|
	016101,	/* | */
 | 
						|
	020101,	/* & */
 | 
						|
	026001,	/* << */
 | 
						|
	026001,	/* >> */
 | 
						|
	022105,	/* == */
 | 
						|
	022105,	/* != */
 | 
						|
	024005,	/* <= */
 | 
						|
	024005,	/* < */
 | 
						|
	024005,	/* >= */
 | 
						|
	024005,	/* > */
 | 
						|
	017005,	/* ^ */
 | 
						|
	000000,	/* 46 */
 | 
						|
	000000,	/* 47 */
 | 
						|
	000000,	/* 48 */
 | 
						|
	012013,	/* = */
 | 
						|
	012213,	/* =+ */
 | 
						|
	012213,	/* =- */
 | 
						|
	012213,	/* =% */
 | 
						|
	012213,	/* =* */
 | 
						|
	012213,	/* =/ */
 | 
						|
	012213,	/* =| */
 | 
						|
	012213,	/* =& */
 | 
						|
	012213,	/* =<< */
 | 
						|
	012213,	/* =>> */
 | 
						|
	012213,	/* === */
 | 
						|
	012213,	/* =!= */
 | 
						|
	012213,	/* =<= */
 | 
						|
	012213,	/* =< */
 | 
						|
	012213,	/* =>= */
 | 
						|
	012213,	/* => */
 | 
						|
	012213,	/* =^ */
 | 
						|
	000000, /* 66 */
 | 
						|
	000000, /* 67 */
 | 
						|
	000000, /* 68 */
 | 
						|
	000000, /* 69 */
 | 
						|
	000000,	/* CON */
 | 
						|
	000000,	/* STRING */
 | 
						|
	000000	/* NAME */
 | 
						|
};
 | 
						|
 | 
						|
const char ctaba[129] = {
 | 
						|
	EOFC, /* -1 */
 | 
						|
	EOFC,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,
 | 
						|
	LETTER,	SPACE,	NEWLN,	SPACE,	SPACE,	UNKN,	UNKN,	UNKN,
 | 
						|
	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,
 | 
						|
	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,	UNKN,
 | 
						|
	SPACE,	EXCLA,	DQUOTE,	HASH,	UNKN,	MOD,	AND,	SQUOTE,
 | 
						|
	LPARN,	RPARN,	TIMES,	PLUS,	COMMA,	MINUS,	UNKN,	DIVIDE,
 | 
						|
	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,	DIGIT,
 | 
						|
	DIGIT,	DIGIT,	COLON,	SEMI,	LESS,	ASSIGN,	GREAT,	QUEST,
 | 
						|
	UNKN,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
 | 
						|
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
 | 
						|
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
 | 
						|
	LETTER,	LETTER,	LETTER,	LBRACK,	UNKN,	RBRACK,	EOR,	LETTER,
 | 
						|
	UNKN,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
 | 
						|
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
 | 
						|
	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,	LETTER,
 | 
						|
	LETTER,	LETTER,	LETTER,	LBRACE,	OR,	RBRACE,	NOT,	UNKN
 | 
						|
};
 | 
						|
const char* ctab = &ctaba[1]; /* allows indexing with -1 */
 | 
						|
 | 
						|
/* debug function */
 | 
						|
void printtoken(int tok, FILE *out)
 | 
						|
{
 | 
						|
	static char *strtab[128];
 | 
						|
	strtab[0] = "EOFC";
 | 
						|
	strtab[1] = "SEMI";
 | 
						|
	strtab[2] = "LBRACE";
 | 
						|
	strtab[3] = "RBRACE";
 | 
						|
	strtab[4] = "LBRACK";
 | 
						|
	strtab[5] = "RBRACK";
 | 
						|
	strtab[6] = "LPARN";
 | 
						|
	strtab[7] = "RPARN";
 | 
						|
	strtab[8] = "COLON";
 | 
						|
	strtab[9] = "COMMA";
 | 
						|
	strtab[10] = "HASH";
 | 
						|
 | 
						|
	strtab[15] = "MCALL";
 | 
						|
	strtab[16] = "CALL";
 | 
						|
	strtab[17] = "DECBEF";
 | 
						|
	strtab[18] = "INCBEF";
 | 
						|
	strtab[19] = "DECAFT";
 | 
						|
	strtab[20] = "INCAFT";
 | 
						|
	strtab[21] = "EXCLA";
 | 
						|
	strtab[22] = "NEG";
 | 
						|
	strtab[23] = "AMPER";
 | 
						|
	strtab[24] = "STAR";
 | 
						|
	strtab[25] = "QUEST";
 | 
						|
	strtab[26] = "NOT";
 | 
						|
 | 
						|
	strtab[30] = "PLUS";
 | 
						|
	strtab[31] = "MINUS";
 | 
						|
	strtab[32] = "MOD";
 | 
						|
	strtab[33] = "TIMES";
 | 
						|
	strtab[34] = "DIVIDE";
 | 
						|
	strtab[35] = "OR";
 | 
						|
	strtab[36] = "AND";
 | 
						|
	strtab[37] = "LSHIFT";
 | 
						|
	strtab[38] = "RSHIFT";
 | 
						|
	strtab[39] = "EQUAL";
 | 
						|
	strtab[40] = "NEQUAL";
 | 
						|
	strtab[41] = "LESSEQ";
 | 
						|
	strtab[42] = "LESS";
 | 
						|
	strtab[43] = "GREATEQ";
 | 
						|
	strtab[44] = "GREAT";
 | 
						|
	strtab[45] = "EOR";
 | 
						|
 | 
						|
	strtab[49] = "ASSIGN";
 | 
						|
	strtab[50] = "ASPLUS";
 | 
						|
	strtab[51] = "ASMINUS";
 | 
						|
	strtab[52] = "ASMOD";
 | 
						|
	strtab[53] = "ASTIMES";
 | 
						|
	strtab[54] = "ASDIV";
 | 
						|
	strtab[55] = "ASOR";
 | 
						|
	strtab[56] = "ASAND";
 | 
						|
	strtab[57] = "ASLSH";
 | 
						|
	strtab[58] = "ASRSH";
 | 
						|
	strtab[59] = "ASEQUAL";
 | 
						|
	strtab[60] = "ASNEQL";
 | 
						|
	strtab[61] = "ASLEQ";
 | 
						|
	strtab[62] = "ASLESS";
 | 
						|
	strtab[63] = "ASGTQ";
 | 
						|
	strtab[64] = "ASGREAT";
 | 
						|
	strtab[65] = "ASEOR";
 | 
						|
 | 
						|
	strtab[70] = "CON";
 | 
						|
	strtab[71] = "STRING";
 | 
						|
	strtab[72] = "NAME";
 | 
						|
	strtab[73] = "KEYW";
 | 
						|
 | 
						|
	strtab[127] = "UNKN";
 | 
						|
 | 
						|
	if (tok == CON || tok == STRING) {
 | 
						|
		fprintf(out, "%s(%d) ", strtab[tok], cval);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	if (tok == NAME) {
 | 
						|
		fprintf(out, "%s(%s) ", strtab[tok], symbuf);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
		
 | 
						|
	fprintf(out, "%s ", strtab[tok]);
 | 
						|
}
 | 
						|
 |