Appendix C:

Small C Compiler Listings

    _____________________________________________________________________ 
                                   notice.h 
    _____________________________________________________________________ 
    /* 
    ** NOTICE.H -- Small C Signon Notice. 
    */ 
    #define VERSION "Small C, Version 2.2, Revision Level 112\n" 
    #define CRIGHT1 "Copyright 1982, 1983, 1985, 1988 J. E. Hendrix\n\n" 
     
    _____________________________________________________________________ 
                                   cc.h 
    _____________________________________________________________________ 
    /* 
    ** CC.H -- Symbol Definitions for Small-C compiler. 
    */ 
     
    /* 
    ** machine dependent parameters 
    */ 
    #define BPW     2   /* bytes per word */ 
    #define LBPW    1   /* log2(BPW) */ 
    #define SBPC    1   /* stack bytes per character */ 
    #define ERRCODE 7   /* op sys return code */ 
     
    /* 
    ** symbol table format 
    */ 
    #define IDENT    0 
    #define TYPE     1 
    #define CLASS    2 
    #define SIZE     3 
    #define OFFSET   5 
    #define NAME     7 
     
    #define SYMAVG  12 
    #define SYMMAX  16 
     
    /* 
    ** symbol table parameters 
    */ 
    #define NUMLOCS   25 
    #define STARTLOC  symtab 
    #define ENDLOC    (symtab+NUMLOCS*SYMAVG) 
    #define NUMGLBS   200 
    #define STARTGLB  ENDLOC 
    #define ENDGLB    (ENDLOC+(NUMGLBS-1)*SYMMAX) 
    #define SYMTBSZ   3050  /* (NUMLOCS*SYMAVG + NUMGLBS*SYMMAX) */ 
     
    /* 
    ** system wide name size (for symbols) 
    */ 
    #define NAMESIZE 9 
    #define NAMEMAX  8 
     
    /* 
    ** values for "IDENT" 
    */ 
    #define LABEL    0 
    #define VARIABLE 1 
    #define ARRAY    2 
    #define POINTER  3 
    #define FUNCTION 4 
     
    /* 
    ** values for "TYPE" 
    **    high order 14 bits give length of object 
    **    low order 2 bits make type unique within length 
    */ 
    /*      LABEL   0 */ 
    #define CHR     (  1 << 2) 
    #define INT     (BPW << 2) 
    #define UCHR   ((  1 << 2) + 1) 
    #define UINT   ((BPW << 2) + 1) 
    #define UNSIGNED             1 
     
    /* 
    ** values for "CLASS" 
    */ 
    /*      LABEL     0 */ 
    #define AUTOMATIC 1 
    #define STATIC    2 
    #define EXTERNAL  3 
    #define AUTOEXT   4 
     
    /* 
    ** segment types 
    */ 
    #define DATASEG 1 
    #define CODESEG 2 
     
    /* 
    ** "switch" table 
    */ 
    #define SWSIZ   (2*BPW) 
    #define SWTABSZ (90*SWSIZ) 
     
    /* 
    ** "while" queue 
    */ 
    #define WQTABSZ  30 
    #define WQSIZ     3 
    #define WQMAX   (wq+WQTABSZ-WQSIZ) 
     
    /* 
    ** field offsets in "while" queue 
    */ 
    #define WQSP    0 
    #define WQLOOP  1 
    #define WQEXIT  2 
     
    /* 
    ** literal pool 
    */ 
    #define LITABSZ 2000 
    #define LITMAX  (LITABSZ-1) 
     
    /* 
    ** input line 
    */ 
    #define LINEMAX  127 
    #define LINESIZE 128 
     
    /* 
    ** entries in staging buffer 
    */ 
    #define STAGESIZE   200 
     
    /* 
    ** macro (#define) pool 
    */ 
    #define MACNBR   300 
    #define MACNSIZE (MACNBR*(NAMESIZE+2)) 
    #define MACNEND  (macn+MACNSIZE) 
    #define MACQSIZE (MACNBR*7) 
    #define MACMAX   (MACQSIZE-1) 
     
    /* 
    ** statement types 
    */ 
    #define STIF      1 
    #define STWHILE   2 
    #define STRETURN  3 
    #define STBREAK   4 
    #define STCONT    5 
    #define STASM     6 
    #define STEXPR    7 
    #define STDO      8 
    #define STFOR     9 
    #define STSWITCH 10 
    #define STCASE   11 
    #define STDEF    12 
    #define STGOTO   13 
    #define STLABEL  14 
     
    /* 
    ** p-code symbols 
    ** 
    ** legend: 
    **  1 = primary register (pr in comments) 
    **  2 = secondary register (sr in comments) 
    **  b = byte 
    **  f = jump on false condition 
    **  l = current literal pool label number 
    **  m = memory reference by label 
    **  n = numeric constant 
    **  p = indirect reference thru pointer in sr 
    **  r = repeated r times 
    **  s = stack frame reference 
    **  u = unsigned 
    **  w = word 
    **  _ (tail) = another p-code completes this one 
    */ 
     
            /* compiler-generated */ 
    #define ADD12     1   /* add sr to pr */ 
    #define ADDSP     2   /* add to stack pointer */ 
    #define AND12     3   /* AND sr to pr */ 
    #define ANEG1     4   /* arith negate pr */ 
    #define ARGCNTn   5   /* pass arg count to function */ 
    #define ASL12     6   /* arith shift left sr by pr into pr */ 
    #define ASR12     7   /* arith shift right sr by pr into pr */ 
    #define CALL1     8   /* call function thru pr */ 
    #define CALLm     9   /* call function directly */ 
    #define BYTE_    10   /* define bytes (part 1) */ 
    #define BYTEn    11   /* define byte of value n */ 
    #define BYTEr0   12   /* define r bytes of value 0 */ 
    #define COM1     13   /* ones complement pr */ 
    #define DBL1     14   /* double pr */ 
    #define DBL2     15   /* double sr */ 
    #define DIV12    16   /* div pr by sr */ 
    #define DIV12u   17   /* div pr by sr unsigned */ 
    #define ENTER    18   /* set stack frame on function entry */ 
    #define EQ10f    19   /* jump if (pr == 0) is false */ 
    #define EQ12     20   /* set pr TRUE if (sr == pr) */ 
    #define GE10f    21   /* jump if (pr >= 0) is false */ 
    #define GE12     22   /* set pr TRUE if (sr >= pr) */ 
    #define GE12u    23   /* set pr TRUE if (sr >= pr) unsigned */ 
    #define POINT1l  24   /* point pr to function's literal pool */ 
    #define POINT1m  25   /* point pr to mem item thru label */ 
    #define GETb1m   26   /* get byte into pr from mem thru label */ 
    #define GETb1mu  27   /* get unsigned byte into pr from mem thru label */ 
    #define GETb1p   28   /* get byte into pr from mem thru sr ptr */ 
    #define GETb1pu  29   /* get unsigned byte into pr from mem thru sr ptr */ 
    #define GETw1m   30   /* get word into pr from mem thru label */ 
    #define GETw1n   31   /* get word of value n into pr */ 
    #define GETw1p   32   /* get word into pr from mem thru sr ptr */ 
    #define GETw2n   33   /* get word of value n into sr */ 
    #define GT10f    34   /* jump if (pr > 0) is false */ 
    #define GT12     35   /* set pr TRUE if (sr > pr) */ 
    #define GT12u    36   /* set pr TRUE if (sr > pr) unsigned */ 
    #define WORD_    37   /* define word (part 1) */ 
    #define WORDn    38   /* define word of value n */ 
    #define WORDr0   39   /* define r words of value 0 */ 
    #define JMPm     40   /* jump to label */ 
    #define LABm     41   /* define label m */ 
    #define LE10f    42   /* jump if (pr <= 0) is false */ 
    #define LE12     43   /* set pr TRUE if (sr <= pr) */ 
    #define LE12u    44   /* set pr TRUE if (sr <= pr) unsigned */ 
    #define LNEG1    45   /* logical negate pr */ 
    #define LT10f    46   /* jump if (pr < 0) is false */ 
    #define LT12     47   /* set pr TRUE if (sr < pr) */ 
    #define LT12u    48   /* set pr TRUE if (sr < pr) unsigned */ 
    #define MOD12    49   /* modulo pr by sr */ 
    #define MOD12u   50   /* modulo pr by sr unsigned */ 
    #define MOVE21   51   /* move pr to sr */ 
    #define MUL12    52   /* multiply pr by sr */ 
    #define MUL12u   53   /* multiply pr by sr unsigned */ 
    #define NE10f    54   /* jump if (pr != 0) is false */ 
    #define NE12     55   /* set pr TRUE if (sr != pr) */ 
    #define NEARm    56   /* define near pointer thru label */ 
    #define OR12     57   /* OR sr onto pr */ 
    #define POINT1s  58   /* point pr to stack item */ 
    #define POP2     59   /* pop stack into sr */ 
    #define PUSH1    60   /* push pr onto stack */ 
    #define PUTbm1   61   /* put pr byte in mem thru label */ 
    #define PUTbp1   62   /* put pr byte in mem thru sr ptr */ 
    #define PUTwm1   63   /* put pr word in mem thru label */ 
    #define PUTwp1   64   /* put pr word in mem thru sr ptr */ 
    #define rDEC1    65   /* dec pr (may repeat) */ 
    #define REFm     66   /* finish instruction with label */ 
    #define RETURN   67   /* restore stack and return */ 
    #define rINC1    68   /* inc pr (may repeat) */ 
    #define SUB12    69   /* sub sr from pr */ 
    #define SWAP12   70   /* swap pr and sr */ 
    #define SWAP1s   71   /* swap pr and top of stack */ 
    #define SWITCH   72   /* find switch case */ 
    #define XOR12    73   /* XOR pr with sr */ 
     
            /* optimizer-generated */ 
    #define ADD1n    74   /* add n to pr */ 
    #define ADD21    75   /* add pr to sr */ 
    #define ADD2n    76   /* add immediate to sr */ 
    #define ADDbpn   77   /* add n to mem byte thru sr ptr */ 
    #define ADDwpn   78   /* add n to mem word thru sr ptr */ 
    #define ADDm_    79   /* add n to mem byte/word thru label (part 1) */ 
    #define COMMAn   80   /* finish instruction with ,n */ 
    #define DECbp    81   /* dec mem byte thru sr ptr */ 
    #define DECwp    82   /* dec mem word thru sr ptr */ 
    #define POINT2m  83   /* point sr to mem thru label */ 
    #define POINT2m_ 84   /* point sr to mem thru label (part 1) */ 
    #define GETb1s   85   /* get byte into pr from stack */ 
    #define GETb1su  86   /* get unsigned byte into pr from stack */ 
    #define GETw1m_  87   /* get word into pr from mem thru label (part 1) */ 
    #define GETw1s   88   /* get word into pr from stack */ 
    #define GETw2m   89   /* get word into sr from mem (label) */ 
    #define GETw2p   90   /* get word into sr thru sr ptr */ 
    #define GETw2s   91   /* get word into sr from stack */ 
    #define INCbp    92   /* inc byte in mem thru sr ptr */ 
    #define INCwp    93   /* inc word in mem thru sr ptr */ 
    #define PLUSn    94   /* finish instruction with +n */ 
    #define POINT2s  95   /* point sr to stack */ 
    #define PUSH2    96   /* push sr */ 
    #define PUSHm    97   /* push word from mem thru label */ 
    #define PUSHp    98   /* push word from mem thru sr ptr */ 
    #define PUSHs    99   /* push word from stack */ 
    #define PUT_m_  100   /* put byte/word into mem thru label (part 1) */ 
    #define rDEC2   101   /* dec sr (may repeat) */ 
    #define rINC2   102   /* inc sr (may repeat) */ 
    #define SUB_m_  103   /* sub from mem byte/word thru label (part 1) */ 
    #define SUB1n   104   /* sub n from pr */ 
    #define SUBbpn  105   /* sub n from mem byte thru sr ptr */ 
    #define SUBwpn  106   /* sub n from mem word thru sr ptr */ 
     
    #define PCODES  107   /* size of code[] */ 
     
    
 
 
    _____________________________________________________________________ 
                                   stdio.h 
    ______________________________________________________________________ 
    /* 
    ** STDIO.H -- Standard Small C Definitions. 
    */ 
    #define stdin    0  /* file descriptor for standard input file */ 
    #define stdout   1  /* file descriptor for standard output file */ 
    #define stderr   2  /* file descriptor for standard error file */ 
    #define stdaux   3  /* file descriptor for standard auxiliary port */ 
    #define stdprn   4  /* file descriptor for standard printer */ 
    #define FILE  char  /* supports "FILE *fp;" declarations */ 
    #define ERR   (-2)  /* return value for errors */ 
    #define EOF   (-1)  /* return value for end-of-file */ 
    #define YES      1  /* true */ 
    #define NO       0  /* false */ 
    #define NULL     0  /* zero */ 
    #define CR      13  /* ASCII carriage return */ 
    #define LF      10  /* ASCII line feed */ 
    #define BELL     7  /* ASCII bell */ 
    #define SPACE  ' '  /* ASCII space */ 
    #define NEWLINE LF  /* Small C newline character */ 
     
     
    _____________________________________________________________________ 
                                   cc1.c 
    _____________________________________________________________________ 
    /* 
    ** Small-C Compiler -- Part 1 --  Top End. 
    ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix 
    ** All rights reserved. 
    */ 
     
    #include <stdio.h> 
    #include "notice.h" 
    #include "cc.h" 
     
 
    /* 
    ** miscellaneous storage 
    */ 
    int 
      nogo,     /* disable goto statements? */ 
      noloc,    /* disable block locals? */ 
      opindex,  /* index to matched operator */ 
      opsize,   /* size of operator in characters */ 
      swactive, /* inside a switch? */ 
      swdefault,/* default label #, else 0 */ 
     *swnext,   /* address of next entry */ 
     *swend,    /* address of last entry */ 
     *stage,    /* staging buffer address */ 
     *wq,       /* while queue */ 
      argcs,    /* static argc */ 
     *argvs,    /* static argv */ 
     *wqptr,    /* ptr to next entry */ 
      litptr,   /* ptr to next entry */ 
      macptr,   /* macro buffer index */ 
      pptr,     /* ptr to parsing buffer */ 
      ch,       /* current character of input line */ 
      nch,      /* next character of input line */ 
      declared, /* # of local bytes to declare, -1 when declared */ 
      iflevel,  /* #if... nest level */ 
      skiplevel,/* level at which #if... skipping started */ 
      nxtlab,   /* next avail label # */ 
      litlab,   /* label # assigned to literal pool */ 
      csp,      /* compiler relative stk ptr */ 
      argstk,   /* function arg sp */ 
      argtop,   /* highest formal argument offset */ 
      ncmp,     /* # open compound statements */ 
      errflag,  /* true after 1st error in statement */ 
      eof,      /* true on final input eof */ 
      output,   /* fd for output file */ 
      files,    /* true if file list specified on cmd line */ 
      filearg,  /* cur file arg index */ 
      input   = EOF, /* fd for input file */ 
      input2  = EOF, /* fd for "#include" file */ 
      usexpr  = YES, /* true if value of expression is used */ 
      ccode   = YES, /* true while parsing C code */ 
     *snext,    /* next addr in stage */ 
     *stail,    /* last addr of data in stage */ 
     *slast,    /* last addr in stage */ 
      listfp,   /* file pointer to list device */ 
      lastst,   /* last parsed statement type */ 
      oldseg;   /* current segment (0, DATASEG, CODESEG) */ 
     
    char 
      optimize, /* optimize output of staging buffer? */ 
      alarm,    /* audible alarm on errors? */ 
      monitor,  /* monitor function headers? */ 
      pause,    /* pause for operator on errors? */ 
     *symtab,   /* symbol table */ 
     *litq,     /* literal pool */ 
     *macn,     /* macro name buffer */ 
     *macq,     /* macro string buffer */ 
     *pline,    /* parsing buffer */ 
     *mline,    /* macro buffer */ 
     *line,     /* ptr to pline or mline */ 
     *lptr,     /* ptr to current character in "line" */ 
     *glbptr,   /* global symbol table */ 
     *locptr,   /* next local symbol table entry */ 
      quote[2] = {'"'}, /* literal string for '"' */ 
     *cptr,     /* work ptrs to any char buffer */ 
     *cptr2, 
     *cptr3, 
      msname[NAMESIZE],   /* macro symbol name */ 
      ssname[NAMESIZE];   /* static symbol name */ 
     
    int op[16] = {   /* p-codes of signed binary operators */ 
      OR12,                        /* level5 */ 
      XOR12,                       /* level6 */ 
      AND12,                       /* level7 */ 
      EQ12,   NE12,                /* level8 */ 
      LE12,   GE12,  LT12,  GT12,  /* level9 */ 
      ASR12,  ASL12,               /* level10 */ 
      ADD12,  SUB12,               /* level11 */ 
      MUL12, DIV12, MOD12          /* level12 */ 
      }; 
     
    int op2[16] = {  /* p-codes of unsigned binary operators */ 
      OR12,                        /* level5 */ 
      XOR12,                       /* level6 */ 
      AND12,                       /* level7 */ 
      EQ12,   NE12,                /* level8 */ 
      LE12u,  GE12u, LT12u, GT12u, /* level9 */ 
      ASR12,  ASL12,               /* level10 */ 
      ADD12,  SUB12,               /* level11 */ 
      MUL12u, DIV12u, MOD12u       /* level12 */ 
      }; 
     
    /* 
    ** execution begins here 
    */ 
    main(argc, argv) int argc, *argv; { 
      fputs(VERSION, stderr); 
      fputs(CRIGHT1, stderr); 
      argcs   = argc; 
      argvs   = argv; 
      swnext  = calloc(SWTABSZ, 1); 
      swend   = swnext+(SWTABSZ-SWSIZ); 
      stage   = calloc(STAGESIZE, 2*BPW); 
      wqptr   = 
      wq      = calloc(WQTABSZ, BPW); 
      litq    = calloc(LITABSZ, 1); 
      macn    = calloc(MACNSIZE, 1); 
      macq    = calloc(MACQSIZE, 1); 
      pline   = calloc(LINESIZE, 1); 
      mline   = calloc(LINESIZE, 1); 
      slast   = stage+(STAGESIZE*2*BPW); 
      symtab  = calloc((NUMLOCS*SYMAVG + NUMGLBS*SYMMAX), 1); 
      locptr  = STARTLOC; 
      glbptr  = STARTGLB; 
     
      ask();          /* get user options */ 
      openfile();     /* and initial input file */ 
      preprocess();   /* fetch first line */ 
      header();       /* intro code */ 
      setcodes();     /* initialize code pointer array */  
      parse();        /* process ALL input */ 
      trailer();      /* follow-up code */ 
      fclose(output); /* explicitly close output */ 
      } 
     
    /******************** high level parsing *******************/ 
     
    /* 
    ** process all input text 
    ** 
    ** At this level, only static declarations, 
    **      defines, includes and function 
    **      definitions are legal... 
    */ 
    parse() { 
      while (eof == 0) { 
        if     (amatch("extern", 6)) dodeclare(EXTERNAL); 
        else if(dodeclare(STATIC))   ; 
        else if( match("#asm"))      doasm(); 
        else if( match("#include"))  doinclude(); 
        else if( match("#define"))   dodefine(); 
        else                         dofunction(); 
        blanks();                 /* force eof if pending */ 
        } 
      } 
     
    /* 
    ** test for global declarations 
    */ 
    dodeclare(class) int class; { 
      if     (amatch("char",     4))  declglb(CHR,  class); 
      else if(amatch("unsigned", 8)) { 
        if   (amatch("char",     4))  declglb(UCHR, class); 
        else {amatch("int",      3);  declglb(UINT, class);} 
        } 
      else if(amatch("int",      3) 
           || class == EXTERNAL)      declglb(INT,  class); 
      else return 0; 
      ns(); 
      return 1; 
      } 
     
    /* 
    ** declare a static variable 
    */ 
    declglb(type, class)  int type, class; { 
      int id, dim; 
      while(1) { 
        if(endst()) return;  /* do line */ 
        if(match("*"))       {id = POINTER;  dim = 0;} 
        else                 {id = VARIABLE; dim = 1;} 
        if(symname(ssname) == 0) illname(); 
        if(findglb(ssname)) multidef(ssname); 
        if(id == VARIABLE) { 
          if     (match("("))  {id = FUNCTION; need(")");} 
          else if(match("["))  {id = ARRAY; dim = needsub();} 
          } 
        if     (class == EXTERNAL) external(ssname, type >> 2, id); 
        else if(   id != FUNCTION) initials(type >> 2, id, dim); 
        if(id == POINTER)  
             addsym(ssname, id, type, BPW, 0, &glbptr, class); 
        else addsym(ssname, id, type, dim * (type >> 2), 0, &glbptr, class); 
        if(match(",") == 0) return; 
        } 
      } 
     
    /* 
    ** initialize global objects 
    */ 
    initials(size, ident, dim) int size, ident, dim; { 
      int savedim; 
      litptr = 0; 
      if(dim == 0) dim = -1;         /* *... or ...[] */ 
      savedim = dim; 
      public(ident); 
      if(match("=")) { 
        if(match("{")) { 
          while(dim) { 
            init(size, ident, &dim); 
            if(match(",") == 0) break; 
            } 
          need("}"); 
          } 
        else init(size, ident, &dim); 
        } 
      if(savedim == -1 && dim == -1) { 
        if(ident == ARRAY) error("need array size"); 
        stowlit(0, size = BPW); 
        } 
      dumplits(size); 
      dumpzero(size, dim);           /* only if dim > 0 */ 
      } 
     
    /* 
    ** evaluate one initializer 
    */ 
    init(size, ident, dim) int size, ident, *dim; { 
      int value; 
      if(string(&value)) { 
        if(ident == VARIABLE || size != 1) 
          error("must assign to char pointer or char array"); 
        *dim -= (litptr - value); 
        if(ident == POINTER) point(); 
        } 
      else if(constexpr(&value)) { 
        if(ident == POINTER) error("cannot assign to pointer"); 
        stowlit(value, size); 
        *dim -= 1; 
        } 
      } 
     
    /* 
    ** get required array size 
    */ 
    needsub()  { 
      int val; 
      if(match("]")) return 0; /* null size */ 
      if(constexpr(&val) == 0) val = 1; 
      if(val < 0) { 
        error("negative size illegal"); 
        val = -val; 
        } 
      need("]");               /* force single dimension */ 
      return val;              /* and return size */ 
      } 
     
    /* 
    ** open an include file 
    */ 
    doinclude() { 
      int i; char str[30]; 
      blanks();       /* skip over to name */ 
      if(*lptr == '"' || *lptr == '<') ++lptr; 
      i = 0; 
      while(lptr[i] 
         && lptr[i] != '"' 
         && lptr[i] != '>' 
         && lptr[i] != '\n') { 
        str[i] = lptr[i]; 
        ++i; 
        } 
      str[i] = NULL; 
      if((input2 = fopen(str,"r")) == NULL) { 
        input2 = EOF; 
        error("open failure on include file"); 
        } 
      kill();   /* make next read come from new file (if open) */ 
      } 
     
    /* 
    ** define a macro symbol 
    */ 
    dodefine() { 
      int k; 
      if(symname(msname) == 0) { 
        illname(); 
        kill(); 
        return; 
        } 
      k = 0; 
      if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) { 
        if(cptr2 = cptr) 
          while(*cptr2++ = msname[k++]) ; 
        else { 
          error("macro name table full"); 
          return; 
          } 
        } 
      putint(macptr, cptr+NAMESIZE, 2); 
      while(white()) gch(); 
      while(putmac(gch())); 
      if(macptr >= MACMAX) { 
        error("macro string queue full"); 
        abort(ERRCODE); 
        } 
      } 
     
    putmac(c)  char c; { 
      macq[macptr] = c; 
      if(macptr < MACMAX) ++macptr; 
      return c; 
      } 
     
    /* 
    ** begin a function 
    ** 
    ** called from "parse" and tries to make a function 
    ** out of the following text 
    */ 
    dofunction()  { 
      char *ptr; 
      nogo   =                      /* enable goto statements */ 
      noloc  =                      /* enable block-local declarations */ 
      lastst =                      /* no statement yet */ 
      litptr = 0;                   /* clear lit pool */ 
      litlab = getlabel();          /* label next lit pool */ 
      locptr = STARTLOC;            /* clear local variables */ 
      if(match("void")) blanks();   /* skip "void" & locate header */ 
      if(monitor) lout(line, stderr); 
      if(symname(ssname) == 0) { 
        error("illegal function or declaration"); 
        errflag = 0; 
        kill();                     /* invalidate line */ 
        return; 
        } 
      if(ptr = findglb(ssname)) {   /* already in symbol table? */ 
        if(ptr[CLASS] == AUTOEXT) 
             ptr[CLASS] = STATIC; 
        else multidef(ssname); 
        } 
      else addsym(ssname, FUNCTION, INT, 0, 0, &glbptr, STATIC); 
      public(FUNCTION); 
      argstk = 0;                  /* init arg count */ 
      if(match("(") == 0) error("no open paren"); 
      while(match(")") == 0) {     /* then count args */ 
        if(symname(ssname)) { 
          if(findloc(ssname)) multidef(ssname); 
          else { 
            addsym(ssname, 0, 0, 0, argstk, &locptr, AUTOMATIC); 
            argstk += BPW; 
            } 
          } 
        else { 
          error("illegal argument name"); 
          skip(); 
          } 
        blanks(); 
        if(streq(lptr,")") == 0 && match(",") == 0) 
          error("no comma"); 
        if(endst()) break; 
        } 
      csp = 0;                     /* preset stack ptr */ 
      argtop = argstk+BPW;         /* account for the pushed BP */ 
      while(argstk) { 
        if     (amatch("char",     4)) {doargs(CHR);  ns();} 
        else if(amatch("int",      3)) {doargs(INT);  ns();} 
        else if(amatch("unsigned", 8)) { 
          if   (amatch("char", 4))     {doargs(UCHR); ns();} 
          else {amatch("int", 3);       doargs(UINT); ns();} 
          } 
        else {error("wrong number of arguments"); break;} 
        } 
      gen(ENTER, 0); 
      statement(); 
      if(lastst != STRETURN && lastst != STGOTO) 
        gen(RETURN, 0); 
      if(litptr) { 
        toseg(DATASEG); 
        gen(REFm, litlab); 
        dumplits(1);               /* dump literals */ 
        } 
      } 
     
    /* 
    ** declare argument types 
    */ 
    doargs(type) int type; { 
      int id, sz; 
      char c, *ptr; 
      while(1) { 
        if(argstk == 0) return;           /* no arguments */ 
        if(decl(type, POINTER, &id, &sz)) { 
          if(ptr = findloc(ssname)) { 
            ptr[IDENT] = id; 
            ptr[TYPE]  = type; 
            putint(sz, ptr+SIZE, 2); 
            putint(argtop-getint(ptr+OFFSET, 2), ptr+OFFSET, 2); 
            } 
          else error("not an argument"); 
          } 
        argstk = argstk - BPW;            /* cnt down */ 
        if(endst()) return; 
        if(match(",") == 0) error("no comma"); 
        } 
      } 
     
 
    /* 
    ** parse next local or argument declaration 
    */ 
    decl(type, aid, id, sz) int type, aid, *id, *sz; { 
      int n, p; 
      if(match("(")) p = 1; 
      else           p = 0; 
      if(match("*"))        {*id = POINTER;  *sz  = BPW;} 
      else                  {*id = VARIABLE; *sz  = type >> 2;} 
      if((n = symname(ssname)) == 0) illname(); 
      if(p && match(")")) ; 
      if(match("(")) { 
        if(!p || *id != POINTER) error("try (*...)()"); 
        need(")"); 
        } 
      else if(*id == VARIABLE && match("[")) { 
        *id = aid; 
        if((*sz *= needsub()) == 0) { 
          if(aid == ARRAY) error("need array size"); 
          *sz  = BPW;      /* size of pointer argument */ 
          } 
        } 
      return n; 
      } 
     
    /******************** start 2nd level parsing *******************/ 
     
    /* 
    ** statement parser 
    */ 
    statement() { 
      if(ch == 0 && eof) return; 
      else if(amatch("char",     4)) {declloc(CHR);    ns();} 
      else if(amatch("int",      3)) {declloc(INT);    ns();} 
      else if(amatch("unsigned", 8)) { 
        if   (amatch("char",     4)) {declloc(UCHR);   ns();} 
        else {amatch("int",      3);  declloc(UINT);   ns();} 
        } 
      else { 
        if(declared >= 0) { 
          if(ncmp > 1) nogo = declared;   /* disable goto */ 
          gen(ADDSP, csp - declared); 
          declared = -1; 
          } 
        if(match("{"))                 compound(); 
        else if(amatch("if",       2)) {doif();           lastst = STIF;} 
        else if(amatch("while",    5)) {dowhile();        lastst = STWHILE;} 
        else if(amatch("do",       2)) {dodo();           lastst = STDO;} 
        else if(amatch("for",      3)) {dofor();          lastst = STFOR;} 
        else if(amatch("switch",   6)) {doswitch();       lastst = STSWITCH;} 
        else if(amatch("case",     4)) {docase();         lastst = STCASE;} 
        else if(amatch("default",  7)) {dodefault();      lastst = STDEF;} 
        else if(amatch("goto",     4)) {dogoto();         lastst = STGOTO;} 
        else if(dolabel())                                lastst = STLABEL; 
        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(";"))            errflag = 0; 
        else if(match("#asm"))         {doasm();          lastst = STASM;} 
        else                           {doexpr(NO); ns(); lastst = STEXPR;} 
        } 
      return lastst; 
      } 
     
    /* 
    ** declare local variables 
    */ 
    declloc(type)  int type;  { 
      int id, sz; 
      if(swactive)     error("not allowed in switch"); 
      if(noloc)        error("not allowed with goto"); 
      if(declared < 0) error("must declare first in block"); 
      while(1) { 
        if(endst()) return; 
        decl(type, ARRAY, &id, &sz); 
        declared += sz; 
        addsym(ssname, id, type,  sz, csp - declared, &locptr, AUTOMATIC); 
        if(match(",") == 0) return; 
        } 
      } 
     
    compound()  { 
      int savcsp; 
      char *savloc; 
      savcsp = csp; 
      savloc = locptr; 
      declared = 0;           /* may now declare local variables */ 
      ++ncmp;                 /* new level open */ 
      while (match("}") == 0) 
        if(eof) { 
          error("no final }"); 
          break; 
          } 
        else statement();     /* do one */ 
      if(--ncmp               /* close current level */ 
      && lastst != STRETURN 
      && lastst != STGOTO) 
        gen(ADDSP, savcsp);   /* delete local variable space */ 
      cptr = savloc;          /* retain labels */ 
      while(cptr < locptr) { 
        cptr2 = nextsym(cptr); 
        if(cptr[IDENT] == LABEL) { 
          while(cptr < cptr2) *savloc++ = *cptr++; 
          } 
        else cptr = cptr2; 
        } 
      locptr = savloc;        /* delete local symbols */ 
      declared = -1;          /* may not declare variables */ 
      } 
     
    doif()  { 
      int flab1, flab2; 
      test(flab1 = getlabel(), YES);  /* get expr, and branch false */ 
      statement();                    /* if true, do a statement */ 
      if(amatch("else", 4) == 0) {    /* if...else ? */ 
        /* simple "if"...print false label */ 
        gen(LABm, flab1); 
        return;                       /* and exit */ 
        } 
      flab2 = getlabel(); 
      if(lastst != STRETURN && lastst != STGOTO) 
        gen(JMPm, flab2); 
      gen(LABm, flab1);    /* print false label */ 
      statement();         /* and do "else" clause */ 
      gen(LABm, flab2);    /* print true label */ 
      } 
     
    dowhile()  { 
      int wq[4];              /* allocate local queue */ 
      addwhile(wq);           /* add entry to queue for "break" */ 
      gen(LABm, wq[WQLOOP]);  /* loop label */ 
      test(wq[WQEXIT], YES);  /* see if true */ 
      statement();            /* if so, do a statement */ 
      gen(JMPm, wq[WQLOOP]);  /* loop to label */ 
      gen(LABm, wq[WQEXIT]);  /* exit label */ 
      delwhile();             /* delete queue entry */ 
      } 
     
    dodo() { 
      int wq[4]; 
      addwhile(wq); 
      gen(LABm, wq[WQLOOP]); 
      statement(); 
      need("while"); 
      test(wq[WQEXIT], YES); 
      gen(JMPm, wq[WQLOOP]); 
      gen(LABm, wq[WQEXIT]); 
      delwhile(); 
      ns(); 
      } 
     
    dofor() { 
      int wq[4], lab1, lab2; 
      addwhile(wq); 
      lab1 = getlabel(); 
      lab2 = getlabel(); 
      need("("); 
      if(match(";") == 0) { 
        doexpr(NO);           /* expr 1 */ 
        ns(); 
        } 
      gen(LABm, lab1); 
      if(match(";") == 0) { 
        test(wq[WQEXIT], NO); /* expr 2 */ 
        ns(); 
        } 
      gen(JMPm, lab2); 
      gen(LABm, wq[WQLOOP]); 
      if(match(")") == 0) { 
        doexpr(NO);           /* expr 3 */ 
        need(")"); 
        } 
      gen(JMPm, lab1); 
      gen(LABm, lab2); 
      statement(); 
      gen(JMPm, wq[WQLOOP]); 
      gen(LABm, wq[WQEXIT]); 
      delwhile(); 
      } 
     
    doswitch() { 
      int wq[4], endlab, swact, swdef, *swnex, *swptr; 
      swact = swactive; 
      swdef = swdefault; 
      swnex = swptr = swnext; 
      addwhile(wq); 
      *(wqptr + WQLOOP - WQSIZ) = 0; 
      need("("); 
      doexpr(YES);                /* evaluate switch expression */ 
      need(")"); 
      swdefault = 0; 
      swactive = 1; 
      gen(JMPm, endlab = getlabel()); 
      statement();                /* cases, etc. */ 
      gen(JMPm, wq[WQEXIT]); 
      gen(LABm, endlab); 
      gen(SWITCH, 0);             /* match cases */ 
      while(swptr < swnext) { 
        gen(NEARm, *swptr++); 
        gen(WORDn,  *swptr++);    /* case value */ 
        } 
      gen(WORDn, 0); 
      if(swdefault) gen(JMPm, swdefault); 
      gen(LABm, wq[WQEXIT]); 
      delwhile(); 
      swnext    = swnex; 
      swdefault = swdef; 
      swactive  = swact; 
      } 
     
    docase() { 
      if(swactive == 0) error("not in switch"); 
      if(swnext > swend) { 
        error("too many cases"); 
        return; 
        } 
      gen(LABm, *swnext++ = getlabel()); 
      constexpr(swnext++); 
      need(":"); 
      } 
     
    dodefault() { 
      if(swactive) { 
        if(swdefault) error("multiple defaults"); 
        } 
      else error("not in switch"); 
      need(":"); 
      gen(LABm, swdefault = getlabel()); 
      } 
     
    dogoto() { 
      if(nogo > 0) error("not allowed with block-locals"); 
      else noloc = 1; 
      if(symname(ssname)) gen(JMPm, addlabel()); 
      else error("bad label"); 
      ns(); 
      } 
     
    dolabel() { 
      char *savelptr; 
      blanks(); 
      savelptr = lptr; 
      if(symname(ssname)) { 
        if(gch() == ':') { 
          gen(LABm, addlabel()); 
          return 1; 
          } 
        else bump(savelptr-lptr); 
        } 
      return 0; 
      } 
     
    addlabel()  { 
      if(cptr = findloc(ssname)) { 
        if(cptr[IDENT] != LABEL) error("not a label"); 
        } 
      else cptr = addsym(ssname, LABEL, LABEL, 0, getlabel(), &locptr, LABEL); 
      return (getint(cptr+OFFSET, 2)); 
      } 
     
    doreturn()  { 
      int savcsp; 
      if(endst() == 0) doexpr(YES); 
      savcsp = csp; 
      gen(RETURN, 0); 
      csp = savcsp; 
      } 
     
    dobreak()  { 
      int *ptr; 
      if((ptr = readwhile(wqptr)) == 0) return; 
      gen(ADDSP, ptr[WQSP]); 
      gen(JMPm, ptr[WQEXIT]); 
      } 
     
    docont()  { 
      int *ptr; 
      ptr = wqptr; 
      while (1) { 
        if((ptr = readwhile(ptr)) == 0) return; 
        if(ptr[WQLOOP]) break; 
        } 
      gen(ADDSP, ptr[WQSP]); 
      gen(JMPm, ptr[WQLOOP]); 
      } 
     
    doasm()  { 
      ccode = 0;           /* mark mode as "asm" */ 
      while (1) { 
        inline(); 
        if(match("#endasm")) break; 
        if(eof)break; 
        fputs(line, output); 
        } 
      kill(); 
      ccode = 1; 
      } 
     
    doexpr(use) int use; { 
      int const, val; 
      int *before, *start; 
      usexpr = use;        /* tell isfree() whether expr value is used */ 
      while(1) { 
        setstage(&before, &start); 
        expression(&const, &val); 
        clearstage(before, start); 
        if(ch != ',') break; 
        bump(1); 
        } 
      usexpr = YES;        /* return to normal value */ 
      } 
     
    /******************** miscellaneous functions *******************/ 
     
    /* 
    ** get run options 
    */ 
    ask() { 
      int i; 
      i = listfp = nxtlab = 0; 
      output = stdout; 
      optimize = YES; 
      alarm = monitor = pause = NO; 
      line = mline; 
      while(getarg(++i, line, LINESIZE, argcs, argvs) != EOF) { 
        if(line[0] != '-') continue; 
        if(toupper(line[1]) == 'L' 
        && isdigit(line[2]) 
        && line[3] <= ' ') { 
          listfp = line[2]-'0'; 
          continue; 
          } 
        if(toupper(line[1]) == 'N' 
        && toupper(line[2]) == 'O' 
        && line[3] <= ' ') { 
          optimize = NO; 
          continue; 
          } 
        if(line[2] <= ' ') { 
          if(toupper(line[1]) == 'A') {alarm   = YES; continue;} 
          if(toupper(line[1]) == 'M') {monitor = YES; continue;} 
          if(toupper(line[1]) == 'P') {pause   = YES; continue;} 
          } 
        fputs("usage: cc [file]... [-m] [-a] [-p] [-l#] [-no]\n", stderr); 
        abort(ERRCODE); 
        } 
      } 
     
    /* 
    ** input and output file opens 
    */ 
    openfile() {        /* entire function revised */ 
      char outfn[15]; 
      int i, j, ext; 
      input = EOF; 
      while(getarg(++filearg, pline, LINESIZE, argcs, argvs) != EOF) { 
        if(pline[0] == '-') continue; 
        ext = NO; 
        i = -1; 
        j = 0; 
        while(pline[++i]) { 
          if(pline[i] == '.') { 
            ext = YES; 
            break; 
            } 
          if(j < 10) outfn[j++] = pline[i]; 
          } 
        if(!ext) strcpy(pline + i, ".C"); 
        input = mustopen(pline, "r"); 
        if(!files && iscons(stdout)) { 
          strcpy(outfn + j, ".ASM"); 
          output = mustopen(outfn, "w"); 
          } 
        files = YES; 
        kill(); 
        return; 
        } 
      if(files++) eof = YES; 
      else input = stdin; 
      kill(); 
      } 
     
    /* 
    ** open a file with error checking 
    */ 
    mustopen(fn, mode) char *fn, *mode; { 
      int fd; 
      if(fd = fopen(fn, mode)) return fd; 
      fputs("open error on ", stderr); 
      lout(fn, stderr); 
      abort(ERRCODE); 
      } 
     
     
    _____________________________________________________________________ 
                                   cc2.c 
    _____________________________________________________________________ 
    /* 
    ** Small-C Compiler -- Part 2 -- Front End and Miscellaneous. 
    ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix 
    ** All rights reserved. 
    */ 
     
    #include <stdio.h> 
    #include "cc.h" 
     
    extern char 
     *symtab, *macn, *macq, *pline, *mline,  optimize, 
      alarm, *glbptr, *line, *lptr, *cptr, *cptr2,  *cptr3, 
     *locptr, msname[NAMESIZE],  pause,  quote[2]; 
     
    extern int 
      *wq,  ccode,  ch,  csp,  eof,  errflag,  iflevel, 
      input,  input2,  listfp,  macptr,  nch, 
      nxtlab,  op[16],  opindex,  opsize,  output,  pptr, 
      skiplevel,  *wqptr; 
     
    /********************** input functions **********************/ 
     
    preprocess() { 
      int k; 
      char c; 
      if(ccode) { 
        line = mline; 
        ifline(); 
        if(eof) return; 
        } 
      else { 
        inline(); 
        return; 
        } 
      pptr = -1; 
      while(ch != NEWLINE && ch) { 
        if(white()) { 
          keepch(' '); 
          while(white()) gch(); 
          } 
        else if(ch == '"') { 
          keepch(ch); 
          gch(); 
          while(ch != '"' || (*(lptr-1) == 92 && *(lptr-2) != 92)) { 
            if(ch == NULL) { 
              error("no quote"); 
              break; 
              } 
            keepch(gch()); 
            } 
          gch(); 
          keepch('"'); 
          } 
        else if(ch == 39) { 
          keepch(39); 
          gch(); 
          while(ch != 39 || (*(lptr-1) == 92 && *(lptr-2) != 92)) { 
            if(ch == NULL) { 
              error("no apostrophe"); 
              break; 
              } 
            keepch(gch()); 
            } 
          gch(); 
          keepch(39); 
          } 
        else if(ch == '/' && nch == '*') { 
          bump(2); 
          while((ch == '*' && nch == '/') == 0) { 
            if(ch) bump(1); 
            else { 
              ifline(); 
              if(eof) break; 
              } 
            } 
          bump(2); 
          } 
        else if(an(ch)) { 
          k = 0; 
          while(an(ch) && k < NAMEMAX) { 
            msname[k++] = ch; 
            gch(); 
            } 
          msname[k] = NULL; 
          if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) { 
            k = getint(cptr+NAMESIZE, 2); 
            while(c = macq[k++]) keepch(c); 
            while(an(ch)) gch(); 
            } 
          else { 
            k = 0; 
            while(c = msname[k++]) keepch(c); 
            } 
          } 
        else keepch(gch()); 
        } 
      if(pptr >= LINEMAX) error("line too long"); 
      keepch(NULL); 
      line = pline; 
      bump(0); 
      } 
     
    keepch(c)  char c; { 
      if(pptr < LINEMAX) pline[++pptr] = c; 
      } 
     
    ifline() { 
      while(1) { 
        inline(); 
        if(eof) return; 
        if(match("#ifdef")) { 
          ++iflevel; 
          if(skiplevel) continue; 
          symname(msname); 
          if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) 
            skiplevel = iflevel; 
          continue; 
          } 
        if(match("#ifndef")) { 
          ++iflevel; 
          if(skiplevel) continue; 
          symname(msname); 
          if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) 
            skiplevel = iflevel; 
          continue; 
          } 
        if(match("#else")) { 
          if(iflevel) { 
            if(skiplevel == iflevel) skiplevel = 0; 
            else if(skiplevel == 0)  skiplevel = iflevel; 
            } 
          else noiferr(); 
          continue; 
          } 
        if(match("#endif")) { 
          if(iflevel) { 
            if(skiplevel == iflevel) skiplevel = 0; 
            --iflevel; 
            } 
          else noiferr(); 
          continue; 
          } 
        if(skiplevel) continue; 
        if(ch == 0) continue; 
        break; 
        } 
      } 
     
    inline() {           /* numerous revisions */ 
      int k, unit; 
      poll(1);           /* allow operator interruption */ 
      if(input == EOF) openfile(); 
      if(eof) return; 
      if((unit = input2) == EOF) unit = input; 
      if(fgets(line, LINEMAX, unit) == NULL) { 
        fclose(unit); 
        if(input2 != EOF) 
             input2 = EOF; 
        else input  = EOF; 
        *line = NULL; 
        } 
      else if(listfp) { 
        if(listfp == output) fputc(';', output); 
        fputs(line, listfp); 
        } 
      bump(0); 
      } 
     
    inbyte()  { 
      while(ch == 0) { 
        if(eof) return 0; 
        preprocess(); 
        } 
      return gch(); 
      } 
     
    /********************* scanning functions ********************/ 
     
    /* 
    ** test if next input string is legal symbol name 
    */ 
    symname(sname) char *sname; { 
      int k;char c; 
      blanks(); 
      if(alpha(ch) == 0) return (*sname = 0); 
      k = 0; 
      while(an(ch)) { 
        sname[k] = gch(); 
        if(k < NAMEMAX) ++k; 
        } 
      sname[k] = 0; 
      return 1; 
      } 
     
    need(str)  char *str; { 
      if(match(str) == 0) error("missing token"); 
      } 
     
    ns()  { 
      if(match(";") == 0) error("no semicolon"); 
      else errflag = 0; 
      } 
     
    match(lit)  char *lit; { 
      int k; 
      blanks(); 
      if(k = streq(lptr, lit)) { 
        bump(k); 
        return 1; 
        } 
      return 0; 
      } 
     
    streq(str1, str2)  char str1[], str2[]; { 
      int k; 
      k = 0; 
      while (str2[k]) { 
        if(str1[k] != str2[k]) return 0; 
        ++k; 
        } 
      return k; 
     } 
     
    amatch(lit, len)  char *lit; int len; { 
      int k; 
      blanks(); 
      if(k = astreq(lptr, lit, len)) { 
        bump(k); 
        return 1; 
        } 
      return 0; 
     } 
     
    astreq(str1, str2, len)  char str1[], str2[]; int len; { 
      int k; 
      k = 0; 
      while (k < len) { 
        if(str1[k] != str2[k]) break; 
        /* 
        ** must detect end of symbol table names terminated by 
        ** symbol length in binary 
        */ 
        if(str2[k] < ' ') break; 
        if(str1[k] < ' ') break; 
        ++k; 
        } 
      if(an(str1[k]) || an(str2[k])) return 0; 
      return k; 
      } 
     
    nextop(list) char *list; { 
      char op[4]; 
      opindex = 0; 
      blanks(); 
      while(1) { 
        opsize = 0; 
        while(*list > ' ') op[opsize++] = *list++; 
        op[opsize] = 0; 
        if(opsize = streq(lptr, op)) 
          if(*(lptr+opsize) != '=' &&  
             *(lptr+opsize) != *(lptr+opsize-1)) 
             return 1; 
        if(*list) { 
          ++list; 
          ++opindex; 
          } 
        else return 0; 
        } 
      } 
     
    blanks() { 
      while(1) { 
        while(ch) { 
          if(white()) gch(); 
          else return; 
          } 
        if(line == mline) return; 
        preprocess(); 
        if(eof) break; 
        } 
      } 
     
    white() { 
      avail(YES);  /* abort on stack/symbol table overflow */ 
      return (*lptr <= ' ' && *lptr); 
      } 
     
    gch() { 
      int c; 
      if(c = ch) bump(1); 
      return c; 
      } 
     
    bump(n) int n; { 
      if(n) lptr += n; 
      else  lptr  = line; 
      if(ch = nch = *lptr) nch = *(lptr+1); 
      } 
     
    kill() { 
      *line = 0; 
      bump(0); 
      } 
     
    skip() { 
      if(an(inbyte())) 
           while(an(ch)) gch(); 
      else while(an(ch) == 0) { 
        if(ch == 0) break; 
        gch(); 
        } 
      blanks(); 
      } 
     
    endst() { 
      blanks(); 
      return (streq(lptr, ";") || ch == 0); 
      } 
     
    /*********** symbol table management functions ***********/ 
     
    addsym(sname, id, type, size, value, lgpp, class) 
      char *sname, id, type;  int size, value, *lgpp, class; { 
      if(lgpp == &glbptr) { 
        if(cptr2 = findglb(sname)) return cptr2; 
        if(cptr == 0) { 
          error("global symbol table overflow"); 
          return 0; 
          } 
        } 
      else { 
        if(locptr > (ENDLOC-SYMMAX)) { 
          error("local symbol table overflow"); 
          abort(ERRCODE); 
          } 
        cptr = *lgpp; 
        } 
      cptr[IDENT] = id; 
      cptr[TYPE]  = type; 
      cptr[CLASS] = class; 
      putint(size, cptr + SIZE, 2); 
      putint(value, cptr + OFFSET, 2); 
      cptr3 = cptr2 = cptr + NAME; 
      while(an(*sname)) *cptr2++ = *sname++; 
      if(lgpp == &locptr) { 
        *cptr2 = cptr2 - cptr3;         /* set length */ 
        *lgpp = ++cptr2; 
        } 
      return cptr; 
      } 
     
    /* 
    ** search for symbol match 
    ** on return cptr points to slot found or empty slot 
    */ 
    search(sname, buf, len, end, max, off) 
      char *sname, *buf, *end;  int len, max, off; { 
      cptr  = 
      cptr2 = buf+((hash(sname)%(max-1))*len); 
      while(*cptr != NULL) { 
        if(astreq(sname, cptr+off, NAMEMAX)) return 1; 
        if((cptr = cptr+len) >= end) cptr = buf; 
        if(cptr == cptr2) return (cptr = 0); 
        } 
      return 0; 
      } 
     
    hash(sname) char *sname; { 
      int i, c; 
      i = 0; 
      while(c = *sname++) i = (i << 1) + c; 
      return i; 
      } 
     
    findglb(sname)  char *sname; { 
      if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) 
        return cptr; 
      return 0; 
      } 
     
    findloc(sname)  char *sname;  { 
      cptr = locptr - 1;  /* search backward for block locals */ 
      while(cptr > STARTLOC) { 
        cptr = cptr - *cptr; 
        if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); 
        cptr = cptr - NAME - 1; 
        } 
      return 0; 
      } 
     
    nextsym(entry) char *entry; { 
      entry = entry + NAME; 
      while(*entry++ >= ' ');    /* find length byte */ 
      return entry; 
      } 
     
    /******** while queue management functions *********/   
     
    addwhile(ptr)  int ptr[]; { 
      int k; 
      ptr[WQSP]   = csp;         /* and stk ptr */ 
      ptr[WQLOOP] = getlabel();  /* and looping label */ 
      ptr[WQEXIT] = getlabel();  /* and exit label */ 
      if(wqptr == WQMAX) { 
        error("control statement nesting limit"); 
        abort(ERRCODE); 
        } 
      k = 0; 
      while (k < WQSIZ) *wqptr++ = ptr[k++]; 
      } 
     
    readwhile(ptr) int *ptr; { 
      if(ptr <= wq) { 
        error("out of context"); 
        return 0; 
        } 
      else return (ptr - WQSIZ); 
     } 
     
    delwhile() { 
      if(wqptr > wq) wqptr -= WQSIZ; 
      } 
     
    /****************** utility functions ********************/   
     
    /* 
    ** test if c is alphabetic 
    */ 
    alpha(c)  char c; { 
      return (isalpha(c) || c == '_'); 
      } 
     
    /* 
    ** test if given character is alphanumeric 
    */ 
    an(c)  char c; { 
      return (alpha(c) || isdigit(c)); 
      } 
     
    /* 
    ** return next avail internal label number 
    */ 
    getlabel() { 
      return(++nxtlab); 
      } 
     
    /* 
    ** get integer of length len from address addr 
    ** (byte sequence set by "putint") 
    */ 
    getint(addr, len) char *addr; int len; { 
      int i; 
      i = *(addr + --len);  /* high order byte sign extended */ 
      while(len--) i = (i << 8) | *(addr + len) & 255; 
      return i; 
      } 
     
    /* 
    ** put integer i of length len into address addr 
    ** (low byte first) 
    */ 
    putint(i, addr, len) char *addr; int i, len; { 
      while(len--) { 
        *addr++ = i; 
        i = i >> 8; 
        } 
      } 
     
    lout(line, fd) char *line; int fd; { 
      fputs(line, fd); 
      fputc(NEWLINE, fd); 
      } 
     
    /******************* error functions *********************/   
     
    illname() { 
      error("illegal symbol"); 
      skip(); 
      } 
     
    multidef(sname)  char *sname; { 
      error("already defined"); 
      } 
     
    needlval() { 
      error("must be lvalue"); 
      } 
     
    noiferr() { 
      error("no matching #if..."); 
      errflag = 0; 
      } 
     
    error(msg) char msg[]; { 
      if(errflag) return; 
      else errflag = 1; 
      lout(line, stderr); 
      errout(msg, stderr); 
      if(alarm) fputc(7, stderr); 
      if(pause) while(fgetc(stderr) != NEWLINE); 
      if(listfp > 0) errout(msg, listfp); 
      } 
     
    errout(msg, fp) char msg[]; int fp; { 
      int k; 
      k = line+2; 
      while(k++ <= lptr) fputc(' ', fp); 
      lout("/_S0",_T fp); 
      fputs("**** ", fp); lout(msg, fp); 
      } 
     
     
    _____________________________________________________________________ 
                                   cc3.c 
    _____________________________________________________________________ 
    /* 
    ** Small-C Compiler -- Part 3 -- Expression Analyzer. 
    ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix 
    ** All rights reserved. 
    */ 
     
    #include <stdio.h> 
    #include "cc.h" 
     
    #define ST 0   /* is[ST] - symbol table address, else 0 */ 
    #define TI 1   /* is[TI] - type of indirect obj to fetch, else 0 */ 
    #define TA 2   /* is[TA] - type of address, else 0 */ 
    #define TC 3   /* is[TC] - type of constant (INT or UINT), else 0 */ 
    #define CV 4   /* is[CV] - value of constant (+ auxiliary uses) */ 
    #define OP 5   /* is[OP] - code of highest/last binary operator */ 
    #define SA 6   /* is[SA] - stage address of "op 0" code, else 0 */ 
     
    extern char 
     *litq, *glbptr, *lptr,  ssname[NAMESIZE],  quote[2]; 
    extern int 
      ch,  csp,  litlab,  litptr,  nch,  op[16],  op2[16], 
      opindex,  opsize, *snext; 
     
    /***************** lead-in functions *******************/ 
     
    constexpr(val) int *val; { 
      int const; 
      int *before, *start; 
      setstage(&before, &start); 
      expression(&const, val); 
      clearstage(before, 0);     /* scratch generated code */ 
      if(const == 0) error("must be constant expression"); 
      return const; 
      } 
     
    expression(con, val) int *con, *val;  { 
      int is[7]; 
      if(level1(is)) fetch(is); 
      *con = is[TC]; 
      *val = is[CV]; 
      } 
     
    test(label, parens)  int label, parens;  { 
      int is[7]; 
      int *before, *start; 
      if(parens) need("("); 
      while(1) { 
        setstage(&before, &start); 
        if(level1(is)) fetch(is); 
        if(match(",")) clearstage(before, start); 
        else break; 
        } 
      if(parens) need(")"); 
      if(is[TC]) {             /* constant expression */ 
        clearstage(before, 0); 
        if(is[CV]) return; 
        gen(JMPm, label); 
        return; 
        } 
      if(is[SA]) {             /* stage address of "oper 0" code */ 
        switch(is[OP]) {       /* operator code */ 
          case EQ12: 
          case LE12u: zerojump(EQ10f, label, is); break; 
          case NE12: 
          case GT12u: zerojump(NE10f, label, is); break; 
          case GT12:  zerojump(GT10f, label, is); break; 
          case GE12:  zerojump(GE10f, label, is); break; 
          case GE12u: clearstage(is[SA], 0);      break; 
          case LT12:  zerojump(LT10f, label, is); break; 
          case LT12u: zerojump(JMPm,  label, is); break; 
          case LE12:  zerojump(LE10f, label, is); break; 
          default:    gen(NE10f, label);          break; 
          } 
        } 
      else gen(NE10f, label); 
      clearstage(before, start); 
      } 
     
    /* 
    ** test primary register against zero and jump if false 
    */ 
    zerojump(oper, label, is) int oper, label, is[]; { 
      clearstage(is[SA], 0);       /* purge conventional code */ 
      gen(oper, label); 
      } 
     
    /***************** precedence levels ******************/ 
     
    level1(is) int is[];  { 
      int k, is2[7], is3[2], oper, oper2; 
      k = down1(level2, is); 
      if(is[TC]) gen(GETw1n, is[CV]); 
           if(match("|="))  {oper =        oper2 = OR12;} 
      else if(match("^="))  {oper =        oper2 = XOR12;} 
      else if(match("&="))  {oper =        oper2 = AND12;} 
      else if(match("+="))  {oper =        oper2 = ADD12;} 
      else if(match("-="))  {oper =        oper2 = SUB12;} 
      else if(match("*="))  {oper = MUL12; oper2 = MUL12u;} 
      else if(match("/="))  {oper = DIV12; oper2 = DIV12u;} 
      else if(match("%="))  {oper = MOD12; oper2 = MOD12u;} 
      else if(match(">>=")) {oper =        oper2 = ASR12;} 
      else if(match("<<=")) {oper =        oper2 = ASL12;} 
      else if(match("="))   {oper =        oper2 = 0;} 
      else return k; 
                            /* have an assignment operator */ 
      if(k == 0) { 
        needlval(); 
        return 0; 
        } 
      is3[ST] = is[ST]; 
      is3[TI] = is[TI]; 
      if(is[TI]) {                             /* indirect target */ 
        if(oper) {                             /* ?= */ 
          gen(PUSH1, 0);                       /* save address */ 
          fetch(is);                           /* fetch left side */ 
          } 
        down2(oper, oper2, level1, is, is2);   /* parse right side */ 
        if(oper) gen(POP2, 0);                 /* retrieve address */ 
        } 
      else {                                   /* direct target */ 
        if(oper) {                             /* ?= */ 
          fetch(is);                           /* fetch left side */ 
          down2(oper, oper2, level1, is, is2); /* parse right side */ 
          } 
        else {                                 /*  = */ 
          if(level1(is2)) fetch(is2);          /* parse right side */ 
          } 
        } 
      store(is3);                              /* store result */ 
      return 0; 
      } 
     
    level2(is1)  int is1[]; { 
      int is2[7], is3[7], k, flab, endlab, *before, *after; 
      k = down1(level3, is1);                   /* expression 1 */ 
      if(match("?") == 0) return k; 
      dropout(k, NE10f, flab = getlabel(), is1); 
      if(down1(level2, is2)) fetch(is2);        /* expression 2 */ 
      else if(is2[TC]) gen(GETw1n, is2[CV]); 
      need(":"); 
      gen(JMPm, endlab = getlabel()); 
      gen(LABm, flab); 
      if(down1(level2, is3)) fetch(is3);        /* expression 3 */ 
      else if(is3[TC]) gen(GETw1n, is3[CV]); 
      gen(LABm, endlab); 
     
      is1[TC] = is1[CV] = 0; 
      if(is2[TC] && is3[TC]) {                  /* expr1 ? const2 : const3 */ 
        is1[TA] = is1[TI] = is1[SA] = 0; 
        } 
      else if(is3[TC]) {                        /* expr1 ? var2 : const3 */ 
        is1[TA] = is2[TA]; 
        is1[TI] = is2[TI]; 
        is1[SA] = is2[SA]; 
        } 
      else if((is2[TC])                         /* expr1 ? const2 : var3 */ 
           || (is2[TA] == is3[TA])) {           /* expr1 ? same2 : same3 */ 
        is1[TA] = is3[TA]; 
        is1[TI] = is3[TI]; 
        is1[SA] = is3[SA]; 
        } 
      else error("mismatched expressions"); 
      return 0; 
      } 
     
    level3 (is) int is[]; {return skim("||", EQ10f, 1, 0, level4,  is);} 
    level4 (is) int is[]; {return skim("&&", NE10f, 0, 1, level5,  is);} 
    level5 (is) int is[]; {return down("|",            0, level6,  is);} 
    level6 (is) int is[]; {return down("^",            1, level7,  is);} 
    level7 (is) int is[]; {return down("&",            2, level8,  is);} 
    level8 (is) int is[]; {return down("== !=",        3, level9,  is);} 
    level9 (is) int is[]; {return down("<= >= < >",    5, level10, is);} 
    level10(is) int is[]; {return down(">> <<",        9, level11, is);} 
    level11(is) int is[]; {return down("+ -",         11, level12, is);} 
    level12(is) int is[]; {return down("* / %",       13, level13, is);} 
     
    level13(is)  int is[];  { 
      int k; 
      char *ptr; 
      if(match("++")) {                 /* ++lval */ 
        if(level13(is) == 0) { 
          needlval(); 
          return 0; 
          } 
        step(rINC1, is, 0); 
        return 0; 
        } 
      else if(match("--")) {            /* --lval */ 
        if(level13(is) == 0) { 
          needlval(); 
          return 0; 
          } 
        step(rDEC1, is, 0); 
        return 0; 
        } 
      else if(match(" ")) {             /*   */ 
        if(level13(is)) fetch(is); 
        gen(COM1, 0); 
        is[CV] =   is[CV]; 
        return (is[SA] = 0); 
        } 
      else if(match("!")) {             /* ! */ 
        if(level13(is)) fetch(is); 
        gen(LNEG1, 0); 
        is[CV] = ! is[CV]; 
        return (is[SA] = 0); 
        } 
      else if(match("-")) {             /* unary - */ 
        if(level13(is)) fetch(is); 
        gen(ANEG1, 0); 
        is[CV] = -is[CV]; 
        return (is[SA] = 0); 
        } 
      else if(match("*")) {             /* unary * */ 
        if(level13(is)) fetch(is); 
        if(ptr = is[ST]) is[TI] = ptr[TYPE]; 
        else             is[TI] = INT; 
        is[SA] =       /* no (op 0) stage address */ 
        is[TA] =       /* not an address */ 
        is[TC] = 0;    /* not a constant */ 
        is[CV] = 1;    /* omit fetch() on func call */ 
        return 1; 
        } 
      else if(amatch("sizeof", 6)) {    /* sizeof() */ 
        int sz, p;  char *ptr, sname[NAMESIZE]; 
        if(match("(")) p = 1; 
        else           p = 0; 
        sz = 0; 
        if     (amatch("unsigned", 8))  sz = BPW; 
        if     (amatch("int",      3))  sz = BPW; 
        else if(amatch("char",     4))  sz = 1; 
        if(sz) {if(match("*"))          sz = BPW;} 
        else if(symname(sname) 
             && ((ptr = findloc(sname)) || 
                 (ptr = findglb(sname))) 
             && ptr[IDENT] != FUNCTION 
             && ptr[IDENT] != LABEL)    sz = getint(ptr+SIZE, 2); 
        else if(sz == 0) error("must be object or type"); 
        if(p) need(")"); 
        is[TC] = INT; 
        is[CV] = sz; 
        is[TA] = is[TI] = is[ST] = 0; 
        return 0; 
        } 
      else if(match("&")) {             /* unary & */ 
        if(level13(is) == 0) { 
          error("illegal address"); 
          return 0; 
          } 
        ptr = is[ST]; 
        is[TA] = ptr[TYPE]; 
        if(is[TI]) return 0; 
        gen(POINT1m, ptr); 
        is[TI] = ptr[TYPE]; 
        return 0; 
        } 
      else { 
        k = level14(is); 
        if(match("++")) {               /* lval++ */ 
          if(k == 0) { 
            needlval(); 
            return 0; 
            } 
          step(rINC1, is, rDEC1); 
          return 0; 
          } 
        else if(match("--")) {          /* lval-- */ 
          if(k == 0) { 
            needlval(); 
            return 0; 
            } 
          step(rDEC1, is, rINC1); 
          return 0; 
          } 
        else return k; 
        } 
      } 
     
    level14(is)  int *is; { 
      int k, const, val; 
      char *ptr, *before, *start; 
      k = primary(is); 
      ptr = is[ST]; 
      blanks(); 
      if(ch == '[' || ch == '(') { 
        int is2[7];                     /* allocate only if needed */ 
        while(1) { 
          if(match("[")) {              /* [subscript] */ 
            if(ptr == 0) { 
              error("can't subscript"); 
              skip(); 
              need("]"); 
              return 0; 
              } 
            if(is[TA]) {if(k) fetch(is);} 
            else       {error("can't subscript"); k = 0;} 
            setstage(&before, &start); 
            is2[TC] = 0; 
            down2(0, 0, level1, is2, is2); 
            need("]"); 
            if(is2[TC]) { 
              clearstage(before, 0); 
              if(is2[CV]) {             /* only add if non-zero */ 
                if(ptr[TYPE] >> 2 == BPW) 
                     gen(GETw2n, is2[CV] << LBPW); 
                else gen(GETw2n, is2[CV]); 
                gen(ADD12, 0); 
                } 
              } 
            else { 
              if(ptr[TYPE] >> 2 == BPW) gen(DBL1, 0); 
              gen(ADD12, 0); 
              } 
            is[TA] = 0; 
            is[TI] = ptr[TYPE]; 
            k = 1; 
            } 
          else if(match("(")) {         /* function(...) */ 
            if(ptr == 0) callfunc(0); 
            else if(ptr[IDENT] != FUNCTION) { 
              if(k && !is[CV]) fetch(is); 
              callfunc(0); 
              } 
            else callfunc(ptr); 
            k = is[ST] = is[TC] = is[CV] = 0; 
            } 
          else return k; 
          } 
        } 
      if(ptr && ptr[IDENT] == FUNCTION) { 
        gen(POINT1m, ptr); 
        is[ST] = 0; 
        return 0; 
        } 
      return k; 
      } 
     
    primary(is)  int *is; { 
      char *ptr, sname[NAMESIZE]; 
      int k; 
      if(match("(")) {                  /* (subexpression) */  
        do k = level1(is); while(match(",")); 
        need(")"); 
        return k; 
        } 
      putint(0, is, 7 << LBPW);         /* clear "is" array */ 
      if(symname(sname)) {              /* is legal symbol */ 
        if(ptr = findloc(sname)) {      /* is local */ 
          if(ptr[IDENT] == LABEL) { 
            experr(); 
            return 0; 
            } 
          gen(POINT1s, getint(ptr+OFFSET, 2)); 
          is[ST] = ptr; 
          is[TI] = ptr[TYPE]; 
          if(ptr[IDENT] == ARRAY) { 
            is[TA] = ptr[TYPE]; 
            return 0; 
            } 
          if(ptr[IDENT] == POINTER) { 
            is[TI] = UINT; 
            is[TA] = ptr[TYPE]; 
            } 
          return 1; 
          } 
        if(ptr = findglb(sname)) {      /* is global */ 
          is[ST] = ptr; 
          if(ptr[IDENT] != FUNCTION) { 
            if(ptr[IDENT] == ARRAY) { 
              gen(POINT1m, ptr); 
              is[TI] =  
              is[TA] = ptr[TYPE]; 
              return 0; 
              } 
            if(ptr[IDENT] == POINTER) 
              is[TA] = ptr[TYPE]; 
            return 1; 
            } 
          } 
        else is[ST] = addsym(sname, FUNCTION, INT, 0, 0, &glbptr, AUTOEXT); 
        return 0; 
        } 
      if(constant(is) == 0) experr(); 
      return 0; 
      } 
     
    experr() { 
      error("invalid expression"); 
      gen(GETw1n, 0); 
      skip(); 
      } 
     
    callfunc(ptr)  char *ptr; {      /* symbol table entry or 0 */ 
      int nargs, const, val; 
      nargs = 0; 
      blanks();                      /* already saw open paren */ 
      while(streq(lptr, ")") == 0) { 
        if(endst()) break; 
        if(ptr) { 
          expression(&const, &val); 
          gen(PUSH1, 0); 
          } 
        else { 
          gen(PUSH1, 0); 
          expression(&const, &val); 
          gen(SWAP1s, 0);            /* don't push addr */ 
          } 
        nargs = nargs + BPW;         /* count args*BPW */ 
        if(match(",") == 0) break; 
        } 
      need(")"); 
      if(streq(ptr + NAME, "CCARGC") == 0) gen(ARGCNTn, nargs >> LBPW); 
      if(ptr) gen(CALLm, ptr); 
      else    gen(CALL1, 0); 
      gen(ADDSP, csp + nargs); 
      } 
     
    /* 
    ** true if is2's operand should be doubled 
    */ 
    double(oper, is1, is2) int oper, is1[], is2[]; { 
      if((oper != ADD12 && oper != SUB12) 
      || (is1[TA] >> 2 != BPW) 
      || (is2[TA])) return 0; 
      return 1; 
      } 
     
    step(oper, is, oper2) int oper, is[], oper2; { 
      fetch(is); 
      gen(oper, is[TA] ? (is[TA] >> 2) : 1); 
      store(is); 
      if(oper2) gen(oper2, is[TA] ? (is[TA] >> 2) : 1); 
      } 
     
    store(is)  int is[]; { 
      char *ptr; 
      if(is[TI]) {                    /* putstk */ 
        if(is[TI] >> 2 == 1) 
             gen(PUTbp1, 0); 
        else gen(PUTwp1, 0); 
        } 
      else {                          /* putmem */ 
        ptr = is[ST]; 
        if(ptr[IDENT] != POINTER 
        && ptr[TYPE] >> 2 == 1) 
             gen(PUTbm1, ptr); 
        else gen(PUTwm1, ptr); 
        } 
      } 
     
    fetch(is) int is[]; { 
      char *ptr; 
      ptr = is[ST]; 
      if(is[TI]) {                                   /* indirect */ 
        if(is[TI] >> 2 == BPW)     gen(GETw1p,  0); 
        else { 
          if(ptr[TYPE] & UNSIGNED) gen(GETb1pu, 0); 
          else                     gen(GETb1p,  0); 
          } 
        }  
      else {                                         /* direct */ 
        if(ptr[IDENT] == POINTER 
        || ptr[TYPE] >> 2 == BPW)  gen(GETw1m,  ptr);  
        else { 
          if(ptr[TYPE] & UNSIGNED) gen(GETb1mu, ptr); 
          else                     gen(GETb1m,  ptr); 
          } 
        } 
      } 
     
    constant(is)  int is[]; { 
      int offset; 
      if     (is[TC] = number(is + CV)) gen(GETw1n,  is[CV]); 
      else if(is[TC] = chrcon(is + CV)) gen(GETw1n,  is[CV]); 
      else if(string(&offset))          gen(POINT1l, offset); 
      else return 0; 
      return 1; 
      } 
     
    number(value)  int *value; { 
      int k, minus; 
      k = minus = 0; 
      while(1) { 
        if(match("+")) ; 
        else if(match("-")) minus = 1; 
        else break; 
        } 
      if(isdigit(ch) == 0) return 0; 
      if(ch == '0') { 
        while(ch == '0') inbyte(); 
        if(toupper(ch) == 'X') { 
          inbyte(); 
          while(isxdigit(ch)) { 
            if(isdigit(ch)) 
                 k = k*16 + (inbyte() - '0'); 
            else k = k*16 + 10 + (toupper(inbyte()) - 'A'); 
            } 
          } 
        else while (ch >= '0' && ch <= '7') 
          k = k*8 + (inbyte() - '0'); 
        } 
      else while (isdigit(ch)) k = k*10 + (inbyte() - '0'); 
      if(minus) { 
        *value = -k; 
        return (INT); 
        } 
      if((*value = k) < 0) return (UINT); 
      else                 return (INT); 
      } 
     
    chrcon(value)  int *value; { 
      int k; 
      k = 0; 
      if(match("'") == 0) return 0; 
      while(ch != '\'') k = (k << 8) + (litchar() & 255); 
      gch(); 
      *value = k; 
      return (INT); 
      } 
     
    string(offset) int *offset; { 
      char c; 
      if(match(quote) == 0) return 0; 
      *offset = litptr; 
      while (ch != '"') { 
        if(ch == 0) break; 
        stowlit(litchar(), 1); 
        } 
      gch(); 
      litq[litptr++] = 0; 
      return 1; 
      } 
     
    stowlit(value, size) int value, size; { 
      if((litptr+size) >= LITMAX) { 
        error("literal queue overflow"); 
        abort(ERRCODE); 
        } 
      putint(value, litq+litptr, size); 
      litptr += size; 
      } 
     
    litchar() { 
      int i, oct; 
      if(ch != '_S0'_T || nch == 0) return gch(); 
      gch(); 
      switch(ch) { 
        case 'n': gch(); return NEWLINE; 
        case 't': gch(); return  9;  /* HT */ 
        case 'b': gch(); return  8;  /* BS */ 
        case 'f': gch(); return 12;  /* FF */ 
        } 
      i = 3; 
      oct = 0; 
      while((i--) > 0 && ch >= '0' && ch <= '7') 
        oct = (oct << 3) + gch() - '0'; 
      if(i == 2) return gch(); 
      else       return oct; 
      } 
     
    /***************** pipeline functions ******************/ 
     
    /* 
    ** skim over terms adjoining || and && operators 
    */ 
    skim(opstr, tcode, dropval, endval, level, is) 
      char *opstr; 
      int tcode, dropval, endval, (*level)(), is[]; { 
      int k, droplab, endlab; 
      droplab = 0; 
      while(1) { 
        k = down1(level, is); 
        if(nextop(opstr)) { 
          bump(opsize); 
          if(droplab == 0) droplab = getlabel(); 
          dropout(k, tcode, droplab, is); 
          } 
        else if(droplab) { 
          dropout(k, tcode, droplab, is); 
          gen(GETw1n, endval); 
          gen(JMPm, endlab = getlabel()); 
          gen(LABm, droplab); 
          gen(GETw1n, dropval); 
          gen(LABm, endlab); 
          is[TI] = is[TA] = is[TC] = is[CV] = is[SA] = 0; 
          return 0; 
          } 
        else return k; 
        } 
      } 
     
    /* 
    ** test for early dropout from || or && sequences 
    */ 
    dropout(k, tcode, exit1, is) 
      int k, tcode, exit1, is[]; { 
      if(k) fetch(is); 
      else if(is[TC]) gen(GETw1n, is[CV]); 
      gen(tcode, exit1);          /* jumps on false */ 
      }  
     
    /* 
    ** drop to a lower level 
    */ 
    down(opstr, opoff, level, is) 
      char *opstr;  int opoff, (*level)(), is[]; { 
      int k; 
      k = down1(level, is); 
      if(nextop(opstr) == 0) return k; 
      if(k) fetch(is); 
      while(1) { 
        if(nextop(opstr)) { 
          int is2[7];     /* allocate only if needed */ 
          bump(opsize); 
          opindex += opoff; 
          down2(op[opindex], op2[opindex], level, is, is2); 
          } 
        else return 0; 
        } 
      } 
     
    /* 
    ** unary drop to a lower level 
    */ 
    down1(level, is) int (*level)(), is[]; { 
      int k, *before, *start; 
      setstage(&before, &start); 
      k = (*level)(is); 
      if(is[TC]) clearstage(before, 0);  /* load constant later */ 
      return k; 
      } 
     
    /* 
    ** binary drop to a lower level 
    */ 
    down2(oper, oper2, level, is, is2) 
      int oper, oper2, (*level)(), is[], is2[]; { 
      int *before, *start; 
      char *ptr; 
      setstage(&before, &start); 
      is[SA] = 0;                     /* not "... op 0" syntax */ 
      if(is[TC]) {                    /* consant op unknown */ 
        if(down1(level, is2)) fetch(is2); 
        if(is[CV] == 0) is[SA] = snext; 
        gen(GETw2n, is[CV] << double(oper, is2, is)); 
        } 
      else {                          /* variable op unknown */ 
        gen(PUSH1, 0);                /* at start in the buffer */ 
        if(down1(level, is2)) fetch(is2); 
        if(is2[TC]) {                 /* variable op constant */ 
          if(is2[CV] == 0) is[SA] = start; 
          csp += BPW;                 /* adjust stack and */ 
          clearstage(before, 0);      /* discard the PUSH */ 
          if(oper == ADD12) {         /* commutative */ 
            gen(GETw2n, is2[CV] << double(oper, is, is2)); 
            } 
          else {                      /* non-commutative */ 
            gen(MOVE21, 0); 
            gen(GETw1n, is2[CV] << double(oper, is, is2)); 
            } 
          } 
        else {                        /* variable op variable */ 
          gen(POP2, 0); 
          if(double(oper, is, is2)) gen(DBL1, 0); 
          if(double(oper, is2, is)) gen(DBL2, 0); 
          } 
        } 
      if(oper) { 
        if(nosign(is) || nosign(is2)) oper = oper2; 
        if(is[TC] = is[TC] & is2[TC]) {               /* constant result */ 
          is[CV] = calc(is[CV], oper, is2[CV]); 
          clearstage(before, 0);   
          if(is2[TC] == UINT) is[TC] = UINT; 
          } 
        else {                                        /* variable result */ 
          gen(oper, 0); 
          if(oper == SUB12 
          && is [TA] >> 2 == BPW 
          && is2[TA] >> 2 == BPW) { /* difference of two word addresses */ 
            gen(SWAP12, 0); 
            gen(GETw1n, 1); 
            gen(ASR12, 0);          /* div by 2 */ 
            } 
          is[OP] = oper;            /* identify the operator */ 
          } 
        if(oper == SUB12 || oper == ADD12) { 
          if(is[TA] && is2[TA])     /*  addr +/- addr */ 
            is[TA] = 0; 
          else if(is2[TA]) {        /* value +/- addr */ 
            is[ST] = is2[ST]; 
            is[TI] = is2[TI]; 
            is[TA] = is2[TA]; 
            } 
          } 
        if(is[ST] == 0 || ((ptr = is2[ST]) && (ptr[TYPE] & UNSIGNED))) 
          is[ST] = is2[ST]; 
        } 
      } 
     
    /* 
    ** unsigned operand? 
    */ 
    nosign(is) int is[]; { 
      char *ptr; 
      if(is[TA] 
      || is[TC] == UINT 
      || ((ptr = is[ST]) && (ptr[TYPE] & UNSIGNED)) 
        ) return 1; 
      return 0; 
      } 
     
    /* 
    ** calcualte signed constant result 
    */ 
    calc(left, oper, right) int left, oper, right; { 
      switch(oper) { 
        case ADD12: return (left  +  right);  
        case SUB12: return (left  -  right); 
        case MUL12: return (left  *  right);  
        case DIV12: return (left  /  right); 
        case MOD12: return (left  %  right);  
        case EQ12:  return (left  == right);  
        case NE12:  return (left  != right); 
        case LE12:  return (left  <= right);  
        case GE12:  return (left  >= right); 
        case LT12:  return (left  <  right);  
        case GT12:  return (left  >  right); 
        case AND12: return (left  &  right); 
        case OR12:  return (left  |  right); 
        case XOR12: return (left  ^  right);  
        case ASR12: return (left  >> right);  
        case ASL12: return (left  << right); 
        }  
      return (calc2(left, oper, right)); 
      } 
     
    /* 
    ** calcualte unsigned constant result 
    */ 
    calc2(left, oper, right) unsigned left, right; int oper; { 
      switch(oper) { 
        case MUL12u: return (left  *  right);  
        case DIV12u: return (left  /  right); 
        case MOD12u: return (left  %  right);  
        case LE12u:  return (left  <= right);  
        case GE12u:  return (left  >= right); 
        case LT12u:  return (left  <  right);  
        case GT12u:  return (left  >  right); 
        }  
      return (0); 
      } 
     
     
    _____________________________________________________________________ 
                                   cc4.c 
    _____________________________________________________________________ 
    /* 
    ** Small-C Compiler -- Part 4 -- Back End. 
    ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix 
    ** All rights reserved. 
    */ 
    #include <stdio.h> 
    #include "cc.h" 
     
    /* #define DISOPT */       /* display optimizations values */ 
     
    /*************************** externals ****************************/ 
     
    extern char 
      *cptr, *macn, *litq, *symtab, optimize, ssname[NAMESIZE]; 
     
    extern int 
      *stage, litlab, litptr, csp, output, oldseg, usexpr, 
      *snext, *stail, *slast; 
     
     
    /***************** optimizer command definitions ******************/ 
     
                 /*     --      p-codes must not overlap these */ 
    #define any     0x00FF   /* matches any p-code */ 
    #define _pop    0x00FE   /* matches if corresponding POP2 exists */ 
    #define pfree   0x00FD   /* matches if pri register free */ 
    #define sfree   0x00FC   /* matches if sec register free */ 
    #define comm    0x00FB   /* matches if registers are commutative */ 
     
                 /*     --      these digits are reserved for n */ 
    #define go      0x0100   /* go n entries */ 
    #define gc      0x0200   /* get code from n entries away */ 
    #define gv      0x0300   /* get value from n entries away */ 
    #define sum     0x0400   /* add value from nth entry away */ 
    #define neg     0x0500   /* negate the value */ 
    #define ife     0x0600   /* if value == n do commands to next 0 */ 
    #define ifl     0x0700   /* if value <  n do commands to next 0 */ 
    #define swv     0x0800   /* swap value with value n entries away */ 
    #define topop   0x0900   /* moves |code and current value to POP2 */ 
     
    #define p1      0x0001   /* plus 1 */ 
    #define p2      0x0002   /* plus 2 */ 
    #define p3      0x0003   /* plus 3 */ 
    #define p4      0x0004   /* plus 4 */ 
    #define m1      0x00FF   /* minus 1 */ 
    #define m2      0x00FE   /* minus 2 */ 
    #define m3      0x00FD   /* minus 3 */ 
    #define m4      0x00FC   /* minus 4 */ 
     
    #define PRI      0030    /* primary register bits */ 
    #define SEC      0003    /* secondary register bits */ 
    #define USES     0011    /* use register contents */ 
    #define ZAPS     0022    /* zap register contents */ 
    #define PUSHES   0100    /* pushes onto the stack */ 
    #define COMMUTES 0200    /* commutative p-code */ 
     
    /******************** optimizer command lists *********************/ 
     
    int 
      seq00[] = {0,ADD12,MOVE21,0,                       /* ADD21 */ 
                 go|p1,ADD21,0}, 
     
      seq01[] = {0,ADD1n,0,                              /* rINC1 or rDEC1 ? */  
                 ifl|m2,0,ifl|0,rDEC1,neg,0,ifl|p3,rINC1,0,0}, 
     
      seq02[] = {0,ADD2n,0,                              /* rINC2 or rDEC2 ? */  
                 ifl|m2,0,ifl|0,rDEC2,neg,0,ifl|p3,rINC2,0,0}, 
     
      seq03[] = {0,rDEC1,PUTbp1,rINC1,0,                 /* SUBbpn or DECbp */ 
                 go|p2,ife|p1,DECbp,0,SUBbpn,0}, 
     
      seq04[] = {0,rDEC1,PUTwp1,rINC1,0,                 /* SUBwpn or DECwp */ 
                 go|p2,ife|p1,DECwp,0,SUBwpn,0}, 
     
      seq05[] = {0,rDEC1,PUTbm1,rINC1,0,                 /* SUB_m_ COMMAn */ 
                 go|p1,SUB_m_,go|p1,COMMAn,go|m1,0}, 
     
      seq06[] = {0,rDEC1,PUTwm1,rINC1,0,                 /* SUB_m_ COMMAn */ 
                 go|p1,SUB_m_,go|p1,COMMAn,go|m1,0}, 
     
      seq07[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1p,0,  /* GETw2m GETb1p */ 
                 go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, 
     
      seq08[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1pu,0, /* GETw2m GETb1pu */ 
                 go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, 
     
      seq09[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETw1p,0,  /* GETw2m GETw1p */ 
                 go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, 
     
      seq10[] = {0,GETw1m,GETw2m,SWAP12,0,               /* GETw2m GETw1m */ 
                 go|p2,GETw1m,gv|m1,go|m1,gv|m1,0}, 
     
      seq11[] = {0,GETw1m,MOVE21,0,                      /* GETw2m */ 
                 go|p1,GETw2m,gv|m1,0}, 
     
      seq12[] = {0,GETw1m,PUSH1,pfree,0,                 /* PUSHm */ 
                 go|p1,PUSHm,gv|m1,0}, 
     
      seq13[] = {0,GETw1n,PUTbm1,pfree,0,                /* PUT_m_ COMMAn */ 
                 PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0}, 
     
      seq14[] = {0,GETw1n,PUTwm1,pfree,0,                /* PUT_m_ COMMAn */  
                 PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0},  
     
      seq15[] = {0,GETw1p,PUSH1,pfree,0,                 /* PUSHp */  
                 go|p1,PUSHp,gv|m1,0}, 
     
      seq16[] = {0,GETw1s,GETw2n,ADD12,MOVE21,0,         /* GETw2s ADD2n */ 
                 go|p3,ADD2n,gv|m2,go|m1,GETw2s,gv|m2,0}, 
     
      seq17[] = {0,GETw1s,GETw2s,SWAP12,0,               /* GETw2s GETw1s */ 
                 go|p2,GETw1s,gv|m1,go|m1,GETw2s,gv|m1,0}, 
     
 
      seq18[] = {0,GETw1s,MOVE21,0,                      /* GETw2s */ 
                 go|p1,GETw2s,gv|m1,0}, 
     
      seq19[] = {0,GETw2m,GETw1n,SWAP12,SUB12,0,         /* GETw1m SUB1n */ 
                 go|p3,SUB1n,gv|m2,go|m1,GETw1m,gv|m2,0}, 
     
      seq20[] = {0,GETw2n,ADD12,0,                       /* ADD1n */  
                 go|p1,ADD1n,gv|m1,0}, 
     
      seq21[] = {0,GETw2s,GETw1n,SWAP12,SUB12,0,         /* GETw1s SUB1n */  
                 go|p3,SUB1n,gv|m2,go|m1,GETw1s,gv|m2,0}, 
     
      seq22[] = {0,rINC1,PUTbm1,rDEC1,0,                 /* ADDm_ COMMAn */  
                 go|p1,ADDm_,go|p1,COMMAn,go|m1,0},  
     
      seq23[] = {0,rINC1,PUTwm1,rDEC1,0,                 /* ADDm_ COMMAn */  
                 go|p1,ADDm_,go|p1,COMMAn,go|m1,0},  
     
      seq24[] = {0,rINC1,PUTbp1,rDEC1,0,                 /* ADDbpn or INCbp */  
                 go|p2,ife|p1,INCbp,0,ADDbpn,0},  
     
      seq25[] = {0,rINC1,PUTwp1,rDEC1,0,                 /* ADDwpn or INCwp */  
                 go|p2,ife|p1,INCwp,0,ADDwpn,0},  
     
      seq26[] = {0,MOVE21,GETw1n,SWAP12,SUB12,0,         /* SUB1n */ 
                 go|p3,SUB1n,gv|m2,0}, 
     
      seq27[] = {0,MOVE21,GETw1n,comm,0,                 /* GETw2n comm */ 
                 go|p1,GETw2n,0}, 
     
      seq28[] = {0,POINT1m,GETw2n,ADD12,MOVE21,0,        /* POINT2m_ PLUSn */ 
                 go|p3,PLUSn,gv|m2,go|m1,POINT2m_,gv|m2,0}, 
     
      seq29[] = {0,POINT1m,MOVE21,pfree,0,               /* POINT2m */ 
                 go|p1,POINT2m,gv|m1,0}, 
     
      seq30[] = {0,POINT1m,PUSH1,pfree,_pop,0,           /* ... POINT2m */ 
                 topop|POINT2m,go|p2,0}, 
     
      seq31[] = {0,POINT1s,GETw2n,ADD12,MOVE21,GETb1p,0, /* GETb1s */ 
                 sum|p1,go|p4,GETb1s,gv|m4,0}, 
     
      seq32[] = {0,POINT1s,GETw2n,ADD12,MOVE21,GETb1pu,0,/* GETb1su */ 
                 sum|p1,go|p4,GETb1su,gv|m4,0}, 
     
      seq33[] = {0,POINT1s,GETw2n,ADD12,MOVE21,GETw1p,0, /* GETw1s */ 
                 sum|p1,go|p4,GETw1s,gv|m4,0}, 
     
      seq34[] = {0,POINT1s,PUSH1,MOVE21,0,               /* POINT2s PUSH2 */ 
                 go|p1,POINT2s,gv|m1,go|p1,PUSH2,go|m1,0}, 
     
      seq35[] = {0,POINT1s,PUSH1,pfree,_pop,0,           /* ... POINT2s */ 
                 topop|POINT2s,go|p2,0}, 
     
      seq36[] = {0,POINT1s,MOVE21,0,                     /* POINT2s */ 
                 go|p1,POINT2s,gv|m1,0}, 
     
      seq37[] = {0,POINT2m,GETb1p,sfree,0,               /* GETb1m */ 
                 go|p1,GETb1m,gv|m1,0}, 
     
      seq38[] = {0,POINT2m,GETb1pu,sfree,0,              /* GETb1mu */ 
                 go|p1,GETb1mu,gv|m1,0}, 
     
      seq39[] = {0,POINT2m,GETw1p,sfree,0,               /* GETw1m */ 
                 go|p1,GETw1m,gv|m1,0}, 
     
      seq40[] = {0,POINT2m_,PLUSn,GETw1p,sfree,0,        /* GETw1m_ PLUSn */ 
                 go|p2,gc|m1,gv|m1,go|m1,GETw1m_,gv|m1,0}, 
     
      seq41[] = {0,POINT2s,GETb1p,sfree,0,               /* GETb1s */ 
                 sum|p1,go|p1,GETb1s,gv|m1,0}, 
     
      seq42[] = {0,POINT2s,GETb1pu,sfree,0,              /* GETb1su */ 
                 sum|p1,go|p1,GETb1su,gv|m1,0}, 
     
      seq43[] = {0,POINT2s,GETw1p,PUSH1,pfree,0,         /* PUSHs */ 
                 sum|p1,go|p2,PUSHs,gv|m2,0}, 
     
      seq44[] = {0,POINT2s,GETw1p,sfree,0,               /* GETw1s */ 
                 sum|p1,go|p1,GETw1s,gv|m1,0}, 
     
      seq45[] = {0,PUSH1,any,POP2,0,                     /* MOVE21 any */ 
                 go|p2,gc|m1,gv|m1,go|m1,MOVE21,0}, 
     
      seq46[] = {0,PUSHm,_pop,0,                         /* ... GETw2m */ 
                 topop|GETw2m,go|p1,0}, 
     
      seq47[] = {0,PUSHp,any,POP2,0,                     /* GETw2p ... */ 
                 go|p2,gc|m1,gv|m1,go|m1,GETw2p,gv|m1,0}, 
     
      seq48[] = {0,PUSHs,_pop,0,                         /* ... GETw2s */ 
                 topop|GETw2s,go|p1,0}, 
     
      seq49[] = {0,SUB1n,0,                              /* rDEC1 or rINC1 ? */ 
                 ifl|m2,0,ifl|0,rINC1,neg,0,ifl|p3,rDEC1,0,0}; 
     
    #define HIGH_SEQ  49 
    int seq[HIGH_SEQ + 1];   
    setseq() { 
      seq[ 0] = seq00;  seq[ 1] = seq01;  seq[ 2] = seq02;  seq[ 3] = seq03; 
      seq[ 4] = seq04;  seq[ 5] = seq05;  seq[ 6] = seq06;  seq[ 7] = seq07; 
      seq[ 8] = seq08;  seq[ 9] = seq09;  seq[10] = seq10;  seq[11] = seq11; 
      seq[12] = seq12;  seq[13] = seq13;  seq[14] = seq14;  seq[15] = seq15; 
      seq[16] = seq16;  seq[17] = seq17;  seq[18] = seq18;  seq[19] = seq19; 
      seq[20] = seq20;  seq[21] = seq21;  seq[22] = seq22;  seq[23] = seq23; 
      seq[24] = seq24;  seq[25] = seq25;  seq[26] = seq26;  seq[27] = seq27; 
      seq[28] = seq28;  seq[29] = seq29;  seq[30] = seq30;  seq[31] = seq31; 
      seq[32] = seq32;  seq[33] = seq33;  seq[34] = seq34;  seq[35] = seq35; 
      seq[36] = seq36;  seq[37] = seq37;  seq[38] = seq38;  seq[39] = seq39; 
      seq[40] = seq40;  seq[41] = seq41;  seq[42] = seq42;  seq[43] = seq43; 
      seq[44] = seq44;  seq[45] = seq45;  seq[46] = seq46;  seq[47] = seq47; 
      seq[48] = seq48;  seq[49] = seq49; 
      }  
     
    /***************** assembly-code strings ******************/ 
     
    int code[PCODES]; 
     
    /* 
    ** First byte contains flag bits indicating: 
    **    the value in ax is needed (010) or zapped (020) 
    **    the value in bx is needed (001) or zapped (002) 
    */ 
    setcodes() { 
      setseq(); 
      code[ADD12]   = "\211ADD AX,BX\n"; 
      code[ADD1n]   = "\010?ADD AX,<n>\n??"; 
      code[ADD21]   = "\211ADD BX,AX\n"; 
      code[ADD2n]   = "\010?ADD BX,<n>\n??"; 
      code[ADDbpn]  = "\001ADD BYTE PTR [BX],<n>\n"; 
      code[ADDwpn]  = "\001ADD WORD PTR [BX],<n>\n"; 
      code[ADDm_]   = "\000ADD <m>"; 
      code[ADDSP]   = "\000?ADD SP,<n>\n??"; 
      code[AND12]   = "\211AND AX,BX\n"; 
      code[ANEG1]   = "\010NEG AX\n"; 
      code[ARGCNTn] = "\000?MOV CL,<n>?XOR CL,CL?\n"; 
      code[ASL12]   = "\011MOV CX,AX\nMOV AX,BX\nSAL AX,CL\n"; 
      code[ASR12]   = "\011MOV CX,AX\nMOV AX,BX\nSAR AX,CL\n"; 
      code[CALL1]   = "\010CALL AX\n"; 
      code[CALLm]   = "\020CALL <m>\n"; 
      code[BYTE_]   = "\000 DB "; 
      code[BYTEn]   = "\000 DB <n>\n"; 
      code[BYTEr0]  = "\000 DB <n> DUP(0)\n"; 
      code[COM1]    = "\010NOT AX\n"; 
      code[COMMAn]  = "\000,<n>\n"; 
      code[DBL1]    = "\010SHL AX,1\n"; 
      code[DBL2]    = "\001SHL BX,1\n"; 
      code[DECbp]   = "\001DEC BYTE PTR [BX]\n"; 
      code[DECwp]   = "\001DEC WORD PTR [BX]\n"; 
      code[DIV12]   = "\011CWD\nIDIV BX\n";                 /* see gen() */ 
      code[DIV12u]  = "\011XOR DX,DX\nDIV BX\n";            /* see gen() */ 
      code[ENTER]   = "\100PUSH BP\nMOV BP,SP\n"; 
      code[EQ10f]   = "\010OR AX,AX\nJE $+5\nJMP _<n>\n"; 
      code[EQ12]    = "\211CALL __EQ\n"; 
      code[GE10f]   = "\010OR AX,AX\nJGE $+5\nJMP _<n>\n"; 
      code[GE12]    = "\011CALL __GE\n"; 
      code[GE12u]   = "\011CALL __UGE\n"; 
      code[GETb1m]  = "\020MOV AL,<m>\nCBW\n"; 
      code[GETb1mu] = "\020MOV AL,<m>\nXOR AH,AH\n"; 
      code[GETb1p]  = "\021MOV AL,?<n>??[BX]\nCBW\n";       /* see gen() */ 
      code[GETb1pu] = "\021MOV AL,?<n>??[BX]\nXOR AH,AH\n"; /* see gen() */ 
      code[GETb1s]  = "\020MOV AL,<n>[BP]\nCBW\n"; 
      code[GETb1su] = "\020MOV AL,<n>[BP]\nXOR AH,AH\n"; 
      code[GETw1m]  = "\020MOV AX,<m>\n"; 
      code[GETw1m_] = "\020MOV AX,<m>"; 
      code[GETw1n]  = "\020?MOV AX,<n>?XOR AX,AX?\n"; 
      code[GETw1p]  = "\021MOV AX,?<n>??[BX]\n";            /* see gen() */ 
      code[GETw1s]  = "\020MOV AX,<n>[BP]\n"; 
      code[GETw2m]  = "\002MOV BX,<m>\n"; 
      code[GETw2n]  = "\002?MOV BX,<n>?XOR BX,BX?\n"; 
      code[GETw2p]  = "\021MOV BX,?<n>??[BX]\n"; 
      code[GETw2s]  = "\002MOV BX,<n>[BP]\n"; 
      code[GT10f]   = "\010OR AX,AX\nJG $+5\nJMP _<n>\n"; 
      code[GT12]    = "\010CALL __GT\n"; 
      code[GT12u]   = "\011CALL __UGT\n"; 
      code[INCbp]   = "\001INC BYTE PTR [BX]\n"; 
      code[INCwp]   = "\001INC WORD PTR [BX]\n"; 
      code[WORD_]   = "\000 DW "; 
      code[WORDn]   = "\000 DW <n>\n"; 
      code[WORDr0]  = "\000 DW <n> DUP(0)\n"; 
      code[JMPm]    = "\000JMP _<n>\n"; 
      code[LABm]    = "\000_<n>:\n"; 
      code[LE10f]   = "\010OR AX,AX\nJLE $+5\nJMP _<n>\n"; 
      code[LE12]    = "\011CALL __LE\n"; 
      code[LE12u]   = "\011CALL __ULE\n"; 
      code[LNEG1]   = "\010CALL __LNEG\n"; 
      code[LT10f]   = "\010OR AX,AX\nJL $+5\nJMP _<n>\n"; 
      code[LT12]    = "\011CALL __LT\n"; 
      code[LT12u]   = "\011CALL __ULT\n"; 
      code[MOD12]   = "\011CWD\nIDIV BX\nMOV AX,DX\n";      /* see gen() */ 
      code[MOD12u]  = "\011XOR DX,DX\nDIV BX\nMOV AX,DX\n"; /* see gen() */ 
      code[MOVE21]  = "\012MOV BX,AX\n"; 
      code[MUL12]   = "\211IMUL BX\n"; 
      code[MUL12u]  = "\211MUL BX\n"; 
      code[NE10f]   = "\010OR AX,AX\nJNE $+5\nJMP _<n>\n"; 
      code[NE12]    = "\211CALL __NE\n"; 
      code[NEARm]   = "\000 DW _<n>\n"; 
      code[OR12]    = "\211OR AX,BX\n"; 
      code[PLUSn]   = "\000?+<n>??\n"; 
      code[POINT1l] = "\020MOV AX,OFFSET _<l>+<n>\n"; 
      code[POINT1m] = "\020MOV AX,OFFSET <m>\n"; 
      code[POINT1s] = "\020LEA AX,<n>[BP]\n"; 
      code[POINT2m] = "\002MOV BX,OFFSET <m>\n"; 
      code[POINT2m_]= "\002MOV BX,OFFSET <m>"; 
      code[POINT2s] = "\002LEA BX,<n>[BP]\n"; 
      code[POP2]    = "\002POP BX\n"; 
      code[PUSH1]   = "\110PUSH AX\n"; 
      code[PUSH2]   = "\101PUSH BX\n"; 
      code[PUSHm]   = "\100PUSH <m>\n"; 
      code[PUSHp]   = "\100PUSH ?<n>??[BX]\n"; 
      code[PUSHs]   = "\100PUSH ?<n>??[BP]\n"; 
      code[PUT_m_]  = "\000MOV <m>"; 
      code[PUTbm1]  = "\010MOV <m>,AL\n"; 
      code[PUTbp1]  = "\011MOV [BX],AL\n"; 
      code[PUTwm1]  = "\010MOV <m>,AX\n"; 
      code[PUTwp1]  = "\011MOV [BX],AX\n"; 
      code[rDEC1]   = "\010#DEC AX\n#"; 
      code[rDEC2]   = "\010#DEC BX\n#"; 
      code[REFm]    = "\000_<n>"; 
      code[RETURN]  = "\000?MOV SP,BP\n??POP BP\nRET\n"; 
      code[rINC1]   = "\010#INC AX\n#"; 
      code[rINC2]   = "\010#INC BX\n#"; 
      code[SUB_m_]  = "\000SUB <m>"; 
      code[SUB12]   = "\011SUB AX,BX\n";                    /* see gen() */ 
      code[SUB1n]   = "\010?SUB AX,<n>\n??"; 
      code[SUBbpn]  = "\001SUB BYTE PTR [BX],<n>\n"; 
      code[SUBwpn]  = "\001SUB WORD PTR [BX],<n>\n"; 
      code[SWAP12]  = "\011XCHG AX,BX\n"; 
      code[SWAP1s]  = "\012POP BX\nXCHG AX,BX\nPUSH BX\n"; 
      code[SWITCH]  = "\012CALL __SWITCH\n"; 
      code[XOR12]   = "\211XOR AX,BX\n"; 
      } 
     
    /***************** code generation functions *****************/ 
     
    /* 
    ** print all assembler info before any code is generated 
    ** and ensure that the segments appear in the correct order. 
    */ 
    header()  { 
      toseg(CODESEG); 
      outline("extrn __eq: near"); 
      outline("extrn __ne: near"); 
      outline("extrn __le: near"); 
      outline("extrn __lt: near"); 
      outline("extrn __ge: near"); 
      outline("extrn __gt: near"); 
      outline("extrn __ule: near"); 
      outline("extrn __ult: near"); 
      outline("extrn __uge: near"); 
      outline("extrn __ugt: near"); 
      outline("extrn __lneg: near"); 
      outline("extrn __switch: near"); 
      outline("dw 0"); /* force non-zero code pointers, word alignment */ 
      toseg(DATASEG); 
      outline("dw 0"); /* force non-zero data pointers, word alignment */ 
      } 
     
    /* 
    ** print any assembler stuff needed at the end 
    */ 
    trailer()  {   
      char *cp; 
      cptr = STARTGLB; 
      while(cptr < ENDGLB) { 
        if(cptr[IDENT] == FUNCTION && cptr[CLASS] == AUTOEXT) 
          external(cptr + NAME, 0, FUNCTION); 
        cptr += SYMMAX; 
        } 
      if((cp = findglb("main")) && cp[CLASS]==STATIC) 
        external("_main", 0, FUNCTION); 
      toseg(NULL); 
      outline("END"); 
    #ifdef DISOPT 
        { 
        int i, *count; 
        printf(";opt   count\n"); 
        for(i = -1; ++i <= HIGH_SEQ; ) { 
          count = seq[i]; 
          printf("; %2u   %5u\n", i, *count); 
          poll(YES); 
          } 
        }   
    #endif  
      } 
     
    /* 
    ** remember where we are in the queue in case we have to back up. 
    */ 
    setstage(before, start) int *before, *start; { 
      if((*before = snext) == 0) 
        snext = stage; 
      *start = snext; 
      } 
     
    /* 
    ** generate code in staging buffer. 
    */ 
    gen(pcode, value) int pcode, value; { 
      int newcsp; 
      switch(pcode) { 
        case GETb1pu: 
        case GETb1p: 
        case GETw1p: gen(MOVE21, 0); break; 
        case SUB12: 
        case MOD12: 
        case MOD12u: 
        case DIV12: 
        case DIV12u: gen(SWAP12, 0); break; 
        case PUSH1:  csp -= BPW;     break; 
        case POP2:   csp += BPW;     break; 
        case ADDSP: 
        case RETURN: newcsp = value; value -= csp; csp = newcsp; 
        } 
      if(snext == 0) { 
        outcode(pcode, value); 
        return; 
        } 
      if(snext >= slast) { 
        error("staging buffer overflow"); 
        return; 
        } 
      snext[0] = pcode; 
      snext[1] = value; 
      snext += 2; 
      } 
     
    /* 
    ** dump the contents of the queue. 
    ** If start = 0, throw away contents. 
    ** If before != 0, don't dump queue yet. 
    */ 
    clearstage(before, start) int *before, *start; { 
      if(before) { 
        snext = before; 
        return; 
        } 
      if(start) dumpstage(); 
      snext = 0; 
      } 
     
    /* 
    ** dump the staging buffer 
    */ 
    dumpstage() { 
      int i; 
      stail = snext; 
      snext = stage; 
      while(snext < stail) { 
        if(optimize) { 
          restart: 
          i = -1;  
          while(++i <= HIGH_SEQ) if(peep(seq[i])) { 
    #ifdef DISOPT 
            if(isatty(output)) 
              fprintf(stderr, "                   optimized %2u\n", i); 
    #endif 
            goto restart; 
            } 
          } 
        outcode(snext[0], snext[1]); 
        snext += 2; 
        } 
      } 
     
    /* 
    ** change to a new segment 
    ** may be called with NULL, CODESEG, or DATASEG 
    */ 
    toseg(newseg) int newseg; { 
      if(oldseg == newseg)  return; 
      if(oldseg == CODESEG) outline("CODE ENDS"); 
      else if(oldseg == DATASEG) outline("DATA ENDS"); 
      if(newseg == CODESEG) { 
        outline("CODE SEGMENT PUBLIC"); 
        outline("ASSUME CS:CODE, SS:DATA, DS:DATA"); 
        } 
      else if(newseg == DATASEG) outline("DATA SEGMENT PUBLIC"); 
      oldseg = newseg; 
      } 
     
    /* 
    ** declare entry point 
    */ 
    public(ident) int ident;{ 
      if(ident == FUNCTION) 
           toseg(CODESEG); 
      else toseg(DATASEG); 
      outstr("PUBLIC "); 
      outname(ssname); 
      newline(); 
      outname(ssname); 
      if(ident == FUNCTION) { 
        colon(); 
        newline(); 
        } 
      } 
     
    /* 
    ** declare external reference 
    */ 
    external(name, size, ident) char *name; int size, ident; { 
      if(ident == FUNCTION) 
           toseg(CODESEG); 
      else toseg(DATASEG); 
      outstr("EXTRN "); 
      outname(name); 
      colon(); 
      outsize(size, ident); 
      newline(); 
      } 
     
    /* 
    ** output the size of the object pointed to. 
    */ 
    outsize(size, ident) int size, ident; { 
      if(size == 1 
      && ident != POINTER 
      && ident != FUNCTION)      outstr("BYTE"); 
      else if(ident != FUNCTION) outstr("WORD"); 
      else                       outstr("NEAR"); 
      } 
     
    /* 
    ** point to following object(s) 
    */ 
    point() { 
      outline(" DW $+2"); 
      } 
     
    /* 
    ** dump the literal pool 
    */ 
    dumplits(size) int size; { 
      int j, k; 
      k = 0; 
      while (k < litptr) { 
        poll(1);                     /* allow program interruption */ 
        if(size == 1) 
             gen(BYTE_, NULL); 
        else gen(WORD_, NULL); 
        j = 10; 
        while(j--) { 
          outdec(getint(litq + k, size)); 
          k += size; 
          if(j == 0 || k >= litptr) { 
            newline(); 
            break; 
            } 
          fputc(',', output); 
          } 
        } 
      } 
     
    /* 
    ** dump zeroes for default initial values 
    */ 
    dumpzero(size, count) int size, count; { 
      if(count > 0) { 
        if(size == 1) 
             gen(BYTEr0, count); 
        else gen(WORDr0, count); 
        } 
      } 
     
    /******************** optimizer functions ***********************/ 
     
    /* 
    ** Try to optimize sequence at snext in the staging buffer. 
    */ 
    peep(seq) int *seq; { 
      int *next, *count, *pop, n, skip, tmp, reply; 
      char c; 
      next = snext; 
      count = seq++; 
      while(*seq) { 
        switch(*seq) { 
          case any:   if(next < stail)       break;      return (NO); 
          case pfree: if(isfree(PRI, next))  break;      return (NO); 
          case sfree: if(isfree(SEC, next))  break;      return (NO); 
          case comm:  if(*next & COMMUTES)   break;      return (NO); 
          case _pop:  if(pop = getpop(next)) break;      return (NO); 
          default:    if(next >= stail || *next != *seq) return (NO); 
          } 
        next += 2; ++seq; 
        } 
     
      /****** have a match, now optimize it ******/ 
     
      *count += 1; 
      reply = skip = NO; 
      while(*(++seq) || skip) { 
        if(skip) { 
          if(*seq == 0) skip = NO; 
          continue; 
          } 
        if(*seq >= PCODES) { 
          c = *seq & 0xFF;            /* get low byte of command */ 
          n = c;                      /* and sign extend into n */ 
          switch(*seq & 0xFF00) { 
            case ife:   if(snext[1] != n) skip = YES;  break; 
            case ifl:   if(snext[1] >= n) skip = YES;  break; 
            case go:    snext += (n<<1);               break; 
            case gc:    snext[0] =  snext[(n<<1)];     goto done; 
            case gv:    snext[1] =  snext[(n<<1)+1];   goto done; 
            case sum:   snext[1] += snext[(n<<1)+1];   goto done; 
            case neg:   snext[1] = -snext[1];          goto done; 
            case topop: pop[0] = n; pop[1] = snext[1]; goto done; 
            case swv:   tmp = snext[1]; 
                        snext[1] = snext[(n<<1)+1]; 
                        snext[(n<<1)+1] = tmp; 
            done:       reply = YES; 
                        break; 
            } 
          } 
        else snext[0] = *seq;         /* set p-code */ 
        } 
      return (reply); 
      } 
     
    /* 
    ** Is the primary or secondary register free? 
    ** Is it zapped or unused by the p-code at pp 
    ** or a successor?  If the primary register is 
    ** unused by it still may not be free if the 
    ** context uses the value of the expression. 
    */ 
    isfree(reg, pp) int reg, *pp; { 
      char *cp; 
      while(pp < stail) { 
        cp = code[*pp]; 
        if(*cp & USES & reg) return (NO); 
        if(*cp & ZAPS & reg) return (YES); 
        pp += 2; 
        } 
      if(usexpr) return (reg & 001);   /* PRI => NO, SEC => YES at end */ 
      else       return (YES); 
      } 
     
    /* 
    ** Get place where the currently pushed value is popped? 
    ** NOTE: Function arguments are not popped, they are 
    ** wasted with an ADDSP. 
    */ 
    getpop(next) int *next; { 
      char *cp; 
      int level;  level = 0; 
      while(YES) { 
        if(next >= stail)                     /* compiler error */ 
          return 0; 
        if(*next == POP2) 
          if(level) --level; 
          else return next;                   /* have a matching POP2 */ 
        else if(*next == ADDSP) {             /* after func call */ 
          if((level -= (next[1]>>LBPW)) < 0) 
            return 0; 
          } 
        else { 
          cp = code[*next];                   /* code string ptr */ 
          if(*cp & PUSHES) ++level;           /* must be a push */ 
          }  
        next += 2; 
        } 
      } 
     
    /******************* output functions *********************/ 
     
    colon() { 
      fputc(':', output); 
      } 
     
    newline() { 
      fputc(NEWLINE, output); 
      } 
     
    /* 
    ** output assembly code. 
    */ 
    outcode(pcode, value) int pcode, value; { 
      int part, skip, count; 
      char *cp, *back; 
      part = back = 0; 
      skip = NO; 
      cp = code[pcode] + 1;          /* skip 1st byte of code string */ 
      while(*cp) { 
        if(*cp == '<') { 
          ++cp;                      /* skip to action code */ 
          if(skip == NO) switch(*cp) { 
            case 'm': outname(value+NAME); break; /* mem ref by label */ 
            case 'n': outdec(value);       break; /* numeric constant */ 
            case 'l': outdec(litlab);      break; /* current literal label */ 
            } 
          cp += 2;                   /* skip past > */ 
          } 
        else if(*cp == '?') {        /* ?..if value...?...if not value...? */ 
          switch(++part) { 
            case 1: if(value == 0) skip = YES; break; 
            case 2: skip = !skip;              break; 
            case 3: part = 0; skip = NO;       break; 
            } 
          ++cp;                      /* skip past ? */ 
          } 
        else if(*cp == '#') {        /* repeat #...# value times */ 
          ++cp; 
          if(back == 0) { 
            if((count = value) < 1) { 
              while(*cp && *cp++ != '#') ; 
              continue; 
              } 
            back = cp; 
            continue; 
            } 
          if(--count > 0) cp = back; 
          else back = 0; 
          } 
        else if(skip == NO) fputc(*cp++, output); 
        else ++cp; 
        } 
      } 
     
    outdec(number)  int number; { 
      int k, zs; 
      char c, *q, *r; 
      zs = 0; 
      k = 10000; 
      if(number < 0) { 
        number = -number; 
        fputc('-', output); 
        } 
      while (k >= 1) { 
        q = 0; 
        r = number; 
        while(r >= k) {++q; r = r - k;} 
        c = q + '0'; 
        if(c != '0' || k == 1 || zs) { 
          zs = 1; 
          fputc(c, output); 
          } 
        number = r; 
        k /= 10; 
        } 
      } 
     
    outline(ptr)  char ptr[];  { 
      outstr(ptr); 
      newline(); 
      } 
     
    outname(ptr) char ptr[]; { 
      outstr("_"); 
      while(*ptr >= ' ') fputc(toupper(*ptr++), output); 
      } 
     
    outstr(ptr) char ptr[]; { 
      poll(1);           /* allow program interruption */ 
      while(*ptr >= ' ') fputc(*ptr++, output); 
      } 

Go to Appendix D Return to Table of Contents