/************************************************/ /* */ /* small-c compiler */ /* */ /* by Ron Cain */ /* and James Van Zandt */ /* */ /************************************************/ #define VERSION " 2 August 1984" /* history... 2 Aug 84 Allocating symbol table and literal pool from heap. 31 Jul 84 No GLOBAL directives for macros. 30 Jul 84 Input file extension capitalized. 29 Jul 84 Displaying input file names. 28 Jul 84 Getting file names and options from command line. 14 Jul 84 outdec() is now recursive & smaller. raise() not called, since ZMAC converts to upper case. When profiling, the appropriate GLOBAL statements are automagically emitted. 28 Jun 84 Adding CR after GLOBAL statement. 25 Jun 84 In addglb(), generating GLOBAL statement. Generating 9 character labels (so 1st 8 characters in a c symbol name are significant). Allowing 800 bytes of literals per function. 2 Sept 83 In doreturn(), changed 'ccleavin' to 'ccleavi'. Introduced 'leave'. 'numeric' & 'outbyte' optimized. Optimized: 'nch', 'gch', 'keepch', 'streq', 'astreq', 'raise'. 1 Sept 83 Initializing firstfct & lastfct after calling ask(). Trace & profile enabled together. 27 Aug 83 Allowing 3 bytes for call count. 26 Aug 83 renamed: leaving => ccleavi, registe => ccregis. Added code to link the call count cells (main, header, trailer, newfunction). 22 Aug 83 converted "," to "'", corrected loading of name pointer. 21 Aug 83 Trace and profile are available. Using clibv.h & a:float.h 1 Aug 83 6 function names are now "nospread", A now set to # words on stack rather than adding another parameter. 29 Mar 83 "callfunction" now reserves symsize bytes rather than namesize bytes for sym. When "printf" is called, the top word on the stack points to the first argument. 7 Mar 83 "callfunction" now adds pointer to first argument for nospread functions. "nospread" introduced (returns true only for "printf"). 10 Nov 82 Rewrote "an" for speed. 24 Oct 82 In "preprocess", searching macro table only with strings beginning with alpha. (Allows long numeric literals.) Rewrote "alpha" for speed. 10 Oct 82 Updated date in signon message. Coersing function values to proper type. 4 Sept 82 Generating colons again. 3 Sep 82 "#includ"ing floating point library. 30 Aug 82 Changed "number" calling sequence back. Colons are optional. 12 Aug 82 Changed "number" calling sequence. 11 Aug 82 Allowing typed function declarations. 7 Aug 82 Correct length of double in local variables, preserving calling addr when calling through TOS & using double argument. 5 Aug 82 Started installing floating point 3 Aug 82 generating no colons after labels. Generating only 7 character labels. 20 Jul 82 Removed the unused variable "iptr". 18 Jul 82 Changed comment recognizer per J. E. Hendrix (ddj n56 p6). 17 Jul 82 Implemented \" and \' sequences. Corrected newfunc & getarg per P. L. Woods (ddj n52 p32) & J. E. Hendrix (ddj n56 p6). 14 Jul 82 "#include"ing clibv.asm & c80v-2.c 28 Jun 82 Skipping first byte in macro table, so index won't be zero. 27 Jun 82 Masking out high order bits of characters extracted from a symbol table entry. 21 Jun 82 Dumping literals at end of each function, per Rodney Black (DDJ n61 p51). 19 Jun 82 Updated symtabsiz. Updated dumpglbs to handle new symbol table. Placing macro names in global symbol table, using smaller macro table. 16 Jun 82 using hash table for global symbols. 18 Apr 81 Changed names so first 5 characters are unique: heir10 => heira heir11 => heirb input2 => inpt2 errorsum => errsum */ #include iolib.h #include float.h #define BANNER "* * * Small-C V1.2 * * *" #define AUTHOR " By Ron Cain and James Van Zandt" /* 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 8008 /* =14*(NUMGLBS+60) */ #define NUMGLBS 512 #define MASKGLBS 511 /* formerly 300 globals */ #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 MACRO 5 /* added 6/19/82, JRVZ */ /* Define possible entries for "type" */ #define cchar 1 #define cint 2 #define DOUBLE 3 /* 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 1000 /* formerly 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 500 /* formerly 1000 JRVZ 6/19/82 */ #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 8 #define ASMSUFF 0 /* Now reserve some storage words */ char *symtab; /* symbol table */ char *glbptr,*locptr; /* ptrs to next entries */ int wq[wqtabsz]; /* while queue */ int *wqptr; /* ptr to next entry */ char *litq; /* 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 */ Zsp, /* compiler relative stk ptr */ undeclared, /* # function arguments not yet declared jrvz 8/6/82 */ 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) */ inpt2, /* 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 filegtf 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 */ trace, /* nonzero if traceback info needed jrvz 8/21/83 */ profile, /* nonzero if profile needed */ caller, /* stack offset for caller links... local[caller] points to name of current fct local[caller-1] points to link for calling fct, where local[0] is 1st word on stack after ret addr */ firstfct, /* label for 1st function */ lastfct, /* label for most recent fct jrvz 8/83 */ fname; /* label for name of current fct */ char *currfn, /* ptr to symtab entry for current fn. gtf 7/17/80 */ *savecurr; /* copy of currfn for #include gtf 7/17/80 */ char quote[2]; /* literal string for '"' */ char *cptr; /* work ptr to any char buffer */ /* >>>>> start cc1 <<<<<< */ /* */ /* Compiler begins execution here */ /* */ main() { litq=alloc(litabsz); /* literal pool */ symtab=alloc(SYMTBSZ); /* allocate symbol table */ glbptr=STARTGLB; while(glbptr=litptr)) {nl(); /* need */ break; } outbyte(','); /* separate bytes */ } } } /* */ /* Dump all static variables */ /* */ dumpglbs() { int i,j; if(glbflag==0)return; /* don't if user said no */ cptr=STARTGLB; i=NUMGLBS; while(i--){ /* 6/19/82 jrvz */ if(*cptr){ if((cptr[ident]!=function) &(cptr[ident]!=MACRO)) /* 6/19/82 jrvz */ /* do if anything but function or macro */ {outname(cptr);col(); /* output name as label... */ defstorage(); /* define storage */ j=((cptr[offset]&255)+ ((cptr[offset+1]&255)<<8)); /* calc # bytes */ if((cptr[type]==cint)| (cptr[ident]==pointer)) j=j+j; else if(cptr[type]==DOUBLE) j=j*6; /* jrvz 8/5/82 */ outdec(j); /* need that many */ nl(); } } cptr=cptr+SYMSIZ; } } /* */ /* Report errors for user */ /* */ errsummary() { /* see if anything left hanging... */ if (ncmp) error("missing closing bracket"); /* open compound statement ... */ nl(); outstr("There were "); outdec(errcnt); /* total # errors */ outstr(" errors in compilation."); nl(); } int argcnt, /* # arguments on command line */ filenum, /* next argument to be used */ argv[20]; /* pointers to arguments in args[] */ char *args; /* stored arguments */ nextarg(n,s,size) /* places in s the n-th argument (up to "size" bytes). If successful, returns s. Returns -1 if the n-th argument doesn't exist. */ int n; char *s; int size; { char *str; int i; if(n<0|n>=argcnt) return -1; i=0; str=argv[n]; while(++i>>>>> 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 */ } /* */ /* 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 */ i, /* ident of an argument jrvz 8/6/82 */ *prevarg; /* pointer to the symbol table entry for the most recent argument jrvz 8/6/82 */ int lgh, /* size (bytes) of an argument jrvz 8/6/82 */ where, /* offset to argument in stack (zero for last argument) jrvz 8/6/82 */ *iptr; /* temporary ptr for stepping along argument chain jrvz 8/6/82 */ 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; /* 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); 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"); if(profile) /* call count jrvz 8/21/83 */ {printlabel(lastfct); col(); defword(); printlabel(lastfct=getlabel()); nl(); defbyte(); ol("0,0,0"); } if(trace|profile) {printlabel(fname=getlabel());col(); defbyte();outbyte(39); outstr(currfn+name); outasm("\',0"); nl(); } outname(n);col();nl(); /* print function name */ locptr=STARTLOC; /* "clear" local symbol table */ prevarg=0; /* initialize ptr to prev argument jrvz 8/6/82 */ undeclared=0; /* init arg count */ while(match(")")==0) /* then count args */ /* any legal name bumps arg count */ {if(symname(n)) {if(findloc(n))multidef(n); else {prevarg=addloc(n,0,cint,prevarg); /* add link to argument chain jrvz 8/6/82 */ undeclared++; /* jrvz 8/6/82 */ } } 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; } Zsp=0; /* preset stack ptr */ if(trace) /* jrvz 8/21/83 */ {caller=Zsp=Zsp-2; immed(); printlabel(fname); nl(); zpush(); callrts("ccregis"); } while(undeclared) /* 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 if(amatch("double",6)) {getarg(DOUBLE);ns();} /* jrvz 8/5/82 */ else{error("wrong number args");break;} } /* offset calculation rewritten jrvz 6/8/82 */ where=2; while(prevarg) {lgh=2; /* all arguments except DOUBLE have length 2 bytes (even char) */ if(prevarg[type]==DOUBLE)lgh=6; i=prevarg[ident]; if(i==pointer)lgh=2; iptr=prevarg+offset; prevarg=*iptr; /* follow ptr to prev. arg */ *iptr=where; /* insert offset */ where=where+lgh; /* calculate next offset */ } if(statement()!=streturn) /* do a statement, but if */ /* it's a return, skip */ /* cleaning up the stack */ leave(); Zsp=0; /* reset stack ptr again */ locptr=STARTLOC; /* deallocate all locals */ dumplits(); /* dump the literal pool for this function */ litlab=getlabel(); litptr=0; /* re-initialize pool */ /* literal dump added 6/21/82 jrvz */ 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, cint or DOUBLE jrvz 8/5/82 */ int t; { char n[namesize],c,*argptr; int j,legalname; /* "address" removed jrvz 8/6/82 */ while(undeclared) /* jrvz 8/6/82 */ {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 of the name */ {argptr[ident]=j; argptr[type]=t; /* address calculation removed jrvz 8/6/82 */ } else error("expecting argument name"); } undeclared--; /* cnt down jrvz 8/6/82 */ 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() { if(cpm(11,0) & 1) /* check for ctrl-C gtf 7/17/80 */ if(getchar()==3) abort(); if ((ch()==0) & (eof)) return; else if(amatch("char",4)) {declloc(cchar);ns();} else if(amatch("int",3)) {declloc(cint);ns();} else if(amatch("double",6)) {declloc(DOUBLE);ns();} /* jrvz 8/5/82 */ 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" sta/* */ 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 */ jump(wq[wqloop]); /* loop to label */ printlabel(wq[wqlab]);col();nl(); /* exit label */ locptr=wq[wqsym]; /* deallocate locals */ Zsp=modstk(wq[wqsp]); /* clean up stk ptr */ delwhile(); /* delete queue entry */ } /* */ /* "return" statement */ /* */ doreturn() { /* if not end of statement, get an expression */ if(endst()==0)force(currfn[type],expression()); /* added type coersion jrvz 10/10/82 */ leave(); } /* */ /* leave a function */ /* */ leave() {if(trace) callrts("ccleavi");/*jrvz 8/21/83*/ 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) {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 heirb, 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) */ { char sym[SYMSIZ]; int nargs; nargs=0; blanks(); /* already saw open paren */ if(ptr==0)zpush(); /* calling HL */ while(streq(line+lptr,")")==0) {if(endst())break; if(expression()==DOUBLE) /* jrvz 8/6/82 */ {if(ptr==0)dpush2(); /* save addr */ else dpush(); nargs=nargs+6; } else {if(ptr==0)swapstk(); /* save addr */ zpush(); /* push argument */ nargs=nargs+2; /* count args*2 */ } if (match(",")==0) break; } needbrack(")"); if(ptr) {if(nospread(ptr)) {ot("LD A,"); outdec(nargs>>1); nl(); } zcall(ptr); } else callstk(); Zsp=modstk(Zsp+nargs); /* clean up arguments */ } nospread(sym) char sym[]; { if(astreq(sym,"printf",6))return 1; if(astreq(sym,"fprint",6))return 1; if(astreq(sym,"sprintf",7))return 1; if(astreq(sym,"scanf",5))return 1; if(astreq(sym,"fscan",5))return 1; if(astreq(sym,"sscanf",6))return 1; return 0; } 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"); } hash(sname) char *sname; { int h,c; h=*sname; while(c=*(++sname)) h=(h<<1)+c; return h; } findglb(sname) /* cptr is set to entry if found, or appropriate empty slot if not */ char *sname; { int h; h=hash(sname)&MASKGLBS; cptr=STARTGLB+h*SYMSIZ; while(0==astreq(sname,cptr,namemax)){ if(*cptr==0) return 0; cptr=cptr+SYMSIZ; if(cptr==ENDGLB)cptr=STARTGLB; } return cptr; } 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(findglb(sname))return cptr; /* declare exported name */ if(id!=MACRO){ot("global "); outname(sname); nl();} if(glbptr>=ENDGLB) {error("global symbol table overflow"); return 0; } ptr=cptr; while(an(*ptr++ = *sname++)); /* copy name */ cptr[ident]=id; cptr[type]=typ; cptr[storage]=statik; cptr[offset]=value; cptr[offset+1]=value>>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) /* rewritten for speed 10/24/82 jrvz */ char c; { c=c&127; if(c>='a') return (c<='z'); if(c<='Z') return (c>='A'); return (c=='_'); } /* Test if given character is numeric */ numeric(c) char c; { c=c&127; if(c<='9') return(c>='0'); return 0; } /* Test if given character is alphanumeric */ an(c) /* rewritten for speed 11/10/82 jrvz */ char c; { if(alpha(c)) return 1; return 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 (k0) {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(inpt2)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)error("line too long"); lptr=mptr=0; while(line[lptr++]=mline[mptr++]); lptr=0; } addmac() { char sname[namesize]; if(symname(sname)==0) {illname(); kill(); return; } addglb(sname,MACRO,0,macptr); /* call replaced code which moved the name into the macro table 6/19/82 jrvz */ while(ch()==' ' | ch()==9) gch(); while(putmac(gch())); if(macptr>=macmax)error("macro table full"); } putmac(c) char c; { macq[macptr]=c; if(macptr9) {outd2(n/10); n=n%10;} outbyte('0'+n); } /* 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') {if(c<='z') c = c - 32; /* 'a'-'A'=32 */ } return(c); /* end raise */} #include c80v-2.c  .