/* small-c compiler rev 1.1(VMS) */ /* Edited 25-Jan-82 Jeff Lomicka */ /* - Test and fix changes of 23-sep-81 */ /* - Produce z80 assembler syntax */ /* - VMS version, open for write is weird */ /* main returns status code 2 on error. */ /* Edited 23-Sep-81 to incorporate changes from */ /* Dr. Dobbs Journal, Feb. 81 */ /************************************************/ /* */ /* small-c compiler */ /* */ /* by Ron Cain */ /* */ /************************************************/ /* Define system dependent parameters */ /* Stand-alone definitions */ /* #define NULL 0 */ /* #define eol 13 */ /* UNIX definitions (if not stand-alone) */ #include #define eol 10 /* Define the symbol table parameters */ #define symsiz 14 #define symtbsz 5040 #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 /* 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 possible entries for "storage" */ #define statik 1 #define stkloc 2 /* Define the "while" statement queue */ #define wqtabsz 100 #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 2000 #define litmax litabsz-1 /* Define the input line */ #define linesize 80 #define linemax linesize-1 #define mpmax linemax /* Define the macro (define) pool */ #define macqsize 1000 #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 /* 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 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 */ stkp, /* compiler relative stk ptr */ argstk, /* function arg sp */ ncmp, /* # open compound statements */ errcnt, /* # errors in compilation */ eof, /* set non-zero on final input eof */ input, /* iob # for input file */ output, /* iob # for output file (if any) */ 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 */ char quote[2]; /* literal string for '"' */ char *cptr; /* work ptr to any char buffer */ int *iptr; /* work ptr to any int buffer */ int status; /* error status, returned by main. 1 ok, 2 failed */ /* >>>>> start cc1 <<<<<< */ /* */ /* Compiler begins execution here */ /* */ main() { glbptr=startglb; /* clear global symbols */ locptr=startloc; /* clear local symbols */ wqptr=wq; /* clear while queue */ macptr= /* clear the macro pool */ litptr= /* clear literal pool */ stkp = /* stack ptr (relative) */ errcnt= /* no errors */ eof= /* not eof yet */ input= /* no input file */ input2= /* or include file */ output= /* no open units */ ncmp= /* no open compound states */ lastst= /* no last statement yet */ quote[1]= 0; /* ...all set to zero.... */ quote[0]='"'; /* fake a quote literal */ cmode=1; /* enable preprocessing */ /* */ /* compiler body */ /* */ ask(); /* get user options */ openout(); /* 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 */ errorsummary(); /* summarize errors */ trailer(); /* follow-up code */ closeout(); /* close the output (if any) */ return (status); /* then exit to system */ } /* */ /* 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(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(); /* print literal label */ k=0; /* init an index... */ while (k=litptr)) {nl(); /* need */ break; } outbyte(','); /* separate bytes */ } } } /* */ /* Dump all static variables */ /* */ dumpglbs() { int j; if(glbflag==0)return; /* don't if user said no */ cptr=startglb; while(cptr>>>>> 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 */ {errrpt("must be constant"); /* it isn't */ num[0]=1; /* so force one */ } if (num[0]<0) {errrpt("negative size 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; if (symname(n)==0) {errrpt("illegal function or declaration"); kill(); /* invalidate line */ return; } if(ptr=findglb(n)) /* already in symbol table ? */ {if(ptr[ident]!=function)multidef(n); /* already variable by that name */ else if(ptr[offset]==function)multidef(n); /* already function by that name */ else ptr[offset]=function; /* otherwise we have what was earlier*/ /* assumed to be a function */ } /* if not in table, define as a function now */ else addglb(n,function,cint,function); /* we had better see open paren for args... */ if(match("(")==0)errrpt("missing open paren"); outstr(n);col();nl(); /* print function name */ /* ** Clear local stack pointer rev. 1P */ locptr = startloc; /* ** 2 lines inserted rev. 1P */ argstk=0; /* init arg count */ while(match(")")==0) /* then count args */ /* any legal name bumps arg count */ {if(symname(n)) /* **+ Modification rev. 1P */ { if (findloc(n)) multidef(n); else { addloc(n, 0, 0, argstk); argstk = argstk + 2; } } /* **- End of modification rev. 1P */ else{errrpt("illegal argument name");junk();} blanks(); /* if not closing paren, should be comma */ if(streq(line+lptr,")")==0) {if(match(",")==0) errrpt("expected comma"); } if(endst())break; } /* ** Next line deleted rev. 1P */ /* ** locptr=startloc; ** */ /* "clear" local symbol table*/ stkp=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{errrpt("wrong number args");break;} } if(statement()!=streturn) /* do a statement, but if */ /* it's a return, skip */ /* cleaning up the stack */ {modstk(0); ret(); } stkp=0; /* reset stack ptr again */ locptr=startloc; /* deallocate all locals */ } /* */ /* Declare argument types */ /* */ /* called from "newfunc" this routine adds an entry in the */ /* local symbol table for each named argument */ /* ** Function completely rewritten rev. 1P */ getarg(t) /* t = cchar or cint */ int t; { int j, argtop, legalname, address; char n[namesize], c, *argptr; argtop = argstk; while(1) {if(argstk==0)return; /* no more args */ if(match("*"))j=pointer; else j=variable; if((legalname = symname(n)) == 0) illname(); if(match("[")) /* pointer ? */ /* it is a pointer, so skip all */ /* stuff between "[]" */ {while(inbyte()!=']') if(endst())break; j=pointer; /* add entry as pointer */ } if (legalname) { if (argptr = findloc(n)) { /* Add in details of the type and address of */ /* the name */ argptr[ident] = j; argptr[type] = t; address = argtop - ((argptr[offset]) + ((argptr[offset+1])*256)); argptr[offset] = address & 255; argptr[offset+1] = (address/256) & 255; } else errrpt("Expected argument name"); } argstk=argstk-2; /* cnt down */ if (endst()) return; if (match(",") == 0) errrpt("expected comma"); } } /* ** End of modifications rev. 1P */ /* */ /* Statement parser */ /* */ /* called whenever syntax requires */ /* a statement. */ /* this routine performs that statement */ /* and returns a number telling which one */ statement() { 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)errrpt("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=stkp; /* record current stk ptr */ flab1=getlabel(); /* get label for false branch */ test(flab1); /* get expression, and branch false */ statement(); /* if true, do a statement */ stkp=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 */ stkp=modstk(fsp); /* then clean up stk ptr */ locptr=flev; /* and deallocate locals */ printlabel(flab2);col();nl(); /* print true label */ } /* */ /* "while" statement */ /* */ dowhile() { int lwq[4]; /* allocate local queue */ lwq[wqsym]=locptr; /* record local level */ lwq[wqsp]=stkp; /* and stk ptr */ lwq[wqloop]=getlabel(); /* and looping label */ lwq[wqlab]=getlabel(); /* and exit label */ addwhile(lwq); /* add entry to queue */ /* (for "break" statement) */ printlabel(lwq[wqloop]);col();nl(); /* loop label */ test(lwq[wqlab]); /* see if true */ statement(); /* if so, do a statement */ jump(lwq[wqloop]); /* loop to label */ printlabel(lwq[wqlab]);col();nl(); /* exit label */ locptr=lwq[wqsym]; /* deallocate locals */ stkp=modstk(lwq[wqsp]); /* clean up stk ptr */ delwhile(); /* delete queue entry */ } /* */ /* "return" statement */ /* */ doreturn() { /* if not end of statement, get an expression */ if(endst()==0)expression(); modstk(0); /* clean up stk */ ret(); /* 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) {inline(); /* 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)push(); /* calling HL */ while(streq(line+lptr,")")==0) {if(endst())break; expression(); /* get an argument */ if(ptr==0)swapstk(); /* don't push addr */ push(); /* push argument */ nargs=nargs+2; /* count args*2 */ if (match(",")==0) break; } needbrack(")"); if(ptr)call(ptr); else callstk(); stkp=modstk(stkp+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() { errrpt("illegal symbol name");junk();} multidef(sname) char *sname; { errrpt("already defined"); comment(); outstr(sname);nl(); } needbrack(str) char *str; { if (match(str)==0) {errrpt("missing bracket"); comment();outstr(str);nl(); } } needlval() { errrpt("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) char *sname,id,typ; int value; { char *ptr; if(cptr=findglb(sname))return (cptr); if(glbptr>=endglb) {errrpt("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&255; cptr[offset+1]=(value/256)&255; 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) {errrpt("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&255; cptr[offset+1]=(value/256)&255; 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; { outstr("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 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) {errrpt("too many active whiles");return;} k=0; while (k0) {if((k==eol)|(lptr>=linemax))break; line[lptr++]=k; } line[lptr]=0; /* append null */ if(k<=0) {fclose(unit); if(input2)input2=0; 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)errrpt("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++])); blanks(); ; while(putmac(gch())); if(macptr>=macmax)errrpt("macro table full"); } putmac(c) char c; { macq[macptr]=c; if(macptr>>>>>> start of cc5 <<<<<<< */ 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])push(); 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("|")) {push(); if(heir3(lval2)) rvalue(lval2); pop(); or(); } 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("^")) {push(); if(heir4(lval2))rvalue(lval2); pop(); xor(); } 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("&")) {push(); if(heir5(lval2))rvalue(lval2); pop(); and(); } 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("==")) {push(); if(heir6(lval2))rvalue(lval2); pop(); eq(); } else if (match("!=")) {push(); if(heir6(lval2))rvalue(lval2); pop(); ne(); } 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("<=")) {push(); if(heir7(lval2))rvalue(lval2); pop(); if(cptr=lval[0]) if(cptr[ident]==pointer) {ule(); continue; } if(cptr=lval2[0]) if(cptr[ident]==pointer) {ule(); continue; } le(); } else if (match(">=")) {push(); if(heir7(lval2))rvalue(lval2); pop(); if(cptr=lval[0]) if(cptr[ident]==pointer) {uge(); continue; } if(cptr=lval2[0]) if(cptr[ident]==pointer) {uge(); continue; } ge(); } else if((streq(line+lptr,"<"))& (streq(line+lptr,"<<")==0)) {inbyte(); push(); if(heir7(lval2))rvalue(lval2); pop(); if(cptr=lval[0]) if(cptr[ident]==pointer) {ult(); continue; } if(cptr=lval2[0]) if(cptr[ident]==pointer) {ult(); continue; } lt(); } else if((streq(line+lptr,">"))& (streq(line+lptr,">>")==0)) {inbyte(); push(); if(heir7(lval2))rvalue(lval2); pop(); if(cptr=lval[0]) if(cptr[ident]==pointer) {ugt(); continue; } if(cptr=lval2[0]) if(cptr[ident]==pointer) {ugt(); continue; } gt(); } 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(">>")) {push(); if(heir8(lval2))rvalue(lval2); pop(); asr(); } else if (match("<<")) {push(); if(heir8(lval2))rvalue(lval2); pop(); 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("+")) {push(); if(heir9(lval2))rvalue(lval2); if(cptr=lval[0]) if((cptr[ident]==pointer)& (cptr[type]==cint)) doublereg(); pop(); add(); } else if (match("-")) {push(); if(heir9(lval2))rvalue(lval2); if(cptr=lval[0]) if((cptr[ident]==pointer)& (cptr[type]==cint)) doublereg(); pop(); sub(); } 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("*")) {push(); if(heir9(lval2))rvalue(lval2); pop(); mult(); } else if (match("/")) {push(); if(heir10(lval2))rvalue(lval2); pop(); div(); } else if (match("%")) {push(); if(heir10(lval2))rvalue(lval2); pop(); mod(); } else return (0); } } heir10(lval) int lval[]; { int k; char *ptr; if(match("++")) {if((k=heir10(lval))==0) {needlval(); return (0); } if(lval[1])push(); 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])push(); 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]; return (1); } else if(match("&")) {k=heir10(lval); if(k==0) {errrpt("illegal address"); return (0); } else if(lval[1])return (0); else {immed(); outstr(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])push(); 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])push(); 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) {errrpt("can't subscript"); junk(); needbrack("]"); return (0); } else if(ptr[ident]==pointer)rvalue(lval); else if(ptr[ident]!=array) {errrpt("can't subscript"); k=0; } push(); expression(); needbrack("]"); if(ptr[type]==cint)doublereg(); pop(); add(); lval[1]=ptr[type]; 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(); outstr(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(); outstr(ptr);nl(); lval[1]=ptr[type]; return (0); } ptr=addglb(sname,function,cint,0); lval[0]=ptr; lval[1]=0; return (0); } if(constant(num)) return(lval[0]=lval[1]=0); else {errrpt("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)return; if (lval[1]==0)getmem(lval[0]); else indirect(lval[1]); } test(label) int label; { needbrack("("); expression(); needbrack(")"); testjump(label); } constant(lval) int lval[]; { if (number(lval)) immed(); else if (pstr(lval)) immed(); else if (qstr(lval)) {immed();printlabel(litlab);outbyte('+');} else return (0); outdec(lval[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;} } 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); } 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(quote)==0) return (0); val[0]=litptr; while (ch()!='"') {if(ch()==0)break; if(litptr>=litmax) {errrpt("string space exhausted"); while(match(quote)==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(';'); } /* Print all assembler info before any code is generated */ header() { comment(); outstr("small-c compiler rev 1.0"); nl(); } /* Print any assembler stuff needed after all code */ trailer() { ol(".END main"); } /* Fetch a static memory cell into the primary register */ getmem(sym) char *sym; { if((sym[ident]!=pointer)&(sym[type]==cchar)) {ot("LD A,("); outstr(sym+name); ot(")");nl(); call("ccsxt"); } else {ot("LD HL,("); outstr(sym+name); ot(")");nl(); } } /* Fetch the address of the specified symbol */ /* into the primary register */ getloc(sym) char *sym; { immed(); outdec((sym[offset] + (sym[offset+1]*256))-stkp); nl(); ol("ADD HL,SP"); } /* Store the primary register into the specified */ /* static memory cell */ putmem(sym) char *sym; { if((sym[ident]!=pointer)&(sym[type]==cchar)) {ol("LD A,L"); ot("LD ("); outstr(sym+name); ot("),A"); } else { ot("LD ("); outstr(sym+name); ot("),HL"); } nl(); } /* Store the specified object type in the primary register */ /* at the address on the top of the stack */ putstk(typeobj) char typeobj; { pop(); if(typeobj==cchar)call("ccpchar"); else call("ccpint"); } /* Fetch the specified object type indirect through the */ /* primary register into the primary register */ indirect(typeobj) char typeobj; { if(typeobj==cchar)call("ccgchar"); else call("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 */ push() { ol("PUSH HL"); stkp=stkp-2; } /* Pop the top of the stack into the secondary register */ pop() { ol("POP DE"); stkp=stkp+2; } /* Swap the primary register and the top of the stack */ swapstk() { ol("EX (SP),HL"); } /* Call the specified subroutine name */ call(sname) char *sname; { ot("CALL "); outstr(sname); nl(); } /* Return from subroutine */ ret() { ol("RET"); } /* Perform subroutine call to value on top of stack */ callstk() { immed(); outstr(".+5"); nl(); swapstk(); ol("JP (HL)"); stkp=stkp-2; } /* 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(".BYTE "); } /*Print pseudo-op to define storage */ defstorage() { ot(".blkb "); } /* Print pseudo-op to define a word */ defword() { ot(".word "); } /* Modify the stack pointer to the new value indicated */ modstk(newsp) int newsp; { int k; k=newsp-stkp; 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) */ add() { ol("ADD HL,DE"); } /* Subtract the primary register from the secondary */ /* (results in primary) */ sub() { call("ccsub"); } /* Multiply the primary and secondary registers */ /* (results in primary */ mult() { call("ccmult"); } /* Divide the secondary register by the primary */ /* (quotient in primary, remainder in secondary) */ div() { call("ccdiv"); } /* Compute remainder (mod) of secondary register divided */ /* by the primary */ /* (remainder in primary, quotient in secondary) */ mod() { div(); swap(); } /* Inclusive 'or' the primary and the secondary registers */ /* (results in primary) */ or() {call("ccor");} /* Exclusive 'or' the primary and seconday registers */ /* (results in primary) */ xor() {call("ccxor");} /* 'And' the primary and secondary registers */ /* (results in primary) */ and() {call("ccand");} /* Arithmetic shift right the secondary register number of */ /* times in primary (results in primary) */ asr() {call("ccasr");} /* Arithmetic left shift the secondary register number of */ /* times in primary (results in primary) */ asl() {call("ccasl");} /* Form two's complement of primary register */ neg() {call("ccneg");} /* Form one's complement of primary register */ com() {call("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 */ eq() {call("cceq");} /* Test for not equal */ ne() {call("ccne");} /* Test for less than (signed) */ lt() {call("cclt");} /* Test for less than or equal to (signed) */ le() {call("ccle");} /* Test for greater than (signed) */ gt() {call("ccgt");} /* Test for greater than or equal to (signed) */ ge() {call("ccge");} /* Test for less than (unsigned) */ ult() {call("ccult");} /* Test for less than or equal to (unsigned) */ ule() {call("ccule");} /* Test for greater than (unsigned) */ ugt() {call("ccugt");} /* Test for greater than or equal to (unsigned) */ uge() {call("ccuge");} /* <<<<< End of compiler >>>>> */