/*
 * esa3.c
 * Lexical processing.
 */
#include <stdio.h>
#include "esa.h"

/*
 * Get the next non white character
 * from the input.
 */
getnb()
{
	register int c;

	while((c=getraw())==' ' || c=='\t');
	return(c);
}

/*
 * Get the next input character.
 * Be very careful with respect to
 * end of lines.
 */
getraw()
{
	register int c;

	if((c = *sptr) != '\0')
		++sptr;
	return(c);
}

/*
 * Test if a character is alphabetic.
 * True return if it is.
 */
alpha(ac)
{
	register int c;

	c = ac;
	if(c=='.' || c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z'))
		return(1);
	return(0);
}

/*
 * Push a character back into the input.
 * Must not push back beyond the start of
 * the line.
 */
putback(c)
{
	if(c != '\0')
		if(--sptr < sbuf)
			error("Putback\n");
}

/*
 * Read in an indentifier.
 * Store it (padded with nulls) into the
 * supplied buffer.
 */
getid(ac, id)
char *id;
{
	register int c;
	register char *p;

	c = ac;
	p = id;
	while(alpha(c) || (c>='0' && c<='9')) {
		if(p < &id[NCPS])
			*p++ = c;
		c = getraw();
	}
	while(p < &id[NCPS])
		*p++ = '\0';
	putback(c);
}

/*
 * Get a number, in either the hexadecimal or
 * the decimal radix.
 * Decimal is indicated by a trailing '.'.
 */
getnum(ac)
{
	register int c, v, hexseen;
	int hex, dec;

	c = ac;
	hex = dec = hexseen = 0;
	while((v=digvalue(c)) >= 0) {
		hex = 16*hex + v;
		dec = 10*dec + v;
		if(v > 9)
			++hexseen;
		c = getraw();
	}
	if(c == '.') {
		if(hexseen)
			err('n');
		return(dec);
	} else {
		putback(c);
		return(hex);
	}
}

/*
 * Given a character, return its numeric value.
 * This is in the range 0 to 15.
 * Return -1 if the input is junk.
 */
digvalue(ac)
{
	register int c;

	c = ac;
	if(c>='0' && c<='9')
		return(c-'0');
	if(c>='a' && c<='f')
		return(c-'a'+10);
	if(c>='A' && c<='F')
		return(c-'A'+10);
	return(-1);
}

/*
 * Lookup a symbol in a symbol table, which
 * may be either `pst' or `ust'.
 * Failures in the `pst' return NULL.
 * Failures in the `ust' cause a new symbol to
 * be added.
 */
struct sym *
lookup(id, astp)
char *id;
struct sym *astp;
{
	register struct sym *stp, *endp;

	if((stp=astp) == ust)
		endp = uptr;
	else
		endp = pptr;
	while(stp < endp) {
		if(match(id, stp->s_name))
			return(stp);
		++stp;
	}
	if(astp == pst)
		return(NULL);
	if(stp >= &ust[USERMAX])
		error("Symbol table overflow\n");
	copy(stp->s_name, id, NCPS);
	stp->s_type = S_UND;
	stp->s_flag = 0;
	stp->s_value = 0;
	++uptr;
	return(stp);
}

/*
 * Compare two names.
 * True return if the same.
 */
match(aa1, aa2)
char *aa1, *aa2;
{
	register char *a1, *a2;
	register int n;

	a1 = aa1;
	a2 = aa2;
	n = NCPS;
	do
		if(*a1++ != *a2++)
			return(0);
	while(--n);
	return(1);
}

/*
 * Get the next character from the input
 * using string mappings.
 */
getmap()
{
	register int n, c, v;

	if((c=getraw()) == '\\')
		switch(c = getraw()) {

		case 'n':
			c = '\n';
			break;

		case 'r':
			c = '\r';
			break;

		case 't':
			c = 0x20;
			break;

		case 'b':
			c = '\b';
			break;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
			v = n = 0;
			while(++n<=3 && c>='0' && c<='7') {
				v = 8*v + c - '0';
				c = getraw();
			}
			putback(c);
			c = v;
			break;

		default:
			putback(c);
			c = '\\';
		}
	else if(c == ' ')
		c = 0xD0;
	else if(c == '/')
		c = 0x40;
	else if(c == '@')
		c = 0x3D + 1; /* Kludge */
	else if(c == '\t')
		c = 0x20;
	else if(c == '_')
		c = 0x3D;
	return(c);
}
