#include cc.def/1 extern int argstk, /* Argument stack offset */ xsp, /* Stack pointer */ lptr, /* index into line */ eof, /* True if end of file */ glbflag, /* True to add prolog */ lastst, /* Type of last statement */ ncmp; /* Depth of compound nesting */ extern char symtab[], /* symbol table */ line[]; /* Current input line */ extern char *locptr; /* Pointer into local symtab */ /* */ /* 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 */ } /* needsub */ /* */ /* 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) { error("illegal function or declaration"); kill(); /* invalidate line */ return; } typlin(n); /* tell user what rtn */ if(streq("main",n)) glbflag = 1; 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,statik); /* we had better see open paren for args... */ if(match("(")==0)error("missing open paren"); outstr(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*/ xsp=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 of args"); break; } } if(statement()!=streturn) { /* do a statement, but if */ /* it's a return, skip */ /* cleaning up the stack */ modstk(0); ret(); } xsp=0; /* reset stack ptr again */ locptr=startloc; /* deallocate all locals */ } /* newfunc */ /* */ /* 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; forever { 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,stkloc); argstk=argstk-2; /* cnt down */ if(endst())return; if(match(",")==0)error("expected comma"); } }/* getarg */ /* */ /* 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(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(amatch("for",3)) {dofor(); lastst = stfor;} else if(amatch("switch",5)) {error("SWITCH not implemented."); kill();} 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; } /* statement */ /* */ /* Semicolon enforcer */ /* */ /* called whenever syntax requires a semicolon */ ns() { if(match(";") == 0 ) error("Missing Semicolon"); } /* ns */ /* */ /* Compound statement */ /* */ /* allow any number of statements to fall between "{}" */ compound() { ++ncmp; /* new level open */ if(ncmp == 1) /* allow declarations at lev 1 only */ forever { /* Parse declarations */ if(amatch("char",4)) declloc(cchar,stkloc); else if(amatch("int", 3)) declloc(cint, stkloc); else if(amatch("extern",6)) decllex(); else break; ns(); /* ensure ending semicolon around */ } while (match("}")==0) if(eof) { error("missing final }"); break; } else statement(); --ncmp; /* close current level */ } /* compound */ /* */ /* "if" statement */ /* */ doif() { int flab1,flab2; flab1=getlabel(); /* get label for false branch */ test(flab1); /* get expression, and branch false */ statement(); /* if true, do a statement */ 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 */ printlabel(flab2);col();nl(); /* print true label */ } /* doif */ /* */ /* "while" statement */ /* */ dowhile() { int wq[wqsiz]; /* allocate local queue */ int faillab; /* target on test failure */ wq[wqloop]=getlabel(); /* and looping label */ wq[wqlab]=getlabel(); /* and exit label */ faillab = getlabel(); /* when while fails */ addwhile(wq); /* add entry to queue */ /* (for "break" statement) */ printlabel(wq[wqloop]);col();nl(); /* loop label */ test(faillab); /* see if true */ statement(); /* if so, do a statement */ jump(wq[wqloop]); /* loop to label */ printlabel(faillab);col();nl(); /* exit label */ printlabel(wq[wqlab]); col(); nl(); delwhile(); /* delete queue entry */ } /* dowhile */ dofor() /* Parse and generaate code for FOR statement */ { int wq[wqsiz], /* while queue entry */ tstlab, /* label of test code */ faillab, /* target when for clause fails */ bodylab; /* Label of body of loop */ blanks(); if(match("(") == 0) { error("Missing '(' in FOR."); kill(); return; } wq[wqloop] = getlabel(); /* label of iteration code */ wq[wqlab] = getlabel(); /* exit of loop label */ faillab = getlabel(); addwhile(wq); /* add to active loop stack */ blanks(); if(match(";") == 0) { /* Initialization expression */ expression(); ns(); } tstlab = getlabel(); /* label of test expression */ printlabel(tstlab); col(); nl(); blanks(); if(match(";") == 0) { /* Test expression */ expression(); ns(); testjump(faillab); /* Branch if no longer true */ } bodylab = getlabel(); /* Label for body of loop */ jump(bodylab); printlabel(wq[wqloop]); /* Next iteration label */ col(); nl(); blanks(); if(match(")") == 0) { /* Iteration expression */ expression(); needbrack(")"); } jump(tstlab); /* Go to test logic */ printlabel(bodylab); /* Start of body */ col(); nl(); statement(); /* Generate code for body */ jump(wq[wqloop]); /* Next iteration */ printlabel(faillab); /* failure label */ col(); nl(); printlabel(wq[wqlab]); col(); nl(); delwhile(); } /* dofor */ /* */ /* "return" statement */ /* */ doreturn() { /* if not end of statement, get an expression */ if(endst()==0)expression(); modstk(0); /* clean up stk */ ret(); /* and exit function */ } /* doreturn */ /* */ /* "break" statement */ /* */ dobreak() { int *ptr; /* see if any "whiles" are open */ if ((ptr=readwhile())==0) return; /* no */ jump(ptr[wqlab]); /* jump to exit label */ } /* dobreak */ /* */ /* "continue" statement */ /* */ docont() { int *ptr; /* see if any "whiles" are open */ if ((ptr=readwhile())==0) return; /* no */ jump(ptr[wqloop]); /* jump to loop label */ } /* docont */ /* */ /* "asm" pseudo-statement */ /* */ /* enters mode where assembly language statement are */ /* passed intact through parser */ doasm() { extern int cmode; /* compilation mode */ cmode=0; /* mark mode as "asm" */ forever { 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 */ } /* doasm */