/* 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=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("="