Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2. ** Small-C Compiler -- Part 1 --  Top End.
  3. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
  4. ** Copyright 1998 H T Walheim
  5. ** All rights reserved.
  6. */
  7.  
  8. #include <stdio.h>
  9. #include "notice.h"
  10. #include "cc.h"
  11.  
  12. /*
  13. ** miscellaneous storage
  14. */
  15. int
  16.   nogo,     /* disable goto statements? */
  17.   noloc,    /* disable block locals? */
  18.   opindex,  /* index to matched operator */
  19.   opsize,   /* size of operator in characters */
  20.   swactive, /* inside a switch? */
  21.   swdefault,/* default label #, else 0 */
  22.  *swnext,   /* address of next entry */
  23.  *swend,    /* address of last entry */
  24.  *stage,    /* staging buffer address */
  25.  *wq,       /* while queue */
  26.   argcs,    /* static argc */
  27.  *argvs,    /* static argv */
  28.  *wqptr,    /* ptr to next entry */
  29.   litptr,   /* ptr to next entry */
  30.   macptr,   /* macro buffer index */
  31.   pptr,     /* ptr to parsing buffer */
  32.   ch,       /* current character of input line */
  33.   nch,      /* next character of input line */
  34.   declared, /* # of local bytes to declare, -1 when declared */
  35.   iflevel,  /* #if... nest level */
  36.   skiplevel,/* level at which #if... skipping started */
  37.   nxtlab,   /* next avail label # */
  38.   litlab,   /* label # assigned to literal pool */
  39.   csp,      /* compiler relative stk ptr */
  40.   argstk,   /* function arg sp */
  41.   argtop,   /* highest formal argument offset */
  42.   ncmp,     /* # open compound statements */
  43.   errflag,  /* true after 1st error in statement */
  44.   eof,      /* true on final input eof */
  45.   output,   /* fd for output file */
  46.   files,    /* true if file list specified on cmd line */
  47.   filearg = 0,   /* cur file arg index */
  48.   input   = EOF, /* fd for input file */
  49.   input2  = EOF, /* fd for "#include" file */
  50.   usexpr  = YES, /* true if value of expression is used */
  51.   ccode   = YES, /* true while parsing C code */
  52.  *snext,    /* next addr in stage */
  53.  *stail,    /* last addr of data in stage */
  54.  *slast,    /* last addr in stage */
  55.   listfp,   /* file pointer to list device */
  56.   lastst,   /* last parsed statement type */
  57.   oldseg;   /* current segment (0, DATASEG, CODESEG) */
  58.  
  59. char
  60.   optimize, /* optimize output of staging buffer? */
  61.   alarm,    /* audible alarm on errors? */
  62.   monitor,  /* monitor function headers? */
  63.   pause,    /* pause for operator on errors? */
  64.  *symtab,   /* symbol table */
  65.  *litq,     /* literal pool */
  66.  *macn,     /* macro name buffer */
  67.  *macq,     /* macro string buffer */
  68.  *pline,    /* parsing buffer */
  69.  *mline,    /* macro buffer */
  70.  *line,     /* ptr to pline or mline */
  71.  *lptr,     /* ptr to current character in "line" */
  72.  *glbptr,   /* global symbol table */
  73.  *locptr,   /* next local symbol table entry */
  74.   quote[2] = {'"'}, /* literal string for '"' */
  75.  *cptr,     /* work ptrs to any char buffer */
  76.  *cptr2,
  77.  *cptr3,
  78.   msname[NAMESIZE],   /* macro symbol name */
  79.   ssname[NAMESIZE];   /* static symbol name */
  80.  
  81. int op[16] = {   /* p-codes of signed binary operators */
  82.   OR12,                        /* level5 */
  83.   XOR12,                       /* level6 */
  84.   AND12,                       /* level7 */
  85.   EQ12,   NE12,                /* level8 */
  86.   LE12,   GE12,  LT12,  GT12,  /* level9 */
  87.   ASR12,  ASL12,               /* level10 */
  88.   ADD12,  SUB12,               /* level11 */
  89.   MUL12, DIV12, MOD12          /* level12 */
  90.   };
  91.  
  92. int op2[16] = {  /* p-codes of unsigned binary operators */
  93.   OR12,                        /* level5 */
  94.   XOR12,                       /* level6 */
  95.   AND12,                       /* level7 */
  96.   EQ12,   NE12,                /* level8 */
  97.   LE12u,  GE12u, LT12u, GT12u, /* level9 */
  98.   ASR12,  ASL12,               /* level10 */
  99.   ADD12,  SUB12,               /* level11 */
  100.   MUL12u, DIV12u, MOD12u       /* level12 */
  101.   };
  102.  
  103. /*
  104. ** execution begins here
  105. */
  106. main(argc, argv) int argc, *argv; {
  107.   fputs(VERSION, stdout);
  108.   fputs(CRIGHT1, stdout);
  109.   fputs(CRIGHT2, stdout);
  110.   argcs   = argc;
  111.   argvs   = argv;
  112.   swnext  = calloc(SWTABSZ, 1);
  113.   swend   = swnext+(SWTABSZ-SWSIZ);
  114.   stage   = calloc(STAGESIZE, 2*INTSIZE);
  115.   wqptr   =
  116.   wq      = calloc(WQTABSZ, INTSIZE);
  117.   litq    = calloc(LITABSZ, 1);
  118.   macn    = calloc(MACNSIZE, 1);
  119.   macq    = calloc(MACQSIZE, 1);
  120.   pline   = calloc(LINESIZE, 1);
  121.   mline   = calloc(LINESIZE, 1);
  122.   slast   = stage+(STAGESIZE*2*INTSIZE);
  123.   symtab  = calloc((NUMLOCS*SYMAVG + NUMGLBS*SYMMAX), 1);
  124.   locptr  = STARTLOC;
  125.   glbptr  = STARTGLB;
  126.  
  127.   ask();          /* get user options */
  128.   openfile();     /* and initial input file */
  129.   preprocess();   /* fetch first line */
  130.   header();       /* intro code */
  131.   setcodes();     /* initialize code pointer array */
  132.   parse();        /* process ALL input */
  133.   trailer();      /* follow-up code */
  134.   fclose(output); /* explicitly close output */
  135.   }
  136.  
  137. /******************** high level parsing *******************/
  138.  
  139. /*
  140. ** process all input text
  141. **
  142. ** At this level, only static declarations,
  143. **      defines, includes and function
  144. **      definitions are legal...
  145. */
  146. parse() {
  147.   while (eof == 0) {
  148.     if     (amatch("extern", 6)) dodeclare(EXTERNAL);
  149.     else if(dodeclare(STATIC))   ;
  150.     else if( match("#asm"))      doasm();
  151.     else if( match("#include"))  doinclude();
  152.     else if( match("#define"))   dodefine();
  153.     else                         dofunction();
  154.     blanks();                 /* force eof if pending */
  155.     }
  156.   }
  157.  
  158. /*
  159. ** test for global declarations
  160. */
  161. dodeclare(class) int class; {
  162.   if     (amatch("char",     4))  declglb(CHR,  class);
  163.   else if(amatch("unsigned", 8)) {
  164.     if   (amatch("char",     4))  declglb(UCHR, class);
  165.     else {amatch("int",      3);  declglb(UINT, class);}
  166.     }
  167.   else if(amatch("int",      3)
  168.        || class == EXTERNAL)      declglb(INT,  class);
  169.   else return 0;
  170.   ns();
  171.   return 1;
  172.   }
  173.  
  174. /*
  175. ** declare a static variable
  176. */
  177. declglb(type, class)
  178. int type, class;
  179.   {
  180.     int id, dim;
  181.    
  182.     while(1)
  183.       {
  184.         if(endst())
  185.           return;  /* do line */
  186.         if(match("*"))
  187.           {
  188.             id = POINTER;  dim = 0;
  189.           }
  190.         else
  191.           {
  192.             id = VARIABLE; dim = 1;
  193.           }
  194.         if(symname(ssname) == 0)
  195.           illname();
  196.         if(findglb(ssname))
  197.           multidef(ssname);
  198.         if(id == VARIABLE)
  199.           {
  200.             if (match("("))
  201.               {
  202.                 id = FUNCTION; need(")");
  203.               }
  204.             else if(match("["))
  205.               {
  206.                 id = ARRAY; dim = needsub();
  207.               }
  208.           }
  209.         if (class == EXTERNAL)
  210.           external(ssname, type >> 2, id);
  211.         else if (id != FUNCTION)
  212.           initials(type >> 2, id, dim);
  213.         if(id == POINTER)
  214.           addsym(ssname, id, type, PTRSIZE, 0, &glbptr, class);
  215.         else
  216.           addsym(ssname, id, type, dim * (type >> 2), 0, &glbptr, class);
  217.         if(match(",") == 0)
  218.           return;
  219.       }
  220.   }
  221.  
  222. /*
  223. ** initialize global objects
  224. */
  225. initials(size, ident, dim) int size, ident, dim; {
  226.   int savedim;
  227.   litptr = 0;
  228.   if(dim == 0) dim = -1;         /* *... or ...[] */
  229.   savedim = dim;
  230. /*  public(ident); */
  231.   if(match("=")) {
  232.     if(match("{")) {
  233.       while(dim) {
  234.         init(size, ident, &dim);
  235.         if(match(",") == 0) break;
  236.         }
  237.       need("}");
  238.       }
  239.     else init(size, ident, &dim);
  240.     }
  241.   if(savedim == -1 && dim == -1) {
  242.     if(ident == ARRAY) error("need array size");
  243.     stowlit(0, size = PTRSIZE);
  244.     }
  245.  
  246. /* FASM */
  247.   public(ident);
  248.   if(litptr>0) dumplits(size);
  249.   else if(dim>0)
  250.   {/*In FASM: "<variable>: TIMES <number> D<type> 0" */
  251.    fputc(':',output);
  252.   }
  253.   dumpzero(size, dim);           /* only if dim > 0 */
  254. /* FASM */
  255.   }
  256.  
  257. /*
  258. ** evaluate one initializer
  259. */
  260. init(size, ident, dim) int size, ident, *dim; {
  261.   int value;
  262.   if(string(&value)) {
  263.     if(ident == VARIABLE || size != 1)
  264.       error("must assign to char pointer or char array");
  265.     *dim -= (litptr - value);
  266.     if(ident == POINTER) point();
  267.     }
  268.   else if(constexpr(&value)) {
  269.     if(ident == POINTER) error("cannot assign to pointer");
  270.     stowlit(value, size);
  271.     *dim -= 1;
  272.     }
  273.   }
  274.  
  275. /*
  276. ** get required array size
  277. */
  278. needsub()  {
  279.   int val;
  280.   if(match("]")) return 0; /* null size */
  281.   if(constexpr(&val) == 0) val = 1;
  282.   if(val < 0) {
  283.     error("negative size illegal");
  284.     val = -val;
  285.     }
  286.   need("]");               /* force single dimension */
  287.   return val;              /* and return size */
  288.   }
  289.  
  290. /*
  291. ** open an include file
  292. */
  293. doinclude() {
  294.   int i; char str[30];
  295.   blanks();       /* skip over to name */
  296.   if(*lptr == '"' || *lptr == '<') ++lptr;
  297.   i = 0;
  298.   while(lptr[i]
  299.      && lptr[i] != '"'
  300.      && lptr[i] != '>'
  301.      && lptr[i] != '\n') {
  302.     str[i] = lptr[i];
  303.     ++i;
  304.     }
  305.   str[i] = NULL;
  306.   if((input2 = fopen(str,"r")) == NULL) {
  307.     input2 = EOF;
  308.     error("open failure on include file");
  309.     }
  310.   kill();   /* make next read come from new file (if open) */
  311.   }
  312.  
  313. /*
  314. ** define a macro symbol
  315. */
  316. dodefine() {
  317.   int k;
  318.   if(symname(msname) == 0) {
  319.     illname();
  320.     kill();
  321.     return;
  322.     }
  323. /*
  324.   puts (msname);
  325.   puts (" is #defined\n");
  326. */
  327.   k = 0;
  328.   if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) {
  329.     if(cptr2 = cptr)
  330.       while(*cptr2++ = msname[k++]) ;
  331.     else {
  332.       error("macro name table full");
  333.       return;
  334.       }
  335.     }
  336.   putint(macptr, cptr+NAMESIZE, 2 /*INTSIZE*/);
  337.   while(white()) gch();
  338.   while(putmac(gch()));
  339.   if(macptr >= MACMAX) {
  340.     error("macro string queue full");
  341.     exit(ERRCODE);
  342.     }
  343.   }
  344.  
  345. putmac(c)  char c; {
  346.   macq[macptr] = c;
  347.   if(macptr < MACMAX) ++macptr;
  348.   return c;
  349.   }
  350.  
  351. /*
  352. ** begin a function
  353. **
  354. ** called from "parse" and tries to make a function
  355. ** out of the following text
  356. */
  357. dofunction()  {
  358.   char *ptr;
  359.   nogo   =                      /* enable goto statements */
  360.   noloc  =                      /* enable block-local declarations */
  361.   lastst =                      /* no statement yet */
  362.   litptr = 0;                   /* clear lit pool */
  363.   litlab = getlabel();          /* label next lit pool */
  364.   locptr = STARTLOC;            /* clear local variables */
  365.   if(match("void")) blanks();   /* skip "void" & locate header */
  366.   if(monitor) lout(line, stderr);
  367.   if(symname(ssname) == 0) {
  368.     error("illegal function or declaration");
  369.     errflag = 0;
  370.     kill();                     /* invalidate line */
  371.     return;
  372.     }
  373.   if(ptr = findglb(ssname)) {   /* already in symbol table? */
  374.     if(ptr[CLASS] == AUTOEXT)
  375.          ptr[CLASS] = STATIC;
  376.     else multidef(ssname);
  377.     }
  378.   else addsym(ssname, FUNCTION, INT, 0, 0, &glbptr, STATIC);
  379.   public(FUNCTION);
  380.   argstk = 0;                  /* init arg count */
  381.   if(match("(") == 0) error("no open paren");
  382.   while(match(")") == 0) {     /* then count args */
  383.     if(symname(ssname)) {
  384.       if(findloc(ssname)) multidef(ssname);
  385.       else {
  386.         addsym(ssname, 0, 0, 0, argstk, &locptr, AUTOMATIC);
  387.         argstk += INTSIZE;
  388.         }
  389.       }
  390.     else {
  391.       error("illegal argument name");
  392.       skip();
  393.       }
  394.     blanks();
  395.     if(streq(lptr,")") == 0 && match(",") == 0)
  396.       error("no comma");
  397.     if(endst()) break;
  398.     }
  399.   csp = 0;                     /* preset stack ptr */
  400.   argtop = argstk+INTSIZE;         /* account for the pushed BP */
  401.   while(argstk) {
  402.     if     (amatch("char",     4)) {doargs(CHR);  ns();}
  403.     else if(amatch("int",      3)) {doargs(INT);  ns();}
  404.     else if(amatch("unsigned", 8)) {
  405.       if   (amatch("char", 4))     {doargs(UCHR); ns();}
  406.       else {amatch("int", 3);       doargs(UINT); ns();}
  407.       }
  408.     else {error("wrong number of arguments"); break;}
  409.     }
  410.   gen(ENTER, 0);
  411.   statement();
  412.   if(lastst != STRETURN && lastst != STGOTO)
  413.     gen(RETURN, 0);
  414.   if(litptr) {
  415.     toseg(DATASEG);
  416.     gen(REFm, litlab);
  417.     dumplits(1);               /* dump literals */
  418.     }
  419.   }
  420.  
  421. /*
  422. ** declare argument types
  423. */
  424. doargs(type) int type; {
  425.   int id, sz;
  426.   char c, *ptr;
  427.   while(1) {
  428.     if(argstk == 0) return;           /* no arguments */
  429.     if(decl(type, POINTER, &id, &sz)) {
  430.       if(ptr = findloc(ssname)) {
  431.         ptr[IDENT] = id;
  432.         ptr[TYPE]  = type;
  433.         putint(sz, ptr+SIZE, INTSIZE);
  434.         putint(argtop-getint(ptr+OFFSET, INTSIZE), ptr+OFFSET, INTSIZE);
  435.         }
  436.       else error("not an argument");
  437.       }
  438.     argstk = argstk - INTSIZE;            /* cnt down */
  439.     if(endst()) return;
  440.     if(match(",") == 0) error("no comma");
  441.     }
  442.   }
  443.  
  444. /*
  445. ** parse next local or argument declaration
  446. */
  447. decl(type, aid, id, sz)
  448. int type, aid, *id, *sz;
  449. {
  450.   int n, p;
  451.   int mod;
  452.   if(match("(")) p = 1;
  453.   else           p = 0;
  454.   if(match("*"))        {*id = POINTER;  *sz  = PTRSIZE;}
  455.   else                  {*id = VARIABLE; *sz  = type >> 2;}
  456.   if((n = symname(ssname)) == 0) illname();
  457.   if(p && match(")")) ;
  458.   if(match("("))
  459.     {
  460.       if(!p || *id != POINTER)
  461.         error("try (*...)()");
  462.       need(")");
  463.     }
  464.   else if(*id == VARIABLE && match("["))
  465.     {
  466.       *id = aid;
  467.       if((*sz *= needsub()) == 0)
  468.         {
  469.           if(aid == ARRAY) error("need array size");
  470.           *sz  = PTRSIZE;      /* size of pointer argument */
  471.         }
  472.     }
  473.   mod = *sz % ALIGN;
  474.  
  475.   if (mod)
  476.     {
  477.       *sz = *sz + (ALIGN-mod);
  478.     }
  479.   return n;
  480.   }
  481.  
  482. /******************** start 2nd level parsing *******************/
  483.  
  484. /*
  485. ** statement parser
  486. */
  487. statement() {
  488.   if(ch == 0 && eof) return;
  489.   else if(amatch("char",     4)) {declloc(CHR);    ns();}
  490.   else if(amatch("int",      3)) {declloc(INT);    ns();}
  491.   else if(amatch("unsigned", 8)) {
  492.     if   (amatch("char",     4)) {declloc(UCHR);   ns();}
  493.     else {amatch("int",      3);  declloc(UINT);   ns();}
  494.     }
  495.   else {
  496.     if(declared >= 0) {
  497.       if(ncmp > 1) nogo = declared;   /* disable goto */
  498.       gen(ADDSP, csp - declared);
  499.       declared = -1;
  500.       }
  501.     if(match("{"))                 compound();
  502.     else if(amatch("if",       2)) {doif();           lastst = STIF;}
  503.     else if(amatch("while",    5)) {dowhile();        lastst = STWHILE;}
  504.     else if(amatch("do",       2)) {dodo();           lastst = STDO;}
  505.     else if(amatch("for",      3)) {dofor();          lastst = STFOR;}
  506.     else if(amatch("switch",   6)) {doswitch();       lastst = STSWITCH;}
  507.     else if(amatch("case",     4)) {docase();         lastst = STCASE;}
  508.     else if(amatch("default",  7)) {dodefault();      lastst = STDEF;}
  509.     else if(amatch("goto",     4)) {dogoto();         lastst = STGOTO;}
  510.     else if(dolabel())                                lastst = STLABEL;
  511.     else if(amatch("return",   6)) {doreturn(); ns(); lastst = STRETURN;}
  512.     else if(amatch("break",    5)) {dobreak();  ns(); lastst = STBREAK;}
  513.     else if(amatch("continue", 8)) {docont();   ns(); lastst = STCONT;}
  514.     else if(match(";"))            errflag = 0;
  515.     else if(match("#asm"))         {doasm();          lastst = STASM;}
  516.     else                           {doexpr(NO); ns(); lastst = STEXPR;}
  517.     }
  518.   return lastst;
  519.   }
  520.  
  521. /*
  522. ** declare local variables
  523. */
  524. declloc(type)  int type;  {
  525.   int id, sz;
  526.   if(swactive)     error("not allowed in switch");
  527.   if(noloc)        error("not allowed with goto");
  528.   if(declared < 0) error("must declare first in block");
  529.   while(1) {
  530.     if(endst()) return;
  531.     decl(type, ARRAY, &id, &sz);
  532.     declared += sz;
  533.     addsym(ssname, id, type,  sz, csp - declared, &locptr, AUTOMATIC);
  534.     if(match(",") == 0) return;
  535.     }
  536.   }
  537.  
  538. compound()  {
  539.   int savcsp;
  540.   char *savloc;
  541.   savcsp = csp;
  542.   savloc = locptr;
  543.   declared = 0;           /* may now declare local variables */
  544.   ++ncmp;                 /* new level open */
  545.   while (match("}") == 0)
  546.     if(eof) {
  547.       error("no final }");
  548.       break;
  549.       }
  550.     else statement();     /* do one */
  551.   if(--ncmp               /* close current level */
  552.   && lastst != STRETURN
  553.   && lastst != STGOTO)
  554.     gen(ADDSP, savcsp);   /* delete local variable space */
  555.   cptr = savloc;          /* retain labels */
  556.   while(cptr < locptr) {
  557.     cptr2 = nextsym(cptr);
  558.     if(cptr[IDENT] == LABEL) {
  559.       while(cptr < cptr2) *savloc++ = *cptr++;
  560.       }
  561.     else cptr = cptr2;
  562.     }
  563.   locptr = savloc;        /* delete local symbols */
  564.   declared = -1;          /* may not declare variables */
  565.   }
  566.  
  567. doif()  {
  568.   int flab1, flab2;
  569.   test(flab1 = getlabel(), YES);  /* get expr, and branch false */
  570.   statement();                    /* if true, do a statement */
  571.   if(amatch("else", 4) == 0) {    /* if...else ? */
  572.     /* simple "if"...print false label */
  573.     gen(LABm, flab1);
  574.     return;                       /* and exit */
  575.     }
  576.   flab2 = getlabel();
  577.   if(lastst != STRETURN && lastst != STGOTO)
  578.     gen(JMPm, flab2);
  579.   gen(LABm, flab1);    /* print false label */
  580.   statement();         /* and do "else" clause */
  581.   gen(LABm, flab2);    /* print true label */
  582.   }
  583.  
  584. dowhile()  {
  585.   int wq[4];              /* allocate local queue */
  586.   addwhile(wq);           /* add entry to queue for "break" */
  587.   gen(LABm, wq[WQLOOP]);  /* loop label */
  588.   test(wq[WQEXIT], YES);  /* see if true */
  589.   statement();            /* if so, do a statement */
  590.   gen(JMPm, wq[WQLOOP]);  /* loop to label */
  591.   gen(LABm, wq[WQEXIT]);  /* exit label */
  592.   delwhile();             /* delete queue entry */
  593.   }
  594.  
  595. dodo() {
  596.   int wq[4];
  597.   addwhile(wq);
  598.   gen(LABm, wq[WQLOOP]);
  599.   statement();
  600.   need("while");
  601.   test(wq[WQEXIT], YES);
  602.   gen(JMPm, wq[WQLOOP]);
  603.   gen(LABm, wq[WQEXIT]);
  604.   delwhile();
  605.   ns();
  606.   }
  607.  
  608. dofor() {
  609.   int wq[4], lab1, lab2;
  610.   addwhile(wq);
  611.   lab1 = getlabel();
  612.   lab2 = getlabel();
  613.   need("(");
  614.   if(match(";") == 0) {
  615.     doexpr(NO);           /* expr 1 */
  616.     ns();
  617.     }
  618.   gen(LABm, lab1);
  619.   if(match(";") == 0) {
  620.     test(wq[WQEXIT], NO); /* expr 2 */
  621.     ns();
  622.     }
  623.   gen(JMPm, lab2);
  624.   gen(LABm, wq[WQLOOP]);
  625.   if(match(")") == 0) {
  626.     doexpr(NO);           /* expr 3 */
  627.     need(")");
  628.     }
  629.   gen(JMPm, lab1);
  630.   gen(LABm, lab2);
  631.   statement();
  632.   gen(JMPm, wq[WQLOOP]);
  633.   gen(LABm, wq[WQEXIT]);
  634.   delwhile();
  635.   }
  636.  
  637. doswitch() {
  638.   int wq[4], endlab, swact, swdef, *swnex, *swptr;
  639.   swact = swactive;
  640.   swdef = swdefault;
  641.   swnex = swptr = swnext;
  642.   addwhile(wq);
  643.   *(wqptr + WQLOOP - WQSIZ) = 0;
  644.   need("(");
  645.   doexpr(YES);                /* evaluate switch expression */
  646.   need(")");
  647.   swdefault = 0;
  648.   swactive = 1;
  649.   gen(JMPm, endlab = getlabel());
  650.   statement();                /* cases, etc. */
  651.   gen(JMPm, wq[WQEXIT]);
  652.   gen(LABm, endlab);
  653.   gen(SWITCH, 0);             /* match cases */
  654.   while(swptr < swnext) {
  655.     gen(NEARm, *swptr++);
  656. #ifdef INT32
  657.     gen(DWORDn, *swptr++);    /* case value */
  658. #else
  659.     gen(WORDn,  *swptr++);    /* case value */
  660. #endif
  661.     }
  662. #ifdef INT32
  663.   gen(DWORDn, 0);
  664. #else
  665.   gen(WORDn, 0);
  666. #endif
  667.   if(swdefault) gen(JMPm, swdefault);
  668.   gen(LABm, wq[WQEXIT]);
  669.   delwhile();
  670.   swnext    = swnex;
  671.   swdefault = swdef;
  672.   swactive  = swact;
  673.   }
  674.  
  675. docase() {
  676.   if(swactive == 0) error("not in switch");
  677.   if(swnext > swend) {
  678.     error("too many cases");
  679.     return;
  680.     }
  681.   gen(LABm, *swnext++ = getlabel());
  682.   constexpr(swnext++);
  683.   need(":");
  684.   }
  685.  
  686. dodefault() {
  687.   if(swactive) {
  688.     if(swdefault) error("multiple defaults");
  689.     }
  690.   else error("not in switch");
  691.   need(":");
  692.   gen(LABm, swdefault = getlabel());
  693.   }
  694.  
  695. dogoto() {
  696.   if(nogo > 0) error("not allowed with block-locals");
  697.   else noloc = 1;
  698.   if(symname(ssname)) gen(JMPm, addlabel(NO));
  699.   else error("bad label");
  700.   ns();
  701.   }
  702.  
  703. dolabel() {
  704.   char *savelptr;
  705.   blanks();
  706.   savelptr = lptr;
  707.   if(symname(ssname)) {
  708.     if(gch() == ':') {
  709.       gen(LABm, addlabel(YES));
  710.       return 1;
  711.       }
  712.     else bump(savelptr-lptr);
  713.     }
  714.   return 0;
  715.   }
  716.  
  717. addlabel(def) int def; {
  718.   if(cptr = findloc(ssname)) {
  719.     if(cptr[IDENT] != LABEL) error("not a label");
  720.     else if(def) {
  721.       if(cptr[TYPE]) error("duplicate label");
  722.       else cptr[TYPE] = YES;
  723.       }
  724.     }
  725.   else cptr = addsym(ssname, LABEL, def, 0, getlabel(), &locptr, LABEL);
  726.   return (getint(cptr+OFFSET, INTSIZE));
  727.   }
  728.  
  729. doreturn()  {
  730.   int savcsp;
  731.   if(endst() == 0) doexpr(YES);
  732.   savcsp = csp;
  733.   gen(RETURN, 0);
  734.   csp = savcsp;
  735.   }
  736.  
  737. dobreak()  {
  738.   int *ptr;
  739.   if((ptr = readwhile(wqptr)) == 0) return;
  740.   gen(ADDSP, ptr[WQSP]);
  741.   gen(JMPm, ptr[WQEXIT]);
  742.   }
  743.  
  744. docont()  {
  745.   int *ptr;
  746.   ptr = wqptr;
  747.   while (1) {
  748.     if((ptr = readwhile(ptr)) == 0) return;
  749.     if(ptr[WQLOOP]) break;
  750.     }
  751.   gen(ADDSP, ptr[WQSP]);
  752.   gen(JMPm, ptr[WQLOOP]);
  753.   }
  754.  
  755. doasm()  {
  756.   ccode = 0;           /* mark mode as "asm" */
  757.   while (1) {
  758.     inline();
  759.     if(match("#endasm")) break;
  760.     if(eof)break;
  761.     fputs(line, output);
  762.     }
  763.   kill();
  764.   ccode = 1;
  765.   }
  766.  
  767. doexpr(use) int use; {
  768.   int constant, val;
  769.   int *before, *start;
  770.   usexpr = use;        /* tell isfree() whether expr value is used */
  771.   while(1) {
  772.     setstage(&before, &start);
  773.     expression(&constant, &val);
  774.     clearstage(before, start);
  775.     if(ch != ',') break;
  776.     bump(1);
  777.     }
  778.   usexpr = YES;        /* return to normal value */
  779.   }
  780.  
  781. /******************** miscellaneous functions *******************/
  782.  
  783. /*
  784. ** get run options
  785. */
  786. ask()
  787.   {
  788.     int i;
  789.     int j;
  790.     i = listfp = nxtlab = 0;
  791.     output = stdout;
  792. #ifdef LATER
  793.     optimize = YES;     // Not working for 32 bit int's yer
  794. #else
  795.     optimize = NO;
  796. #endif
  797.     alarm = monitor = pause = NO;
  798.     line = mline;
  799.     while(getarg(++i, line, LINESIZE, argcs, argvs) != EOF)
  800.       {
  801.         if(line[0] != '-' && line[0] != '/')
  802.           continue;
  803.         if(toupper(line[1]) == 'L'      // List
  804.            && isdigit(line[2])
  805.            && line[3] <= ' ')
  806.           {
  807.             listfp = line[2]-'0';
  808.             continue;
  809.           }
  810.         if(toupper(line[1]) == 'N'      // No optimize
  811.            && toupper(line[2]) == 'O'
  812.            && line[3] <= ' ')
  813.           {
  814.             optimize = NO;
  815.             continue;
  816.           }
  817.         if(toupper(line[1]) == 'D')
  818.           {
  819.             j = 0;
  820.             ch = line[j+2];
  821.             lptr = line + j+2;
  822.             /*
  823.             while (line[j+2] != ' ')
  824.               {
  825.                 if (j < (NAMEMAX-1))
  826.                   {
  827.                     msname[j] = line[j+1];
  828.                     ++j;
  829.                   }
  830.                 else
  831.                   {
  832.                     break;
  833.                   }
  834.               }
  835.             msname[j] = '\0';
  836.             */
  837.             dodefine ();
  838.             continue;
  839.           }
  840.        
  841.         if(line[2] <= ' ')
  842.           {
  843.             if(toupper(line[1]) == 'A') {alarm   = YES; continue;}
  844.             if(toupper(line[1]) == 'M') {monitor = YES; continue;}
  845.             if(toupper(line[1]) == 'P') {pause   = YES; continue;}
  846.           }
  847.         fputs("usage: cc [file]... [-m] [-a] [-p] [-l#] [-no] [-d<id>]\n", stderr);
  848.         fputs(" -m     monitor\n", stderr);
  849.         fputs(" -a     alarm\n", stderr);
  850.         fputs(" -p     pause\n", stderr);
  851.         fputs(" -l#    list\n", stderr);
  852.         fputs(" -no    no optimize\n", stderr);
  853.         fputs(" -d<id> pre-#define id\n", stderr);
  854.         exit(ERRCODE);
  855.       }
  856.   }
  857.  
  858. /*
  859. ** input and output file opens
  860. */
  861. openfile() {        /* entire function revised */
  862.   char outfn[15];
  863.   int i, j, ext;
  864.   input = EOF;
  865.   while(getarg(++filearg, pline, LINESIZE, argcs, argvs) != EOF) {
  866.     if(pline[0] == '-' || pline[0] == '/') continue;
  867.     ext = NO;
  868.     i = -1;
  869.     j = 0;
  870.     while(pline[++i]) {
  871.       if(pline[i] == '.') {
  872.         ext = YES;
  873.         break;
  874.         }
  875.       if(j < 10) outfn[j++] = pline[i];
  876.       }
  877.     if(!ext) strcpy(pline + i, ".C");
  878.     input = mustopen(pline, "r");
  879. #ifdef _MSC_VER
  880.  
  881.     if(!files) {
  882.       strcpy(outfn + j, ".ASM");
  883.       output = mustopen(outfn, "w");
  884.     }
  885.  
  886. #else
  887.     if(!files /* && iscons(stdout)*/) {
  888.       strcpy(outfn + j, ".ASM");
  889.       output = mustopen(outfn, "w");
  890.       }
  891. #endif
  892.     files = YES;
  893.     kill();
  894.     return;
  895.     }
  896.   if(files++) eof = YES;
  897.   else input = stdin;
  898.   kill();
  899.   }
  900.  
  901. /*
  902. ** open a file with error checking
  903. */
  904. mustopen(fn, mode) char *fn, *mode; {
  905.   int fd;
  906.   if(fd = fopen(fn, mode)) return fd;
  907.   fputs("open error on ", stderr);
  908.   lout(fn, stderr);
  909.   exit(ERRCODE);
  910.   }
  911.  
  912.