OpenCores
URL https://opencores.org/ocsvn/light8080/light8080/trunk

Subversion Repositories light8080

[/] [light8080/] [trunk/] [tools/] [c80/] [c80.c] - Rev 90

Compare with Previous | Blame | View Log

//************************************************
//
//		Small-C Compiler 
// 
//		by Ron Cain 
// 
//************************************************
 
// with minor mods by RDK 
#define BANNER  " <><><>   Small-C  V1.2  DOS--CP/M Cross Compiler   <><><>"
#define VERSION " <><><><><>   CP/M Large String Space Version   <><><><><>"
#define AUTHOR  " <><><><><><><><><><>   By Ron Cain   <><><><><><><><><><>"
#define TLINE   " <><><><><><><><><><><><><><>X<><><><><><><><><><><><><><>"
 
/*	Define system dependent parameters	*/
/*	Stand-alone definitions			*/
/* INCLUDE THE LIBRARY TO COMPILE THE COMPILER (RDK) */
/* #include smallc.lib */ /* small-c library included in source now */
/* IN DOS USE THE SMALL-C OBJ LIBRARY RATHER THAN IN-LINE ASSEMBLER */
#define NULL 0
#define eol 10 /* was 13 */
 
#include "stdio.h"  /* was <stdio.h> */
 
/*	Define the symbol table parameters	*/
#define	symsiz		16
#define	symtbsz		5760
#define numglbs 	300
#define	startglb 	symtab
#define	endglb		startglb+numglbs*symsiz
#define	startloc 	endglb+symsiz
#define	endloc		symtab+symtbsz-symsiz
 
/*	Define symbol table entry format	*/
#define	name		0
#define	ident		9
#define	type		10
#define	storage		11
#define	offset		12
#define initptr		14
 
/*	System wide name size (for symbols)	*/
#define	namesize 	9
#define namemax  	8
 
/*	Define possible entries for "ident"	*/
#define	variable	1
#define	array		2
#define	pointer		3
#define	function	4
 
/*	Define possible entries for "type"	*/
#define	cchar		1
#define	cint		2
#define cport		3 
 
/*	Define possible entries for "storage"	*/
#define	statik		1
#define	stkloc		2
 
/*	Define the "while" statement queue	*/
#define	wqtabsz		300
#define	wqsiz		4
#define	wqmax		wq+wqtabsz-wqsiz
 
/*	Define entry offsets in while queue	*/
#define	wqsym		0
#define	wqsp		1
#define	wqloop		2
#define	wqlab		3
 
/*	Define the literal pool			*/
#define	litabsz		8000
#define	litmax		litabsz-1
 
/*	Define the input line			*/
#define	linesize 	256
#define	linemax		linesize-1
#define	mpmax		linemax
 
/*	Define the macro (define) pool		*/
#define	macqsize 	3000
#define	macmax		macqsize-1
 
/*	Define statement types (tokens)		*/
#define	stif		1
#define	stwhile		2
#define	streturn 	3
#define	stbreak		4
#define	stcont		5
#define	stasm		6
#define	stexp		7
 
/* Define how to carve up a name too long for the assembler */
#define asmpref		7
#define asmsuff		7
 
// define the global variable init values que size 
#define initqsz		8192
 
/*	Now reserve some storage words		*/
char	symtab[symtbsz];	/* symbol table */
char	*glbptr,*locptr;	/* ptrs to next entries */
 
int		wq[wqtabsz];		/* while queue */
int		*wqptr;				/* ptr to next entry */
 
char	litq[litabsz];		/* literal pool */
int		litptr;				/* ptr to next entry */
 
char	macq[macqsize];		/* macro string buffer */
int		macptr;				/* and its index */
 
char	inittbq[initqsz];	// init value buffer 
int		inittbptr;			// and its index 
 
char	line[linesize];		/* parsing buffer */
char	mline[linesize];	/* temp macro buffer */
int		lptr,mptr;			/* ptrs into each */
 
/*	Misc storage	*/
int	nxtlab,		/* next avail label # */
	litlab,		/* label # assigned to literal pool */
	Zsp,		/* compiler relative stk ptr */
	argstk,		/* function arg sp */
	ncmp,		/* # open compound statements */
	errcnt,		/* # errors in compilation */
	errstop,	/* stop on error			gtf 7/17/80 */
	eof,		/* set non-zero on final input eof */
	input,		/* iob # for input file */
	output,		/* iob # for output file (if any) */
	outputv,	/* output valid flag */
	input2,		/* iob # for "include" file */
	glbflag,	/* non-zero if internal globals */
	ctext,		/* non-zero to intermix c-source */
	cmode,		/* non-zero while parsing c-code */
			/* zero when passing assembly code */
	lastst,		/* last executed statement type */
	mainflg,	/* output is to be first asm file	gtf 4/9/80 */
	saveout,	/* holds output ptr when diverted to console	   */
			/*					gtf 7/16/80 */
	fnstart,	/* line# of start of current fn.	gtf 7/2/80 */
	lineno,		/* line# in current file		gtf 7/2/80 */
	infunc,		/* "inside function" flag		gtf 7/2/80 */
	savestart,	/* copy of fnstart "	"		gtf 7/16/80 */
	saveline,	/* copy of lineno  "	"		gtf 7/16/80 */
	saveinfn;	/* copy of infunc  "	"		gtf 7/16/80 */
 
char   *currfn,		/* ptr to symtab entry for current fn.	gtf 7/17/80 */
       *savecurr;	/* copy of currfn for #include		gtf 7/17/80 */
char	*cptr;		/* work ptr to any char buffer */
int	*iptr;		/* work ptr to any int buffer */
 
// interactive mode flag 
int intmode;
// pointer array to input files list from argv[] 
#define MAXINFILES		64
char *infiles[MAXINFILES];
int filesnum, filesidx;
// initial stack pointer value 
int stackptr;
 
/*	>>>>> start cc1 <<<<<<		*/
 
/*					*/
/*	Compiler begins execution here	*/
/*					*/
void main(int argc, char *argv[])
{
int argi, phelp;
 
	glbptr=startglb;	/* clear global symbols */
	locptr=startloc;	/* clear local symbols */
	wqptr=wq;0;		/* clear while queue */
	macptr=0;		/* clear the macro pool */
	litptr=0;		/* clear literal pool */
  	Zsp =0;			/* stack ptr (relative) */
	errcnt=0;		/* no errors */
	errstop=0;		/* keep going after an error		gtf 7/17/80 */
	eof=0;			/* not eof yet */
	input=0;		/* no input file */
	input2=0;		/* or include file */
	output=0;		/* no open units */
	outputv=0;		/* output is not valid */
	saveout=0;		/* no diverted output */
	ncmp=0;			/* no open compound states */
	lastst=0;		/* no last statement yet */
	mainflg=0;		/* not first file to asm 		gtf 4/9/80 */
	fnstart=0;		/* current "function" started at line 0 gtf 7/2/80 */
	lineno=0;		/* no lines read from file		gtf 7/2/80 */
	infunc=0;		/* not in function now			gtf 7/2/80 */
	currfn=NULL;	/* no function yet			gtf 7/2/80 */
	cmode=1;		/* enable preprocessing */
	stackptr=0;		/* default value of stack pointer */
	inittbptr=0;	// clear pointer to init array 
 
	intmode = 1;	// default mode is interactive mode 
	filesnum = 0;	// no input files for now 
	filesidx = 0;
 
	// print original banner 
	printf("\n");
	printf(" <><><><><><><><><><><><><><>X<><><><><><><><><><><><><><>\n");
	printf(" <><><>   Small-C  V1.2  DOS--CP/M Cross Compiler   <><><>\n");
	printf(" <><><><><><><><><><>   By Ron Cain   <><><><><><><><><><>\n");
	printf(" <><><><><>   CP/M Large String Space Version   <><><><><>\n");
	printf(" <><><><><><><><><><><><><><>X<><><><><><><><><><><><><><>\n");
 
	// print adapted banner and usage 
	printf("\n");
	printf(" <><><><><><><><><><><><><><>X<><><><><><><><><><><><><><>\n");
	printf(" <><><>  Small-C adapted for embedded systems by  <><><><>\n");
	printf(" <><><><><><><><><>  Moti  Litochevski  <><><><><><><><><>\n");
	printf(" <><><><><><> Version 0.1 (February 20, 2012) <><><><><><>\n");
	printf(" <><><><><><><><><><><><><><>X<><><><><><><><><><><><><><>\n");
	printf("\n");
	// check if command line options where specified 
	if (argc <= 1) {
		printf(" command line mode usage:\n");
		printf("      c80 -s<hexvalue> -o<filename> <input files>\n");
		printf(" options:\n");
		printf("      -s<hexvalue>   Initial stack pointer value in hex value.\n");
		printf("                     Example: -s800 will init the stack pointer\n");
		printf("                     to 0x800.\n");
		printf("      -o<filename>   Compiler output filename including extension.\n");
		printf(" \n");
	}
 
	// start from the first valid argument 
	argi = 1;
	phelp = 0;
    // loop through input options 
    while (argi < argc) {
	    // copy pointer of the current option to the work buffer 
	    cptr = argv[argi];
	    // loop through input options 
	    if (cptr[0] == '-') {
		    // compiler options 
		    if (cptr[1] == 's') {
			    // stack pointer address value 
			    sscanf(&cptr[2], "%x", &stackptr);
			} else if (cptr[1] == 'o') {
				// copy the output filename to the line 
				strcpy(line, &cptr[2]);
				// open output file 
				openout(0);
			} else if ((cptr[1] == 'h') | (cptr[1] == '?')) {
				// sign that only help should be printed 
				phelp = 1;
		    } else {
			    printf("error: illegal option.\n");
		    }
		} else {
			// after all other options the list of input files is given and 
			// compiler is operated in non-interactive mode 
			intmode = 0;
 
			// copy the input files names pointers to the local array 
			for (filesnum=0; (argi < argc) && (filesnum < MAXINFILES); filesnum++) {
				infiles[filesnum] = argv[argi];
				argi++;
			}
		}   
		// update argument index 
		argi++;
    }
 
    // check if compiler should be started 
    if (!phelp) {
	    // announce interactive mode compiler 
		printf(" Starting compiler in interactive mode.\n\n");
		// compiler body 
		ask();			/* get user options */
		if (outputv == 0) openout(1);		/* get an output file */
		openin();		/* and initial input file */
		header();		/* intro code */
		parse(); 		/* process ALL input */
		dumplits();		/* then dump literal pool */
		dumpglbs();		/* and all static memory */
		trailer();		/* follow-up code */
		closeout();		/* close the output (if any) */
		errorsummary();		/* summarize errors (on console!) */
	}
	return;			/* then exit to system */
}
 
/*					*/
/*	Abort compilation		*/
/*		gtf 7/17/80		*/
zabort()
{
	if(input2)
		endinclude();
	if(input)
		fclose(input);
	closeout();
	toconsole();
	pl("Compilation aborted.");  nl();
	exit();
/* end zabort */}
 
/*					*/
/*	Process all input text		*/
/*					*/
/* At this level, only static declarations, */
/*	defines, includes, and function */
/*	definitions are legal...	*/
parse()
{
	while (eof==0)		/* do until no more input */
	{
		if(amatch("char",4)){declglb(cchar);ns();}
		else if(amatch("int",3)){declglb(cint);ns();}
		else if(amatch("port",4)){declglb(cport);ns();}
		else if(match("#asm"))doasm();
		else if(match("#include"))doinclude();
		else if(match("#define"))addmac();
		else newfunc();
		blanks();	/* force eof if pending */
	}
}
/*					*/
/*	Dump the literal pool		*/
/*					*/
dumplits()
	{int j,k;
	if (litptr==0) return;	/* if nothing there, exit...*/
	printlabel(litlab);col();nl(); /* print literal label */
	k=0;			/* init an index... */
	while (k<litptr)	/* 	to loop with */
		{defbyte();	/* pseudo-op to define byte */
		j=10;		/* max bytes per line */
		while(j--)
			{outdec((litq[k++]&127));
			if ((j==0) | (k>=litptr))
				{nl();		/* need <cr> */
				break;
				}
			outbyte(',');	/* separate bytes */
			}
		}
	}
/*					*/
/*	Dump all static variables	*/
/*					*/
dumpglbs()
{
int j,dptr,idx;
 
	if (glbflag==0) return;	/* don't if user said no */
	cptr=startglb;
	while (cptr<glbptr) {
		if ((cptr[ident]!=function) && (cptr[type]!=cport)) {
			// do if anything but function or port 
			// output name as label ... 
			outname(cptr);col();nl();
			// calculate number of bytes 
			j = ((cptr[offset]&255) + ((cptr[offset+1]&255)<<8));
			if ((cptr[type]==cint) | (cptr[ident]==pointer)) 
				j=j+j;	// 2 bytes for integer values 
			// check if the global has an init value 
			dptr = ((cptr[initptr]&255) + ((cptr[initptr+1]&255)<<8));
			// the value below represent the -1 value 
			if (dptr==0xffff) {
				// no init value, use original storage definition 
				// define storage 
				defstorage();
				outdec(j);	/* need that many */
				nl();
			} 
			else {
				// define the data section 
				defbyte();
				// loop through init value 
				idx=1;
				while (j--) {
					// write the next byte 
					outdec(inittbq[dptr++]);
					if ((j==0) | (dptr>=inittbptr)) {
						nl();		/* need <cr> */
						break;
					}
					// every 10 values reopen the line 
					if (idx++ == 10) {
						// add <cr> and restart byte definition 
						nl(); 
						defbyte();
						idx=1;
					} else 
						// separate bytes 
						outbyte(',');	
				}
			}
		}
		cptr=cptr+symsiz;
	}
}
/*					*/
/*	Report errors for user		*/
/*					*/
errorsummary()
{
	/* see if anything left hanging... */
	if (ncmp) error("missing closing bracket");
		/* open compound statement ... */
	printf("\nThere were %d errors in compilation.\n\n", errcnt);
}
 
/* Get options from user */
ask()
{
int k,num[1];
 
	kill();			/* clear input line */
	// by default enabling C text in the output file in form of comments (for clarity) 
	ctext=1;	/* user said yes */
	// by default assuming all files are compiled together 
	glbflag=1;	/* define globals */
	mainflg=1;	/* first file to assembler */
	nxtlab =0;	/* start numbers at lowest possible */
	// compiler does noy pause on errors 
	errstop=0;
 
	litlab=getlabel();	/* first label=literal pool */ 
	kill();			/* erase line */
}
 
/*					*/
/*	Get output filename		*/
/*					*/
openout(char flag)
{
	if (flag) {
		kill();			/* erase line */
		output=0;		/* start with none */
		pl("Output filename? "); /* ask...*/
		gets(line);	/* get a filename */
	}
	if(ch()==0)return;	/* none given... */
	/* if given, open */ 
	if((output=fopen(line,"w"))==NULL) {
		output=0;	/* can't open */
		error("Open failure!");
	} else 
		outputv = 1;
	kill();			/* erase line */
}
/*					*/
/*	Get (next) input file		*/
/*					*/
openin()
{
	input=0;		/* none to start with */
	while (input==0) {	/* any above 1 allowed */
		kill();		/* clear line */
		// check if we are using interactive mode or not 
		if (intmode) {
			// use the old style input file from the user 
			if (eof) break;	/* if user said none */
			pl("Input filename? ");
			gets(line);	/* get a name */
			if (ch()==0)
				{eof=1;break;} /* none given... */
		} else {
			// copy the file names from the name array 
			if (filesidx < filesnum) {
				strcpy(line, infiles[filesidx]);
				printf("Processing Input file %d: %s\n", filesidx, line);
				filesidx++;
			} else {
				// no more files 
				eof=1; 
				break;
			}
		}
 
		if ((input=fopen(line,"r"))!=NULL)
			newfile();			/* gtf 7/16/80 */
		else {	
			input=0;	/* can't open it */
			pl("Open failure");
		}
	}
	kill();		/* erase line */
}
 
/*					*/
/*	Reset line count, etc.		*/
/*			gtf 7/16/80	*/
newfile()
{
	lineno  = 0;	/* no lines read */
	fnstart = 0;	/* no fn. start yet. */
	currfn  = NULL;	/* because no fn. yet */
	infunc  = 0;	/* therefore not in fn. */
/* end newfile */}
 
/*					*/
/*	Open an include file		*/
/*					*/
doinclude()
{
	blanks();	/* skip over to name */
 
	toconsole();					/* gtf 7/16/80 */
	outstr("#include "); outstr(line+lptr); nl();
	tofile();
 
	if(input2)					/* gtf 7/16/80 */
		error("Cannot nest include files");
	else if ((input2=fopen(line+lptr,"r"))==NULL) {
		input2=0;
		error("Open failure on include file");
	} 
	else {	
		saveline = lineno;
		savecurr = currfn;
		saveinfn = infunc;
		savestart= fnstart;
		newfile();
	}
	kill();		/* clear rest of line */
			/* so next read will come from */
			/* new file (if open */
}
 
/*					*/
/*	Close an include file		*/
/*			gtf 7/16/80	*/
endinclude()
{
	toconsole();
	outstr("#end include"); nl();
	tofile();
 
	input2  = 0;
	lineno  = saveline;
	currfn  = savecurr;
	infunc  = saveinfn;
	fnstart = savestart;
/* end endinclude */}
 
/*					*/
/*	Close the output file		*/
/*					*/
closeout()
{
	tofile();	/* if diverted, return to file */
	if(output)fclose(output); /* if open, close it */
	output=0;		/* mark as closed */
}
/*					*/
/*	Declare a static variable	*/
/*	  (i.e. define for use)		*/
/*					*/
/* makes an entry in the symbol table so subsequent */
/*  references can call symbol by name	*/
declglb(typ)		/* typ is cchar or cint or cport (added by Moti Litchevski) */
	int typ;
{	
int k,j,iptr,idx,num[1];
char sname[namesize];
 
	while (1) {
		while (1) {
			if(endst())return;	/* do line */
			k=1;		/* assume 1 element */
			if(match("*"))	/* pointer ? */
				j=pointer;	/* yes */
			else 
				j=variable; /* no */
 
			// added by Moti Litochevski 
			if (match("(")) {
				// make sure this option is only used for port definition 
				if (typ != cport)
					error("port address definition is only used for port type");
				// get port address 
				k=portadr(); 
				k=k&0xff;
			} else if (typ == cport) {
				error("port definition syntax error, need to define port address in brackets");
			}
 
			if (symname(sname)==0) /* name ok? */
				illname(); /* no... */
			if(findglb(sname)) /* already there? */
				multidef(sname);
			if (match("[")) {	/* array? */
				if (typ==cport) error("port cannot be defined as an array");
				k=needsub();	/* get size */
				if(k)j=array;	/* !0=array */
				else j=pointer; /* 0=ptr */
			}
 
			// check if the declared global has a default value 
			if (match("=")) {
				// check if variable type supports init 
				if ((typ!=cchar) & (typ!=cint))
					error("variable type does not support init value");
 
				// set the init pointer to the current init pointer 
				iptr=inittbptr;
				idx=0;
 
				// new defined variable has a default init value 
				// check if the variable is defined as string, list of values {} or a 
				// single value
				if (match("\"")) {
					// init value is defined as a string 
					// copy the string values to the init buffer 
					while (idx++ < k) {
						// check if new value is valid 
						if ((ch() != '"') & (ch() != 0))
							inittbq[inittbptr++] = gch();
						else 
							inittbq[inittbptr++] = 0;
 
						// check that init buffer is full 
						if (inittbptr == initqsz) {
							// clear the variable init pointer and print error message 
							iptr=0xffff;
							error("init buffer is full, variable will not be initialized");
							// sign that init is done 
							idx=k;
						}
					}
					// look for matching quote mark 
					if (match("\"")==0) {
						error("end of string expected");
					}
				}
				else if (match("{")) {
					// init value is defined as a list of values 
					// copy the list of values to the init buffer 
					while (idx++ < k) {
						// check if new value is valid 
						if ((ch() != '}') & (ch() != 0)) {
							// make sure that the next value is a number 
							if (!number(num) & !pstr(num))
								error("could not find valid value in initialization list");
						}
						else 
							// use zero value as init 
							num[0]=0;
 
						// save the values according to array type 
						if (typ==cint) {
							inittbq[inittbptr++] = (char)(num[0]&255);
							inittbq[inittbptr++] = (char)((num[0]>>8)&255);
						}
						else 
							inittbq[inittbptr++] = (char)(num[0]&255);
 
						// check that init buffer is full 
						if (inittbptr == initqsz) {
							// clear the variable init pointer and print error message 
							iptr=0xffff;
							error("init buffer is full, variable will not be initialized");
							// sign that init is done 
							idx=k;
						}
						// remove comma if it is there 
						match(",");
					}
					// look for ending brackets 
					if (match("}")==0) {
						error("end of initialization list expected");
					}
				}
				else {
					// expecting a single input value 
					if (!number(num) & !pstr(num))
						error("could not find initialization value");
 
					// save the values according to variable type 
					if (typ==cint) {
						inittbq[inittbptr++] = (char)(num[0]&255);
						inittbq[inittbptr++] = (char)((num[0]>>8)&255);
					}
					else 
						inittbq[inittbptr++] = (char)(num[0]&255);
					// update index 
					idx=1;
 
					// init to end of array is more than one 
					while (idx++ < k) {
						// fill the rest of the init list with zeros 
						if (typ==cint) {
							inittbq[inittbptr++] = 0;
							inittbq[inittbptr++] = 0;
						}
						else 
							inittbq[inittbptr++] = 0;
 
						// check that init buffer is full 
						if (inittbptr == initqsz) {
							// clear the variable init pointer and print error message 
							iptr=0xffff;
							error("init buffer is full, variable will not be initialized");
							// sign that init is done 
							idx=k;
						}
					}
				}
			} else {
				// no default value point init pointer to null 
				iptr=0xffff;
			}
			// add symbol 
			addglb(sname,j,typ,k,iptr); 
			break;
		}
		if (match(",")==0) return; /* more? */
	}
}
/*					*/
/*	Declare local variables		*/
/*	(i.e. define for use)		*/
/*					*/
/* works just like "declglb" but modifies machine stack */
/*	and adds symbol table entry with appropriate */
/*	stack offset to find it again			*/
declloc(typ)		/* typ is cchar or cint */
	int typ;
	{
	int k,j;char sname[namesize];
	while(1)
		{while(1)
			{if(endst())return;
			if(match("*"))
				j=pointer;
				else j=variable;
			if (symname(sname)==0)
				illname();
			if(findloc(sname))
				multidef(sname);
			if (match("["))
				{k=needsub();
				if(k)
					{j=array;
					if(typ==cint)k=k+k;
					}
				else
					{j=pointer;
					k=2;
					}
				}
			else
				if((typ==cchar)
					&(j!=pointer))
					k=1;else k=2;
			/* change machine stack */
			Zsp=modstk(Zsp-k);
			addloc(sname,j,typ,Zsp);
			break;
			}
		if (match(",")==0) return;
		}
	}
/*	>>>>>> start of cc2 <<<<<<<<	*/
 
/*					*/
/*	Get required array size		*/
/*					*/
/* invoked when declared variable is followed by "[" */
/*	this routine makes subscript the absolute */
/*	size of the array. */
needsub()
{
int num[1];
 
	if(match("]"))return 0;	/* null size */
	if (number(num)==0)	/* go after a number */
		{error("must be constant");	/* it isn't */
		num[0]=1;		/* so force one */
		}
	if (num[0]<0)
		{error("negative size illegal");
		num[0]=(-num[0]);
		}
	needbrack("]");		/* force single dimension */
	return num[0];		/* and return size */
}
//
// get array size function changed to get a port address 
//
portadr()
{
int num[1];
 
	if(match(")")) {
		error("port address value must be defined");
		return 0;	/* null size */
	}
	if (number(num)==0) {	/* go after a number */
		error("port address must be constant");	/* it isn't */
		num[0]=1;		/* so force one */
	}
	if (num[0]<0) {
		error("negative port address illegal");
		num[0]=(-num[0]);
	}
	needbrack(")");		/* force single dimension */
	return num[0];		/* and return size */
}
 
/*					*/
/*	Begin a function		*/
/*					*/
/* Called from "parse" this routine tries to make a function */
/*	out of what follows.	*/
newfunc()
	{
	char n[namesize];	/* ptr => currfn,  gtf 7/16/80 */
	if (symname(n)==0)
		{error("illegal function or declaration");
		kill();	/* invalidate line */
		return;
		}
	fnstart=lineno;		/* remember where fn began	gtf 7/2/80 */
	infunc=1;		/* note, in function now.	gtf 7/16/80 */
	if(currfn=findglb(n))	/* already in symbol table ? */
		{if(currfn[ident]!=function)multidef(n);
			/* already variable by that name */
		else if(currfn[offset]==function)multidef(n);
			/* already function by that name */
		else currfn[offset]=function;
			/* otherwise we have what was earlier*/
			/*  assumed to be a function */
		}
	/* if not in table, define as a function now */
	else currfn=addglb(n,function,cint,function,-1);
 
	toconsole();					/* gtf 7/16/80 */
	outstr("====== "); outstr(currfn+name); outstr("()"); nl();
	tofile();
 
	/* we had better see open paren for args... */
	if(match("(")==0)error("missing open paren");
	outname(n);col();nl();	/* print function name */
	argstk=0;		/* init arg count */
	while(match(")")==0)	/* then count args */
		/* any legal name bumps arg count */
		{if(symname(n))argstk=argstk+2;
		else{error("illegal argument name");junk();}
		blanks();
		/* if not closing paren, should be comma */
		if(streq(line+lptr,")")==0)
			{if(match(",")==0)
			error("expected comma");
			}
		if(endst())break;
		}
	locptr=startloc;	/* "clear" local symbol table*/
	Zsp=0;			/* preset stack ptr */
	while(argstk)
		/* now let user declare what types of things */
		/*	those arguments were */
		{if(amatch("char",4)){getarg(cchar);ns();}
		else if(amatch("int",3)){getarg(cint);ns();}
		else{error("wrong number args");break;}
		}
	if(statement()!=streturn) /* do a statement, but if */
				/* it's a return, skip */
				/* cleaning up the stack */
		{modstk(0);
		zret();
		}
	Zsp=0;			/* reset stack ptr again */
	locptr=startloc;	/* deallocate all locals */
	infunc=0;		/* not in fn. any more		gtf 7/2/80 */
	}
/*					*/
/*	Declare argument types		*/
/*					*/
/* called from "newfunc" this routine adds an entry in the */
/*	local symbol table for each named argument */
getarg(t)		/* t = cchar or cint */
	int t;
	{
	char n[namesize],c;int j;
	while(1)
		{if(argstk==0)return;	/* no more args */
		if(match("*"))j=pointer;
			else j=variable;
		if(symname(n)==0) illname();
		if(findloc(n))multidef(n);
		if(match("["))	/* pointer ? */
		/* it is a pointer, so skip all */
		/* stuff between "[]" */
			{while(inbyte()!=']')
				if(endst())break;
			j=pointer;
			/* add entry as pointer */
			}
		addloc(n,j,t,argstk);
		argstk=argstk-2;	/* cnt down */
		if(endst())return;
		if(match(",")==0)error("expected comma");
		}
	}
/*					*/
/*	Statement parser		*/
/*					*/
/* called whenever syntax requires	*/
/*	a statement. 			 */
/*  this routine performs that statement */
/*  and returns a number telling which one */
statement()
{
        /* NOTE (RDK) --- On DOS there is no CPM function so just try */
        /* commenting it out for the first test compilation to see if */
        /* the compiler basic framework works OK in the DOS environment */
	/* if(cpm(11,0) & 1)	/* check for ctrl-C gtf 7/17/80 */
		/* if(getchar()==3) */
			/* zabort(); */
 
	if ((ch()==0) & (eof)) return;
	else if(amatch("char",4))
		{declloc(cchar);ns();}
	else if(amatch("int",3))
		{declloc(cint);ns();}
	else if(match("{"))compound();
	else if(amatch("if",2))
		{doif();lastst=stif;}
	else if(amatch("while",5))
		{dowhile();lastst=stwhile;}
	else if(amatch("return",6))
		{doreturn();ns();lastst=streturn;}
	else if(amatch("break",5))
		{dobreak();ns();lastst=stbreak;}
	else if(amatch("continue",8))
		{docont();ns();lastst=stcont;}
	else if(match(";"));
	else if(match("#asm"))
		{doasm();lastst=stasm;}
	/* if nothing else, assume it's an expression */
	else{expression();ns();lastst=stexp;}
	return lastst;
}
/*					*/
/*	Semicolon enforcer		*/
/*					*/
/* called whenever syntax requires a semicolon */
ns()	{if(match(";")==0)error("missing semicolon");}
/*					*/
/*	Compound statement		*/
/*					*/
/* allow any number of statements to fall between "{}" */
compound()
	{
	++ncmp;		/* new level open */
	while (match("}")==0) statement(); /* do one */
	--ncmp;		/* close current level */
	}
/*					*/
/*		"if" statement		*/
/*					*/
doif()
	{
	int flev,fsp,flab1,flab2;
	flev=locptr;	/* record current local level */
	fsp=Zsp;		/* record current stk ptr */
	flab1=getlabel(); /* get label for false branch */
	test(flab1);	/* get expression, and branch false */
	statement();	/* if true, do a statement */
	Zsp=modstk(fsp);	/* then clean up the stack */
	locptr=flev;	/* and deallocate any locals */
	if (amatch("else",4)==0)	/* if...else ? */
		/* simple "if"...print false label */
		{printlabel(flab1);col();nl();
		return;		/* and exit */
		}
	/* an "if...else" statement. */
	jump(flab2=getlabel());	/* jump around false code */
	printlabel(flab1);col();nl();	/* print false label */
	statement();		/* and do "else" clause */
	Zsp=modstk(fsp);		/* then clean up stk ptr */
	locptr=flev;		/* and deallocate locals */
	printlabel(flab2);col();nl();	/* print true label */
	}
/*					*/
/*	"while" statement		*/
/*					*/
dowhile()
	{
	int wq[4];		/* allocate local queue */
	wq[wqsym]=locptr;	/* record local level */
	wq[wqsp]=Zsp;		/* and stk ptr */
	wq[wqloop]=getlabel();	/* and looping label */
	wq[wqlab]=getlabel();	/* and exit label */
	addwhile(wq);		/* add entry to queue */
				/* (for "break" statement) */
	printlabel(wq[wqloop]);col();nl(); /* loop label */
	test(wq[wqlab]);	/* see if true */
	statement();		/* if so, do a statement */
	Zsp = modstk(wq[wqsp]);	/* zap local vars: 9/25/80 gtf */
	jump(wq[wqloop]);	/* loop to label */
	printlabel(wq[wqlab]);col();nl(); /* exit label */
	locptr=wq[wqsym];	/* deallocate locals */
	delwhile();		/* delete queue entry */
	}
/*					*/
/*	"return" statement		*/
/*					*/
doreturn()
	{
	/* if not end of statement, get an expression */
	if(endst()==0)expression();
	modstk(0);	/* clean up stk */
	zret();		/* and exit function */
	}
/*					*/
/*	"break" statement		*/
/*					*/
dobreak()
	{
	int *ptr;
	/* see if any "whiles" are open */
	if ((ptr=readwhile())==0) return;	/* no */
	modstk((ptr[wqsp]));	/* else clean up stk ptr */
	jump(ptr[wqlab]);	/* jump to exit label */
	}
/*					*/
/*	"continue" statement		*/
/*					*/
docont()
	{
	int *ptr;
	/* see if any "whiles" are open */
	if ((ptr=readwhile())==0) return;	/* no */
	modstk((ptr[wqsp]));	/* else clean up stk ptr */
	jump(ptr[wqloop]);	/* jump to loop label */
	}
/*					*/
/*	"asm" pseudo-statement		*/
/*					*/
/* enters mode where assembly language statement are */
/*	passed intact through parser	*/
doasm()
{
	cmode=0;		/* mark mode as "asm" */
	while (1) {
		finline();	/* get and print lines */
		if (match("#endasm")) break;	/* until... */
		if(eof)break;
		outstr(line);
		nl();
	}
	kill();		/* invalidate line */
	cmode=1;		/* then back to parse level */
}
/*	>>>>> start of cc3 <<<<<<<<<	*/
 
/*					*/
/*	Perform a function call		*/
/*					*/
/* called from heir11, this routine will either call */
/*	the named function, or if the supplied ptr is */
/*	zero, will call the contents of HL		*/
callfunction(ptr)
	char *ptr;	/* symbol table entry (or 0) */
{	int nargs;
	nargs=0;
	blanks();	/* already saw open paren */
	if(ptr==0)zpush();	/* calling HL */
	while(streq(line+lptr,")")==0)
		{if(endst())break;
		expression();	/* get an argument */
		if(ptr==0)swapstk(); /* don't push addr */
		zpush();	/* push argument */
		nargs=nargs+2;	/* count args*2 */
		if (match(",")==0) break;
		}
	needbrack(")");
	if(ptr)zcall(ptr);
	else callstk();
	Zsp=modstk(Zsp+nargs);	/* clean up arguments */
}
junk()
{	if(an(inbyte()))
		while(an(ch()))gch();
	else while(an(ch())==0)
		{if(ch()==0)break;
		gch();
		}
	blanks();
}
endst()
{	blanks();
	return ((streq(line+lptr,";")|(ch()==0)));
}
illname()
{	error("illegal symbol name");junk();}
multidef(sname)
	char *sname;
{	error("already defined");
	comment();
	outstr(sname);nl();
}
needbrack(str)
	char *str;
{	
	if (match(str)==0) {
		error("missing bracket");
		comment();outstr(str);nl();
	}
}
needlval()
{	error("must be lvalue");
}
findglb(sname)
	char *sname;
{	char *ptr;
	ptr=startglb;
	while(ptr!=glbptr) {
		if (astreq(sname,ptr,namemax)) return ptr;
		ptr=ptr+symsiz;
	}
	return 0;
}
findloc(sname)
	char *sname;
{	char *ptr;
	ptr=startloc;
	while (ptr!=locptr) {
		if(astreq(sname,ptr,namemax))return ptr;
		ptr=ptr+symsiz;
	}
	return 0;
}
addglb(sname,id,typ,value,iptr)
	char *sname,id,typ;
	int value,iptr;
{	char *ptr;
	if(cptr=findglb(sname))return cptr;
	if(glbptr>=endglb)
		{error("global symbol table overflow");
		return 0;
		}
	cptr=ptr=glbptr;
	while (an(*ptr++ = *sname++));	/* copy name */
	cptr[ident]=id;
	cptr[type]=typ;
	cptr[storage]=statik;
	cptr[offset]=value;
	cptr[offset+1]=value>>8;
	cptr[initptr]=iptr&255;
	cptr[initptr+1]=iptr>>8;
	glbptr=glbptr+symsiz;
	return cptr;
}
addloc(sname,id,typ,value)
	char *sname,id,typ;
	int value;
{	char *ptr;
	if(cptr=findloc(sname))return cptr;
	if(locptr>=endloc)
		{error("local symbol table overflow");
		return 0;
		}
	cptr=ptr=locptr;
	while(an(*ptr++ = *sname++));	/* copy name */
	cptr[ident]=id;
	cptr[type]=typ;
	cptr[storage]=stkloc;
	cptr[offset]=value;
	cptr[offset+1]=value>>8;
	locptr=locptr+symsiz;
	return cptr;
}
/* Test if next input string is legal symbol name */
symname(sname)
	char *sname;
{	int k;char c;
	blanks();
	if(alpha(ch())==0)return 0;
	k=0;
	while(an(ch()))sname[k++]=gch();
	sname[k]=0;
	return 1;
	}
/* Return next avail internal label number */
getlabel()
{	return(++nxtlab);
}
/* Print specified number as label */
printlabel(label)
	int label;
{	outasm("cc");
	outdec(label);
}
/* Test if given character is alpha */
alpha(c)
	char c;
{	c=c&127;
	return(((c>='a')&(c<='z'))|
		((c>='A')&(c<='Z'))|
		(c=='_'));
}
// Test if given character is numeric 
numeric(c)
	char c;
{	c=c&127;
	return ((c>='0')&(c<='9'));
}
// Test if given character is hexadecimal 
hexnum(c)
	char c;
{	c=c&127;
	return (((c>='0')&(c<='9')) | ((c>='a')&(c<='f')) | ((c>='A')&(c<='F')));
}
/* Test if given character is alphanumeric */
an(c)
	char c;
{	return((alpha(c))|(numeric(c)));
}
/* Print a carriage return and a string only to console */
pl(str)
	char *str;
{	int k;
	k=0;
	putchar(eol);
	while(str[k])putchar(str[k++]);
}
addwhile(ptr)
	int ptr[];
 {
	int k;
	if (wqptr==wqmax)
		{error("too many active whiles");return;}
	k=0;
	while (k<wqsiz)
		{*wqptr++ = ptr[k++];}
}
delwhile()
	{if(readwhile()) wqptr=wqptr-wqsiz;
	}
readwhile()
 {
	if (wqptr==wq){error("no active whiles");return 0;}
	else return (wqptr-wqsiz);
 }
ch()
{	return(line[lptr]&127);
}
nch()
{	if(ch()==0)return 0;
		else return(line[lptr+1]&127);
}
gch()
{	if(ch()==0)return 0;
		else return(line[lptr++]&127);
}
kill()
{	lptr=0;
	line[lptr]=0;
}
inbyte()
{
	while(ch()==0)
		{if (eof) return 0;
		finline();
		preprocess();
		}
	return gch();
}
inchar()
{
	if(ch()==0)finline();
	if(eof)return 0;
	return(gch());
}
finline()
{
	int k,unit;
	while(1)
		{if (input==0)openin();
		if(eof)return;
		if((unit=input2)==0)unit=input;
		kill();
		while((k=getc(unit))>0)
			{if((k==eol)|(lptr>=linemax))break;
			line[lptr++]=k;
			}
		line[lptr]=0;	/* append null */
		lineno++;	/* read one more line		gtf 7/2/80 */
		if(k<=0)
			{fclose(unit);
			if(input2)endinclude();		/* gtf 7/16/80 */
				else input=0;
			}
		if(lptr)
			{if((ctext)&(cmode))
				{comment();
				outstr(line);
				nl();
				}
			lptr=0;
			return;
			}
		}
}
/*	>>>>>> start of cc4 <<<<<<<	*/
 
keepch(c)
	char c;
{	mline[mptr]=c;
	if(mptr<mpmax)mptr++;
	return c;
}
preprocess()
{	int k;
	char c,sname[namesize];
	if(cmode==0)return;
	mptr=lptr=0;
	while(ch())
		{if((ch()==' ')|(ch()==9))
			{keepch(' ');
			while((ch()==' ')|
				(ch()==9))
				gch();
			}
		else if(ch()=='"')
			{keepch(ch());
			gch();
			while(ch()!='"')
				{if(ch()==0)
				  {error("missing quote");
				  break;
				  }
				keepch(gch());
				}
			gch();
			keepch('"');
			}
		else if(ch()==39)
			{keepch(39);
			gch();
			while(ch()!=39)
				{if(ch()==0)
				  {error("missing apostrophe");
				  break;
				  }
				keepch(gch());
				}
			gch();
			keepch(39);
			}
		else if((ch()=='/')&(nch()=='/')) {
			// delete the entire line 
			kill();
		}
		else if((ch()=='/')&(nch()=='*')) {
			inchar();inchar();
			while (((ch()=='*') & (nch()=='/'))==0) {
				if(ch()==0)finline();
					else inchar();
				if(eof)break;
			}
			inchar();inchar();
		}
		else if(alpha(ch()))	/* from an(): 9/22/80 gtf */
			{k=0;
			while(an(ch()))
				{if(k<namemax)sname[k++]=ch();
				gch();
				}
			sname[k]=0;
			if(k=findmac(sname))
				while(c=macq[k++])
					keepch(c);
			else
				{k=0;
				while(c=sname[k++])
					keepch(c);
				}
			}
		else keepch(gch());
		}
	keepch(0);
	if(mptr>=mpmax)error("line too long");
	lptr=mptr=0;
	while(line[lptr++]=mline[mptr++]);
	lptr=0;
	}
addmac()
{	
char sname[namesize];
int k;
 
	if (symname(sname)==0) {
		illname();
		kill();
		return;
	}
	k=0;
	while (putmac(sname[k++]));
	while (ch()==' ' | ch()==9) gch();
	while (putmac(gch()));
	if (macptr>=macmax) error("macro table full");
}
putmac(c)
	char c;
{	
	macq[macptr]=c;
	if(macptr<macmax)macptr++;
	return c;
}
findmac(sname)
	char *sname;
{	int k;
	k=0;
	while (k<macptr) {
		if (astreq(sname, macq+k, namemax)) {
			while(macq[k++]);
			return k;
			}
		while(macq[k++]);
		while(macq[k++]);
	}
	return 0;
}
/* direct output to console		gtf 7/16/80 */
toconsole()
{
	saveout = output;
	output = 0;
/* end toconsole */}
 
/* direct output back to file		gtf 7/16/80 */
tofile()
{
	if(saveout)
		output = saveout;
	saveout = 0;
/* end tofile */}
 
outbyte(c)
	char c;
{
	if(c==0)return 0;
	if(output)
		{if((putc(c,output))<=0)
			{closeout();
			error("Output file error");
			zabort();			/* gtf 7/17/80 */
			}
		}
	else putchar(c);
	return c;
}
outstr(ptr)
	char ptr[];
 {
	int k;
	k=0;
	while(outbyte(ptr[k++]));
 }
 
/* write text destined for the assembler to read */
/* (i.e. stuff not in comments)			*/
/*  gtf  6/26/80 */
outasm(ptr)
char *ptr;
{
	while(outbyte(lower(*ptr++)));
/* end outasm */}
 
nl()
	{outbyte(eol);}
tab()
	{outbyte(9);}
col()
	{outbyte(58);}
bell()				/* gtf 7/16/80 */
	{outbyte(7);}
/*				replaced 7/2/80 gtf
 * error(ptr)
 *	char ptr[];
 * {
 *	int k;
 *	comment();outstr(line);nl();comment();
 *	k=0;
 *	while(k<lptr)
 *		{if(line[k]==9) tab();
 *			else outbyte(' ');
 *		++k;
 *		}
 *	outbyte('^');
 *	nl();comment();outstr("******  ");
 *	outstr(ptr);
 *	outstr("  ******");
 *	nl();
 *	++errcnt;
 * }
 */
 
error(ptr)
char ptr[];
{	int k;
	char junk[81];
 
	toconsole();
	bell();
	outstr("Line "); outdec(lineno); outstr(", ");
	if(infunc==0)
		outbyte('(');
	if(currfn==NULL)
		outstr("start of file");
	else	outstr(currfn+name);
	if(infunc==0)
		outbyte(')');
	outstr(" + ");
	outdec(lineno-fnstart);
	outstr(": ");  outstr(ptr);  nl();
 
	outstr(line); nl();
 
	k=0;	/* skip to error position */
	while(k<lptr){
		if(line[k++]==9)
			tab();
		else	outbyte(' ');
		}
	outbyte('^');  nl();
	++errcnt;
 
	if(errstop){
		pl("Continue (Y,n,g) ? ");
		gets(junk);		
		k=junk[0];
		if((k=='N') | (k=='n'))
			zabort();
		if((k=='G') | (k=='g'))
			errstop=0;
		}
	tofile();
/* end error */}
 
ol(ptr)
	char ptr[];
{
	ot(ptr);
	nl();
}
ot(ptr)
	char ptr[];
{
	tab();
	outasm(ptr);
}
streq(str1,str2)
	char str1[],str2[];
{
int k;
 
	k=0;
	while (str2[k])
		{if ((str1[k])!=(str2[k])) return 0;
		k++;
		}
	return k;
}
astreq(str1,str2,len)
	char str1[],str2[];int len;
{
int k;
 
	k=0;
	while (k<len) {
		if ((str1[k])!=(str2[k]))break;
		if(str1[k]==0)break;
		if(str2[k]==0)break;
		k++;
	}
	if (an(str1[k]))return 0;
	if (an(str2[k]))return 0;
	return k;
}
match(lit)
	char *lit;
{
	int k;
	blanks();
	if (k=streq(line+lptr,lit)) {
		lptr=lptr+k;
		return 1;
	}
 	return 0;
}
amatch(lit,len)
	char *lit;int len;
 {
	int k;
	blanks();
	if (k=astreq(line+lptr,lit,len))
		{lptr=lptr+k;
		while(an(ch())) inbyte();
		return 1;
		}
	return 0;
 }
blanks()
{
	while (1) {
		while (ch()==0) {
			finline();
			preprocess();
			if(eof)break;
		}
		if (ch()==' ') gch();
		else if (ch()==9) gch();
		else return;
	}
}
/* output a decimal number - rewritten 4/1/81 gtf */
outdec(n)
int n;
{
	if(n<0)
		outbyte('-');
	else	n = -n;
	outint(n);
/* end outdec */}
 
outint(n)	/* added 4/1/81 */
int n;
{	int q;
 
	q = n/10;
	if(q) outint(q);
	outbyte('0'+(n-q*10));
/* end outint */}
 
/* return the length of a string */
/* gtf 4/8/80 */
strlen(s)
char *s;
{	char *t;
 
	t = s;
	while(*s) s++;
	return(s-t);
/* end strlen */}
 
/* convert lower case to upper */
/* gtf 6/26/80 */
raise(c)
char c;
{
	if((c>='a') & (c<='z'))
		c = c - 'a' + 'A';
	return(c);
/* end raise */}
 
/* convert upper case to lower */
/* ml 28/2/2012 */
lower(c)
char c;
{
	if((c>='A') & (c<='Z'))
		c = c - 'A' + 'a';
	return(c);
/* end raise */}
 
/* ------------------------------------------------------------- */
 
/*	>>>>>>> start of cc5 <<<<<<<	*/
 
/* as of 5/5/81 rj */
 
expression()
{
	int lval[2];
	if(heir1(lval))rvalue(lval);
}
heir1(lval)
	int lval[];
{
	int k,lval2[2];
	k=heir2(lval);
	if (match("="))
		{if(k==0){needlval();return 0;}
		if (lval[1])zpush();
		if(heir1(lval2))rvalue(lval2);
		store(lval);
		return 0;
		}
	else return k;
}
heir2(lval)
	int lval[];
{	int k,lval2[2];
	k=heir3(lval);
	blanks();
	if(ch()!='|')return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("|"))
			{zpush();
			if(heir3(lval2)) rvalue(lval2);
			zpop();
			zor();
			}
		else return 0;
		}
}
heir3(lval)
	int lval[];
{	int k,lval2[2];
	k=heir4(lval);
	blanks();
	if(ch()!='^')return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("^"))
			{zpush();
			if(heir4(lval2))rvalue(lval2);
			zpop();
			zxor();
			}
		else return 0;
		}
}
heir4(lval)
	int lval[];
{	int k,lval2[2];
	k=heir5(lval);
	blanks();
	if(ch()!='&')return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("&"))
			{zpush();
			if(heir5(lval2))rvalue(lval2);
			zpop();
			zand();
			}
		else return 0;
		}
}
heir5(lval)
	int lval[];
{
	int k,lval2[2];
	k=heir6(lval);
	blanks();
	if((streq(line+lptr,"==")==0)&
		(streq(line+lptr,"!=")==0))return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("=="))
			{zpush();
			if(heir6(lval2))rvalue(lval2);
			zpop();
			zeq();
			}
		else if (match("!="))
			{zpush();
			if(heir6(lval2))rvalue(lval2);
			zpop();
			zne();
			}
		else return 0;
		}
}
heir6(lval)
	int lval[];
{
	int k,lval2[2];
	k=heir7(lval);
	blanks();
	if((streq(line+lptr,"<")==0)&
		(streq(line+lptr,">")==0)&
		(streq(line+lptr,"<=")==0)&
		(streq(line+lptr,">=")==0))return k;
		if(streq(line+lptr,">>"))return k;
		if(streq(line+lptr,"<<"))return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("<="))
			{zpush();
			if(heir7(lval2))rvalue(lval2);
			zpop();
			if(cptr=lval[0])
				if(cptr[ident]==pointer)
				{ule();
				continue;
				}
			if(cptr=lval2[0])
				if(cptr[ident]==pointer)
				{ule();
				continue;
				}
			zle();
			}
		else if (match(">="))
			{zpush();
			if(heir7(lval2))rvalue(lval2);
			zpop();
			if(cptr=lval[0])
				if(cptr[ident]==pointer)
				{uge();
				continue;
				}
			if(cptr=lval2[0])
				if(cptr[ident]==pointer)
				{uge();
				continue;
				}
			zge();
			}
		else if((streq(line+lptr,"<"))&
			(streq(line+lptr,"<<")==0))
			{inbyte();
			zpush();
			if(heir7(lval2))rvalue(lval2);
			zpop();
			if(cptr=lval[0])
				if(cptr[ident]==pointer)
				{ult();
				continue;
				}
			if(cptr=lval2[0])
				if(cptr[ident]==pointer)
				{ult();
				continue;
				}
			zlt();
			}
		else if((streq(line+lptr,">"))&
			(streq(line+lptr,">>")==0))
			{inbyte();
			zpush();
			if(heir7(lval2))rvalue(lval2);
			zpop();
			if(cptr=lval[0])
				if(cptr[ident]==pointer)
				{ugt();
				continue;
				}
			if(cptr=lval2[0])
				if(cptr[ident]==pointer)
				{ugt();
				continue;
				}
			zgt();
			}
		else return 0;
		}
}
/*	>>>>>> start of cc6 <<<<<<	*/
 
heir7(lval)
	int lval[];
{
	int k,lval2[2];
	k=heir8(lval);
	blanks();
	if((streq(line+lptr,">>")==0)&
		(streq(line+lptr,"<<")==0))return k;
	if(k)rvalue(lval);
	while(1)
		{if (match(">>"))
			{zpush();
			if(heir8(lval2))rvalue(lval2);
			zpop();
			asr();
			}
		else if (match("<<"))
			{zpush();
			if(heir8(lval2))rvalue(lval2);
			zpop();
			asl();
			}
		else return 0;
		}
}
heir8(lval)
	int lval[];
{
	int k,lval2[2];
	k=heir9(lval);
	blanks();
	if((ch()!='+')&(ch()!='-'))return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("+"))
			{zpush();
			if(heir9(lval2))rvalue(lval2);
			if(cptr=lval[0])
				if((cptr[ident]==pointer)&
				(cptr[type]==cint))
				doublereg();
			zpop();
			zadd();
			}
		else if (match("-"))
			{zpush();
			if(heir9(lval2))rvalue(lval2);
			if(cptr=lval[0])
				if((cptr[ident]==pointer)&
				(cptr[type]==cint))
				doublereg();
			zpop();
			zsub();
			}
		else return 0;
		}
}
heir9(lval)
	int lval[];
{
	int k,lval2[2];
	k=heir10(lval);
	blanks();
	if((ch()!='*')&(ch()!='/')&
		(ch()!='%'))return k;
	if(k)rvalue(lval);
	while(1)
		{if (match("*"))
			{zpush();
			if(heir9(lval2))rvalue(lval2);
			zpop();
			mult();
			}
		else if (match("/"))
			{zpush();
			if(heir10(lval2))rvalue(lval2);
			zpop();
			div();
			}
		else if (match("%"))
			{zpush();
			if(heir10(lval2))rvalue(lval2);
			zpop();
			zmod();
			}
		else return 0;
		}
}
heir10(lval)
	int lval[];
{
	int k;
	char *ptr;
	if(match("++"))
		{if((k=heir10(lval))==0)
			{needlval();
			return 0;
			}
		if(lval[1])zpush();
		rvalue(lval);
		inc();
		ptr=lval[0];
		if((ptr[ident]==pointer)&
			(ptr[type]==cint))
				inc();
		store(lval);
		return 0;
		}
	else if(match("--"))
		{if((k=heir10(lval))==0)
			{needlval();
			return 0;
			}
		if(lval[1])zpush();
		rvalue(lval);
		dec();
		ptr=lval[0];
		if((ptr[ident]==pointer)&
			(ptr[type]==cint))
				dec();
		store(lval);
		return 0;
		}
	else if (match("-"))
		{k=heir10(lval);
		if (k) rvalue(lval);
		neg();
		return 0;
		}
	else if(match("*"))
		{k=heir10(lval);
		if(k)rvalue(lval);
		lval[1]=cint;
		if(ptr=lval[0])lval[1]=ptr[type];
		lval[0]=0;
		return 1;
		}
	else if(match("&"))
		{k=heir10(lval);
		if(k==0)
			{error("illegal address");
			return 0;
			}
		else if(lval[1])return 0;
		else
			{immed();
			outname(ptr=lval[0]);
			nl();
			lval[1]=ptr[type];
			return 0;
			}
		}
	else 
		{k=heir11(lval);
		if(match("++"))
			{if(k==0)
				{needlval();
				return 0;
				}
			if(lval[1])zpush();
			rvalue(lval);
			inc();
			ptr=lval[0];
			if((ptr[ident]==pointer)&
				(ptr[type]==cint))
					inc();
			store(lval);
			dec();
			if((ptr[ident]==pointer)&
				(ptr[type]==cint))
				dec();
			return 0;
			}
		else if(match("--"))
			{if(k==0)
				{needlval();
				return 0;
				}
			if(lval[1])zpush();
			rvalue(lval);
			dec();
			ptr=lval[0];
			if((ptr[ident]==pointer)&
				(ptr[type]==cint))
					dec();
			store(lval);
			inc();
			if((ptr[ident]==pointer)&
				(ptr[type]==cint))
				inc();
			return 0;
			}
		else return k;
		}
	}
/*	>>>>>> start of cc7 <<<<<<	*/
 
heir11(lval)
	int *lval;
{	int k;char *ptr;
	k=primary(lval);
	ptr=lval[0];
	blanks();
	if((ch()=='[')|(ch()=='('))
	while(1)
		{if(match("["))
			{if(ptr==0)
				{error("can't subscript");
				junk();
				needbrack("]");
				return 0;
				}
			else if(ptr[ident]==pointer)rvalue(lval);
			else if(ptr[ident]!=array)
				{error("can't subscript");
				k=0;
				}
			zpush();
			expression();
			needbrack("]");
			if(ptr[type]==cint)doublereg();
			zpop();
			zadd();
			lval[1]=ptr[type];
				/* 4/1/81 - after subscripting, not ptr anymore */
			lval[0]=0;
			k=1;
			}
		else if(match("("))
			{if(ptr==0)
				{callfunction(0);
				}
			else if(ptr[ident]!=function)
				{rvalue(lval);
				callfunction(0);
				}
			else callfunction(ptr);
			k=lval[0]=0;
			}
		else return k;
		}
	if(ptr==0)return k;
	if(ptr[ident]==function)
		{immed();
		outname(ptr);
		nl();
		return 0;
		}
	return k;
}
primary(lval)
	int *lval;
{	char *ptr,sname[namesize];int num[1];
	int k;
	if(match("("))
		{k=heir1(lval);
		needbrack(")");
		return k;
		}
	if(symname(sname))
		{if(ptr=findloc(sname))
			{getloc(ptr);
			lval[0]=ptr;
			lval[1]=ptr[type];
			if(ptr[ident]==pointer)lval[1]=cint;
			if(ptr[ident]==array)return 0;
				else return 1;
			}
		if(ptr=findglb(sname))
			if(ptr[ident]!=function)
			{lval[0]=ptr;
			lval[1]=0;
			if(ptr[ident]!=array)return 1;
			immed();
			outname(ptr);nl();
			lval[1]=ptr[type];
			return 0;
			}
		ptr=addglb(sname,function,cint,0,-1);
		lval[0]=ptr;
		lval[1]=0;
		return 0;
		}
	if(constant(num))
		return(lval[0]=lval[1]=0);
	else
		{error("invalid expression");
		immed();outdec(0);nl();
		junk();
		return 0;
		}
	}
store(lval)
	int *lval;
{	if (lval[1]==0)putmem(lval[0]);
	else putstk(lval[1]);
}
rvalue(lval)
	int *lval;
{	if((lval[0] != 0) & (lval[1] == 0))
		getmem(lval[0]);
		else indirect(lval[1]);
}
test(label)
	int label;
{
	needbrack("(");
	expression();
	needbrack(")");
	testjump(label);
}
constant(val)
	int val[];
{	
	if (number(val)) {
		immed();
		outdec(val[0]);
	}
	else if (pstr(val)) {
		immed();
		outdec(val[0]);
	}
	else if (qstr(val)) {
		immed();
		printlabel(litlab);
		outbyte('+');
		outdec(val[0]);
	}
	else 
		return 0;	
	nl();
	return 1;
}
// get a numeric value from the source file 
number(val)
int val[];
{	
int k,minus;
char c;
 
	k=minus=1;
	while (k) { 
		k=0;
		if (match("+")) k=1;
		if (match("-")) {
			minus=(-minus);
			k=1;
		}
	}
	// check if hexadecimal value 
	if ((ch()=='0') & (nch()=='x')) {
		// remove first two characters ("0x") 
		inchar();inchar();
		// make sure the next value is legal 
		if (hexnum(ch())==0) return 0;
		// continue to read hexadecimal value 
		while (hexnum(ch())) {
			c=raise(inbyte());
			if (numeric(c)!=0)
				k=k*16+(c-'0');
			else 
				k=k*16+(c-'A')+10;
		}
		if (minus<0) k=(-k);
		val[0]=k;
		return 1;
	} 
	// check if decimal value 
	else if (numeric(ch())!=0) {
		while (numeric(ch())) {
			c=inbyte();
			k=k*10+(c-'0');
		}
		if (minus<0) k=(-k);
		val[0]=k;
		return 1;
	} 
	else 
		return 0;
}
 
pstr(val)
int val[];
{	
int k;
char c;
 
	k=0;
	if (match("'")==0) return 0;
	while((c=gch())!=39)
		k=(k&255)*256 + (c&127);
	val[0]=k;
	return 1;
}
qstr(val)
int val[];
{
char c;
 
	if (match("\"")==0) return 0;
	val[0]=litptr;
	while (ch()!='"')
		{if(ch()==0)break;
		if(litptr>=litmax)
			{error("string space exhausted");
			while(match("\"")==0)
				if(gch()==0)break;
			return 1;
			}
		litq[litptr++]=gch();
		}
	gch();
	litq[litptr++]=0;
	return 1;
}
/*	>>>>>> start of cc8 <<<<<<<	*/
 
/* Begin a comment line for the assembler */
comment()
{	outbyte(';');
}
 
/* Put out assembler info before any code is generated */
header()
{	comment();
	outstr(BANNER);
	nl();
	comment();
	outstr(VERSION);
	nl();
	comment();
	outstr(AUTHOR);
	nl();
	comment();
	nl();
	if (mainflg) {		/* do stuff needed for first */
		ol("code");
		ol("org #0000"); /* assembler file. */		   
		ot("ld hl,"); outdec(stackptr); nl();	/* set up stack */
		ol("ld sp,hl");
		zcall("main");	/* call the code generated by small-c */
	}
}
/* Print any assembler stuff needed after all code */
trailer()
{	/* ol("END"); */	/*...note: commented out! */
 
	nl();			/* 6 May 80 rj errorsummary() now goes to console */
	comment();
	outstr(" --- End of Compilation ---");
	nl();
}
/* Print out a name such that it won't annoy the assembler */
/*	(by matching anything reserved, like opcodes.) */
/*	gtf 4/7/80 */
outname(sname)
char *sname;
{	int len, i,j;
 
	outasm("__");
	len = strlen(sname);
	if (len>(asmpref+asmsuff)) {
		i = asmpref;
		len = len-asmpref-asmsuff;
		while(i-- > 0)
			outbyte(lower(*sname++));
		while(len-- > 0)
			sname++;
		while(*sname)
			outbyte(lower(*sname++));
		}
	else	outasm(sname);
/* end outname */}
/* Fetch a static memory cell into the primary register */
getmem(sym)
	char *sym;
{	
int padr;
 
	if ((sym[ident]!=pointer)&(sym[type]==cchar)) {
		ot("ld a,(");
		outname(sym+name);
		outasm(")");
		nl();
		callrts("ccsxt");
	} else if (sym[type]==cport) { 
		padr=sym[offset] & 0xff;
		ot("in a,(");outdec(padr);outasm(")");nl();
		callrts("ccsxt");
	} else {
		ot("ld hl,(");
		outname(sym+name);
		outasm(")");
		nl();
	}
}
/* Fetch the address of the specified symbol */
/*	into the primary register */
getloc(sym)
	char *sym;
{	
int off_val;
 
	immed();
	off_val = ((sym[offset]&255)+((sym[offset+1]&255)<<8))-Zsp;
	off_val &= 0xffff;
	outdec(off_val);
	nl();
	ol("add hl,sp");
}
/* Store the primary register into the specified */
/*	static memory cell */
putmem(sym)
	char *sym;
{	
int padr;
 
	if((sym[ident]!=pointer)&(sym[type]==cchar)) {
		ol("ld a,l");
		ot("ld (");
		outname(sym+name);
		outasm("),a");
	} else if (sym[type]==cport) {
		padr=sym[offset] & 0xff;
		ol("ld a,l");
		ot("out (");outdec(padr);outasm("),a");nl();
	} else { 
		ot("ld (");
		outname(sym+name);
		outasm("),hl");
	}
 
	nl();
	}
/* Store the specified object type in the primary register */
/*	at the address on the top of the stack */
putstk(typeobj)
char typeobj;
{	zpop();
	if(typeobj==cint)
		callrts("ccpint");
	else {	ol("ld a,l");		/* per Ron Cain: gtf 9/25/80 */
		ol("ld (de),a");
		}
	}
/* Fetch the specified object type indirect through the */
/*	primary register into the primary register */
indirect(typeobj)
	char typeobj;
{	if(typeobj==cchar)callrts("ccgchar");
		else callrts("ccgint");
}
/* Swap the primary and secondary registers */
swap()
{	ol("ex de,hl");
}
/* Print partial instruction to get an immediate value */
/*	into the primary register */
immed()
{	ot("ld hl,");
}
/* Push the primary register onto the stack */
zpush()
{	ol("push hl");
	Zsp=Zsp-2;
}
/* Pop the top of the stack into the secondary register */
zpop()
{	ol("pop de");
	Zsp=Zsp+2;
}
/* Swap the primary register and the top of the stack */
swapstk()
{	ol("ex (sp),hl");
}
/* Call the specified subroutine name */
zcall(sname)
	char *sname;
{	ot("call ");
	outname(sname);
	nl();
}
/* Call a run-time library routine */
callrts(sname)
char *sname;
{
	ot("call ");
	outasm(sname);
	nl();
/*end callrts*/}
 
/* Return from subroutine */
zret()
{	ol("ret");
}
/* Perform subroutine call to value on top of stack */
callstk()
{	immed();
	outasm("$+5");
	nl();
	swapstk();
	ol("jp (hl)");
	Zsp=Zsp+2; /* corrected 5 May 81 rj */
	}
/* Jump to specified internal label number */
jump(label)
	int label;
{	ot("jp ");
	printlabel(label);
	nl();
	}
/* Test the primary register and jump if false to label */
testjump(label)
	int label;
{	ol("ld a,h");
	ol("or l");
	ot("jp z,");
	printlabel(label);
	nl();
	}
/* Print pseudo-op to define a byte */
defbyte()
{	ot("db ");
}
/*Print pseudo-op to define storage */
defstorage()
{	ot("ds ");
}
/* Print pseudo-op to define a word */
defword()
{	ot("dw ");
}
/* Modify the stack pointer to the new value indicated */
modstk(newsp)
	int newsp;
 {	int k;
	k=newsp-Zsp;
	if(k==0)return newsp;
	if(k>=0)
		{if(k<7)
			{if(k&1)
				{ol("inc sp");
				k--;
				}
			while(k)
				{ol("pop bc");
				k=k-2;
				}
			return newsp;
			}
		}
	if(k<0)
		{if(k>-7)
			{if(k&1)
				{ol("dec sp");
				k++;
				}
			while(k)
				{ol("push bc");
				k=k+2;
				}
			return newsp;
			}
		}
	swap();
	immed();outdec(k);nl();
	ol("add hl,sp");
	ol("ld sp,hl");
	swap();
	return newsp;
}
/* Double the primary register */
doublereg()
{	ol("add hl,hl");
}
/* Add the primary and secondary registers */
/*	(results in primary) */
zadd()
{	ol("add hl,de");
}
/* Subtract the primary register from the secondary */
/*	(results in primary) */
zsub()
{	callrts("ccsub");
}
/* Multiply the primary and secondary registers */
/*	(results in primary */
mult()
{	callrts("ccmult");
}
/* Divide the secondary register by the primary */
/*	(quotient in primary, remainder in secondary) */
div()
{	callrts("ccdiv");
}
/* Compute remainder (mod) of secondary register divided */
/*	by the primary */
/*	(remainder in primary, quotient in secondary) */
zmod()
{	div();
	swap();
	}
/* Inclusive 'or' the primary and the secondary registers */
/*	(results in primary) */
zor()
	{callrts("ccor");}
/* Exclusive 'or' the primary and seconday registers */
/*	(results in primary) */
zxor()
	{callrts("ccxor");}
/* 'And' the primary and secondary registers */
/*	(results in primary) */
zand()
	{callrts("ccand");}
/* Arithmetic shift right the secondary register number of */
/*	times in primary (results in primary) */
asr()
	{callrts("ccasr");}
/* Arithmetic left shift the secondary register number of */
/*	times in primary (results in primary) */
asl()
	{callrts("ccasl");}
/* Form two's complement of primary register */
neg()
	{callrts("ccneg");}
/* Form one's complement of primary register */
com()
	{callrts("cccom");}
/* Increment the primary register by one */
inc()
	{ol("inc hl");}
/* Decrement the primary register by one */
dec()
	{ol("dec hl");}
 
/* Following are the conditional operators */
/* They compare the secondary register against the primary */
/* and put a literal 1 in the primary if the condition is */
/* true, otherwise they clear the primary register */
 
/* Test for equal */
zeq()
	{callrts("cceq");}
/* Test for not equal */
zne()
	{callrts("ccne");}
/* Test for less than (signed) */
zlt()
	{callrts("cclt");}
/* Test for less than or equal to (signed) */
zle()
	{callrts("ccle");}
/* Test for greater than (signed) */
zgt()
	{callrts("ccgt");}
/* Test for greater than or equal to (signed) */
zge()
	{callrts("ccge");}
/* Test for less than (unsigned) */
ult()
	{callrts("ccult");}
/* Test for less than or equal to (unsigned) */
ule()
	{callrts("ccule");}
/* Test for greater than (unsigned) */
ugt()
	{callrts("ccugt");}
/* Test for greater than or equal to (unsigned) */
uge()
	{callrts("ccuge");}
 
/*	<<<<<  End of small-c compiler	>>>>>	*/
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.