
/*
** execution begins here
*/
/*
 * there are four different versions of the beginning of the
 * main procedure, depending on the compiler used and whether
 * command line processing is used.
 */
#ifdef CMD_LINE
#ifdef N_CMD_LN

#ifdef FULLC
main(argc, argv) int argc; char *argv[]; {
#else  /* FULLC */
main(argc, argv) int argc, argv[]; {
#endif  /* FULLC */

  int ii;

  if (argc > MAXARGS) {
    lout("too many command arguments", stderr);
    abort(ERRCODE);
    }
  argcs=argc;
  ii = 0;
  while(argc--)
    argvs[ii++] = *argv++;  /* make static copy of args */

#else  /* N_CMD_LN */
/*
 * original command line processing.
 * NOTE: the function 'getarg' is not in the library
 * supplied with this distribution.
 */
main(argc, argv) int argc, *argv; {
  argcs=argc;
  argvs=argv;
#endif  /* N_CMD_LN */

#else /* CMD_LINE */
main() {
#endif /* CMD_LINE */

  sout("Small-C Ver. ", stderr);
  sout(VERSION, stderr);
  sout("   ", stderr);
  lout(DATE, stderr);

#ifdef DYNAMIC
  swnext=CCALLOC(SWTABSZ);
  swend=swnext+((SWTABSZ-SWSIZ)>>1);
  stage=CCALLOC(STAGESIZE);
  stagelast=stage+STAGELIMIT;
  wq=CCALLOC(WQTABSZ*BPW);
  litq=CCALLOC(LITABSZ);

#ifdef HASH
  macn=CCALLOC(MACNSIZE);
  cptr=macn-1;
  while(++cptr < MACNEND) *cptr=0;
#endif /* HASH */

  macq=CCALLOC(MACQSIZE);
  pline=CCALLOC(LINESIZE);
  mline=CCALLOC(LINESIZE);

#else /* DYNAMIC */
  swnext=swq;
  swend=swnext+SWTABSZ-SWSIZ;
  stagelast=stage+STAGELIMIT;
#endif /* DYNAMIC */

  swactive=       /* not in switch */
  stagenext=      /* direct output mode */
  iflevel=        /* #if... nesting level = 0 */
  skiplevel=      /* #if... not encountered */
  macptr=         /* clear the macro pool */
  csp =           /* stack ptr (relative) */
  errflag=        /* not skipping errors till ";" */
  eof=            /* not eof yet */
  ncmp=           /* not in compound statement */
  files=
  filearg= 0;
  quote[1]='\0';
  func1=          /* first function */
  ccode=1;        /* enable preprocessing */
  wqptr=wq;       /* clear while queue */
  quote[0]='"';   /* fake a quote literal */
  input=input2= EOF;

/*
 * this is where the nitty-gritty begins
 */
  ask();          /* get user options */
  openin();       /* and initial input file */
  preprocess();   /* fetch first line */

#ifdef SMALL_VM
  fopen(" ",NULL);/* pre-alloc FCB for include file */
#endif

#ifdef DYNAMIC
#ifdef HASH
  symtab=CCALLOC(NUMLOCS*SYMAVG + NUMGLBS*SYMMAX);
#else /* HASH */
  symtab=CCALLOC(NUMLOCS*SYMAVG);
  /*  global space is allocated with each new entry  */
#endif /* HASH */
#endif /* DYNAMIC */

#ifdef HASH
  cptr=STARTGLB-1;
  while(++cptr < ENDGLB) *cptr=0;
#endif /* HASH */

  glbptr=STARTGLB;
  glbflag=1;
  ctext=0;
  header();          /* intro code */
  setops();          /* set values in op arrays */
  parse();           /* process ALL input */
  outside();         /* verify outside any function */
  trailer();         /* follow-up code */
  fclose(output);
  }

/*
** 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")) addmac();
    else                      newfunc();
    blanks();       /* force eof if pending */
    }
  }

/*
** dump the literal pool
*/
dumplits(size) int size; {
  int j, k;
  k=0;
  while (k<litptr) {

#ifdef POLL
    CCPOLL(1); /* allow program interruption */
#endif

    defstorage(size);
    j=10;
    while(j--) {
      outdec(getint(litq+k, size));
      k=k+size;
      if ((j==0)|(k>=litptr)) {
        nl();
        break;
        }
      outbyte(',');
      }
    }
  }

/*
** dump zeroes for default initial values
*/
dumpzero(size, count) int size, count; {
  int j;
  while (count > 0) {

#ifdef POLL
    CCPOLL(1); /* allow program interruption */
#endif

    defstorage(size);
    j=30;
    while(j--) {
      outdec(0);
      if ((--count <= 0)|(j==0)) {
        nl();
        break;
        }
      outbyte(',');
      }
    }
  }

/*
** verify compile ends outside any function
*/
outside()  {
  if (ncmp) error("no closing bracket");
  }

/*
** get run options
*/
#ifdef CMD_LINE
ask() {
  int i;
  i=listfp=nxtlab=0;

#ifdef C80
  output=fout;    /* V6 convention */
#else /* C80 */
  output=stdout;  /* V7 convention */
#endif /* C80 */

#ifdef OPTIMIZE
  optimize=
#endif /* OPTIMIZE */

  alarm=monitor=pause=m80flg=NO;
  line=mline;

#ifdef N_CMD_LN
  while(++i < argcs) {
    line = argvs[i];
    if (line[0] == '-') {
      switch (upper(line[1])) {
        case 'L':  if (numeric(line[2]) & (line[3] <= ' ')) {
                     listfp = line[2] - '0';
                     break;
                     }
                   else
                     goto errcase;
        case 'A':  alarm = YES;
                   break;
        case 'M':  monitor = YES;
                   break;
        case 'C':  m80flg = YES;
                   break;
        case 'P':  pause = YES;
                   break;

#ifdef OPTIMIZE
        case 'O':  optimize = YES;
                   break;
#endif /* OPTIMIZE */

#ifndef LINK
        case 'B': if (numeric(line[2]) & (line[3] <= ' ')) {
                    bump(0); bump(2);
                    if(number(&nxtlab)) break;
                    }
                    /* fall through to error case */
#endif /* LINK */

        errcase:
        default:  sout("usage: cc [file]... [-c] [-m] [-a] [-p] [-l#]", stderr);

#ifdef OPTIMIZE
                  sout(" [-o]", stderr);
#endif /* OPTIMIZE */

#ifndef LINK
                  sout(" [-b#]", stderr);
#endif /* LINK */

                  sout("\n", stderr);
                  abort(ERRCODE);
        }
      }
    }

#else   /* N_CMD_LN */
  /*
  ** use original input processing abortion
  */
  while(getarg(++i, line, LINESIZE, argcs, argvs)!=EOF) {
    if(line[0]!='-') continue;
    if((upper(line[1])=='L')&(numeric(line[2]))&(line[3]<=' ')) {
      listfp=line[2]-'0';
      continue;
      }
    if(line[2]<=' ') {
      if(upper(line[1])=='A') {
        alarm=YES;
        continue;
        }
      if(upper(line[1])=='M') {
        monitor=YES;
        continue;
        }
      if(upper(line[1]=='C') {
        m80flg=YES;
        continue;
        }
#ifdef OPTIMIZE
      if(upper(line[1])=='O') {
        optimize=YES;
        continue;
        }
#endif /* OPTIMIZE */
      if(upper(line[1])=='P') {
        pause=YES;
        continue;
        }
      }
#ifndef LINK
    if(upper(line[1])=='B') {
      bump(0); bump(2);
      if(number(&nxtlab)) continue;
      }
#endif /* LINK */

    sout("usage: cc [file]... [-c] [-m] [-a] [-p] [-l#]", stderr);

#ifdef OPTIMIZE
    sout(" [-o]", stderr);
#endif /* OPTIMIZE */

#ifndef LINK
    sout(" [-b#]", stderr);
#endif /* LINK */

    sout("\n", stderr);
    abort(ERRCODE);
    }
#endif  /* N_CMD_LN */

  }

#else /* CMD_LINE */
ask() {

#ifdef OPTIMIZE
  optimize=
#endif /* OPTIMIZE */

  monitor=alarm=pause=m80flg=listfp=nxtlab=0;
  line=mline;
  while(1) {
    prompt("Output file: ", line, LINESIZE);
    if(output=fopen(line, "w")) break;
    else { sout("open error: ", stderr); lout(line, stderr); }
    }

#ifndef LINK
  while(1) {
    prompt("Beginning label number: ", line, LINESIZE);
    bump(0);
    if(number(&nxtlab)) break;
    }
#endif /* LINK */

  while(1) {
    prompt("Monitor function headers? ", line, LINESIZE);
    if(upper(*line)=='Y') monitor=YES;
    else if(upper(*line)!='N') continue;
    break;
    }
  while(1) {
    prompt("Sound alarm on errors? ", line, LINESIZE);
    if(upper(*line)=='Y') alarm=YES;
    else if(upper(*line)!='N') continue;
    break;
    }
  while(1) {
    prompt("Pause on errors? ", line, LINESIZE);
    if(upper(*line)=='Y') pause=YES;
    else if(upper(*line)!='N') continue;
    break;
    }
  while(1) {
    prompt("Generate M80 code? ", line, LINESIZE);
    if(upper(*line)=='Y') m80flg=YES;
    else if(upper(*line)!='N') continue;
    break;
    }

#ifdef OPTIMIZE
  while(1) {
    prompt("Optimize for size? ", line, LINESIZE);
    if(upper(*line)=='Y') optimize=YES;
    else if(upper(*line)!='N') continue;
    break;
    }
#endif /* OPTIMIZE */

  while(1) {
    prompt("Listing file descriptor: ", line, LINESIZE);
    if(numeric(*line)&(line[1]==NULL)) listfp = *line-'0';
    else if(*line!=NULL) continue;
    break;
    }
  }
#endif /* CMD_LINE */

/*
** get next input file
*/
openin() {
  input = EOF;
  line = pline;

#ifdef CMD_LINE

#ifdef N_CMD_LN
  while(++filearg < argcs) {
    line = argvs[filearg];
#else  /* N_CMD_LN */
  while(getarg(++filearg, line, LINESIZE, argcs, argvs)!=EOF) {
#endif  /* N_CMD_LN */
    if(line[0]=='-') continue;

#else /* CMD_LINE */
  while(prompt("Input file: ", line, LINESIZE)) {
#endif /* CMD_LINE */

    if((input=fopen(line,"r"))==NULL) {
      sout("open error: ", stderr);
      lout(line, stderr);
      abort(ERRCODE);
      }
    files=YES;
    kill();
    return;
    }
  if(files++) eof=YES;

#ifdef C80
  else input=fin;    /* V6 convention */
#else
  else input=stdin;  /* V7 convention */
#endif

  kill();
  }

#ifndef CMD_LINE
prompt(msg, ans, anslen) char *msg, *ans; int anslen; {
  sout(msg, stderr);
  xgets(ans, anslen, stderr);
  }
#endif /* CMD_LINE */

setops() {
  op2[00]=     op[00]=  zzor;  /* heir5 */
  op2[01]=     op[01]= zzxor;  /* heir6 */
  op2[02]=     op[02]= zzand;  /* heir7 */
  op2[03]=     op[03]=  zzeq;  /* heir8 */
  op2[04]=     op[04]=  zzne;
  op2[05]=ule; op[05]=  zzle;  /* heir9 */
  op2[06]=uge; op[06]=  zzge;
  op2[07]=ult; op[07]=  zzlt;
  op2[08]=ugt; op[08]=  zzgt;
  op2[09]=     op[09]= zzasr;  /* heir10 */
  op2[10]=     op[10]= zzasl;
  op2[11]=     op[11]= zzadd;  /* heir11 */
  op2[12]=     op[12]= zzsub;
  op2[13]=     op[13]=zzmult;  /* heir12 */
  op2[14]=     op[14]= zzdiv;
  op2[15]=     op[15]= zzmod;
  }
