/*
 *      Copyright (c) 1987 Paul Campbell
 *      All Rights Reserved
 *      THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF Paul Campbell
 *      The copyright notice above does not evidence any
 *      actual or intended publication of such source code.
 */

#pragma segment lex
#include <stdio.h>
#include <stdlib.h>
#ifdef MPW
#include <osutils.h>
#endif
#include "y.tab.h"
#include "lex.h"
FILE *fin;

int yydebug, do_nl, eofed;
extern int nowarn;

extern int yydebug;
int yyerrcount;
unsigned long yyline;
static char *yyfile;
static char name[257];

struct keywords {
	int 	type;
	char 	*name;
};

struct keywords keywords[] = {
	t_a,		"a",
	t_ab,		"ab",
	t_acall,	"acall",
	t_add,		"add",
	t_addc,		"addc",
	t_ajmp,		"ajmp",
	t_anl,		"anl",
	t_b,		"b",
	t_byte,		"byte",
	t_c,		"c",
	t_cjne,		"cjne",
	t_clr,		"clr",
	t_cpl,		"cpl",
	t_da,		"da",
	t_data,		"data",
	t_db,		"db",
	t_dec,		"dec",
	t_div,		"div",
	t_djnz,		"djnz",
	t_dl,		"dl",
	t_dptr,		"dptr",
	t_dw,		"dw",
	t_dx,		"dx",
	t_end,		"end",
	t_even,		"even",
	t_inc,		"inc",
	t_jb,		"jb",
	t_jbc,		"jbc",
	t_jc,		"jc",
	t_jmp,		"jmp",
	t_jnb,		"jnb",
	t_jnc,		"jnc",
	t_jnz,		"jnz",
	t_jz,		"jz",
	t_lcall,	"lcall",
	t_ljmp,		"ljmp",
	t_long,		"long",
	t_mov,		"mov",
	t_movc,		"movc",
	t_movx,		"movx",
	t_mul,		"mul",
	t_nop,		"nop",
	t_odd,		"odd",
	t_orl,		"orl",
	t_pc,		"pc",
	t_pop,		"pop",
	t_push,		"push",
	t_r0,		"r0",
	t_r1,		"r1",
	t_r2,		"r2",
	t_r3,		"r3",
	t_r4,		"r4",
	t_r5,		"r5",
	t_r6,		"r6",
	t_r7,		"r7",
	t_ret,		"ret",
	t_reti,		"reti",
	t_rl,		"rl",
	t_rlc,		"rlc",
	t_rr,		"rr",
	t_rrc,		"rrc",
	t_setb,		"setb",
	t_sjmp,		"sjmp",
	t_subb,		"subb",
	t_swap,		"swap",
	t_text,		"text",
	t_word,		"word",
	t_xcall,	"xcall",
	t_xch,		"xch",
	t_xchd,		"xchd",
	t_xrl,		"xrl",
	0,			"\177",
};

struct builtin {
	char 			*name;
	unsigned short 	val;
};

struct builtin builtin[] = {
	"r0_0",		0x00,
	"r1_0",		0x01,
	"r2_0",		0x02,
	"r3_0",		0x03,
	"r4_0",		0x04,
	"r5_0",		0x05,
	"r6_0",		0x06,
	"r7_0",		0x07,
	
	"r0_1",		0x08,
	"r1_1",		0x09,
	"r2_1",		0x0a,
	"r3_1",		0x0b,
	"r4_1",		0x0c,
	"r5_1",		0x0d,
	"r6_1",		0x0e,
	"r7_1",		0x0f,
	
	"r0_2",		0x10,
	"r1_2",		0x11,
	"r2_2",		0x12,
	"r3_2",		0x13,
	"r4_2",		0x14,
	"r5_2",		0x15,
	"r6_2",		0x16,
	"r7_2",		0x17,
	
	"r0_3",		0x18,
	"r1_3",		0x19,
	"r2_3",		0x1a,
	"r3_3",		0x1b,
	"r4_3",		0x1c,
	"r5_3",		0x1d,
	"r6_3",		0x1e,
	"r7_3",		0x1f,
	
	"p0",		0x80,
	"sp",		0x81,
	"dpl",		0x82,
	"dph",		0x83,
	"adres0",	0x84,
	"gmod",		0x84,
	"tfifo",	0x85,
	"pcon",		0x87,
	
	"tcon",		0x88,
	"tmod",		0x89,
	"tl0",		0x8a,
	"tl1",		0x8b,
	"th0",		0x8c,
	"th1",		0x8d,
	"auxr",		0x8e,

	"p1",		0x90,
	"dcon0",	0x92,
	"dcon1",	0x93,
	"adres1",	0x94,
	"baud",		0x94,
	"adr0",		0x95,
	"acon",		0x97,
	
	"scon",		0x98,
	"sbuf",		0x99,
	"c1capm0",	0x9a,
	"c1capm1",	0x9b,
	"c1capm2",	0x9c,
	"c1capm3",	0x9d,
	"c1capm4",	0x9e,
	"c1mod",	0x9f,

	"p2",		0xa0,
	"sarl0",	0xa2,
	"sarh0",	0xa3,
	"adres2",	0xa4,
	"ifs",		0xa4,
	"ofdcon",	0xa5,
	"adr1",		0xa5,
	"wdtcon",	0xa6,
	"iea",		0xa7,

	"ie",		0xa8,
	"saddr",	0xa9,
	"c1cap0l",	0xaa,
	"c1cap1l",	0xab,
	"c1cap2l",	0xac,
	"c1cap3l",	0xad,
	"c1cap4l",	0xae,
	"cl1",		0xaf,

	"p3",		0xb0,
	"sarl1",	0xb2,
	"sarh1",	0xb3,
	"adres3",	0xb4,
	"slottm",	0xb4,
	"ipa1",		0xb5,
	"adr2",		0xb5,
	"ipa",		0xb6,
	"ipl",		0xb7,
	"iph",		0xb7,
	
	"ip",		0xb8,
	"saden",	0xb9,
	"c1cap0h",	0xba,
	"c1cap1h",	0xbb,
	"c1cap2h",	0xbc,
	"c1cap3hl",	0xbd,
	"c1cap4h",	0xbe,
	"ch1",		0xbf,

	"p4",		0xc0,
	"darl0",	0xc2,
	"darh0",	0xc3,
	"adres4",	0xc4,
	"bkoff",	0xc4,
	"adr3",		0xc5,
	"exicon",	0xc6,
	"acmp",		0xc7,

	"t2con",	0xc8,
	"ien1",		0xc8,
	"t2mod",	0xc9,
	"rcap2l",	0xca,
	"rcap2h",	0xcb,
	"tl2",		0xcc,
	"th2",		0xcd,
	"fcon",		0xce,
	"ft",		0xcf,

	"psw",		0xd0,
	"darl1",	0xd2,
	"darh1",	0xd3,
	"adres5",	0xd4,
	"tcdcnt",	0xd4,
	"amsk0",	0xd5,
	"sepcon",	0xd7,

	"ccon",		0xd8,
	"tstat",	0xd8,
	"cmod",		0xd9,
	"ccapm0",	0xda,
	"ccapm1",	0xdb,
	"ccapm2",	0xdc,
	"ccapm3",	0xdd,
	"ccapm4",	0xde,

	"acc",		0xe0,
	"bcrl0",	0xe2,
	"bcrh0",	0xe3,
	"adres6",	0xe4,
	"prbs",		0xe4,
	"amsk1",	0xe5,
	"hstat",	0xe6,
	"sepdat",	0xe7,
	"hcon",		0xe7,
	
	"c1con",	0xe8,
	"slcon",	0xe8,
	"rstst",	0xe8,
	"cl",		0xe9,
	"sstat",	0xe9,
	"ccap0l",	0xea,
	"iwpr",		0xea,
	"ccap1l",	0xeb,
	"irpr",		0xeb,
	"ccap2l",	0xec,
	"cbp",		0xec,
	"ccap3l",	0xed,
	"ccap4l",	0xee,
	"fin",		0xee,
	"cin",		0xef,

	"b",		0xf0,
	"bcrl1",	0xf2,
	"bcrh1",	0xf3,
	"adres7",	0xf4,
	"rfifo",	0xf4,
	"myslot",	0xf5,
	"ithr",		0xf6,
	"sepsta",	0xf7,
	"othr",		0xf7,
	
	"p5",		0xf8,
	"ipn1",		0xf8,
	"ch",		0xf9,
	"mode",		0xf9,
	"ccap0h",	0xfa,
	"orpr",		0xfa,
	"ccap1h",	0xfb,
	"owpr",		0xfb,
	"ccap2h",	0xfc,
	"imin",		0xfc,
	"ccap3h",	0xfd,
	"imout",	0xfd,
	"ccap4h",	0xfe,
	"fout",		0xfe,
	"count",	0xff,
	
	NULL, 		0, 
};

struct bits {
	char 			*name;
	unsigned short 	val;
};

struct bits bits[] = {

	"it0", 		0x88,
	"ie0", 		0x89,
	"it1", 		0x8a,
	"ie1", 		0x8b,
	"tr0", 		0x8c,
	"tf0", 		0x8d,
	"tr1", 		0x8e,
	"tf1", 		0x8f,
	
	"ri", 		0x98,
	"ti", 		0x99,
	"rb8", 		0x9a,
	"tb8", 		0x9b,
	"ren", 		0x9c,
	"sm2", 		0x9d,
	"sm1", 		0x9e,
	"sm0", 		0x9f,
	"fe", 		0x9f,
	
	"ex0", 		0xa8,
	"et0", 		0xa9,
	"ex1", 		0xaa,
	"et1", 		0xab,
	"es", 		0xac,
	"et2", 		0xad,
	"ec", 		0xae,
	"ea", 		0xaf,
	
	"px0", 		0xb8,
	"pt0", 		0xb9,
	"px1", 		0xba,
	"pt1", 		0xbb,
	"ps", 		0xbc,
	"pt2", 		0xbd,
	"pc", 		0xbe,
	
	"cp_rl2", 	0xc8,
	"c_t2", 	0xc9,
	"tr2", 		0xca,
	"exen2", 	0xcb,
	"tclk", 	0xcc,
	"rclk", 	0xcd,
	"exf2", 	0xce,
	"tf2", 		0xcf,
	
	"egsrv", 	0xc8,
	"egsre", 	0xc9,
	"edma0", 	0xca,
	"egstv", 	0xcb,
	"edma1", 	0xcc,
	"egste", 	0xcd,
	
	"p", 		0xd0,
	"ov", 		0xd2,
	"rs0", 		0xd3,
	"rs1", 		0xd4,
	"f0", 		0xd5,
	"ac", 		0xd6,
	"cy", 		0xd7,
	
	"ccf0", 	0xd8,
	"ccf1", 	0xd9,
	"ccf2", 	0xda,
	"ccf3", 	0xdb,
	"ccf4", 	0xdc,
	"cr", 		0xde,
	"cf", 		0xdf,
	
	"dma",	 	0xd8,
	"ten", 		0xd9,
	"tfnf", 	0xda,
	"tdn", 		0xdb,
	"tcdt", 	0xdc,
	"ur", 		0xdd,
	"noack", 	0xde,
	"lni", 		0xdf,
	
	"c1cf0", 	0xe8,
	"c1cf1", 	0xe9,
	"c1cf2", 	0xea,
	"c1cf3", 	0xeb,
	"c1cf4", 	0xec,
	"cre", 		0xed,
	"cr1", 		0xee,
	"cf1", 		0xef,
	
	"haben", 	0xe8,
	"gren", 	0xe9,
	"rfne", 	0xea,
	"rdn", 		0xeb,
	"crce", 	0xec,
	"ae", 		0xed,
	"rcabt", 	0xee,
	"ovr", 		0xef,
	
	"pgsrv", 	0xf8,
	"pgsre", 	0xf9,
	"pdma0", 	0xfa,
	"pgstv", 	0xfb,
	"pdma1", 	0xfc,
	"pgste", 	0xfd,
		
	NULL,		0,
};

#define next_char()	(getc(fin))
#define back_char(c) { ungetc(c, fin); }

struct dict *dict_head = NULL;

struct dict *
find_name(char *name)
{
	register struct dict *dp;
	register int i;
	
	dp = dict_head;
	for (;;) {
		if (dp == NULL)
			return(NULL);
		i = strcmp(name, dp->name);
		if (i == 0)
			return(dp);
		if (i > 0) {
			dp = dp->gt;
		} else {
			dp = dp->lt;
		}
	}
}

struct dict *
add_name(char *name)
{
	register struct dict *dp, *dp2;
	register int i;

	i = strlen(name)+1+sizeof(*dp);
	dp2 = (struct dict *)malloc(strlen(name)+1+sizeof(*dp2));
	strcpy(dp2->name, name);
	dp2->val = 0;
	dp2->valid = 0;
	dp2->bits = 0;
	dp2->builtin = 0;
	dp2->lt = NULL;
	dp2->gt = NULL;
	if ((dp = dict_head) == NULL) {
		dict_head = dp2;
	} else {
		for (;;) {
			i = strcmp(name, dp->name);
			if (i == 0) {
				yyerror("Duplicate variable '%s'", (long)name, 0, 0, 0, 0, 0);
				free(dp2);
				return(dp);
			}
			if (i > 0) {
				if (dp->gt == NULL) {
					dp->gt = dp2;
					break;
				}
				dp = dp->gt;
			} else {
				if (dp->lt == NULL) {
					dp->lt = dp2;
					break;
				}
				dp = dp->lt;
			}
		}
	}
	return(dp2);
}

void
ptree(struct dict *dp, int flag)
{
	if (dp == NULL)
		return;
	ptree(dp->lt, flag);
	if (flag || !dp->builtin)
		printf("%04x: %s %s\n", dp->val, (dp->bits?"(b)":"   "), dp->name);
	ptree(dp->gt, flag);
}

void
pmap(int flag)
{
	ptree(dict_head, flag);
}

void
yyinit()
{
	int i, j;
	struct dict *dp;
	char t[64];
	
	for (i = 0; builtin[i].name;i++) {
		dp = add_name(builtin[i].name);
		dp->valid = 1;
		dp->bits = 0;
		dp->builtin = 1;
		dp->val = builtin[i].val;
		strcpy(t, builtin[i].name);
		for (j = 0; t[j]; j++)
			if (t[j] >= 'a' && t[j] <= 'z')
				t[j] += 'A'-'a';
		dp = add_name(t);
		dp->valid = 1;
		dp->bits = 0;
		dp->builtin = 1;
		dp->val = builtin[i].val;
	}
	for (i = 0; bits[i].name;i++) {
		dp = add_name(bits[i].name);
		dp->valid = 1;
		dp->bits = 1;
		dp->builtin = 1;
		dp->val = bits[i].val;
		strcpy(t, bits[i].name);
		for (j = 0; t[j]; j++)
			if (t[j] >= 'a' && t[j] <= 'z')
				t[j] += 'A'-'a';
		dp = add_name(t);
		dp->valid = 1;
		dp->bits = 1;
		dp->builtin = 1;
		dp->val = bits[i].val;
	}
/*	ptree(dict_head, 0);*/
}


int
yyopen(char *file)
{
	yyline = 1;
	do_nl = 0;
	yyfile = file;
	yyerrcount = 0;
	eofed = 0;
	fin = fopen(file, "r");
	if (fin)
		return(0);
	return(1);
}

void
yyrewind()
{
	yyline = 1;
	do_nl = 0;
	eofed = 0;
	rewind(fin);
}

void
yyerror(char *s, long a, long b, long c, long d, long e, long f)
{
	fprintf(stderr, "File	\"%s\"; Line %d # ", yyfile, yyline);
	fprintf(stderr, s, a, b, c, d, e, f);
	fprintf(stderr, "\n");
	yyerrcount++;
}

void 
yywarnline(int err, char *s, long a, long b, long c, long d, long e, long f)
{
	long *x = (long *)&s;

	if (nowarn)
		return;
	fprintf(stderr, "File	\"%s\"; Line %d # Warning: ", yyfile, err);
	fprintf(stderr, s, a,b,c,d,e,f);
	fprintf(stderr, "\n");
}

void 
yyerrline(int err, char *s, long a, long b, long c, long d, long e, long f)
{
	int i = yyline;
	long *x = (long *)&s;
	
	yyline = err;
	yyerror(s, a,b,c,d,e,f);
	yyline = i;
}

void 
yyerrlinex(long err, char *s, long a, long b, long c, long d, long e, long f)
{
	int i = yyline;
	long *x = (long *)&s;
	
	yyline = err;
	yyerror(s, a,b,c,d,e,f);
	yyline = i;
}

void
yyclose()
{
	fclose(fin);
}

int
yylex()
{
	register long c, i, j, k;
	struct dict *dp;
	char *cp;
	
	if (do_nl) {
		do_nl = 0;
		yyline++;
	}
	if (eofed)
		return(EOF);
	for (;;) {
again:	for (;;) {
			c = next_char();
			if (c == ' ' || c == '\t')
				continue;
			break;
		}
		if ((c >= 'a' && c <= 'z') ||
			(c >= 'A' && c <= 'Z') ||
			 c == '_') {
			name[0] = c;
			for (i = 1;;i++) {
				c = next_char();
				if ((c >= 'a' && c <= 'z') ||
					(c >= 'A' && c <= 'Z') ||
					(c >= '0' && c <= '9') ||
					 c == '$' ||
					 c == '_') {
					 name[i] = c;
					 continue;
				}
				name[i] = 0;
				break;
			}
names:
			back_char(c);
			for (j = 0; ;j++) {
				if ((k = strcmp(name, keywords[j].name)) == 0) 
					return(keywords[j].type);
				if (k < 0)
					break;
			}
			dp = find_name(name);
			if (dp == NULL)
				dp = add_name(name);
			yylval = (long)dp;
			return(dp->bits ? t_bit : t_name);
		} 
		if (c >= '0' && c <= '9') {
			i = 0;
			if (c == '0') {
				c = next_char();
				if (c == 'x' || c == 'X') {
					c = next_char();
					while ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
						if (c >= '0' && c <= '9') {
							i = (i<<4)+c-'0';
						} else
						if (c >= 'A' && c <= 'F') {
							i = (i<<4)+10+c-'A';
						} else {
							i = (i<<4)+10+c-'a';
						}
						c = next_char();
					}
				} else 
				if (c >= '0' || c <= '7') {
					while (c >= '0' && c <= '7') {
						i = (i<<3)+c-'0';
						c = next_char();
					}
				} 
			} else {
				while (c >= '0' && c <= '9') {
					i = i*10+c-'0';
					c = next_char();
				}
			}
			back_char(c);
			yylval = i;
			return(t_val);
		} 
		switch (c&0xff) {
		case '\'':
				for (i = 0;;i++) {
					name[i] = c = next_char();
					if (c == '\n' || c == EOF) {
						yyerror("string overflowed line",0,0,0,0,0,0);
						if (c == '\n') {
							do_nl = 1;
						} else {
							eofed = 1;
						}
						return(t_nl);
					}
					if (c == '\'') {
						break;
					}
					if (c == '\\') {
						c = next_char();
						switch (c) {
						case 'n':
							c = 0xa;
							break;
						case 'r':
							c = 0xd;
							break;
						case 't':
							c = '\t';
							break;
						case 'f':
							c = '\f';
							break;
						case 'b':
							c = '\b';
							break;
						}
						name[i] = c;
					}
					if (i >= 3) {
						yyerror("string > 2 chars",0,0,0,0,0,0);
						i = 2;
						break;
					}
				}
				if (i == 1) {
					yylval = name[0]&0xff;
				} else
				if (i == 2) {
					yylval = *(unsigned short *)name;
				} 
				return(t_val);
				
		case '"':
				for (i = 0;;i++) {
					name[i] = c = next_char();
					if (c == '\n' || c == EOF) {
						yyerror("string overflowed line",0,0,0,0,0,0);
						if (c == '\n') {
							do_nl = 1;
						} else {
							eofed = 1;
						}
						return(t_nl);
					}
					if (c == '"') {
						name[i] = 0;
						break;
					}
					if (c == '\\') {
						c = next_char();
						switch (c) {
						case 'n':
							c = 0xa;
							break;
						case 'r':
							c = 0xd;
							break;
						case 't':
							c = '\t';
							break;
						case 'f':
							c = '\f';
							break;
						case 'b':
							c = '\b';
							break;
						case 'z':
							c = 0x80;
							break;
						}
						name[i] = c;
					}
				}
				cp = (char *)malloc(strlen(name)+1);
				strcpy(cp, name);
				yylval = (long)cp;
				return(t_string);
				
		case ';':
				for (;;) {
					c = next_char();
					if (c == '\n' || c == EOF) 
						break;
				}
				if (c == '\n') {
					do_nl = 1;
				} else {
					eofed = 1;
				}
				return(t_nl);
				
				
		case '\n':
				do_nl = 1;
				return(t_nl);				
		}
		if (c == EOF) {
			eofed = 1;
			return(t_nl);
		}
		return(c);
	}
}
