@dram reported a build failure in FreeBSD at https://github.com/davidgiven/ack/issues/1#issuecomment-273668299 Linux manual for getopt(3) says: > If the first character of optstring is '-', then each nonoption > argv-element is handled as if it were the argument of an option with > character code 1.... > > The use of '+' and '-' in optstring is a GNU extension. GNU/Linux and OpenBSD handle '-' in this special way, but FreeBSD seems not to. If '-' is not special, then em_ego can't find its input file, so the build must fail. This commit stops using '-' in both em_b and em_ego, but doesn't change mcg. Also fix em_ego -O3 to not act like -O4.
		
			
				
	
	
		
			1391 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1391 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;
 | |
| 
 | |
| 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 */
 | |
| };
 | |
| 
 | |
| char ctab[128] = {
 | |
| 	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
 | |
| };
 | |
| 
 | |
| /* 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]);
 | |
| }
 | |
| 
 |