#include "common"

int peek -1;		/* holds returned lookahead character */
char name[NSIZE];	/* name buffer */

get()	{int c;
	c = (peek < 0) ? getchar() : peek;
	peek = (c == '\0') ? '\0' : -1;
	if (c == '\n') line++;
	return (c);
	}

putback(c)
	int c;
	{if ((peek = c) == '\n') --line;
	}

alf(c)	int c;
	{return ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
		|| c == '.' || c == '_'
		? TRUE : FALSE);
	}

num(c)	int c;
	{return ('0' <= c && c <= '9' ? TRUE : FALSE);
	}

op(c)	int c;
	{int i, j;
	for (i = 0; j = "=+-<>?*/&~!|^"[i]; i++)
		if (j == c) return ("=+-<>?*/&!!^^"[i]);
	return (FALSE);
	}

strend(c)
	int c;
	{if (c == '\'') return (TRUE);
	if (c == '\n' || c == '\0')
		{putback(c);
		error("unbalanced '");
		return (TRUE); }
	return (FALSE);
	}

strc(c)	int c;
	{if (c != '\\') return (c);
	if (strend(c = get())) return ('\'');
	if (c == '0') return (000);
	else if (c == 'a') return (006);
	else if (c == 'e') return (004);
	else if (c == 'n') return (012);
	else if (c == 'p') return (033);
	else if (c == 'r') return (015);
	else if (c == 't') return (011);
	else return (c);
	}

char tname[NSIZE + 2];

char *sn(p)
	char *p;
	{int i;
	for (i = 0; i < NSIZE && (tname[i] = *p++); i++) ;
	tname[i] = '\0';
	return (tname);
	}

compare(p1, p2)
	char *p1, *p2;
	{int i;
	i = 0;
	do	if (*p1 != *p2++) return (FALSE);
		while (*p1++ && ++i < NSIZE);
	return (TRUE);
	}

struct symbol *lookup(p1, n)
	struct symbol *p1;
	char *n;
	{struct symbol *p;
	for (p = sptop; p != p1; p = p->prev)
		if (compare(p->name, n)) return (p);
	return (FALSE);
	}

struct symbol *add(s, f, t, v, z)
	char *s;
	int f, t, v, z;
	{struct symbol *p;
	int i;
	if (--space < 0)
		{if ((p = sbrk(100 * sizeof *p)) < 0)
			{error("symbol table full");
			exit(TRUE); }
		if (symtab == NULL) symtab = p;
		space = 99;
		}
	p = &symtab[spused++];
	p->prev = sptop;
	sptop = p;
	for (i = 0; i < NSIZE && (p->name[i] = s[i]); i++) ;
	while (i < NSIZE) p->name[i++] = '\0';

	p->flags = f;
	p->type = t;
	p->value = v;
	p->bias = test(p, DEFF) ? 0 : p - symtab;
	p->size = z;
	return (p);
	}

lex()	{int c, cop, escape, i;
	struct symbol *p;
	escape = FALSE;
	e.flags = e.value = e.bias = 0;
	e.size = 2;
	e.prev = e.tbran = e.fbran = NULL;
    while (c = get()) {
	if (c == ' ' || c == '\t' || c == '\n') continue;
	if (c == '%')
		{while ((c = get()) != '\n' && c) ;
		continue; }

	if (c == ';') return (SCOLON);
	if (c == ',') return (COMMA);

	if (c == '0')
		{e.flags = DEFF;
		do	e.value = (e.value << 3) + (c - '0');
			while (num(c = get()));
		putback(c);
		return (CON);
		}
	if (c == '\'')
		{e.flags = DEFF;
		if (strend(c = get())) return (CON);
		e.value = strc(c);

		if (strend(c = get())) return (CON);
		e.value =| strc(c) << 8;

		if (strend(c = get())) return (CON);
		putback(c);
		return (STRING);
		}
	if (c == '[') return (LBRAK);
	if (c == ']') return (RBRAK);
	if (c == '(' || c == '{') return (LPAREN);
	if (c == ')' || c == '}') return (RPAREN);
	if (c == '"') return (QUOTES);
	if (c == '\0') return (EOF);

	if (c == '\\')
		{escape = !escape;
		continue; }
	if (c == 021)
		{debug = (debug + 1) % 3;
		continue; }
	if (c == 001)
		{--line;
		continue; }

	if (cop = op(c))
		{i = 0;
		do	if (i < NSIZE) name[i++] = cop;
			while (cop = op(c = get()));
		if (i < NSIZE) name[i] = '\0';
		putback(c);

		if (e.value = lookup(NULL, name)) return ((e.value)->type);
		error("illegal operator %s", sn(name));
		setvb(&e, NOP, 0);
		return (OP);
		}
	if (alf(c))
		{i = 0;
		do	if (i < NSIZE) name[i++] = c;
			while (alf(c = get()) || num(c));
		if (i < NSIZE) name[i] = '\0';
		putback(c);

		if ((p = lookup(NULL, name)) == NULL)
			{e.flags =| DCLF;
			return (MEM); }
		if (escape && p->type < KOND)
			{p->type = MEM;
			p->flags = p->value = p->bias = 0;
			p->size = 2; }
		e.flags = p->flags & ATTR;
		e.value = p;
		e.size = p->size;
		return (p->type);
		}
	if (num(c))
		{e.flags = DEFF;
		do	e.value = (e.value * 10) + (c - '0');
			while (num(c = get()));
		putback(c);
		return (CON);
		}
	error("illegal character %o", c);
	    }
	}

dostring(p1)
	struct at *p1;
	{int c, i;
	gen(i = p1->value, 0);
	while (strend(c = get()) == FALSE)
		{i = strc(c);
		if (strend(c = get()))
			{gen(i, 0);
			return (i); }
		gen(i =| (strc(c) << 8), 0);
		}
	return (i);
	}
