home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 156_01 / c80v.c < prev    next >
Text File  |  1985-08-21  |  40KB  |  1,636 lines

  1. /************************************************/
  2. /*                        */
  3. /*        small-c compiler        */
  4. /*                        */
  5. /*          by Ron Cain            */
  6. /*          and James Van Zandt        */
  7. /*                        */
  8. /************************************************/
  9.  
  10. #define VERSION "     2 August 1984"
  11. /*    history...
  12.         2 Aug 84  Allocating symbol table and literal
  13.             pool from heap.
  14.         31 Jul 84  No GLOBAL directives for macros.
  15.         30 Jul 84  Input file extension capitalized.
  16.          29 Jul 84  Displaying input file names.
  17.         28 Jul 84  Getting file names and options from
  18.             command line.
  19.         14 Jul 84  outdec() is now recursive & smaller.
  20.             raise() not called, since ZMAC converts
  21.             to upper case. When profiling, the
  22.             appropriate GLOBAL statements are
  23.             automagically emitted.
  24.         28 Jun 84  Adding CR after GLOBAL statement.
  25.         25 Jun 84  In addglb(), generating GLOBAL
  26.     statement. Generating 9 character labels (so 1st 8
  27.     characters in a c symbol name are significant).
  28.     Allowing 800 bytes of literals per function.
  29.         2 Sept 83  In doreturn(), changed 'ccleavin'
  30.     to 'ccleavi'.  Introduced 'leave'. 'numeric' &
  31.     'outbyte' optimized. Optimized: 'nch', 'gch', 'keepch',
  32.     'streq', 'astreq', 'raise'.
  33.         1 Sept 83  Initializing firstfct & lastfct
  34.     after calling ask().  Trace & profile enabled together.
  35.         27 Aug 83  Allowing 3 bytes for call count.
  36.         26 Aug 83  renamed: leaving => ccleavi,
  37.     registe => ccregis. Added code to link the call count
  38.     cells (main, header, trailer, newfunction).
  39.         22 Aug 83  converted "," to "'", corrected
  40.     loading of name pointer.
  41.         21 Aug 83  Trace and profile are available.
  42.     Using clibv.h & a:float.h
  43.         1 Aug 83  6 function names are now
  44.     "nospread", A now set to # words on stack rather
  45.     than adding another parameter. 
  46.         29 Mar 83  "callfunction" now reserves
  47.     symsize bytes rather than namesize bytes for sym.
  48.     When "printf" is called, the top word on the stack
  49.     points to the first argument.
  50.         7 Mar 83  "callfunction" now adds pointer
  51.     to first argument for nospread functions. "nospread"
  52.     introduced (returns true only for "printf").
  53.         10 Nov 82  Rewrote "an" for speed.
  54.         24 Oct 82  In "preprocess", searching macro
  55.     table only with strings beginning with alpha. (Allows
  56.     long numeric literals.) Rewrote "alpha" for speed.
  57.         10 Oct 82  Updated date in signon message.
  58.     Coersing function values to proper type.
  59.         4 Sept 82  Generating colons again.
  60.         3 Sep 82  "#includ"ing floating point
  61.     library.
  62.         30 Aug 82  Changed "number" calling sequence
  63.     back. Colons are optional.
  64.         12 Aug 82  Changed "number" calling sequence.
  65.         11 Aug 82  Allowing typed function
  66.     declarations.
  67.         7 Aug 82  Correct length of double in
  68.     local variables, preserving calling addr when
  69.     calling through TOS & using double argument.
  70.         5 Aug 82 Started installing floating point
  71.         3 Aug 82    generating no colons
  72.     after labels. Generating only 7 character labels.
  73.         20 Jul 82    Removed the unused
  74.     variable "iptr".
  75.         18 Jul 82    Changed comment
  76.     recognizer per J. E. Hendrix (ddj n56 p6).
  77.         17 Jul 82    Implemented \" and
  78.     \' sequences.  Corrected newfunc & getarg per
  79.     P. L. Woods (ddj n52 p32) & J. E. Hendrix (ddj n56 p6).
  80.         14 Jul 82    "#include"ing
  81.     clibv.asm & c80v-2.c
  82.         28 Jun 82    Skipping first byte
  83.     in macro table, so index won't be zero.
  84.         27 Jun 82    Masking out high
  85.     order bits of characters extracted from
  86.     a symbol table entry.
  87.         21 Jun 82    Dumping literals
  88.     at end of each function, per Rodney Black
  89.     (DDJ n61 p51).
  90.         19 Jun 82    Updated symtabsiz.
  91.     Updated dumpglbs to handle new symbol table.
  92.     Placing macro names in global symbol table,
  93.     using smaller macro table.
  94.         16 Jun 82    using hash table
  95.     for global symbols.
  96.         18 Apr 81    Changed names so
  97.     first 5 characters are unique:
  98.     heir10 => heira        heir11 => heirb
  99.     input2 => inpt2        errorsum => errsum
  100. */
  101. #include iolib.h
  102. #include float.h
  103.  
  104. #define BANNER  "* * *  Small-C  V1.2  * * *"
  105.  
  106. #define AUTHOR "       By Ron Cain  and  James Van Zandt"
  107.  
  108. /*    Define system dependent parameters    */
  109.  
  110. /*    Stand-alone definitions            */
  111.  
  112. #define NULL 0
  113. #define EOL 13
  114.  
  115. /*    UNIX definitions (if not stand-alone)    */
  116.  
  117. /* #include <stdio.h>    */
  118. /* #define EOL 10    */
  119.  
  120. /*    Define the symbol table parameters    */
  121.  
  122. #define    SYMSIZ    14
  123. #define    SYMTBSZ    8008
  124. /*            =14*(NUMGLBS+60)    */
  125. #define NUMGLBS 512
  126. #define MASKGLBS 511
  127. /*            formerly 300 globals    */
  128. #define    STARTGLB symtab
  129. #define    ENDGLB    STARTGLB+NUMGLBS*SYMSIZ
  130. #define    STARTLOC ENDGLB+SYMSIZ
  131. #define    ENDLOC    symtab+SYMTBSZ-SYMSIZ
  132.  
  133. /*    Define symbol table entry format    */
  134.  
  135. #define    name    0
  136. #define    ident    9
  137. #define    type    10
  138. #define    storage    11
  139. #define    offset    12
  140.  
  141. /*    System wide name size (for symbols)    */
  142.  
  143. #define    namesize 9
  144. #define namemax  8
  145.  
  146. /*    Define possible entries for "ident"    */
  147.  
  148. #define    variable 1
  149. #define    array    2
  150. #define    pointer    3
  151. #define    function 4
  152. #define MACRO 5
  153.             /* added 6/19/82, JRVZ */
  154.  
  155. /*    Define possible entries for "type"    */
  156.  
  157. #define    cchar    1
  158. #define    cint    2
  159. #define DOUBLE    3
  160.  
  161. /*    Define possible entries for "storage"    */
  162.  
  163. #define    statik    1
  164. #define    stkloc    2
  165.  
  166. /*    Define the "while" statement queue    */
  167.  
  168. #define    wqtabsz    100
  169. #define    wqsiz    4
  170. #define    wqmax    wq+wqtabsz-wqsiz
  171.  
  172. /*    Define entry offsets in while queue    */
  173.  
  174. #define    wqsym    0
  175. #define    wqsp    1
  176. #define    wqloop    2
  177. #define    wqlab    3
  178.  
  179. /*    Define the literal pool            */
  180.  
  181. #define    litabsz 1000
  182. /*        formerly 2000            */
  183. #define    litmax    litabsz-1
  184.  
  185. /*    Define the input line            */
  186.  
  187. #define    linesize 80
  188. #define    linemax    linesize-1
  189. #define    mpmax    linemax
  190.  
  191. /*    Define the macro (define) pool        */
  192.  
  193. #define    macqsize 500
  194. /*            formerly 1000   JRVZ 6/19/82  */
  195. #define    macmax    macqsize-1
  196.  
  197. /*    Define statement types (tokens)        */
  198.  
  199. #define    stif    1
  200. #define    stwhile    2
  201. #define    streturn 3
  202. #define    stbreak    4
  203. #define    stcont    5
  204. #define    stasm    6
  205. #define    stexp    7
  206.  
  207. /* Define how to carve up a name too long for the assembler */
  208.  
  209. #define ASMPREF    8
  210. #define ASMSUFF    0
  211.  
  212. /*    Now reserve some storage words        */
  213.  
  214. char    *symtab;        /* symbol table */
  215. char    *glbptr,*locptr;    /* ptrs to next entries */
  216.  
  217. int    wq[wqtabsz];        /* while queue */
  218. int    *wqptr;            /* ptr to next entry */
  219.  
  220. char    *litq;            /* literal pool */
  221. int    litptr;            /* ptr to next entry */
  222.  
  223. char    macq[macqsize];        /* macro string buffer */
  224. int    macptr;            /* and its index */
  225.  
  226. char    line[linesize];        /* parsing buffer */
  227. char    mline[linesize];    /* temp macro buffer */
  228. int    lptr,mptr;        /* ptrs into each */
  229.  
  230. /*    Misc storage    */
  231.  
  232. int    nxtlab,        /* next avail label # */
  233.     litlab,        /* label # assigned to literal pool */
  234.     Zsp,        /* compiler relative stk ptr */
  235.     undeclared,    /* # function arguments
  236.             not yet declared  jrvz 8/6/82 */
  237.     ncmp,        /* # open compound statements */
  238.     errcnt,        /* # errors in compilation */
  239.     errstop,    /* stop on error            gtf 7/17/80 */
  240.     eof,        /* set non-zero on final input eof */
  241.     input,        /* iob # for input file */
  242.     output,        /* iob # for output file (if any) */
  243.     inpt2,        /* iob # for "include" file */
  244.     glbflag,    /* non-zero if internal globals */
  245.     ctext,        /* non-zero to intermix c-source */
  246.     cmode,        /* non-zero while parsing c-code */
  247.             /* zero when passing assembly code */
  248.     lastst,        /* last executed statement type */
  249.     mainflg,    /* output is to be first asm filegtf 4/9/80 */
  250.     saveout,    /* holds output ptr when diverted to console       */
  251.             /*                gtf 7/16/80 */
  252.     fnstart,    /* line# of start of current fn.gtf 7/2/80 */
  253.     lineno,        /* line# in current file    gtf 7/2/80 */
  254.     infunc,        /* "inside function" flag    gtf 7/2/80 */
  255.     savestart,    /* copy of fnstart "    "    gtf 7/16/80 */
  256.     saveline,    /* copy of lineno  "    "    gtf 7/16/80 */
  257.     saveinfn,    /* copy of infunc  "    "    gtf 7/16/80 */
  258.     trace,        /* nonzero if traceback info needed
  259.                         jrvz 8/21/83    */
  260.     profile,    /* nonzero if profile needed      */
  261.     caller,        /* stack offset for caller links...
  262.         local[caller] points to name of current fct
  263.         local[caller-1] points to link for calling fct,
  264.         where local[0] is 1st word on stack after ret addr  */
  265.     firstfct,    /* label for 1st function */
  266.     lastfct,    /* label for most recent fct  jrvz 8/83 */
  267.     fname;        /* label for name of current fct  */
  268. char   *currfn,        /* ptr to symtab entry for current fn.    gtf 7/17/80 */
  269.        *savecurr;    /* copy of currfn for #include        gtf 7/17/80 */
  270. char    quote[2];    /* literal string for '"' */
  271. char    *cptr;        /* work ptr to any char buffer */
  272.  
  273. /*    >>>>> start cc1 <<<<<<        */
  274.  
  275. /*                    */
  276. /*    Compiler begins execution here    */
  277. /*                    */
  278. main()
  279.     {
  280.     litq=alloc(litabsz);    /* literal pool */
  281.     symtab=alloc(SYMTBSZ);    /* allocate symbol table */
  282.     glbptr=STARTGLB;
  283.     while(glbptr<ENDGLB){
  284.         *glbptr=0;
  285.         glbptr=glbptr+SYMSIZ;
  286.     }
  287.     glbptr=STARTGLB+SYMSIZ*5; /* clear global symbols */
  288.     locptr=STARTLOC;    /* clear local symbols */
  289.     wqptr=wq;        /* clear while queue */
  290.     litptr=        /* clear literal pool */
  291.       Zsp =        /* stack ptr (relative) */
  292.     errcnt=        /* no errors */
  293.     errstop=    /* keep going after an error        gtf 7/17/80 */
  294.     eof=        /* not eof yet */
  295.     input=        /* no input file */
  296.     inpt2=        /* or include file */
  297.     output=        /* no open units */
  298.     saveout=    /* no diverted output */
  299.     ncmp=        /* no open compound states */
  300.     lastst=        /* not first file to asm  gtf 4/9/80 */
  301.     fnstart=    /* current "function" started
  302.                 at line 0 gtf 7/2/80 */
  303.     lineno=        /* no lines read from file        gtf 7/2/80 */
  304.     infunc=        /* not in function now            gtf 7/2/80 */
  305.     quote[1]=
  306.     0;        /*  ...all set to zero.... */
  307.     quote[0]='"';        /* fake a quote literal */
  308.     currfn=NULL;    /* no function yet            gtf 7/2/80 */
  309.     macptr=        /* clear macro pool   jrvz 6/28/82 */
  310.     cmode=1;    /* enable preprocessing */
  311.     /*                */
  312.     /*    compiler body        */
  313.     /*                */
  314.     ask();            /* get user options */
  315.     lastfct=firstfct=getlabel(); /* jrvz 8/26/83 */
  316.     openout();        /* get an output file */
  317.     openin();        /* and initial input file */
  318.     header();        /* intro code */
  319.     parse();         /* process ALL input */
  320. /*    dumplits();        deleted 6/21/82  jrvz */
  321.     dumpglbs();        /* define static variables */
  322.     trailer();        /* follow-up code */
  323.     closeout();        /* close the output (if any) */
  324.     errsummary();        /* summarize errors */
  325.     return;            /* then exit to system */
  326.     }
  327.  
  328. /*                    */
  329. /*    Abort compilation        */
  330. /*        gtf 7/17/80        */
  331. abort()
  332. {
  333.     if(inpt2)
  334.         endinclude();
  335.     if(input)
  336.         fclose(input);
  337.     closeout();
  338.     toconsole();
  339.     pl("Compilation aborted.");  nl();
  340.     exit();
  341. /* end abort */}
  342.  
  343. /*                    */
  344. /*    Process all input text        */
  345. /*                    */
  346. /* At this level, only static declarations, */
  347. /*    defines, includes, and function */
  348. /*    definitions are legal...    */
  349. parse()
  350.     {
  351.     while (eof==0)        /* do until no more input */
  352.         {
  353.         if(amatch("char",4)){declglb(cchar);ns();}
  354.         else if(amatch("int",3)){declglb(cint);ns();}
  355.         else if(amatch("double",6))  /* jrvz 8/5/82 */
  356.             {declglb(DOUBLE);ns();}
  357.         else if(match("#asm"))doasm();
  358.         else if(match("#include"))doinclude();
  359.         else if(match("#define"))addmac();
  360.         else newfunc();
  361.         blanks();    /* force eof if pending */
  362.         }
  363.     }
  364. /*                    */
  365. /*    Dump the literal pool        */
  366. /*                    */
  367. dumplits()
  368.     {int j,k;
  369.     if (litptr==0) return;    /* if nothing there, exit...*/
  370.     printlabel(litlab);col(); /* print literal label */
  371.     k=0;            /* init an index... */
  372.     while (k<litptr)    /*     to loop with */
  373.         {defbyte();    /* pseudo-op to define byte */
  374.         j=10;        /* max bytes per line */
  375.         while(j--)
  376.             {outdec((litq[k++]&255));
  377.             /* now masking with 255 instead of 127
  378.             so floating constants can be put
  379.             in the literal pool  jrvz 9/4/82 */
  380.             if ((j==0) | (k>=litptr))
  381.                 {nl();        /* need <cr> */
  382.                 break;
  383.                 }
  384.             outbyte(',');    /* separate bytes */
  385.             }
  386.         }
  387.     }
  388. /*                    */
  389. /*    Dump all static variables    */
  390. /*                    */
  391. dumpglbs()
  392.     {
  393.     int i,j;
  394.     if(glbflag==0)return;    /* don't if user said no */
  395.     cptr=STARTGLB;
  396.     i=NUMGLBS;
  397.     while(i--){  /* 6/19/82  jrvz */
  398.         if(*cptr){
  399.         if((cptr[ident]!=function)
  400.         &(cptr[ident]!=MACRO))  /* 6/19/82  jrvz */
  401.             /* do if anything but function
  402.                 or macro */
  403.             {outname(cptr);col();
  404.                 /* output name as label... */
  405.             defstorage();    /* define storage */
  406.             j=((cptr[offset]&255)+
  407.                 ((cptr[offset+1]&255)<<8));
  408.                     /* calc # bytes */
  409.             if((cptr[type]==cint)|
  410.                 (cptr[ident]==pointer))
  411.                 j=j+j;
  412.             else if(cptr[type]==DOUBLE)
  413.                 j=j*6;  /* jrvz 8/5/82 */
  414.             outdec(j);    /* need that many */
  415.             nl();
  416.             }
  417.         }
  418.         cptr=cptr+SYMSIZ;
  419.         }
  420.     }
  421. /*                    */
  422. /*    Report errors for user        */
  423. /*                    */
  424. errsummary()
  425.     {
  426.     /* see if anything left hanging... */
  427.     if (ncmp) error("missing closing bracket");
  428.         /* open compound statement ... */
  429.     nl();
  430.     outstr("There were ");
  431.     outdec(errcnt);    /* total # errors */
  432.     outstr(" errors in compilation.");
  433.     nl();
  434.     }
  435.  
  436. int argcnt,        /* # arguments on command line */
  437. filenum,    /* next argument to be used */
  438. argv[20];    /* pointers to arguments in args[] */
  439. char *args;    /* stored arguments */
  440.  
  441. nextarg(n,s,size) /* places in s the n-th argument (up to "size"
  442.         bytes). If successful, returns s. Returns -1
  443.         if the n-th argument doesn't exist. */
  444. int n; char *s; int size;
  445. {    char *str;
  446.     int i;
  447.  
  448.     if(n<0|n>=argcnt) return -1;
  449.     i=0;
  450.     str=argv[n];
  451.     while(++i<size)
  452.         {if((*s++=*str++)==NULL) break;
  453.         }
  454.     return s;
  455. }
  456. ask()        /* fetch arguments */
  457. {    char *count,    /* *count is # characters in command line */
  458.     c,    /* an option character */
  459.     *ptr,    /* *ptr is next character in command line */
  460.     *lastc,    /* points to last character in command line */
  461.     *next;    /* where the next byte goes in args[] */
  462.  
  463.     kill();            /* clear input line */
  464.     pl(BANNER);        /* print banner */
  465.     nl();
  466.     pl(AUTHOR);
  467. /*    nl();nl();
  468.     pl("Distributed by: The Code Works(tm)");
  469.     pl("                Box 550, Goleta, CA 93017");
  470. */
  471.     nl();
  472.     pl(VERSION);
  473.     nl();
  474.     nl();
  475.     nxtlab =0;    /* start numbers at lowest possible */
  476.         /* initialize the options */
  477.     ctext=0;    /* don't include the C text as comments */
  478.     glbflag=1;    /* define globals */
  479.     mainflg=1;    /* this file contains main() */
  480.     errstop=0;    /* don't stop after errors */
  481.     profile=trace=0; /* no profile or tracing */
  482.     count=128;    /* CP/M command buffer */
  483.     ptr=count+1;
  484.     lastc=ptr+*count;
  485.     *lastc=' ';        /* place a sentinal */
  486.     args=alloc(*count);    /* allocate the buffer */
  487.     argv[0]=args;
  488.     next=args;
  489.     argcnt=0;
  490.     while(++ptr<lastc)
  491.         {if(*ptr==' ') continue;
  492.         if(*ptr=='-')        /* option */
  493.             {c=*++ptr;
  494.             if(c=='C') ctext=1;
  495.             else if(c=='G') glbflag=0;
  496.             else if(c=='M') mainflg=0;
  497.             else if(c=='E') errstop=1;
  498.             else if(c=='P') profile=trace=1;
  499.             while(++*ptr!=' ') {}
  500.             }
  501.         else            /* file name */
  502.             {argv[argcnt++]=next;
  503.             while(*ptr!=' ') *next++=*ptr++;
  504.             *next++=NULL;
  505.             }
  506.         }
  507.     litlab=getlabel();    /* first label=literal pool */ 
  508.     kill();            /* erase line */
  509. }
  510.  
  511. /*                    */
  512. /*    Get output filename        */
  513. /*                    */
  514. openout()
  515.     {kill();        /* erase line */
  516.     filenum=output=0;    /* start with none */
  517.     if(nextarg(filenum,line,16)==-1) return;
  518.     append(line,".asm");
  519.     if((output=fopen(line,"w"))==NULL) /* if given, open */
  520.         {output=0;    /* can't open */
  521.         error("Can't open output file!");
  522.         }
  523.     kill();            /* erase line */
  524. }
  525.  
  526. /*                    */
  527. /*    Get (next) input file        */
  528. /*                    */
  529. openin()
  530. {
  531.     input=0;        /* none to start with */
  532.     while(input==0){    /* any above 1 allowed */
  533.         kill();        /* clear line */
  534.         if(eof)break;    /* if user said none */
  535.         if(nextarg(filenum++,line,16)==-1)
  536.             {eof=1;break;} /* none given... */
  537.         append(line,".C");
  538.         pl(line); pl("\n");
  539.         if((input=fopen(line,"r"))!=NULL)
  540.             newfile();    /* gtf 7/16/80 */
  541.         else {    input=0;    /* can't open it */
  542.             pl("CAN'T OPEN ");
  543.             }
  544.         }
  545.     kill();        /* erase line */
  546.     }
  547.  
  548. append(s,t) char *s,*t;    /* append t to s */
  549. {    while(*s) ++s;        /* scan to end of s */
  550.     while(*s++=*t++){}    /* append t */
  551. }
  552.  
  553. /*                    */
  554. /*    Reset line count, etc.        */
  555. /*            gtf 7/16/80    */
  556. newfile()
  557. {
  558.     lineno  = 0;    /* no lines read */
  559.     fnstart = 0;    /* no fn. start yet. */
  560.     currfn  = NULL;    /* because no fn. yet */
  561.     infunc  = 0;    /* therefore not in fn. */
  562. /* end newfile */}
  563.  
  564. /*                    */
  565. /*    Open an include file        */
  566. /*                    */
  567. doinclude()
  568. {
  569.     blanks();    /* skip over to name */
  570.  
  571.     toconsole();                    /* gtf 7/16/80 */
  572.     outstr("#include "); outstr(line+lptr); nl();
  573.     tofile();
  574.  
  575.     if(inpt2)                    /* gtf 7/16/80 */
  576.         error("Cannot nest include files");
  577.     else if((inpt2=fopen(line+lptr,"r"))==NULL)
  578.         {inpt2=0;
  579.         error("Open failure on include file");
  580.         }
  581.     else {    saveline = lineno;
  582.         savecurr = currfn;
  583.         saveinfn = infunc;
  584.         savestart= fnstart;
  585.         newfile();
  586.         }
  587.     kill();        /* clear rest of line */
  588.             /* so next read will come from */
  589.             /* new file (if open */
  590. }
  591.  
  592. /*                    */
  593. /*    Close an include file        */
  594. /*            gtf 7/16/80    */
  595. endinclude()
  596. {
  597.     toconsole();
  598.     outstr("#end include"); nl();
  599.     tofile();
  600.  
  601.     inpt2  = 0;
  602.     lineno  = saveline;
  603.     currfn  = savecurr;
  604.     infunc  = saveinfn;
  605.     fnstart = savestart;
  606. /* end endinclude */}
  607.  
  608. /*                    */
  609. /*    Close the output file        */
  610. /*                    */
  611. closeout()
  612. {
  613.     tofile();    /* if diverted, return to file */
  614.     if(output)fclose(output); /* if open, close it */
  615.     output=0;        /* mark as closed */
  616. }
  617. /*                    */
  618. /*    Declare a static variable    */
  619. /*      (i.e. define for use)        */
  620. /*                    */
  621. /* makes an entry in the symbol table so subsequent */
  622. /*  references can call symbol by name    */
  623. declglb(typ)    /* typ is cchar, cint or DOUBLE jrvz 8/5/82 */
  624.     int typ;
  625. {    int k,j;char sname[namesize];
  626.     while(1)
  627.         {while(1)
  628.             {if(endst())return;    /* do line */
  629.             k=1;        /* assume 1 element */
  630.             if(match("*"))    /* pointer ? */
  631.                 j=pointer;    /* yes */
  632.                 else j=variable; /* no */
  633.              if (symname(sname)==0) /* name ok? */
  634.                 illname(); /* no... */
  635.             if(findglb(sname)) /* already there? */
  636.                 multidef(sname);
  637.             if (match("["))        /* array? */
  638.                 {k=needsub();    /* get size */
  639.                 if(k)j=array;    /* !0=array */
  640.                 else j=pointer; /* 0=ptr */
  641.                 }
  642.             if (match("("))    /* function?  */
  643.                 {k=0;
  644.                 j=function;
  645.                 needbrack(")");
  646.                 }    /* jrvz 8/11/82 */
  647.             addglb(sname,j,typ,k); /* add symbol */
  648.             break;
  649.             }
  650.         if (match(",")==0) return; /* more? */
  651.         }
  652.     }
  653. /*                    */
  654. /*    Declare local variables        */
  655. /*    (i.e. define for use)        */
  656. /*                    */
  657. /* works just like "declglb" but modifies machine stack */
  658. /*    and adds symbol table entry with appropriate */
  659. /*    stack offset to find it again            */
  660. declloc(typ)    /* typ is cchar, cint or DOUBLE jrvz 8/5/82 */
  661.     int typ;
  662.     {
  663.     int k,j;char sname[namesize];
  664.     while(1)
  665.         {while(1)
  666.             {if(endst())return;
  667.             if(match("*"))
  668.                 j=pointer;
  669.                 else j=variable;
  670.             if (symname(sname)==0)
  671.                 illname();
  672.             if(findloc(sname))
  673.                 multidef(sname);
  674.             if (match("["))
  675.                 {k=needsub();
  676.                 if(k)
  677.                     {j=array;
  678.                     if(typ==cint)k=k+k;
  679.                     else if(typ==DOUBLE)k=k*6;
  680.                     /* jrvz 8/5/82 */
  681.                     }
  682.                 else
  683.                     {j=pointer;
  684.                     k=2;
  685.                     }
  686.                 }
  687.             else
  688.                 if((typ==cchar)&(j!=pointer))
  689.                 k=1;
  690.                 else if((typ==DOUBLE)&(j!=pointer))
  691.                 k=6;    /* jrvz 8/7/82 */
  692.                 else k=2;
  693.             /* change machine stack */
  694.             Zsp=modstk(Zsp-k);
  695.             addloc(sname,j,typ,Zsp);
  696.             break;
  697.             }
  698.         if (match(",")==0) return;
  699.         }
  700.     }
  701. /*    >>>>>> start of cc2 <<<<<<<<    */
  702.  
  703. /*                    */
  704. /*    Get required array size        */
  705. /*                    */
  706. /* invoked when declared variable is followed by "[" */
  707. /*    this routine makes subscript the absolute */
  708. /*    size of the array. */
  709. needsub()
  710.     {
  711.     int num[1];
  712.     if(match("]"))return 0;    /* null size */
  713.     if (number(num)==0)
  714.             /* go after a number */
  715.         {error("must be constant");    /* it isn't */
  716.         num[0]=1;        /* so force one */
  717.         }
  718.     if (num[0]<0)
  719.         {error("negative size illegal");
  720.         num[0]=(-num[0]);
  721.         }
  722.     needbrack("]");        /* force single dimension */
  723.     return num[0];        /* and return size */
  724.     }
  725. /*                    */
  726. /*    Begin a function        */
  727. /*                    */
  728. /* Called from "parse" this routine tries to make a function */
  729. /*    out of what follows.    */
  730. newfunc()
  731.     {
  732.     char n[namesize], /* ptr => currfn,  gtf 7/16/80 */
  733.     i,        /* ident of an argument  jrvz 8/6/82 */
  734.     *prevarg;    /* pointer to the symbol table entry
  735.         for the most recent argument jrvz 8/6/82 */
  736.     int lgh,    /* size (bytes) of an argument
  737.                 jrvz 8/6/82 */
  738.     where,        /* offset to argument in stack
  739.             (zero for last argument) jrvz 8/6/82 */
  740.     *iptr;  /* temporary ptr for stepping along argument
  741.                     chain jrvz 8/6/82 */
  742.     if (symname(n)==0)
  743.         {error("illegal function or declaration");
  744.         kill();    /* invalidate line */
  745.         return;
  746.         }
  747.     fnstart=lineno;
  748.         /* remember where fn began    gtf 7/2/80 */
  749.     infunc=1;
  750.         /* note, in function now.    gtf 7/16/80 */
  751.     if(currfn=findglb(n))    /* already in symbol table ? */
  752.         {if(currfn[ident]!=function)multidef(n);
  753.             /* already variable by that name */
  754.         else if(currfn[offset]==function)multidef(n);
  755.             /* already function by that name */
  756.         else currfn[offset]=function;
  757.             /*  we have what was earlier*/
  758.             /*  assumed to be a function */
  759.         }
  760.     /* if not in table, define as a function now */
  761.     else currfn=addglb(n,function,cint,function);
  762.  
  763.     toconsole();            /* gtf 7/16/80 */
  764.     outstr("====== "); outstr(currfn+name); outstr("()");
  765.     nl(); tofile();
  766.  
  767.     /* we had better see open paren for args... */
  768.     if(match("(")==0)error("missing open paren");
  769.     if(profile)        /* call count  jrvz 8/21/83 */
  770.         {printlabel(lastfct); col(); defword();
  771.         printlabel(lastfct=getlabel()); nl();
  772.         defbyte(); ol("0,0,0");
  773.         }
  774.     if(trace|profile)
  775.         {printlabel(fname=getlabel());col();
  776.         defbyte();outbyte(39);
  777.         outstr(currfn+name); outasm("\',0"); nl();
  778.         }
  779.     outname(n);col();nl();    /* print function name */
  780.     locptr=STARTLOC;      /* "clear" local symbol table */
  781.     prevarg=0;  /* initialize ptr to prev argument
  782.                 jrvz 8/6/82 */
  783.     undeclared=0;        /* init arg count */
  784.     while(match(")")==0)    /* then count args */
  785.         /* any legal name bumps arg count */
  786.         {if(symname(n))
  787.             {if(findloc(n))multidef(n);
  788.             else
  789.                 {prevarg=addloc(n,0,cint,prevarg);
  790.                 /* add link to argument chain
  791.                         jrvz 8/6/82 */
  792.                 undeclared++; /* jrvz 8/6/82 */
  793.                 }
  794.             }
  795.         else{error("illegal argument name");junk();}
  796.         blanks();
  797.         /* if not closing paren, should be comma */
  798.         if(streq(line+lptr,")")==0)
  799.             {if(match(",")==0)
  800.             error("expected comma");
  801.             }
  802.         if(endst())break;
  803.         }
  804.     Zsp=0;            /* preset stack ptr */
  805.     if(trace)        /* jrvz 8/21/83 */
  806.         {caller=Zsp=Zsp-2;
  807.         immed(); printlabel(fname); nl();
  808.         zpush();
  809.         callrts("ccregis");
  810.         }
  811.     while(undeclared)
  812.         /* now let user declare what types of things */
  813.         /*    those arguments were */
  814.         {if(amatch("char",4)){getarg(cchar);ns();}
  815.         else if(amatch("int",3)){getarg(cint);ns();}
  816.         else if(amatch("double",6))
  817.             {getarg(DOUBLE);ns();} /* jrvz 8/5/82 */
  818.         else{error("wrong number args");break;}
  819.         }
  820.     /* offset calculation rewritten  jrvz 6/8/82 */
  821.     where=2;
  822.     while(prevarg)
  823.         {lgh=2;  /* all arguments except DOUBLE
  824.             have length 2 bytes (even char) */
  825.         if(prevarg[type]==DOUBLE)lgh=6;
  826.         i=prevarg[ident];
  827.         if(i==pointer)lgh=2;
  828.         iptr=prevarg+offset;
  829.         prevarg=*iptr;  /* follow ptr to prev. arg */
  830.         *iptr=where;    /* insert offset */
  831.         where=where+lgh; /* calculate next offset */
  832.         }
  833.     if(statement()!=streturn) /* do a statement, but if */
  834.                 /* it's a return, skip */
  835.                 /* cleaning up the stack */
  836.         leave();
  837.     Zsp=0;            /* reset stack ptr again */
  838.     locptr=STARTLOC;    /* deallocate all locals */
  839.     dumplits();        /* dump the literal pool
  840.                 for this function */
  841.     litlab=getlabel();
  842.     litptr=0;        /* re-initialize pool */
  843.             /* literal dump added 6/21/82  jrvz */
  844.     infunc=0;        /* not in fn. any more
  845.                 gtf 7/2/80 */
  846.     }
  847. /*                    */
  848. /*    Declare argument types        */
  849. /*                    */
  850. /* called from "newfunc" this routine adds an entry in the */
  851. /*    local symbol table for each named argument */
  852. getarg(t)    /* t = cchar, cint or DOUBLE jrvz 8/5/82 */
  853.     int t;
  854.     {
  855.     char n[namesize],c,*argptr;
  856.     int j,legalname; /* "address" removed  jrvz 8/6/82 */
  857.     while(undeclared)  /* jrvz 8/6/82 */
  858.         {if(match("*"))j=pointer;
  859.             else j=variable;
  860.         if((legalname=symname(n))==0) illname();
  861.         if(match("["))    /* pointer ? */
  862.         /* it is a pointer, so skip all */
  863.         /* stuff between "[]" */
  864.             {while(inbyte()!=']')
  865.                 if(endst())break;
  866.             j=pointer;
  867.             /* add entry as pointer */
  868.             }
  869.         if(legalname)
  870.             {if(argptr=findloc(n))
  871.                 /* add in details of the type
  872.                 of the name */
  873.                 {argptr[ident]=j;
  874.                 argptr[type]=t;
  875.                 /* address calculation removed
  876.                     jrvz 8/6/82 */
  877.                 }
  878.             else error("expecting argument name");
  879.             }
  880.         undeclared--;    /* cnt down  jrvz 8/6/82 */
  881.         if(endst())return;
  882.         if(match(",")==0)error("expected comma");
  883.         }
  884.     }
  885. /*                    */
  886. /*    Statement parser        */
  887. /*                    */
  888. /* called whenever syntax requires    */
  889. /*    a statement.              */
  890. /*  this routine performs that statement */
  891. /*  and returns a number telling which one */
  892. statement()
  893. {
  894.     if(cpm(11,0) & 1)    /* check for ctrl-C        gtf 7/17/80 */
  895.         if(getchar()==3)
  896.             abort();
  897.  
  898.     if ((ch()==0) & (eof)) return;
  899.     else if(amatch("char",4))
  900.         {declloc(cchar);ns();}
  901.     else if(amatch("int",3))
  902.         {declloc(cint);ns();}
  903.     else if(amatch("double",6))
  904.         {declloc(DOUBLE);ns();} /* jrvz 8/5/82 */
  905.     else if(match("{"))compound();
  906.     else if(amatch("if",2))
  907.         {doif();lastst=stif;}
  908.     else if(amatch("while",5))
  909.         {dowhile();lastst=stwhile;}
  910.     else if(amatch("return",6))
  911.         {doreturn();ns();lastst=streturn;}
  912.     else if(amatch("break",5))
  913.         {dobreak();ns();lastst=stbreak;}
  914.     else if(amatch("continue",8))
  915.         {docont();ns();lastst=stcont;}
  916.     else if(match(";"));
  917.     else if(match("#asm"))
  918.         {doasm();lastst=stasm;}
  919.     /* if nothing else, assume it's an expression */
  920.     else{expression();ns();lastst=stexp;}
  921.     return lastst;
  922. }
  923. /*                    */
  924. /*    Semicolon enforcer        */
  925. /*                    */
  926. /* called whenever syntax requires a semicolon */
  927. ns()    {if(match(";")==0)error("missing semicolon");}
  928. /*                    */
  929. /*    Compound statement        */
  930. /*                    */
  931. /* allow any number of statements to fall between "{}" */
  932. compound()
  933.     {
  934.     ++ncmp;        /* new level open */
  935.     while (match("}")==0) statement(); /* do one */
  936.     --ncmp;        /* close current level */
  937.     }
  938. /*                    */
  939. /*        "if" sta/*                    */
  940. doif()
  941.     {
  942.     int flev,fsp,flab1,flab2;
  943.     flev=locptr;    /* record current local level */
  944.     fsp=Zsp;        /* record current stk ptr */
  945.     flab1=getlabel(); /* get label for false branch */
  946.     test(flab1);    /* get expression, and branch false */
  947.     statement();    /* if true, do a statement */
  948.     Zsp=modstk(fsp);    /* then clean up the stack */
  949.     locptr=flev;    /* and deallocate any locals */
  950.     if (amatch("else",4)==0)    /* if...else ? */
  951.         /* simple "if"...print false label */
  952.         {printlabel(flab1);col();nl();
  953.         return;        /* and exit */
  954.         }
  955.     /* an "if...else" statement. */
  956.     jump(flab2=getlabel());    /* jump around false code */
  957.     printlabel(flab1);col();nl();    /* print false label */
  958.     statement();        /* and do "else" clause */
  959.     Zsp=modstk(fsp);        /* then clean up stk ptr */
  960.     locptr=flev;        /* and deallocate locals */
  961.     printlabel(flab2);col();nl();    /* print true label */
  962.     }
  963. /*                    */
  964. /*    "while" statement        */
  965. /*                    */
  966. dowhile()
  967.     {
  968.     int wq[4];        /* allocate local queue */
  969.     wq[wqsym]=locptr;    /* record local level */
  970.     wq[wqsp]=Zsp;        /* and stk ptr */
  971.     wq[wqloop]=getlabel();    /* and looping label */
  972.     wq[wqlab]=getlabel();    /* and exit label */
  973.     addwhile(wq);        /* add entry to queue */
  974.                 /* (for "break" statement) */
  975.     printlabel(wq[wqloop]);col();nl(); /* loop label */
  976.     test(wq[wqlab]);    /* see if true */
  977.     statement();        /* if so, do a statement */
  978.     jump(wq[wqloop]);    /* loop to label */
  979.     printlabel(wq[wqlab]);col();nl(); /* exit label */
  980.     locptr=wq[wqsym];    /* deallocate locals */
  981.     Zsp=modstk(wq[wqsp]);    /* clean up stk ptr */
  982.     delwhile();        /* delete queue entry */
  983.     }
  984. /*                    */
  985. /*    "return" statement        */
  986. /*                    */
  987. doreturn()
  988.     {
  989.     /* if not end of statement, get an expression */
  990.     if(endst()==0)force(currfn[type],expression());
  991.         /* added type coersion jrvz 10/10/82 */
  992.     leave();
  993.     }
  994. /*                    */
  995. /*    leave a function        */
  996. /*                    */
  997. leave()
  998.     {if(trace) callrts("ccleavi");/*jrvz 8/21/83*/
  999.     modstk(0);    /* clean up stk */
  1000.     zret();        /* and exit function */
  1001.     }
  1002. /*                    */
  1003. /*    "break" statement        */
  1004. /*                    */
  1005. dobreak()
  1006.     {
  1007.     int *ptr;
  1008.     /* see if any "whiles" are open */
  1009.     if ((ptr=readwhile())==0) return;    /* no */
  1010.     modstk((ptr[wqsp]));    /* else clean up stk ptr */
  1011.     jump(ptr[wqlab]);    /* jump to exit label */
  1012.     }
  1013. /*                    */
  1014. /*    "continue" statement        */
  1015. /*                    */
  1016. docont()
  1017.     {
  1018.     int *ptr;
  1019.     /* see if any "whiles" are open */
  1020.     if ((ptr=readwhile())==0) return;    /* no */
  1021.     modstk((ptr[wqsp]));    /* else clean up stk ptr */
  1022.     jump(ptr[wqloop]);    /* jump to loop label */
  1023.     }
  1024. /*                    */
  1025. /*    "asm" pseudo-statement        */
  1026. /*                    */
  1027. /* enters mode where assembly language statement are */
  1028. /*    passed intact through parser    */
  1029. doasm()
  1030.     {
  1031.     cmode=0;        /* mark mode as "asm" */
  1032.     while (1)
  1033.         {inline();    /* get and print lines */
  1034.         if (match("#endasm")) break;    /* until... */
  1035.         if(eof)break;
  1036.         outstr(line);
  1037.         nl();
  1038.         }
  1039.     kill();        /* invalidate line */
  1040.     cmode=1;        /* then back to parse level */
  1041.     }
  1042. /*    >>>>> start of cc3 <<<<<<<<<    */
  1043.  
  1044. /*                    */
  1045. /*    Perform a function call        */
  1046. /*                    */
  1047. /* called from heirb, this routine will either call */
  1048. /*    the named function, or if the supplied ptr is */
  1049. /*    zero, will call the contents of HL        */
  1050. callfunction(ptr)
  1051.     char *ptr;    /* symbol table entry (or 0) */
  1052. {    char sym[SYMSIZ];
  1053.     int nargs;
  1054.     nargs=0;
  1055.     blanks();    /* already saw open paren */
  1056.     if(ptr==0)zpush();    /* calling HL */
  1057.     while(streq(line+lptr,")")==0)
  1058.         {if(endst())break;
  1059.         if(expression()==DOUBLE)  /* jrvz 8/6/82 */
  1060.             {if(ptr==0)dpush2(); /* save addr */
  1061.             else dpush();
  1062.             nargs=nargs+6;
  1063.             }
  1064.         else
  1065.             {if(ptr==0)swapstk(); /* save addr */
  1066.             zpush();    /* push argument */
  1067.             nargs=nargs+2;    /* count args*2 */
  1068.             }
  1069.         if (match(",")==0) break;
  1070.         }
  1071.     needbrack(")");
  1072.     if(ptr)
  1073.         {if(nospread(ptr))
  1074.             {ot("LD A,");
  1075.             outdec(nargs>>1);
  1076.             nl();
  1077.             }
  1078.         zcall(ptr);
  1079.         }
  1080.     else callstk();
  1081.     Zsp=modstk(Zsp+nargs);    /* clean up arguments */
  1082. }
  1083. nospread(sym) char sym[];
  1084. {    if(astreq(sym,"printf",6))return 1;
  1085.     if(astreq(sym,"fprint",6))return 1;
  1086.     if(astreq(sym,"sprintf",7))return 1;
  1087.     if(astreq(sym,"scanf",5))return 1;
  1088.     if(astreq(sym,"fscan",5))return 1;
  1089.     if(astreq(sym,"sscanf",6))return 1;
  1090.     return 0;
  1091. }
  1092. junk()
  1093. {    if(an(inbyte()))
  1094.         while(an(ch()))gch();
  1095.     else while(an(ch())==0)
  1096.         {if(ch()==0)break;
  1097.         gch();
  1098.         }
  1099.     blanks();
  1100. }
  1101. endst()
  1102. {    blanks();
  1103.     return ((streq(line+lptr,";")|(ch()==0)));
  1104. }
  1105. illname()
  1106. {    error("illegal symbol name");junk();}
  1107. multidef(sname)
  1108.     char *sname;
  1109. {    error("already defined");
  1110.     comment();
  1111.     outstr(sname);nl();
  1112. }
  1113. needbrack(str)
  1114.     char *str;
  1115. {    if (match(str)==0)
  1116.         {error("missing bracket");
  1117.         comment();outstr(str);nl();
  1118.         }
  1119. }
  1120. needlval()
  1121. {    error("must be lvalue");
  1122. }
  1123. hash(sname)
  1124.     char *sname;
  1125. {    int h,c;
  1126.     h=*sname;
  1127.     while(c=*(++sname)) h=(h<<1)+c;
  1128.     return h;
  1129. }
  1130. findglb(sname)    /* cptr is set to entry if found,
  1131.         or appropriate empty slot if not */
  1132.     char *sname;
  1133. {    int h;
  1134.     h=hash(sname)&MASKGLBS;
  1135.     cptr=STARTGLB+h*SYMSIZ;
  1136.     while(0==astreq(sname,cptr,namemax)){
  1137.         if(*cptr==0) return 0;
  1138.         cptr=cptr+SYMSIZ;
  1139.         if(cptr==ENDGLB)cptr=STARTGLB;
  1140.     }
  1141.     return cptr;
  1142. }
  1143. findloc(sname)
  1144.     char *sname;
  1145. {    char *ptr;
  1146.     ptr=STARTLOC;
  1147.     while(ptr!=locptr)
  1148.         {if(astreq(sname,ptr,namemax))return ptr;
  1149.         ptr=ptr+SYMSIZ;
  1150.         }
  1151.     return 0;
  1152. }
  1153. addglb(sname,id,typ,value)
  1154.     char *sname,id,typ;
  1155.     int value;
  1156. {    char *ptr;
  1157.     if(findglb(sname))return cptr;
  1158.              /* declare exported name */
  1159.     if(id!=MACRO){ot("global "); outname(sname); nl();}
  1160.     if(glbptr>=ENDGLB)
  1161.         {error("global symbol table overflow");
  1162.         return 0;
  1163.         }
  1164.     ptr=cptr;
  1165.     while(an(*ptr++ = *sname++));    /* copy name */
  1166.     cptr[ident]=id;
  1167.     cptr[type]=typ;
  1168.     cptr[storage]=statik;
  1169.     cptr[offset]=value;
  1170.     cptr[offset+1]=value>>8;
  1171.     glbptr=glbptr+SYMSIZ;
  1172.     return cptr;
  1173. }
  1174. addloc(sname,id,typ,value)
  1175.     char *sname,id,typ;
  1176.     int value;
  1177. {    char *ptr;
  1178.     if(cptr=findloc(sname))return cptr;
  1179.     if(locptr>=ENDLOC)
  1180.         {error("local symbol table overflow");
  1181.         return 0;
  1182.         }
  1183.     cptr=ptr=locptr;
  1184.     while(an(*ptr++ = *sname++));    /* copy name */
  1185.     cptr[ident]=id;
  1186.     cptr[type]=typ;
  1187.     cptr[storage]=stkloc;
  1188.     cptr[offset]=value;
  1189.     cptr[offset+1]=value>>8;
  1190.     locptr=locptr+SYMSIZ;
  1191.     return cptr;
  1192. }
  1193. /* Test if next input string is legal symbol name */
  1194. symname(sname)
  1195.     char *sname;
  1196. {    int k;char c;
  1197.     blanks();
  1198.     if(alpha(ch())==0)return 0;
  1199.     k=0;
  1200.     while(an(ch()))sname[k++]=gch();
  1201.     sname[k]=0;
  1202.     return 1;
  1203.     }
  1204. /* Return next avail internal label number */
  1205. getlabel()
  1206. {    return(++nxtlab);
  1207. }
  1208. /* Print specified number as label */
  1209. printlabel(label)
  1210.     int label;
  1211. {    outasm("cc");
  1212.     outdec(label);
  1213. }
  1214. /* Test if given character is alpha */
  1215. alpha(c)  /* rewritten for speed 10/24/82 jrvz */
  1216.     char c;
  1217. {    c=c&127;
  1218.     if(c>='a') return (c<='z');
  1219.     if(c<='Z') return (c>='A');
  1220.     return (c=='_');
  1221. }
  1222. /* Test if given character is numeric */
  1223. numeric(c)
  1224.     char c;
  1225. {    c=c&127;
  1226.     if(c<='9') return(c>='0');
  1227.     return 0;
  1228. }
  1229. /* Test if given character is alphanumeric */
  1230. an(c)        /* rewritten for speed  11/10/82 jrvz */
  1231.     char c;
  1232. {    if(alpha(c)) return 1;
  1233.     return numeric(c);
  1234. }
  1235. /* Print a carriage return and a string only to console */
  1236. pl(str)
  1237.     char *str;
  1238. {    int k;
  1239.     k=0;
  1240.     putchar(EOL);
  1241.     while(str[k])putchar(str[k++]);
  1242. }
  1243. addwhile(ptr)
  1244.     int ptr[];
  1245.  {
  1246.     int k;
  1247.     if (wqptr==wqmax)
  1248.         {error("too many active whiles");return;}
  1249.     k=0;
  1250.     while (k<wqsiz)
  1251.         {*wqptr++ = ptr[k++];}
  1252. }
  1253. delwhile()
  1254.     {if(readwhile()) wqptr=wqptr-wqsiz;
  1255.     }
  1256. readwhile()
  1257. {    if (wqptr==wq){error("no active whiles");return 0;}
  1258.     else return (wqptr-wqsiz);
  1259. }
  1260. ch()
  1261. {    return(line[lptr]&127);
  1262. }
  1263. nch()
  1264. {/*    if(ch()==0)return 0;
  1265.         else return(line[lptr+1]&127);
  1266. */
  1267.     if(ch()) return(line[lptr+1]&127);
  1268.     return 0;
  1269. }
  1270. gch()
  1271. {/*    if(ch()==0)return 0;
  1272.         else return(line[lptr++]&127);
  1273. */
  1274.     if(ch()) return(line[lptr++]&127);
  1275.     return 0;
  1276. }
  1277. kill()
  1278. {    lptr=0;
  1279.     line[lptr]=0;
  1280. }
  1281. inbyte()
  1282. {
  1283.     while(ch()==0)
  1284.         {if (eof) return 0;
  1285.         inline();
  1286.         preprocess();
  1287.         }
  1288.     return gch();
  1289. }
  1290. inline()
  1291. {
  1292.     int k,unit;
  1293.     while(1)
  1294.         {if (input==0)openin();
  1295.         if(eof)return;
  1296.         if((unit=inpt2)==0)unit=input;
  1297.         kill();
  1298.         while((k=getc(unit))>0)
  1299.             {if((k==EOL)|(lptr>=linemax))break;
  1300.             line[lptr++]=k;
  1301.             }
  1302.         line[lptr]=0;    /* append null */
  1303.         lineno++;    /* read one more line        gtf 7/2/80 */
  1304.         if(k<=0)
  1305.             {fclose(unit);
  1306.             if(inpt2)endinclude();        /* gtf 7/16/80 */
  1307.                 else input=0;
  1308.             }
  1309.         if(lptr)
  1310.             {if((ctext)&(cmode))
  1311.                 {comment();
  1312.                 outstr(line);
  1313.                 nl();
  1314.                 }
  1315.             lptr=0;
  1316.             return;
  1317.             }
  1318.         }
  1319. }
  1320. /*    >>>>>> start of cc4 <<<<<<<    */
  1321.  
  1322. keepch(c)
  1323.     char c;
  1324. {    mline[mptr]=c;
  1325.     if(mptr<mpmax)++mptr;
  1326.     return c;
  1327. }
  1328. preprocess()
  1329. {    int k;
  1330.     char c,sname[namesize];
  1331.     if(cmode==0)return;
  1332.     mptr=lptr=0;
  1333.     while(ch())
  1334.         {if((ch()==' ')|(ch()==9))
  1335.             {keepch(' ');
  1336.             while((ch()==' ')|
  1337.                 (ch()==9))
  1338.                 gch();
  1339.             }
  1340.         else if(ch()=='"')
  1341.             {keepch(ch());
  1342.             gch();
  1343.             while((ch()!='"')|
  1344.             ((line[lptr-1]==92)&(line[lptr-2]!=92))
  1345.             )
  1346.                 {if(ch()==0)
  1347.                    {error("missing quote");
  1348.                    break;
  1349.                    }
  1350.                 keepch(gch());
  1351.                 }
  1352.             gch();
  1353.             keepch('"');
  1354.             }
  1355.         else if(ch()==39)
  1356.             {keepch(39);
  1357.             gch();
  1358.             while((ch()!=39)|
  1359.             ((line[lptr-1]==92)&
  1360.             (line[lptr-2]!=92)))
  1361.                {if(ch()==0)
  1362.                 {error("missing apostrophe");
  1363.                 break;
  1364.                 }
  1365.                keepch(gch());
  1366.                }
  1367.             gch();
  1368.             keepch(39);
  1369.             }
  1370.         else if((ch()=='/')&(nch()=='*'))
  1371.             {lptr=lptr+2;
  1372.             while(((ch()=='*')&
  1373.                 (nch()=='/'))==0)
  1374.                 {if(ch()==0)inline();
  1375.                     else lptr++;
  1376.                 if(eof)break;
  1377.                 }
  1378.             lptr=lptr+2;
  1379.             }
  1380.         else if(alpha(ch())) /* 10/24/82 jrvz */
  1381.             {k=0;
  1382.             while(an(ch()))
  1383.                 {if(k<namemax)sname[k++]=ch();
  1384.                 gch();
  1385.                 }
  1386.             sname[k]=0;
  1387.             if(k=findmac(sname))
  1388.                 while(c=macq[k++])
  1389.                     keepch(c);
  1390.             else
  1391.                 {k=0;
  1392.                 while(c=sname[k++])
  1393.                     keepch(c);
  1394.                 }
  1395.             }
  1396.         else keepch(gch());
  1397.         }
  1398.     keepch(0);
  1399.     if(mptr>=mpmax)error("line too long");
  1400.     lptr=mptr=0;
  1401.     while(line[lptr++]=mline[mptr++]);
  1402.     lptr=0;
  1403.     }
  1404. addmac()
  1405. {    char sname[namesize];
  1406.     if(symname(sname)==0)
  1407.         {illname();
  1408.         kill();
  1409.         return;
  1410.         }
  1411.     addglb(sname,MACRO,0,macptr);
  1412.         /* call replaced code which moved the name
  1413.         into the macro table    6/19/82  jrvz */
  1414.     while(ch()==' ' | ch()==9) gch();
  1415.     while(putmac(gch()));
  1416.     if(macptr>=macmax)error("macro table full");
  1417.     }
  1418. putmac(c)
  1419.     char c;
  1420. {    macq[macptr]=c;
  1421.     if(macptr<macmax)macptr++;
  1422.     return c;
  1423. }
  1424. findmac(sname)  /* function rewritten 6/19/82  jrvz */
  1425.     char *sname;
  1426. {    if((findglb(sname)!=0)&(cptr[ident]==MACRO))
  1427.         {return((cptr[offset]&255)+
  1428.         (cptr[offset+1]<<8));
  1429.         }
  1430.     return 0;
  1431. }
  1432. /* direct output to console        gtf 7/16/80 */
  1433. toconsole()
  1434. {
  1435.     saveout = output;
  1436.     output = 0;
  1437. /* end toconsole */}
  1438.  
  1439. /* direct output back to file        gtf 7/16/80 */
  1440. tofile()
  1441. {
  1442.     if(saveout)
  1443.         output = saveout;
  1444.     saveout = 0;
  1445. /* end tofile */}
  1446.  
  1447. outbyte(c)
  1448.     char c;
  1449. {
  1450.     if(c)    /* sense of test reversed  jrvz 9/2/83 */
  1451.         {if(output)
  1452.             {if((putc(c,output))<=0)
  1453.                 {closeout();
  1454.                 error("Output file error");
  1455.                 abort();    /* gtf 7/17/80 */
  1456.                 }
  1457.             }
  1458.         else putchar(c);
  1459.         }
  1460.     return c;
  1461. }
  1462. outstr(ptr)
  1463.     char ptr[];
  1464.  {    while(outbyte(*ptr++));    /* jrvz 8/21/83 */
  1465.  }
  1466.  
  1467. /* write text destined for the assembler to read */
  1468. /* (i.e. stuff not in comments)            */
  1469. /*  gtf  6/26/80 */
  1470. outasm(ptr)
  1471. char *ptr;
  1472. {
  1473. /*    while(outbyte(raise(*ptr++)));*/
  1474.     while(outbyte(*ptr++));    /* ZMAC changes to upper case */
  1475. /* end outasm */}
  1476.  
  1477. nl()
  1478.     {outbyte(EOL);}
  1479. tab()
  1480.     {outbyte(9);}
  1481. col()
  1482.     {outbyte(58);}
  1483. bell()                /* gtf 7/16/80 */
  1484.     {outbyte(7);}
  1485.  
  1486. error(ptr)
  1487. char ptr[];
  1488. {    int k;
  1489.     char junk[81];
  1490.  
  1491.     toconsole();
  1492.     bell();
  1493.     outstr("Line "); outdec(lineno); outstr(", ");
  1494.     if(infunc==0)
  1495.         outbyte('(');
  1496.     if(currfn==NULL)
  1497.         outstr("start of file");
  1498.     else    outstr(currfn+name);
  1499.     if(infunc==0)
  1500.         outbyte(')');
  1501.     outstr(" + ");
  1502.     outdec(lineno-fnstart);
  1503.     outstr(": ");  outstr(ptr);  nl();
  1504.  
  1505.     outstr(line); nl();
  1506.  
  1507.     k=0;    /* skip to error position */
  1508.     while(k<lptr){
  1509.         if(line[k++]==9)
  1510.             tab();
  1511.         else    outbyte(' ');
  1512.         }
  1513.     outbyte('^');  nl();
  1514.     ++errcnt;
  1515.  
  1516.     if(errstop){
  1517.         pl("Continue (Y,n,g) ? ");
  1518.         gets(junk);        
  1519.         k=junk[0];
  1520.         if((k=='N') | (k=='n'))
  1521.             abort();
  1522.         if((k=='G') | (k=='g'))
  1523.             errstop=0;
  1524.         }
  1525.     tofile();
  1526. /* end error */}
  1527.  
  1528. ol(ptr)
  1529.     char ptr[];
  1530. {
  1531.     ot(ptr);
  1532.     nl();
  1533. }
  1534. ot(ptr)
  1535.     char ptr[];
  1536. {
  1537.     tab();
  1538.     outasm(ptr);
  1539. }
  1540. streq(str1,str2)
  1541.     char str1[],str2[];
  1542.  {
  1543.     int k;
  1544.     k=0;
  1545.     while (*str2)
  1546.         {if ((*str1++)!=(*str2++)) return 0;
  1547.         k++;
  1548.         }
  1549.     return k;
  1550.  }
  1551. astreq(str1,str2,len)
  1552.     char str1[],str2[];int len;
  1553.  {
  1554.     int k;
  1555.     k=0;
  1556.     while (k<len)
  1557.         {if ((*str1)!=(*str2))break;
  1558.         if(*str1==0)break;
  1559.         if(*str2==0)break;
  1560.         ++str1; ++str2; ++k;
  1561.         }
  1562.     if (an(*str1))return 0;
  1563.     if (an(*str2))return 0;
  1564.     return k;
  1565.  }
  1566. match(lit)
  1567.     char *lit;
  1568. {
  1569.     int k;
  1570.     blanks();
  1571.     if (k=streq(line+lptr,lit))
  1572.         {lptr=lptr+k;
  1573.         return 1;
  1574.         }
  1575.      return 0;
  1576. }
  1577. amatch(lit,len)
  1578.     char *lit;int len;
  1579.  {
  1580.     int k;
  1581.     blanks();
  1582.     if (k=astreq(line+lptr,lit,len))
  1583.         {lptr=lptr+k;
  1584.         while(an(ch())) inbyte();
  1585.         return 1;
  1586.         }
  1587.     return 0;
  1588.  }
  1589. blanks()
  1590.     {while(1)
  1591.         {while(ch()==0)
  1592.             {inline();
  1593.             preprocess();
  1594.             if(eof)break;
  1595.             }
  1596.         if(ch()==' ')gch();
  1597.         else if(ch()==9)gch();
  1598.         else return;
  1599.         }
  1600.     }
  1601. outdec(number)
  1602.     int number;
  1603.  {    if (number<0)
  1604.         {number=(-number);
  1605.         outbyte('-');
  1606.         }
  1607.     outd2(number);
  1608. }
  1609. outd2(n) int n;
  1610. {    if(n>9) {outd2(n/10); n=n%10;}
  1611.     outbyte('0'+n);
  1612.  }
  1613. /* return the length of a string */
  1614. /* gtf 4/8/80 */
  1615. strlen(s)
  1616. char *s;
  1617. {    char *t;
  1618.  
  1619.     t = s;
  1620.     while(*s) s++;
  1621.     return(s-t);
  1622. /* end strlen */}
  1623.  
  1624. /* convert lower case to upper */
  1625. /* gtf 6/26/80 */
  1626. raise(c)
  1627. char c;
  1628. {
  1629.     if(c>='a')
  1630.         {if(c<='z')
  1631.             c = c - 32; /* 'a'-'A'=32 */
  1632.         }
  1633.     return(c);
  1634. /* end raise */}
  1635. #include c80v-2.c
  1636.