/* Small C compiler - (Part 2) */

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)
		{
			inline();
			preproc();
			if(eof) break;
		}
		if(ch()==' ')gch();
		else if(ch()==9)gch();
		else return;
	}
}
outdec(number)
int number;
{
	int k,zs;
	char c;
	zs=0;
	k=10000;
	if(number<0)
	{       /* Possible $8000 can't be negatived */
		if((number^0xFFFF)==0x7FFF){outstr("0-32768");return;}
		number=(-number);
		outbyte('0');
		outbyte('-');
	}
	while(k>=1)
	{
		c=number/k +'0';
		if((c!='0')|(k==1)|(zs))
		{
			zs=1;
			outbyte(c);
		}
		number=number%k;
		k=k/10;
	}
}
/* Expression analyser includes mods by J.E.Hendrix (DDJ No. 62)

  (Additional mods to correct errors in integer array arithmetic
   are marked "Mod JMHH")

lval[0] is a symbol table address or 0 for constants
lval[1] is a type for indirect objects or 0 for static objects
lval[2] is a type for a pointer or array or 0

 */

expresn()
{
	int lval[3];
	if(heir1(lval))rvalue(lval);
}
heir1(lval)
int lval[];
{
	int k,lval2[3];
	k=heir2(lval);
	if(match("="))
	{
		if(k==0){
			ndlval();
			return 0;
		}
		if(lval[1])fpush();
		if(heir1(lval2))rvalue(lval2);
		store(lval);
		return 0;
	}
	else return k;
}
heir2(lval)
int lval[];
{
	int k,lval2[3];
	k=heir3(lval);
	blanks();
	if(ch()!='|')return k;
	if(k)rvalue(lval);
	while(1)
	{
		if(match("|"))
		{
			fpush();
			if(heir3(lval2)) rvalue(lval2);
			fpop();
			orfn();
		}
		else return 0;
	}
}
heir3(lval)
int lval[];
{
	int k,lval2[3];
	k=heir4(lval);
	blanks();
	if(ch()!='^')return k;
	if(k)rvalue(lval);
	while (1)
	{
		if(match("^"))
		{
			fpush();
			if(heir4(lval2))rvalue(lval2);
			fpop();
			xorfn();
		}
		else return 0;
	}
}
heir4(lval)
int lval[];
{
	int k, lval2[3];
	k=heir5(lval);
	blanks();
	if(ch()!='&')return k;
	if(k)rvalue(lval);
	while(1)
	{
		if(match("&"))
		{
			fpush();
			if(heir5(lval2))rvalue(lval2);
			fpop();
			andfn();
		}
		else return 0;
	}
}
heir5(lval)
int lval[];
{
	int k,lval2[3];
	k=heir6(lval);
	blanks();
	if((streq(line+lptr,"==")==0) &
	    (streq(line+lptr,"!=")==0))return k;
	if(k)rvalue(lval);
	while(1)
	{
		if(match("=="))
		{
			fpush();
			if(heir6(lval2))rvalue(lval2);
			fpop();
			eq();
		}
		else if(match("!="))
		{
			fpush();
			if(heir6(lval2))rvalue(lval2);
			fpop();
			ne();
		}
		else return 0;
	}
}
heir6(lval)
int lval[];
{
	int k,lval2[3];
	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("<="))
		{
			fpush();
			if(heir7(lval2))rvalue(lval2);
			fpop();
			if(lval[2] | lval2[2])
			{
				ule();
				continue;
			}
			le();
		}
		else if(match(">="))
		{
			fpush();
			if(heir7(lval2))rvalue(lval2);
			fpop();
			if(lval[2] | lval2[2])
			{
				uge();
				continue;
			}
			ge();
		}
		else if((streq(line+lptr,"<"))&
		    (streq(line+lptr,"<<")==0))
		{
			inbyte();
			fpush();
			if(heir7(lval2))rvalue(lval2);
			fpop();
			if(lval[2] | lval2[2])
			{
				ult();
				continue;
			}
			lt();
		}
		else if((streq(line+lptr,">"))&
		    (streq(line+lptr,">>")==0))
		{
			inbyte();
			fpush();
			if(heir7(lval2))rvalue(lval2);
			fpop();
			if(lval[2] | lval2[2])
			{
				ugt();
				continue;
			}
			gt();
		}
		else return 0;
	}
}
heir7(lval)
int lval[];
{
	int k,lval2[3];
	k=heir8(lval);
	blanks();
	if((streq(line+lptr,">>")==0)&
	    (streq(line+lptr,"<<")==0)) return k;
	if(k)rvalue(lval);
	while(1)
	{
		if(match(">>"))
		{
			fpush();
			if(heir8(lval2))rvalue(lval2);
			fpop();
			asrfn();
		}
		else if(match("<<"))
		{
			fpush();
			if(heir8(lval2))rvalue(lval2);
			fpop();
			aslfn();
		}
		else return 0;
	}
}
heir8(lval)
int lval[];
{
	int k,lval2[3];
	k=heir9(lval);
	blanks();
	if((ch()!='+')&(ch()!='-'))return k;
	if(k)rvalue(lval);
	while(1)
	{
		if(match("+"))
		{
			fpush();
			if(heir9(lval2))rvalue(lval2);
			if(dbltest(lval,lval2))
				doubreg();
			fpop();
			if(dbltest(lval2,lval)){
				swap();
				doubreg();
				swap();
			}
			addfn();
			result(lval,lval2);
		}
		else if (match("-"))
		{
			fpush();
			if(heir9(lval2))rvalue(lval2);
			if(dbltest(lval,lval2))
				doubreg();
			fpop();
			if(dbltest(lval2,lval)){
				swap();
				doubreg();
				swap();
			}
			subfn();
			if((lval[2]==cint)&(lval2[2]==cint))
			{  swap();
			   ol("LD HL,1"); /*Mod to avoid tab in address field*/
			   asrfn(); /* div by 2 */
			}
			result(lval,lval2);
		}
		else return 0;
	}
}
heir9(lval)
int lval[];
{
	int k,lval2[3];
	k=heir10(lval);
	blanks();
	if((ch()!='*')&(ch()!='/')&(ch()!='%'))
		return k;
	if(k)rvalue(lval);
	while(1)
	{
		if(match("*"))
		{
			fpush();
			if(heir9(lval2))rvalue(lval2);
			fpop();
			mult();
		}
		else if (match("/"))
		{
			fpush();
			if(heir10(lval2))rvalue(lval2);
			fpop();
			div();
		}
		else if (match("%"))
		{
			fpush();
			if(heir10(lval2))rvalue(lval2);
			fpop();
			mod();
		}
		else return 0;
	}
}
heir10(lval)
int lval[];
{
	int k;
	char *ptr;
	if(match("++"))
	{
		if((k=heir10(lval))==0)
		{
			ndlval();
			return 0;
		}
		if(lval[1])fpush();
		rvalue(lval);
		ptr=lval[0];/*Mod JMHH*/
		finc();
		if((lval[2]==cint)&((lval[1]==0)|(ptr[ident]==pointer))) /* Mod JMHH */
			finc();
		store(lval);
		return 0;
	}
	else if(match("--"))
	{
		if((k=heir10(lval))==0)
		{
			ndlval();
			return 0;
		}
		if(lval[1])fpush();
		rvalue(lval);
		ptr=lval[0];/*Mod JMHH*/
		fdec();
		if((lval[2]==cint)&((lval[1]==0)|(ptr[ident]==pointer))) /* Mod JMHH */
			fdec();
		store(lval);
		return 0;
	}
	else if(match("-"))
	{
		k=heir10(lval);
		if (k) rvalue(lval);
		negfn();
		return 0;
	}
	else if(match("*"))
	{
		k=heir10(lval);
		if(k) rvalue(lval);
		if(ptr=lval[0])lval[1]=ptr[type];
		else lval[1]=cint;
		lval[2]=0;/**flag as not pointer or array**/
		return 1;
	}
	else if(match("&"))
	{
		k=heir10(lval);
		if(k==0)
		{
			error("Illegal address");
			return 0;
		}
		ptr=lval[0];
		lval[2]=ptr[type];
		if(lval[1]) return 0;
		/*global & non-array*/
		immed();
		outstr(ptr);
		nl();
		lval[1]=ptr[type];
		return 0;
	}
	else
	{
		k=heir11(lval);
		if(match("++"))
		{
			if(k==0)
			{
				ndlval();
				return 0;
			}
			if(lval[1]) fpush();
			rvalue(lval);
			ptr=lval[0];/*Mod JMHH*/
			finc();
		     if((lval[2]==cint)&((lval[1]==0)|(ptr[ident]==pointer)))				/* Mod JMHH */
				finc();
			store(lval);
			fdec();
		     if((lval[2]==cint)&((lval[1]==0)|(ptr[ident]==pointer)))
			/* Mod JMHH */
				fdec();
			return 0;
		}
		else if(match("--"))
		{
			if(k==0)
			{
				ndlval();
				return 0;
			}
			if(lval[1])fpush();
			rvalue(lval);
			ptr=lval[0];/*Mod JMHH*/
			fdec();
		    if((lval[2]==cint)&((lval[1]==0)|(ptr[ident]==pointer)))
			/* Mod JMHH */
				fdec();
			store(lval);
			finc();
		    if((lval[2]==cint)&((lval[1]==0)|(ptr[ident]==pointer)))
			/* Mod JMHH */
				finc();
			return 0;
		}
		else return k;
	}
}
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();
					ndbrack("]");
					return 0;
				}
				else if(ptr[ident]==pointer)rvalue(lval);
				else if(ptr[ident]!=array)
				{
					error("Can't subscript");
					k=0;
				}
				fpush();
				expresn();
				ndbrack("]");
				if(ptr[type]==cint)doubreg();
				fpop();
				addfn();
				lval[0]=0;
				lval[1]=ptr[type];
				k=1;
			}
			else if(match("("))
			{
				if(ptr==0)
				{
					callfnc(0);
				}
				else if(ptr[ident]!=fnction)
				{
					rvalue(lval);
					callfnc(0);
				}
				else callfnc(ptr);
				k=lval[0]=0;
			}
			else return k;
		}
	if(ptr==0)return k;
	if(ptr[ident]==fnction)
	{
		immed();
		outstr(ptr);
		nl();
		return 0;
	}
	return k;
}
primary(lval)
int *lval;
{
	char *ptr,sname[namesiz];
	int num[1];
	int k;
	lval[2]=0; /*clear pointer/array type*/
	if(match("("))
	{
		k=heir1(lval);
		ndbrack(")");
		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;
				lval[2]=ptr[type];
			}
			if(ptr[ident]==array) {
				lval[2]=ptr[type];
				return 0;
			}
			else return 1;
		}
		if(ptr=findglb(sname))
			if(ptr[ident]!=fnction)
			{
				lval[0]=ptr;
				lval[1]=0;
				if(ptr[ident]!=array) {
				    if(ptr[ident]==pointer) lval[2]=ptr[type];
					return 1;
				}
				immed();
				outstr(ptr);
				nl();
				lval[1]=lval[2]=ptr[type];
				return 0;
			}
		ptr=addglb(sname,fnction,cint,0);
		lval[0]=ptr;
		lval[1]=0;
		return 0;
	}
	if(cnstant(num))
		return(lval[0]=lval[1]=0);
	else
	{
		error("Invalid expression");
		immed();
		outdec(0);
		nl();
		junk();
		return 0;
	}
}

/*True if val1 -> int pointer or int array and val2 not ptr or array*/
dbltest(val1,val2)
int val1[],val2[];
{char *ptr; /*Mod JMHH*/
	ptr=val1[0];/*Mod JMHH*/
	if(val1[2]!=cint) return 0;
	if((ptr[ident]!=pointer)&(ptr[ident]!=array))return 0;/*Mod JMHH*/
	if(val2[2]) return 0;
	return 1;
}
/*Determine type of binary operation*/
result(lval,lval2)
int lval[],lval2[];
{
	if(lval[2] & lval2[2]) {
		lval[2]=0;
	}
	else if(lval2[2]) {
		lval[0]=lval2[0];
		lval[1]=lval2[1];
		lval[2]=lval2[2];
	}
}
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 indrct(lval[1]);
}
test(label)
int label;
{
	ndbrack("(");
	expresn();
	ndbrack(")");
	testjmp(label);
}
cnstant(val)
int val[];
{
	if(number(val))
		immed();
	else if(pstr(val))
		immed();
	else if(qstr(val))
	{
		immed();
		prlabel(litlab);
		outbyte('+');
	}
	else return 0;
	outdec(val[0]);
	nl();
	return 1;
}
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 for hex no */
if((ch()=='0')&((nch()=='X')|(nch()=='x')))
{ if(ch()=='0')gch();
  gch();
  if(hex(ch())==0)return 0;
  while(hex(ch()))
  {c=inbyte();
   if(c<='9')k=k*16+(c-'0');
   else k=k*16 +((c&95)-'7');
  }
  val[0]=k;
  return 1;
}
	if(numeric(ch())==0) return 0;
	while(numeric(ch()))
	{
		c=inbyte();
		k=k*10+(c-'0');
	}
	if(minus<0) k=(-k);
	val[0]=k;
	return 1;
}

hex(c)
char c;
{ c=c&127;
  return(((c>='0')&(c<='9'))|((c>='a')&(c<='f'))|((c>='A')&(c<='F')));
}
pstr(val)
int val[];
{
	int k;
	char c;
	k=0;
	if(match("'")==0) return 0;
	while((c=gch())!=39)
		{
		if(c==92) /* '\' */ 
		{c=gch(); /* Support \n,\r,\t,\b,\f,\0,\' & \\ */
		 if(ch()!=39)return 0;
		 if(c=='n')c=10;
		 if(c=='f')c=12;
		 if(c=='r')c=13;
		 if(c=='t')c=9;
		 if(c=='b')c=8;
		 if(c=='0')c=0;
		}
		k=(k&255)*256+(c&127);
		}
	val[0]=k;
	return 1;
}
qstr(val)
int val[];
{
	char c;
	if(match(quote)==0) return 0;
	val[0]=litptr;
	while (ch()!='"')
        {
                if(ch()==0) break;
                if(litptr>=litmax)
                {
                        error("String space exhausted");
			while(match(quote)==0)
				if(gch()==0)break;
			return 1;
		}
		litq[litptr++]=gch();
	}
	gch();
	litq[litptr++]=0;
	return 1;
}
/*Begin comment line for assembler*/
comment()
{
	outbyte(';');
}
/*Print header for assembler*/
header()
{
	comment();
	outstr("Small C Compiler");
	nl();
}
/*Print END */
trailer()
{
	ol("END");
}
/*Fetch static memory cell into primary register*/
getmem(sym)
char *sym;
{   if((sym[ident]!=pointer)&(sym[type]==cchar))
 {
 ot("LD A,(");
 outstr(sym+name);
 outbyte(')');
 nl();
 callfn("ccsxt");
	}
	else
	{
  ot("LD HL,(");
  outstr(sym+name);
  outbyte(')');
  nl();
	}
}
/*Fetch addr of specified symbol into primary register*/
getloc(sym)
char *sym;
{
	immed();
	outdec(((sym[offset]&255)+((sym[offset+1]&255)<<8))-sptr);
	nl();
	ol("ADD HL,SP");
}
/*Store primary reg. to specified memory static cell*/
putmem(sym)
char *sym;
{
	if((sym[ident]!=pointer)&(sym[type]==cchar))
	{
	   ol("LD A,L");
	   ot("LD (");
	   outstr(sym+name);
	   outstr("),A");
	}
	else {
	   ot("LD (");
	   outstr(sym+name);
	   outstr("),HL");
	}
	nl();
}
/*Store specified object type in primary reg.*/
/* at addr. on the top of the stack */
putstk(typeobj)
char typeobj;
{
	fpop();
	if(typeobj==cchar) callfn("ccpchar");
	else callfn("ccpint");
}
/* Fetch specified object type indirect through the */
/* primary reg. into the primary reg. */
indrct(typeobj)
char typeobj;
{
	if(typeobj==cchar)callfn("ccgchar");
	else callfn("ccgint");
}
/* Swap primary and secondary regs.*/
swap()
{
   ol("EX DE,HL");
}
/*Print part of instruction to load primary reg. */
immed()
{
 ot("LD HL,");
}
/*Push primary reg. onto stack*/
fpush()
{
  ol("PUSH HL");
	sptr=sptr-2;
}
/*Pop top of stack into secondary reg. */
fpop()
{
  ol("POP DE");
	sptr=sptr+2;
}
/* Swap primary reg. and top of stack */
swapstk()
{
 ol("EX (SP),HL");
}
/* Call specified subroutine name */
callfn(sname)
char *sname;
{
	ot("CALL ");
	outstr(sname);
	nl();
}
/* Return from subroutine */
retfn()
{
	ol("RET");
}
/* Perform subroutine call to address on top of stack */
callstk()
{
	immed();
	outstr("$+5");
	nl();
	swapstk();
	ol("JP (HL)");
	sptr=sptr+2;
}
/* Jump to specified internal label number */
jump(label)
int label;
{
	ot("JP ");
	prlabel(label);
	nl();
}
/* Test primary reg. and jump if false to label */
testjmp(label)
int label;
{
	ol("LD A,H");
	ol("OR L");
	ot("JP Z,");
	prlabel(label);
	nl();
}
/* Print pseudo-op to define a byte */
defbyte()
{
 ot("DEFB ");
}
/* Print pseudo-op to define storage */
defstrg()
{
 ot("DEFS ");
}
/* Print pseudo-op to define a word */
defword()
{
 ot("DEFW ");
}
/* Modify stack pointer to new value indicated */
modstk(newsp)
int newsp;
{
	int k;
	k=newsp-sptr;
	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 primary reg. */
doubreg()
{
 ol("ADD HL,HL");
}
/* Add primary and secondary regs. */
/* result in primary reg. */
addfn()
{
 ol("ADD HL,DE");
}
/*Sub primary reg. from secondary, result in primary reg.*/
subfn()
{
	callfn("ccsub");
}
/* Multiply primary and secondary regs., result in primary */
mult()
{
	callfn("ccmult");
}
/*Divide secondary re. by primary */
/*quotient in primary, remainder in secondary*/
div()
{
	callfn("ccdiv");
}
/*Compute remainder (mod) of secondary reg divided by primary */
/* remainder in primary, quotient in secondary*/
mod()
{
	div();
	swap();
}
/* inclusive or the primary and secondary regs.*/
/* result in primary*/
orfn()
{
	callfn("ccor");
}
/* Exclusive or primary and secondary regs. */
/* result in primary */
xorfn()
{
	callfn("ccxor");
}
/* And the primary and secondary regs. */
/* result in primary */
andfn()
{
	callfn("ccand");
}
/* Arith shift right the secondary number of times in primary reg.*/
/* result in primary */
asrfn()
{
	callfn("ccasr");
}
/* Arith shift left (as for 'asr') */
aslfn()
{
	callfn("ccasl");
}
/* Form 2's complement of primary reg.*/
negfn()
{
	callfn("ccneg");
}
/* Form 1's complement of primary reg. */
com()
{
	callfn("cccom");
}
/* Inc primary reg.*/
finc()
{
 ol("INC HL");
}
/* Decrement primary reg.*/
fdec()
{
 ol("DEC HL");
}
/*Conditional operators. They compare the secondary reg.*/
/*against the primary and put 1 in primary if condition true*/
/*otherwise they clear the primary */
/*Equal*/
eq()
{
	callfn("cceq");
}
/*Not equal*/
ne()
{
	callfn("ccne");
}
/*Less than (signed)*/
lt()
{
	callfn("cclt");
}
/*Less than or equal (signed)*/
le()
{
	callfn("ccle");
}
/*Greater than (signed)*/
gt()
{
	callfn("ccgt");
}
/*Greater than or equal to (signed)*/
ge()
{
	callfn("ccge");
}
/*Less than (unsigned)*/
ult()
{
	callfn("ccult");
}
/*Less than or equal to (unsigned)*/
ule()
{
	callfn("ccule");
}
/*Greater than	(unsigned)*/
ugt()
{
	callfn("ccugt");
}
/*Greater than or equal to (unsigned)*/
uge()
{
	callfn("ccuge");
}
getchar()
{
return cpm(1,1);
}
putchar(c)
char c;
{
cpm(c,2);
return c;
}
/* END */

lue(lval);
}
heir1(lval)
int lval[];
{
	int k,lval2[3];
	k=heir2(lval);
	if(match("="