[net.sources] Small-C V2.0 source

ian (01/07/83)

# This is a shell file to make up the sources for.... Small C Version 2, J. E. Hendrix
# file created at UTCS Thu Jan  6 12:37:45 EST 1983
# Small C Version 2 is copyright 1982 by J. E. Hendrix
# "Public domain" software .. may be used freely but not sold as a product.
echo Extracting abs.c
cat > abs.c << "//SYSIN DD SYSOUT=*"
/*
** abs -- returns absolute value of nbr
*/
abs(nbr)  int nbr;
  {if(nbr<0) return -nbr; else return nbr;}
//SYSIN DD SYSOUT=*
echo Extracting call.asm
cat > call.asm << "//SYSIN DD SYSOUT=*"
#asm
;----- call.a: Small-C arithmetic and logical library
;
CCDDGC:ENTRY
DAD D
JMP CCGCHAR
;
CCDSGC:ENTRY
INX H
INX H
DAD SP
;
;FETCH A SINGLE BYTE FROM THE ADDRESS IN HL AND
; SIGN EXTEND INTO HL
CCGCHAR:ENTRY
MOV A,M
;PUT THE ACCUM INTO HL AND SIGN EXTEND THROUGH H.
CCARGC:ENTRY
CCSXT:ENTRY
MOV L,A
RLC
SBB A
MOV H,A
RET
;
CCDDGI:ENTRY
DAD D
JMP CCGINT
;
CCDSGI:ENTRY
INX H
INX H
DAD SP
;
;FETCH A FULL 16-BIT INTEGER FROM THE ADDRESS IN HL
;INTO HL
CCGINT:ENTRY
MOV A,M
INX H
MOV H,M
MOV L,A
RET
;
CCDECC:ENTRY
INX H
INX H
DAD SP
MOV D,H
MOV E,L
CALL CCGCHAR
DCX H
MOV A,L
STAX D
RET
;
CCINCC:ENTRY
INX H
INX H
DAD SP
MOV D,H
MOV E,L
CALL CCGCHAR
INX H
MOV A,L
STAX D
RET
;
CCDDPDPC:ENTRY
DAD D
CCPDPC:ENTRY
POP B;;RET ADDR
POP D
PUSH B
;
;STORE A SINGLE BYTE FROM HL AT THE ADDRESS IN DE
CCPCHAR:ENTRY
PCHAR:MOV A,L
STAX D
RET
;
CCDECI:ENTRY
INX H
INX H
DAD SP
MOV D,H
MOV E,L
CALL CCGINT
DCX H
JMP CCPINT
;
CCINCI:ENTRY
INX H
INX H
DAD SP
MOV D,H
MOV E,L
CALL CCGINT
INX H
JMP CCPINT
;
CCDDPDPI:ENTRY
DAD D
CCPDPI:ENTRY
POP B;;RET ADDR
POP D
PUSH B
;
;STORE A 16-BIT INTEGER IN HL AT THE ADDRESS IN DE
CCPINT:ENTRY
PINT:MOV A,L
STAX D
INX D
MOV A,H
STAX D
RET
;INCLUSIVE "OR" HL AND DE INTO HL
CCOR:ENTRY
MOV A,L
ORA E
MOV L,A
MOV A,H
ORA D
MOV H,A
RET
;EXCLUSIVE "OR" HL AND DE INTO HL
CCXOR:ENTRY
MOV A,L
XRA E
MOV L,A
MOV A,H
XRA D
MOV H,A
RET
;"AND" HL AND DE INTO HL
CCAND:ENTRY
MOV A,L
ANA E
MOV L,A
MOV A,H
ANA D
MOV H,A
RET
;
;IN ALL THE FOLLOWING COMPARE ROUTINES, HL IS SET TO 1 IF THE
;CONDITION IS TRUE, OTHERWISE IT IS SET TO 0 (ZERO).
;
;TEST IF HL = DE
CCEQ:ENTRY
CALL CCCMP
RZ
DCX H
RET
;TEST IF DE != HL
CCNE:ENTRY
CALL CCCMP
RNZ
DCX H
RET
;TEST IF DE > HL (SIGNED)
CCGT:ENTRY
XCHG
CALL CCCMP
RC
DCX H
RET
;TEST IF DE <= HL (SIGNED)
CCLE:ENTRY
CALL CCCMP
RZ
RC
DCX H
RET
;TEST IF DE >= HL (SIGNED)
CCGE:ENTRY
CALL CCCMP
RNC
DCX H
RET
;TEST IF DE < HL (SIGNED)
CCLT:ENTRY
CALL CCCMP
RC
DCX H
RET
;COMMON ROUTINE TO PERFORM A SIGNED COMPARE
; OF DE AND HL
;THIS ROUTINE PERFORMS DE - HL AND SETS THE CONDITIONS:
; CARRY REFLECTS SIGN OF DIFFERENCE (SET MEANS DE < HL)
; ZERO/NON-ZERO SET ACCORDING TO EQUALITY.
CCCMP:ENTRY
MOV A,H;;INVERT SIGN OF HL
XRI 80H
MOV H,A
MOV A,D;;INVERT SIGN OF DE
XRI 80H
CMP H;;COMPARE MSBS
JNZ CCCMP1;;DONE IF NEQ
MOV A,E;;COMPARE LSBS
CMP L
CCCMP1:LXI H,1;;PRESET TRUE COND
RET
;
;TEST IF DE >= HL (UNSIGNED)
CCUGE:ENTRY
CALL CCUCMP
RNC
DCX H
RET
;
;TEST IF DE < HL (UNSIGNED)
CCULT:ENTRY
CALL CCUCMP
RC
DCX H
RET
;
;TEST IF DE > HL (UNSIGNED)
CCUGT:ENTRY
XCHG
CALL CCUCMP
RC
DCX H
RET
;
;TEST IF DE <= HL (UNSIGNED)
CCULE:ENTRY
CALL CCUCMP
RZ
RC
DCX H
RET
;
;COMMON ROUTINE TO PERFORM UNSIGNED COMPARE
;CARRY SET IF DE < HL
;ZERO/NONZERO SET ACCORDINGLY
CCUCMP:ENTRY
MOV A,D
CMP H
JNZ CCUCMP1
MOV A,E
CMP L
CCUCMP1: LXI H,1
RET
;
;SHIFT DE ARITHMETICALLY RIGHT BY HL AND RETURN IN HL
CCASR:ENTRY
XCHG
DCR E
RM
MOV A,H
RAL
MOV A,H
RAR
MOV H,A
MOV A,L
RAR
MOV L,A
JMP CCASR+1
;SHIFT DE ARITHMETICALLY LEFT BY HL AND RETURN IN HL
CCASL:ENTRY
XCHG
DCR E
RM
DAD H
JMP CCASL+1
;SUBTRACT HL FROM DE AND RETURN IN HL
CCSUB:ENTRY
MOV A,E
SUB L
MOV L,A
MOV A,D
SBB H
MOV H,A
RET
;FORM THE TWO'S COMPLEMENT OF HL
CCNEG:ENTRY
CALL CCCOM
INX H
RET
;FORM THE ONE'S COMPLEMENT OF HL
CCCOM:ENTRY
MOV A,H
CMA
MOV H,A
MOV A,L
CMA
MOV L,A
RET
;MULTIPLY DE BY HL AND RETURN IN HL
;(SIGNED MULTIPLY)
CCMULT:ENTRY
MULT:MOV B,H
MOV C,L
LXI H,0
CCMULT1: MOV A,C
RRC
JNC CCMULT2
DAD D
CCMULT2: XRA A
MOV A,B
RAR
MOV B,A
MOV A,C
RAR
MOV C,A
ORA B
RZ
XRA A
MOV A,E
RAL
MOV E,A
MOV A,D
RAL
MOV D,A
ORA E
RZ
JMP CCMULT1
;DIVIDE DE BY HL AND RETURN QUOTIENT IN HL, REMAINDER IN DE
;(SIGNED DIVIDE)
CCDIV:ENTRY
DIV:MOV B,H
MOV C,L
MOV A,D
XRA B
PUSH PSW
MOV A,D
ORA A
CM CCDENEG
MOV A,B
ORA A
CM CCBCNEG
MVI A,16
PUSH PSW
XCHG
LXI D,0
CCDIV1: DAD H
CALL CCRDEL
JZ CCDIV2
CALL CCCMPBCDE
JM CCDIV2
MOV A,L
ORI 1
MOV L,A
MOV A,E
SUB C
MOV E,A
MOV A,D
SBB B
MOV D,A
CCDIV2: POP PSW
DCR A
JZ CCDIV3
PUSH PSW
JMP CCDIV1
CCDIV3: POP PSW
RP
CALL CCDENEG
XCHG
CALL CCDENEG
XCHG
RET
;NEGATE THE INTEGER IN DE
;(INTERNAL ROUTINE)
CCDENEG: MOV A,D
CMA
MOV D,A
MOV A,E
CMA
MOV E,A
INX D
RET
;NEGATE THE INTEGER IN BC
;(INTERNAL ROUTINE)
CCBCNEG: MOV A,B
CMA
MOV B,A
MOV A,C
CMA
MOV C,A
INX B
RET
;ROTATE DE LEFT ONE BIT
;(INTERNAL ROUTINE)
CCRDEL: MOV A,E
RAL
MOV E,A
MOV A,D
RAL
MOV D,A
ORA E
RET
;COMPARE BC TO DE
;(INTERNAL ROUTINE)
CCCMPBCDE: MOV A,E
SUB C
MOV A,D
SBB B
RET
;
; LOGICAL NEGATION
CCLNEG:ENTRY
MOV A,H
ORA L
JNZ $+6
MVI L,1
RET
LXI H,0
RET
;
; EXECUTE "SWITCH" STATEMENT
;
;  HL  =  SWITCH VALUE
; (SP) -> SWITCH TABLE
;         DW ADDR1, VALUE1
;         DW ADDR2, VALUE2
;         ...
;         DW 0
;        [JMP default]
;         continuation
;
CCSWITCH:ENTRY
XCHG;;DE =  SWITCH VALUE
POP H;;HL -> SWITCH TABLE
SWLOOP:MOV C,M
INX H
MOV B,M;;BC -> CASE ADDR, ELSE 0
INX H
MOV A,B
ORA C
JZ SWEND;;DEFAULT OR CONTINUATION CODE
MOV A,M
INX H
CMP E
MOV A,M
INX H
JNZ SWLOOP
CMP D
JNZ SWLOOP
MOV H,B;;CASE MATCHED
MOV L,C
SWEND:PCHL
;
#endasm
//SYSIN DD SYSOUT=*
echo Extracting cc.def
cat > cc.def << "//SYSIN DD SYSOUT=*"
/*
** Small-C Compiler Version 2.0
**
** Copyright 1982 J. E. Hendrix
**
** Macro Definitions
*/

/*
** compile options
*/
#define PHASE2   /* 2nd and later compiles */
#define SEPARATE /* compile separately */
#define OPTIMIZE /* compile output optimizer */
#define NOCCARGC /* no calls to CCARGC */
/* #define HASH     /* use hash search for macros */
#define SMALL_VM /* uses Small-VM interface */
#define CMD_LINE /* command line run options */
#define DYNAMIC  /* allocate memory dynamically */
#define POLL     /* poll for operator interruptions */
#define PDS      /* uses PDS assembler and loader */
#define COL      /* terminate labels with a colon */
/* #define TAB  9   /* put out tabs of this value */
#define UPPER    /* force symbols to upper case */
#define LINK     /* will use with linking loader */

/*
** 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 OFFSET   3
#define NAME     5
#define OFFSIZE (NAME-OFFSET)
#define SYMAVG  10
#define SYMMAX  14

/*
** symbol table parameters
*/
#define NUMLOCS   25
#define STARTLOC  symtab
#define ENDLOC   (symtab+(NUMLOCS*SYMAVG))
#define NUMGLBS   180
#define STARTGLB  ENDLOC
#define ENDGLB   (ENDLOC+((NUMGLBS-1)*SYMMAX))
#define SYMTBSZ   2770  /* NUMLOCS*SYMAVG + NUMGLBS*SYMMAX */
 
/*
** System wide name size (for symbols)
*/
#define NAMESIZE 9
#define NAMEMAX  8
 
/*
** possible entries for "IDENT"
*/
#define LABEL    0
#define VARIABLE 1
#define ARRAY    2
#define POINTER  3
#define FUNCTION 4
 
/*
** possible entries for "TYPE"
**    low order 2 bits make type unique within length
**    high order bits give length of object
*/
/*      LABEL   0 */
#define CCHAR   (1<<2)
#define CINT    (BPW<<2)
 
/*
** possible entries for "CLASS"
*/
/*      LABEL     0 */
#define STATIC    1
#define AUTOMATIC 2
#define EXTERNAL  3

/*
** "switch" table
*/

#ifdef PHASE2
#define SWSIZ   (2*BPW)
#define SWTABSZ (25*SWSIZ)
#else
#define SWSIZ    4
#define SWTABSZ 100
#endif
 
/*
** "while" statement queue
*/
#define WQTABSZ  30
#define WQSIZ     3
#define WQMAX   (wq+WQTABSZ-WQSIZ)
 
/*
** entry offsets in while queue
*/
#define WQSP    0
#define WQLOOP  1
#define WQEXIT  2
 
/*
** literal pool
*/
#define LITABSZ 700
#define LITMAX  (LITABSZ-1)
 
/*
** input line
*/
#define LINEMAX  80
#define LINESIZE 81

/*
** output staging buffer size
*/
#define STAGESIZE   800
#define STAGELIMIT  (STAGESIZE-1)
 
/*
** macro (define) pool
*/
#ifdef HASH
#define MACNBR   90
#define MACNSIZE 990   /* 90*(NAMESIZE+2) */
#define MACNEND  (macn+MACNSIZE)
#define MACQSIZE 450   /* 90*5 */
#else
#define MACQSIZE 950
#endif
#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 /* compile "do" logic */
/* #define STFOR     9 /* compile "for" logic */
/* #define STSWITCH 10 /* compile "switch/case/default" logic */
#define STCASE   11
#define STDEF    12
/* #define STGOTO   13 /* compile "goto" logic */
//SYSIN DD SYSOUT=*
echo Extracting cc1.c
cat > cc1.c << "//SYSIN DD SYSOUT=*"
/*
** Small-C Compiler Version 2.0
**
** Copyright 1982 J. E. Hendrix
**
** Part 1
*/
#include stdiol.h,2
#include cc.def,2

/*
** miscellaneous storage
*/
char
#ifdef OPTIMIZE
  optimize, /* optimize output of staging buffer */
#endif
  alarm,    /* audible alarm on errors? */
  monitor,  /* monitor function headers? */
  pause,    /* pause for operator on errors? */
#ifdef DYNAMIC
 *stage,    /* output staging buffer */
 *symtab,   /* symbol table */
 *litq,     /* literal pool */
#ifdef HASH
 *macn,     /* macro name buffer */
#endif
 *macq,     /* macro string buffer */
 *pline,    /* parsing buffer */
 *mline,    /* macro buffer */
#else
  stage[STAGESIZE],
  symtab[SYMTBSZ],
  litq[LITABSZ],
#ifdef HASH
  macn[MACNSIZE],
#endif
  macq[MACQSIZE],
  pline[LINESIZE],
  mline[LINESIZE],
  swq[SWTABSZ],
#endif
 *line,     /* points to pline or mline */
 *lptr,     /* ptr to either */
 *glbptr,   /* ptrs to next entries */
 *locptr,   /* ptr to next local symbol */
 *stagenext,/* next addr in stage */
 *stagelast,/* last addr in stage */
  quote[2], /* literal string for '"' */
 *cptr,     /* work ptrs to any char buffer */
 *cptr2,
 *cptr3,
  msname[NAMESIZE], /* macro symbol name array */
  ssname[NAMESIZE]; /* static symbol name array */
int
#ifdef STGOTO
  nogo,     /* > 0 disables goto statements */
  noloc,    /* > 0 disables block locals */
#endif
  op[16],   /* function addresses of binary operators */
  op2[16],  /* same for unsigned operators */
  opindex,  /* index to matched operator */
  opsize,   /* size of operator in bytes */
  swactive, /* true inside a switch */
  swdefault,/* default label #, else 0 */
 *swnext,   /* address of next entry */
 *swend,    /* address of last table entry */
#ifdef DYNAMIC
 *wq,       /* while queue */
#else
  wq[WQTABSZ],
#endif
#ifdef CMD_LINE
  argcs,    /* static argc */
 *argvs,    /* static argv */
#endif
 *wqptr,    /* ptr to next entry */
  litptr,   /* ptr to next entry */
  macptr,   /* macro buffer index */
#ifndef HASH
  mack,     /* variable k for findmac routine */
#endif
  pptr,     /* ptr to parsing buffer */
  oper,     /* address of binary operator function */
  ch,       /* current character of line being scanned */
  nch,      /* next character of line being scanned */
  declared, /* # of local bytes declared, else -1 when done */
  iflevel,  /* #if... nest level */
  skiplevel,/* level at which #if... skipping started */
  func1,    /* true for first function */
  nxtlab,   /* next avail label # */
  litlab,   /* label # assigned to literal pool */
  beglab,   /* beginning label -- first function */
  csp,      /* compiler relative stk ptr */
  argstk,   /* function arg sp */
  argtop,
  ncmp,     /* # open compound statements */
  errflag,  /* non-zero after 1st error in statement */
  eof,      /* set non-zero on final input eof */
  input,    /* fd # for input file */
  input2,   /* fd # for "include" file */
  output,   /* fd # for output file */
  files,    /* non-zero if file list specified on cmd line */
  filearg,  /* cur file arg index */
  glbflag,  /* non-zero if internal globals */
  ctext,    /* non-zero to intermix c-source */
  ccode,    /* non-zero while parsing c-code */
            /* zero when passing assembly code */
  listfp,   /* file pointer to list device */
  lastst,   /* last executed statement type */
 *iptr;     /* work ptr to any int buffer */

#ifdef SEPARATE
#ifdef LINK
#ifdef PDS
#asm
CC2.R:LIBRY
CC3.R:LIBRY
CC4.R:LIBRY
#endasm
#endif
#endif
extern int
  addmac(),  addsym(),  addwhile(),  amatch(),  blanks(),
  bump(),  clearstage(),  col(),  delwhile(),  endst(),
  error(),  findglb(),  findloc(),  gch(),  getint(),
  getlabel(),  illname(),  inbyte(),  inline(),  junk(),
  kill(),  lout(),  match(),  multidef(),  needtoken(),
  nextsym(),  nl(),  numeric(),  outbyte(),  outdec(),
  postlabel(),  preprocess(),  printlabel(),  putint(),
  readwhile(),  setstage(),  sout(),  streq(),  symname(),
  upper();

extern int
  constexpr(),  expression(),  number(),  qstr(),
  test(),  stowlit();

extern int
  add(),  and(),  asl(),  asr(),  defstora(),
  div(),  eq(),  entry(),  external(),  ge(),
  gt(),  header(),  jump(),  le(),  lt(),  mod(),  modstk(),
  mult(),  ne(),  or(),  point(),  ret(),  sub(),  sw(),
  trailer(),  uge(),  ugt(),  ule(),  ult(),  xor();
#endif

#include cc11.c,2
#include cc12.c,2
#include cc13.c,2

#ifndef SEPARATE
#include cc21.c,2
#include cc22.c,2
#include cc31.c,2
#include cc32.c,2
#include cc33.c,2
#include cc41.c,2
#include cc42.c,2
#endif
//SYSIN DD SYSOUT=*
echo Extracting cc11.c
cat > cc11.c << "//SYSIN DD SYSOUT=*"

/*
** execution begins here
*/
#ifdef CMD_LINE
main(argc, argv) int argc, *argv; {
  argcs=argc;
  argvs=argv;
#else
main() {
#endif
#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
  macq=CCALLOC(MACQSIZE);
  pline=CCALLOC(LINESIZE);
  mline=CCALLOC(LINESIZE);
#else
  swend=(swnext=swq)+SWTABSZ-SWSIZ;
  stagelast=stage+STAGELIMIT;
#endif
  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=
  quote[1]=0;
  func1=          /* first function */
  ccode=1;        /* enable preprocessing */
  wqptr=wq;       /* clear while queue */
  quote[0]='"';   /* fake a quote literal */
  input=input2=EOF;
  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
  symtab=CCALLOC(NUMLOCS*SYMAVG);
  /*  global space is allocated with each new entry  */
#endif
#endif
#ifdef HASH
  cptr=STARTGLB-1;
  while(++cptr < ENDGLB) *cptr=0;
#endif
  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;
  output=stdout;
#ifdef OPTIMIZE
  optimize=
#endif
  alarm=monitor=pause=NO;
  line=mline;
  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;
        }
#ifdef OPTIMIZE
      if(upper(line[1])=='O') {
        optimize=YES;
        continue;
        }
#endif
      if(upper(line[1])=='P') {
        pause=YES;
        continue;
        }
      }
#ifndef LINK
    if(upper(line[1])=='B') {
      bump(0); bump(2);
      if(number(&nxtlab)) continue;
      }
#endif
    sout("usage: cc [file]... [-m] [-a] [-p] [-l#]", stderr);
#ifdef OPTIMIZE
    sout(" [-o]", stderr);
#endif
#ifndef LINK
    sout(" [-b#]", stderr);
#endif
    sout("\n", stderr);
    abort(ERRCODE);
    }
  }

#else

ask() {
#ifdef OPTIMIZE
  optimize=
#endif
  monitor=alarm=pause=listfp=nxtlab=0;
  line=mline;
  while(1) {
    prompt("Output file: ", line, LINESIZE);
    if(output=fopen(line, "w")) break;
    else lout("open error");
    }
#ifndef LINK
  while(1) {
    prompt("Beginning label number: ", line, LINESIZE);
    bump(0);
    if(number(&nxtlab)) break;
    }
#endif
  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;
    }
#ifdef OPTIMIZE
  while(1) {
    prompt("Optimize for size? ", line, LINESIZE);
    if(upper(*line)=='Y') optimize=YES;
    else if(upper(*line)!='N') continue;
    break;
    }
#endif
  while(1) {
    prompt("Listing file descriptor: ", line, LINESIZE);
    if(numeric(*line)&(line[1]==NULL)) listfp=*line-'0';
    else if(*line!=NULL) continue;
    break;
    }
  }
#endif

/*
** get next input file
*/
openin() {
  input=EOF;
#ifdef CMD_LINE
  while(getarg(++filearg, pline, LINESIZE, argcs, argvs)!=EOF) {
    if(pline[0]=='-') continue;
#else
  while(prompt("Input file: ", pline, LINESIZE)) {
#endif
    if((input=fopen(pline,"r"))==NULL) {
      lout("open error", stderr);
      abort(ERRCODE);
      }
    files=YES;
    kill();
    return;
    }
  if(files++) eof=YES;
  else input=stdin;
  kill();
  }
#ifndef CMD_LINE

prompt(msg, ans, anslen) char *msg, *ans; int anslen; {
  sout(msg, stderr);
  fgets(ans, anslen, stderr);
  }
#endif

setops() {
  op2[00]=     op[00]=  or;  /* heir5 */
  op2[01]=     op[01]= xor;  /* heir6 */
  op2[02]=     op[02]= and;  /* heir7 */
  op2[03]=     op[03]=  eq;  /* heir8 */
  op2[04]=     op[04]=  ne;
  op2[05]=ule; op[05]=  le;  /* heir9 */
  op2[06]=uge; op[06]=  ge;
  op2[07]=ult; op[07]=  lt;
  op2[08]=ugt; op[08]=  gt;
  op2[09]=     op[09]= asr;  /* heir10 */
  op2[10]=     op[10]= asl;
  op2[11]=     op[11]= add;  /* heir11 */
  op2[12]=     op[12]= sub;
  op2[13]=     op[13]=mult;  /* heir12 */
  op2[14]=     op[14]= div;
  op2[15]=     op[15]= mod;
  }
//SYSIN DD SYSOUT=*
echo Extracting cc12.c
cat > cc12.c << "//SYSIN DD SYSOUT=*"
/*
** open an include file
*/
doinclude()  {
  blanks();       /* skip over to name */
  if((input2=fopen(lptr,"r"))==NULL) {
    input2=EOF;
    error("open failure on include file");
    }
  kill();         /* clear rest of line */
      /* so next read will come from */
      /* new file (if open */
  }

/*
** test for global declarations
*/
dodeclare(class) int class; {
  if(amatch("char",4)) {
    declglb(CCHAR, class);
    ns();
    return 1;
    }
  else if((amatch("int",3))|(class==EXTERNAL)) {
    declglb(CINT, class);
    ns();
    return 1;
    }
  return 0;
  }

/*
** delcare a static variable
*/
declglb(type, class)  int type, class; {
  int k, j;
  while(1) {
    if(endst()) return;     /* do line */
    if(match("*")) {
      j=POINTER;
      k=0;
      }
    else {
      j=VARIABLE;
      k=1;
      }
    if (symname(ssname, YES)==0) illname();
    if(findglb(ssname)) multidef(ssname);
    if(match("()")) j=FUNCTION;
    else if (match("[")) {
      k=needsub();    /* get size */
      j=ARRAY;   /* !0=array */
      }
    if(class==EXTERNAL) external(ssname);
    else j=initials(type>>2, j, k);
    addsym(ssname, j, type, k, &glbptr, class);
    if (match(",")==0) return; /* more? */
    }
  }

/*
** declare local variables
*/
declloc(typ)  int typ;  {
  int k,j;
#ifdef STGOTO
  if(noloc) error("not allowed with goto");
#endif
  if(declared < 0) error("must declare first in block");
  while(1) {
    while(1) {
      if(endst()) return;
      if(match("*")) j=POINTER;
      else j=VARIABLE;
      if (symname(ssname, YES)==0) illname();
      /* no multidef check, block-locals are together */
      k=BPW;
      if (match("[")) {
        k=needsub();
        if(k) {
          j=ARRAY;
          if(typ==CINT)k=k<<LBPW;
          }
        else j=POINTER;
        }
      else if(match("()")) j=FUNCTION;
      else if((typ==CCHAR)&(j==VARIABLE)) k=SBPC;
      declared = declared + k;
      addsym(ssname, j, typ, csp - declared, &locptr, AUTOMATIC);
      break;
      }
    if (match(",")==0) return;
    }
  }

/*
** initialize global objects
*/
initials(size, ident, dim) int size, ident, dim; {
  int savedim;
  litptr=0;
  if(dim==0) dim = -1;
  savedim=dim;
  entry();
  if(match("=")) {
    if(match("{")) {
      while(dim) {
        init(size, ident, &dim);
        if(match(",")==0) break;
        }
      needtoken("}");
      }
    else init(size, ident, &dim);
    }
  if((dim == -1)&(dim==savedim)) {
     stowlit(0, size=BPW);
    ident=POINTER;
    }
  dumplits(size);
  dumpzero(size, dim);
  return ident;
  }

/*
** evaluate one initializer
*/
init(size, ident, dim) int size, ident, *dim; {
  int value;
  if(qstr(&value)) {
    if((ident==VARIABLE)|(size!=1))
      error("must assign to char pointer or array");
    *dim = *dim - (litptr - value);
    if(ident==POINTER) point();
    }
  else if(constexpr(&value)) {
    if(ident==POINTER) error("cannot assign to pointer");
    stowlit(value, size);
    *dim = *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;
    }
  needtoken("]");      /* force single dimension */
  return val;          /* and return size */
  }

/*
** begin a function
**
** called from "parse" and tries to make a function
** out of the following text
**
** Patched per P.L. Woods (DDJ #52)
*/
newfunc()  {
  char *ptr;
#ifdef STGOTO
  nogo  =             /* enable goto statements */
  noloc = 0;          /* enable block-local declarations */
#endif
  lastst=             /* no statement yet */
  litptr=0;           /* clear lit pool */
  litlab=getlabel();  /* label next lit pool */
  locptr=STARTLOC;    /* clear local variables */
  if(monitor) lout(line, stderr);
  if (symname(ssname, YES)==0) {
    error("illegal function or declaration");
    kill(); /* invalidate line */
    return;
    }
  if(func1) {
    postlabel(beglab);
    func1=0;
    }
  if(ptr=findglb(ssname)) {      /* already in symbol table ? */
    if(ptr[IDENT]!=FUNCTION)       multidef(ssname);
    else if(ptr[OFFSET]==FUNCTION) multidef(ssname);
    else ptr[OFFSET]=FUNCTION;
      /*  earlier assumed to be a function */
    }
  else
    addsym(ssname, FUNCTION, CINT, FUNCTION, &glbptr, STATIC);
  if(match("(")==0) error("no open paren");
  entry();
  locptr=STARTLOC;
  argstk=0;               /* init arg count */
  while(match(")")==0) {  /* then count args */
    /* any legal name bumps arg count */
    if(symname(ssname, YES)) {
      if(findloc(ssname)) multidef(ssname);
      else {
        addsym(ssname, 0, 0, argstk, &locptr, AUTOMATIC);
        argstk=argstk+BPW;
        }
      }
    else {error("illegal argument name");junk();}
    blanks();
    /* if not closing paren, should be comma */
    if(streq(lptr,")")==0) {
      if(match(",")==0) error("no comma");
      }
    if(endst()) break;
    }
  csp=0;        /* preset stack ptr */
  argtop=argstk;
  while(argstk) {
    /* now let user declare what types of things */
    /*      those arguments were */
    if(amatch("char",4))     {doargs(CCHAR);ns();}
    else if(amatch("int",3)) {doargs(CINT);ns();}
    else {error("wrong number of arguments");break;}
    }
  if(statement()!=STRETURN) ret();
  if(litptr) {
    printlabel(litlab);
    col();
    dumplits(1); /* dump literals */
    }
  }

/*
** declare argument types
**
** called from "newfunc" this routine adds an entry in the
** local symbol table for each named argument
**
** rewritten per P.L. Woods (DDJ #52)
*/
doargs(t) int t; {
  int j, legalname;
  char c, *argptr;
  while(1) {
    if(argstk==0) return; /* no arguments */
    if(match("*")) j=POINTER; else j=VARIABLE;
    if((legalname=symname(ssname, YES))==0) illname();
    if(match("[")) {   /* is it a pointer? */
      /* yes, so skip stuff between "[...]" */
      while(inbyte()!=']') if(endst()) break;
      j=POINTER; /* add entry as pointer */
      }
    if(legalname) {
      if(argptr=findloc(ssname)) {
        /* add details of type and address */
        argptr[IDENT]=j;
        argptr[TYPE]=t;
        putint(argtop-getint(argptr+OFFSET, OFFSIZE), argptr+OFFSET, OFFSIZE);
        }
      else error("not an argument");
      }
    argstk=argstk-BPW;        /* cnt down */
    if(endst())return;
    if(match(",")==0) error("no comma");
    }
  }
//SYSIN DD SYSOUT=*
echo Extracting cc13.c
cat > cc13.c << "//SYSIN DD SYSOUT=*"
/*
** statement parser
**
** called whenever syntax requires a statement
**  this routine performs that statement
**  and returns a number telling which one
*/
statement() {
  if ((ch==0) & (eof)) return;
  else if(amatch("char",4))  {declloc(CCHAR);ns();}
  else if(amatch("int",3))   {declloc(CINT);ns();}
  else {
    if(declared >= 0) {
#ifdef STGOTO
      if(ncmp > 1) nogo=declared; /* disable goto if any */
#endif
      csp=modstk(csp - declared, NO);
      declared = -1;
      }
    if(match("{"))               compound();
    else if(amatch("if",2))      {doif();lastst=STIF;}
    else if(amatch("while",5))   {dowhile();lastst=STWHILE;}
#ifdef STDO
    else if(amatch("do",2))      {dodo();lastst=STDO;}
#endif
#ifdef STFOR
    else if(amatch("for",3))     {dofor();lastst=STFOR;}
#endif
#ifdef STSWITCH
    else if(amatch("switch",6))  {doswitch();lastst=STSWITCH;}
    else if(amatch("case",4))    {docase();lastst=STCASE;}
    else if(amatch("default",7)) {dodefault();lastst=STDEF;}
#endif
#ifdef STGOTO
    else if(amatch("goto", 4))   {dogoto(); lastst=STGOTO;}
    else if(dolabel())           ;
#endif
    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();ns();lastst=STEXPR;}
    }
  return lastst;
  }

/*
** semicolon enforcer
**
** called whenever syntax requires a semicolon
*/
ns()  {
  if(match(";")==0) error("no semicolon");
  else errflag=0;
  }

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 */
  --ncmp;                 /* close current level */
  csp=modstk(savcsp, NO); /* delete local variable space */
#ifdef STGOTO
  cptr=savloc;            /* retain labels */
  while(cptr < locptr) {
    cptr2=nextsym(cptr);
    if(cptr[IDENT] == LABEL) {
      while(cptr < cptr2) *savloc++ = *cptr++;
      }
    else cptr=cptr2;
    }
#endif
  locptr=savloc;          /* delete local symbols */
  declared = -1;          /* may not declare variables */
  }

doif()  {
  int flab1,flab2;
  flab1=getlabel(); /* get label for false branch */
  test(flab1, YES); /* get expression, and branch false */
  statement();      /* if true, do a statement */
  if (amatch("else",4)==0) {      /* if...else ? */
    /* simple "if"...print false label */
    postlabel(flab1);
    return;         /* and exit */
    }
  flab2=getlabel();
#ifdef STGOTO
  if((lastst != STRETURN)&(lastst != STGOTO)) jump(flab2);
#else
  if(lastst != STRETURN) jump(flab2);
#endif
  postlabel(flab1); /* print false label */
  statement();      /* and do "else" clause */
  postlabel(flab2); /* print true label */
  }

doexpr() {
  int const, val;
  char *before, *start;
  while(1) {
    setstage(&before, &start);
    expression(&const, &val);
    clearstage(before, start);
    if(ch != ',') break;
    bump(1);
    }
  }

dowhile()  {
  int wq[4];              /* allocate local queue */
  addwhile(wq);           /* add entry to queue for "break" */
  postlabel(wq[WQLOOP]);  /* loop label */
  test(wq[WQEXIT], YES);  /* see if true */
  statement();            /* if so, do a statement */
  jump(wq[WQLOOP]);       /* loop to label */
  postlabel(wq[WQEXIT]);  /* exit label */
  delwhile();             /* delete queue entry */
  }

#ifdef STDO
dodo() {
  int wq[4], top;
  addwhile(wq);
  postlabel(top=getlabel());
  statement();
  needtoken("while");
  postlabel(wq[WQLOOP]);
  test(wq[WQEXIT], YES);
  jump(top);
  postlabel(wq[WQEXIT]);
  delwhile();
  ns();
  }
#endif

#ifdef STFOR
dofor() {
  int wq[4], lab1, lab2;
  addwhile(wq);
  lab1=getlabel();
  lab2=getlabel();
  needtoken("(");
  if(match(";")==0) {
    doexpr();            /* expr 1 */
    ns();
    }
  postlabel(lab1);
  if(match(";")==0) {
    test(wq[WQEXIT], NO); /* expr 2 */
    ns();
    }
  jump(lab2);
  postlabel(wq[WQLOOP]);
  if(match(")")==0) {
    doexpr();            /* expr 3 */
    needtoken(")");
    }
  jump(lab1);
  postlabel(lab2);
  statement();
  jump(wq[WQLOOP]);
  postlabel(wq[WQEXIT]);
  delwhile();
  }
#endif

#ifdef STSWITCH
doswitch() {
  int wq[4], endlab, swact, swdef, *swnex, *swptr;
  swact=swactive;
  swdef=swdefault;
  swnex=swptr=swnext;
  addwhile(wq);
  needtoken("(");
  doexpr();      /* evaluate switch expression */
  needtoken(")");
  swdefault=0;
  swactive=1;
  jump(endlab=getlabel());
  statement();   /* cases, etc. */
  jump(wq[WQEXIT]);
  postlabel(endlab);
  sw();          /* match cases */
  while(swptr < swnext) {
    defstorage(CINT>>2);
    printlabel(*swptr++);  /* case label */
    outbyte(',');
    outdec(*swptr++);      /* case value */
    nl();
    }
  defstorage(CINT>>2);
  outdec(0);
  nl();
  if(swdefault) jump(swdefault);
  postlabel(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;
    }
  postlabel(*swnext++ = getlabel());
  constexpr(swnext++);
  needtoken(":");
  }

dodefault() {
  if(swactive) {
    if(swdefault) error("multiple defaults");
    }
  else error("not in switch");
  needtoken(":");
  postlabel(swdefault=getlabel());
  }
#endif

#ifdef STGOTO
dogoto() {
  if(nogo > 0) error("not allowed with block-locals");
  else noloc = 1;
  if(symname(ssname, YES)) jump(addlabel());
  else error("bad label");
  ns();
  }

dolabel() {
  char *savelptr;
  blanks();
  savelptr=lptr;
  if(symname(ssname, YES)) {
    if(gch()==':') {
      postlabel(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, getlabel(), &locptr, LABEL);
  return (getint(cptr+OFFSET, OFFSIZE));
  }
#endif

doreturn()  {
  if(endst()==0) {
    doexpr();
    modstk(0, YES);
    }
  else modstk(0, NO);
  ret();
  }

dobreak()  {
  int *ptr;
  if ((ptr=readwhile())==0) return; /* no loops open */
  modstk((ptr[WQSP]), NO);          /* clean up stk ptr */
  jump(ptr[WQEXIT]);                /* jump to exit label */
  }

docont()  {
  int *ptr;
  if ((ptr=readwhile())==0) return; /* no loops open */
  modstk((ptr[WQSP]), NO);          /* clean up stk ptr */
  jump(ptr[WQLOOP]);                /* jump to loop label */
  }

doasm()  {
  ccode=0;                /* mark mode as "asm" */
  while (1) {
    inline();
    if (match("#endasm")) break;
    if(eof)break;
    lout(line, output);
    }
  kill();
  ccode=1;
  }
//SYSIN DD SYSOUT=*
echo Extracting cc2.c
cat > cc2.c << "//SYSIN DD SYSOUT=*"
/*
** Small-C Compiler Version 2.0
**
** Copyright 1982 J. E. Hendrix
**
** Part 2
*/
#include stdio.h,2
#include cc.def,2

/*
** external references in part 1
*/
extern char
#ifdef DYNAMIC
 *symtab,
 *stage,
#ifdef HASH
 *macn,
#endif
 *macq,
 *pline,
 *mline,
#else
  symtab[SYMTBSZ],
  stage[STAGESIZE],
#ifdef HASH
  macn[MACNSIZE],
#endif
  macq[MACQSIZE],
  pline[LINESIZE],
  mline[LINESIZE],
#endif
  alarm, *glbptr, *line, *lptr, *cptr, *cptr2,  *cptr3,
 *locptr, msname[NAMESIZE],  optimize,  pause,  quote[2],
 *stagelast, *stagenext;
extern int
#ifdef DYNAMIC
  *wq,
#else
  wq[WQTABSZ],
#endif
#ifndef HASH
  mack,
#endif
  ccode,  ch,  csp,  eof,  errflag,  iflevel,
  input,  input2,  listfp,  macptr,  nch,
  nxtlab,  op[16],  opindex,  opsize,  output,  pptr,
  skiplevel,  *wqptr;
extern int
  openin();

/*
** external references in part 4
*/
#ifdef OPTIMIZE
extern int
  peephole();
#endif

#include cc21.c,2
#include cc22.c,2
//SYSIN DD SYSOUT=*
echo Extracting cc21.c
cat > cc21.c << "//SYSIN DD SYSOUT=*"
junk() {
  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)));
  }

illname() {
  error("illegal symbol");
  junk();
  }
  

multidef(sname)  char *sname; {
  error("already defined");
  }

needtoken(str)  char *str; {
  if (match(str)==0) error("missing token");
  }

needlval() {
  error("must be lvalue");
  }

findglb(sname)  char *sname; {
#ifdef HASH
  if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME))
    return cptr;
#else
  cptr=STARTGLB;
  while(cptr < glbptr) {
    if(astreq(sname, cptr+NAME, NAMEMAX)) return cptr;
    cptr=nextsym(cptr);
    }
#endif
  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;
  }

addsym(sname, id, typ, value, lgptrptr, class)
  char *sname, id, typ;  int value, *lgptrptr, class; {
  if(lgptrptr == &glbptr) {
    if(cptr2=findglb(sname)) return cptr2;
#ifdef HASH
    if(cptr==0) {
      error("global symbol table overflow");
      return 0;
      }
#else
#ifndef DYNAMIC
    if(glbptr >= ENDGLB) {
      error("global symbol table overflow");
      return 0;
      }
#endif
    cptr=*lgptrptr;
#endif
    }
  else {
    if(locptr > (ENDLOC-SYMMAX)) {
      error("local symbol table overflow");
      abort(ERRCODE);
      }
    cptr=*lgptrptr;
    }
  cptr[IDENT]=id;
  cptr[TYPE]=typ;
  cptr[CLASS]=class;
  putint(value, cptr+OFFSET, OFFSIZE);
  cptr3 = cptr2 = cptr + NAME;
  while(an(*sname)) *cptr2++ = *sname++;
#ifdef HASH
  if(lgptrptr == &locptr) {
    *cptr2 = cptr2 - cptr3;         /* set length */
    *lgptrptr = ++cptr2;
    }
#else
  *cptr2 = cptr2 - cptr3;         /* set length */
  *lgptrptr = ++cptr2;
#ifdef DYNAMIC
  if(lgptrptr == &glbptr) CCALLOC(cptr2 - cptr);
  /*  gets allocation error if no more memory  */
#endif
#endif
  return cptr;
  }

#ifndef HASH
nextsym(entry) char *entry; {
  entry = entry + NAME;
  while(*entry++ >= ' '); /* find length byte */
  return entry;
  }
#endif

/*
** 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;
    }
  }

/*
** test if next input string is legal symbol name
*/
symname(sname, ucase) char *sname; int ucase; {
  int k;char c;
  blanks();
  if(alpha(ch)==0) return 0;
  k=0;
  while(an(ch)) {
#ifdef UPPER
    if(ucase)
      sname[k]=upper(gch());
    else
#endif
      sname[k]=gch();
    if(k<NAMEMAX) ++k;
    }
  sname[k]=0;
  return 1;
  }

#ifdef UPPER
/*
** force upper case alphabetics
*/
upper(c)  char c; {
  if((c >= 'a') & (c <= 'z')) return (c - 32);
  else return c;
  }
#endif

/*
** return next avail internal label number
*/
getlabel() {
  return(++nxtlab);
  }

/*
** post a label in the program
*/
postlabel(label) int label; {
  printlabel(label);
  col();
  nl();
  }

/*
** print specified number as a label
*/
printlabel(label)  int label; {
  outstr("CC");
  outdec(label);
  }

/*
** test if given character is alphabetic
*/
alpha(c)  char c; {
  return (((c>='a')&(c<='z'))|((c>='A')&(c<='Z'))|(c=='_'));
  }

/*
** test if given character is numeric
*/
numeric(c)  char c; {
  return((c>='0')&(c<='9'));
  }

/*
** test if given character is alphanumeric
*/
an(c)  char c; {
  return ((alpha(c))|(numeric(c)));
  }

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("too many active loops");
    abort(ERRCODE);
    }
  k=0;
  while (k<WQSIZ) *wqptr++ = ptr[k++];
  }

delwhile() {
  if(readwhile()) wqptr=wqptr-WQSIZ;
  }

readwhile() {
  if (wqptr==wq) {
    error("no active loops");
    return 0;
    }
  else return (wqptr-WQSIZ);
 }

white() {
  /* test for stack/program overlap */
  /* primary -> symname -> blanks -> white */
#ifdef DYNAMIC
  CCAVAIL();  /* abort on stack/symbol table overflow */
#endif
  if(*lptr==' ') return 1;
  if(*lptr==9)   return 1;
  return 0;
  }

gch() {
  int c;
  if(c=ch) bump(1);
  return c;
  }

bump(n) int n; {
  if(n) lptr=lptr+n;
  else  lptr=line;
  if(ch=nch=*lptr) nch=*(lptr+1);
  }

kill() {
  *line=0;
  bump(0);
  }

inbyte()  {
  while(ch==0) {
    if (eof) return 0;
    preprocess();
    }
  return gch();
  }

inline() {
  int k,unit;
#ifdef POLL
  CCPOLL(1);  /* allow program interruption */
#endif
  while(1) {
    if (input==EOF) openin();
    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;
      }
    else {
      bump(0);
      return;
      }
    }
  }
//SYSIN DD SYSOUT=*
echo Extracting cc22.c
cat > cc22.c << "//SYSIN DD SYSOUT=*"
ifline() {
  while(1) {
    inline();
    if(eof) return;
    if(match("#ifdef")) {
      ++iflevel;
      if(skiplevel) continue;
      blanks();
#ifdef HASH
      if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0)
#else
      if(findmac(lptr)==0)
#endif
        skiplevel=iflevel;
      continue;
      }
    if(match("#ifndef")) {
      ++iflevel;
      if(skiplevel) continue;
      blanks();
#ifdef HASH
      if(search(lptr, macn, NAMESIZE+2, MACNEND, MACNBR, 0))
#else
      if(findmac(lptr))
#endif
        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(listfp) {
      if(listfp==output) cout(';', output);
      lout(line, listfp);
      }
    if(ch==0) continue;
    break;
    }
  }

keepch(c)  char c; {
  if(pptr<LINEMAX) pline[++pptr]=c;
  }

preprocess() {
  int k;
  char c;
  if(ccode) {
    line=mline;
    ifline();
    if(eof) return;
    }
  else {
    line=pline;
    inline();
    return;
    }
  pptr = -1;
  while(ch) {
    if(white()) {
      keepch(' ');
      while(white()) gch();
      }
    else if(ch=='"') {
      keepch(ch);
      gch();
      while((ch!='"')|((*(lptr-1)==92)&(*(lptr-2)!=92))) {
        if(ch==0) {
          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==0) {
          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)) {
        if(k<NAMEMAX) msname[k++]=ch;
        gch();
        }
      msname[k]=0;
#ifdef HASH
      if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) {
        k=getint(cptr+NAMESIZE, 2);
        while(c=macq[k++]) keepch(c);
        }
#else
      if(k=findmac(msname)) while(c=macq[k++]) keepch(c);
#endif
      else {
        k=0;
        while(c=msname[k++]) keepch(c);
        }
      }
    else keepch(gch());
    }
  if(pptr>=LINEMAX) error("line too long");
  keepch(0);
  line=pline;
  bump(0);
  }

noiferr() {
  error("no matching #if...");
  errflag=0;
  }

addmac() {
  int k;
  if(symname(msname, NO)==0) {
    illname();
    kill();
    return;
    }
  k=0;
#ifdef HASH
  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);
#else
  while(putmac(msname[k++]));
#endif
  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;
  }

#ifdef HASH
/*
** 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 != 0) {
    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;
  }

#else

findmac(sname)  char *sname; {
  mack=0;
  while(mack<macptr) {
    if(astreq(sname,macq+mack,NAMEMAX)) {
      while(macq[mack++]);
      return mack;
      }
    while(macq[mack++]);
    while(macq[mack++]);
    }
  return 0;
  }
#endif

setstage(before, start) int *before, *start; {
  if((*before=stagenext)==0) stagenext=stage;
  *start=stagenext;
  }

clearstage(before, start) char *before, *start; {
  *stagenext=0;
  if(stagenext=before) return;
  if(start) {
#ifdef OPTIMIZE
    peephole(start);
#else
    sout(start, output);
#endif
    }
  }

outdec(number)  int number; {
  int k,zs;
  char c;
  zs = 0;
  k=10000;
  if (number<0) {
    number=(-number);
    outbyte('-');
    }
  while (k>=1) {
    c=number/k + '0';
    if ((c!='0')|(k==1)|(zs)) {
      zs=1;
      outbyte(c);
      }
    number=number%k;
    k=k/10;
    }
  }

ol(ptr)  char ptr[];  {
  ot(ptr);
  nl();
  }

ot(ptr) char ptr[]; {
#ifdef TAB
  tab();
#endif
  outstr(ptr);
  }

outstr(ptr) char ptr[]; {
#ifdef POLL
  CCPOLL(1); /* allow program interruption */
#endif
  /* must work with symbol table names terminated by length */
  while(*ptr >= ' ') outbyte(*ptr++);
  }

outbyte(c) char c; {
  if(stagenext) {
    if(stagenext==stagelast) {
      error("staging buffer overflow");
      return 0;
      }
    else *stagenext++ = c;
    }
  else cout(c,output);
  return c;
  }

cout(c, fd) char c; int fd; {
  if(fputc(c, fd)==EOF) xout();
  }

sout(string, fd) char *string; int fd; {
  if(fputs(string, fd)==EOF) xout();
  }

lout(line, fd) char *line; int fd; {
  sout(line, fd);
  cout('\n', fd);
  }

xout() {
  fputs("output error\n", stderr);
  abort(ERRCODE);
  }

nl() {
  outbyte('\n');
  }

tab() {
  outbyte(TAB);
  }

col() {
#ifdef COL
  outbyte(':');
#endif
  }

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)!='\n');
  if(listfp>0) errout(msg, listfp);
  }

errout(msg, fp) char msg[]; int fp; {
  int k; k=line+2;
  while(k++ <= lptr) cout(' ', fp);
  lout("/\\", fp);
  sout("**** ", fp); lout(msg, fp);
  }

streq(str1,str2)  char str1[],str2[]; {
  int k;
  k=0;
  while (str2[k]) {
    if ((str1[k])!=(str2[k])) return 0;
    ++k;
    }
  return k;
 }

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(str1[k] < ' ') break;
    if(str2[k] < ' ') break;
    ++k;
    }
  if (an(str1[k]))return 0;
  if (an(str2[k]))return 0;
  return k;
 }

match(lit)  char *lit; {
  int k;
  blanks();
  if (k=streq(lptr,lit)) {
    bump(k);
    return 1;
    }
  return 0;
  }

amatch(lit,len)  char *lit;int len; {
  int k;
  blanks();
  if (k=astreq(lptr,lit,len)) {
    bump(k);
    while(an(ch)) inbyte();
    return 1;
    }
  return 0;
 }

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;
    }
  }
//SYSIN DD SYSOUT=*
echo Extracting cc3.c
cat > cc3.c << "//SYSIN DD SYSOUT=*"
/*
** Small-C Compiler Version 2.0
**
** Copyright 1982 J. E. Hendrix
**
** Part 3
*/
#include stdio.h,2
#include cc.def,2

/*
** external references in part 1
*/
extern char
#ifdef DYNAMIC
 *stage,
 *litq,
#else
  stage[STAGESIZE],
  litq[LITABSZ],
#endif
 *glbptr, *lptr,  ssname[NAMESIZE],  quote[2], *stagenext;
extern int
  ch,  csp,  litlab,  litptr,  nch,  op[16],  op2[16],
  oper,  opindex,  opsize;

/*
** external references in part 2
*/
extern int
  addsym(),  blanks(),  bump(),  clearstage(),  endst(),
  error(),  findglb(),  findloc(),  gch(),  getlabel(),
  inbyte(),  junk(),  match(),  needlval(),  needtoken(),
  nextop(),  nl(),  numeric(),  outbyte(),  outdec(),
  outstr(),  postlabel(),  printlabel(),  putint(),
  setstage(),  streq(),  symname();

/*
** external references in part 4
*/
extern int
  add(),  and(),  asl(),  asr(),  call(),  callstk(),
  com(),  dec(),  div(),  doublereg(),  eq(),  eq0(),
  ge(),  ge0(),  getloc(),  getmem(),  gt(),  gt0(),
  immed(),  immed2(),  inc(),  indirect(),  jump(),
  le(),  le0(),  lneg(),  loadargc(),  lt(),  lt0(),
  mod(),  modstk(),  move(),  mult(),  ne(),  ne0(),
  neg(),  or(),  pop(),  push(),  putmem(),
  putstk(),  ret(),  smartpop(),  sub(),  swap(),  swapstk(),
  testjump(),  uge(),  ugt(),  ule(),  ult(),  ult0(),
  xor(),  zerojump();

#include cc31.c,2
#include cc32.c,2
#include cc33.c,2
//SYSIN DD SYSOUT=*
echo Extracting cc31.c
cat > cc31.c << "//SYSIN DD SYSOUT=*"
/*
** lval[0] - symbol table address, else 0 for constant
** lval[1] - type of indirect obj to fetch, else 0 for static
** lval[2] - type of pointer or array, else 0 for all other
** lval[3] - true if constant expression
** lval[4] - value of constant expression
** lval[5] - true if secondary register altered
** lval[6] - function address of highest/last binary operator
** lval[7] - stage address of "oper 0" code, else 0
*/

/*
** skim over terms adjoining || and && operators
*/
skim(opstr, testfunc, dropval, endval, heir, lval)
  char *opstr;
  int testfunc, dropval, endval, heir, lval[]; {
  int k, hits, droplab, endlab;
  hits=0;
  while(1) {
    k=plunge1(heir, lval);
    if(nextop(opstr)) {
      bump(opsize);
      if(hits==0) {
        hits=1;
        droplab=getlabel();
        }
      dropout(k, testfunc, droplab, lval);
      }
    else if(hits) {
      dropout(k, testfunc, droplab, lval);
      const(endval);
      jump(endlab=getlabel());
      postlabel(droplab);
      const(dropval);
      postlabel(endlab);
      lval[1]=lval[2]=lval[3]=lval[7]=0;
      return 0;
      }
    else return k;
    }
  }

/*
** test for early dropout from || or && evaluations
*/
dropout(k, testfunc, exit1, lval) int k, testfunc, exit1, lval[]; {
  if(k) rvalue(lval);
  else if(lval[3]) const(lval[4]);
  testfunc(exit1); /* jumps on false */
  }

/*
** plunge to a lower level
*/
plunge(opstr, opoff, heir, lval)
  char *opstr;
  int opoff, heir, lval[]; {
  int k, lval2[8];
  k=plunge1(heir, lval);
  if(nextop(opstr)==0) return k;
  if(k) rvalue(lval);
  while(1) {
    if(nextop(opstr)) {
      bump(opsize);
      opindex=opindex+opoff;
      plunge2(op[opindex], op2[opindex], heir, lval, lval2);
      }
    else return 0;
    }
  }

/*
** unary plunge to lower level
*/
plunge1(heir, lval) int heir, lval[]; {
  char *before, *start;
  int k;
  setstage(&before, &start);
  k=heir(lval);
  if(lval[3]) clearstage(before,0); /* load constant later */
  return k;
  }

/*
** binary plunge to lower level
*/
plunge2(oper, oper2, heir, lval, lval2)
  int oper, oper2, heir, lval[], lval2[]; {
  char *before, *start;
  setstage(&before, &start);
  lval[5]=1;          /* flag secondary register used */
  lval[7]=0;          /* flag as not "... oper 0" syntax */
  if(lval[3]) {       /* constant on left side not yet loaded */
    if(plunge1(heir, lval2)) rvalue(lval2);
    if(lval[4]==0) lval[7]=stagenext;
    const2(lval[4]<<dbltest(lval2, lval));
    }
  else {              /* non-constant on left side */
    push();
    if(plunge1(heir, lval2)) rvalue(lval2);
    if(lval2[3]) {    /* constant on right side */
      if(lval2[4]==0) lval[7]=start;
      if(oper==add) { /* may test other commutative operators */
        csp=csp+2;
        clearstage(before, 0);
        const2(lval2[4]<<dbltest(lval, lval2));   /* load secondary */
        }
      else {
        const(lval2[4]<<dbltest(lval, lval2));    /* load primary */
        smartpop(lval2, start);
        }
      }
    else {            /* non-constants on both sides */
      smartpop(lval2, start);
      if((oper==add)|(oper==sub)) {
        if(dbltest(lval,lval2)) doublereg();
        if(dbltest(lval2,lval)) {
          swap();
          doublereg();
          if(oper==sub) swap();
          }
        }
      }
    }
  if(oper) {
    if(lval[3]=lval[3]&lval2[3]) {
      lval[4]=calc(lval[4], oper, lval2[4]);
      clearstage(before, 0);  
      lval[5]=0;
      }
    else {
      if((lval[2]==0)&(lval2[2]==0)) {
        oper();
        lval[6]=oper;    /* identify the operator */
        }
      else {
        oper2();
        lval[6]=oper2;   /* identify the operator */
        }
      }
    if(oper==sub) {
      if((lval[2]==CINT)&(lval2[2]==CINT)) {
        swap();
        const(1);
        asr();  /** div by 2 **/
        }
      }
    if((oper==sub)|(oper==add)) result(lval, lval2);
    }
  }

calc(left, oper, right) int left, oper, right; {
       if(oper ==  or) return (left  |  right);
  else if(oper == xor) return (left  ^  right);
  else if(oper == and) return (left  &  right);
  else if(oper ==  eq) return (left  == right);
  else if(oper ==  ne) return (left  != right);
  else if(oper ==  le) return (left  <= right);
  else if(oper ==  ge) return (left  >= right);
  else if(oper ==  lt) return (left  <  right);
  else if(oper ==  gt) return (left  >  right);
  else if(oper == asr) return (left  >> right);
  else if(oper == asl) return (left  << right);
  else if(oper == add) return (left  +  right);
  else if(oper == sub) return (left  -  right);
  else if(oper ==mult) return (left  *  right);
  else if(oper == div) return (left  /  right);
  else if(oper == mod) return (left  %  right);
  else return 0;
  }

expression(const, val) int *const, *val;  {
  int lval[8];
  if(heir1(lval)) rvalue(lval);
  if(lval[3]) {
    *const=1;
    *val=lval[4];
    }
  else *const=0;
  }

heir1(lval)  int lval[];  {
  int k,lval2[8], oper;
  k=plunge1(heir3, lval);
  if(lval[3]) const(lval[4]);
       if(match("|="))  oper=or;
  else if(match("^="))  oper=xor;
  else if(match("&="))  oper=and;
  else if(match("+="))  oper=add;
  else if(match("-="))  oper=sub;
  else if(match("*="))  oper=mult;
  else if(match("/="))  oper=div;
  else if(match("%="))  oper=mod;
  else if(match(">>=")) oper=asr;
  else if(match("<<=")) oper=asl;
  else if(match("="))   oper=0;
  else return k;
  if(k==0) {
    needlval();
    return 0;
    }
  if(lval[1]) {
    if(oper) {
      push();
      rvalue(lval);
      }
    plunge2(oper, oper, heir1, lval, lval2);
    if(oper) pop();
    }
  else {
    if(oper) {
      rvalue(lval);
      plunge2(oper, oper, heir1, lval, lval2);
      }
    else {
      if(heir1(lval2)) rvalue(lval2);
      lval[5]=lval2[5];
      }
    }
  store(lval);
  return 0;
  }

heir3(lval)  int lval[]; {
  return skim("||", eq0, 1, 0, heir4, lval);
  }

heir4(lval)  int lval[]; {
  return skim("&&", ne0, 0, 1, heir5, lval);
  }

heir5(lval)  int lval[]; {
  return plunge("|", 0, heir6, lval);
  }

heir6(lval)  int lval[]; {
  return plunge("^", 1, heir7, lval);
  }

heir7(lval)  int lval[]; {
  return plunge("&", 2, heir8, lval);
  }

heir8(lval)  int lval[];  {
  return plunge("== !=", 3, heir9, lval);
  }

heir9(lval)  int lval[];  {
  return plunge("<= >= < >", 5, heir10, lval);
  }

heir10(lval)  int lval[];  {
  return plunge(">> <<", 9, heir11, lval);
  }

heir11(lval)  int lval[];  {
  return plunge("+ -", 11, heir12, lval);
  }

heir12(lval)  int lval[];  {
  return plunge("* / %", 13, heir13, lval);
  }
//SYSIN DD SYSOUT=*
echo Extracting cc32.c
cat > cc32.c << "//SYSIN DD SYSOUT=*"
heir13(lval)  int lval[];  {
  int k;
  char *ptr;
  if(match("++")) {                   /* ++lval */
    if(heir13(lval)==0) {
      needlval();
      return 0;
      }
    step(inc, lval);
    return 0;
    }
  else if(match("--")) {              /* --lval */
    if(heir13(lval)==0) {
      needlval();
      return 0;
      }
    step(dec, lval);
    return 0;
    }
  else if (match("~")) {              /* ~ */
    if(heir13(lval)) rvalue(lval);
    com();
#ifdef PHASE2
    lval[4] = ~lval[4];
#endif
    return 0;
    }
  else if (match("!")) {              /* ! */
    if(heir13(lval)) rvalue(lval);
    lneg();
#ifdef PHASE2
    lval[4] = !lval[4];
#endif
    return 0;
    }
  else if (match("-")) {              /* unary - */
    if(heir13(lval)) rvalue(lval);
    neg();
    lval[4] = -lval[4];
    return 0;
    }
  else if(match("*")) {               /* unary * */
    if(heir13(lval)) rvalue(lval);
    if(ptr=lval[0])lval[1]=ptr[TYPE];
    else lval[1]=CINT;
    lval[2]=0;  /* flag as not pointer or array */
    lval[3]=0;  /* flag as not constant */
    return 1;
    }
  else if(match("&")) {               /* unary & */
    if(heir13(lval)==0) {
      error("illegal address");
      return 0;
      }
    ptr=lval[0];
    lval[2]=ptr[TYPE];
    if(lval[1]) return 0;
    /* global & non-array */
    address(ptr);
    lval[1]=ptr[TYPE];
    return 0;
    }
  else {
    k=heir14(lval);
    if(match("++")) {                 /* lval++ */
      if(k==0) {
        needlval();
        return 0;
        }
      step(inc, lval);
      dec(lval[2]>>2);
      return 0;
      }
    else if(match("--")) {            /* lval-- */
      if(k==0) {
        needlval();
        return 0;
        }
      step(dec, lval);
      inc(lval[2]>>2);
      return 0;
      }
    else return k;
    }
  }

heir14(lval)  int *lval; {
  int k, const, val, lval2[8];
  char *ptr, *before, *start;
  k=primary(lval);
  ptr=lval[0];
  blanks();
  if((ch=='[')|(ch=='(')) {
    lval[5]=1;    /* secondary register will be used */
    while(1) {
      if(match("[")) {                /* [subscript] */
        if(ptr==0) {
          error("can't subscript");
          junk();
          needtoken("]");
          return 0;
          }
        else if(ptr[IDENT]==POINTER)rvalue(lval);
        else if(ptr[IDENT]!=ARRAY) {
          error("can't subscript");
          k=0;
          }
        setstage(&before, &start);
        lval2[3]=0;
        plunge2(0, 0, heir1, lval2, lval2); /* lval2 deadend */
        needtoken("]");
        if(lval2[3]) {
          clearstage(before, 0);
          if(lval2[4]) {
            if(ptr[TYPE]==CINT) const2(lval2[4]<<LBPW);
            else                const2(lval2[4]);
            add();
            }
          }
        else {
          if(ptr[TYPE]==CINT) doublereg();
          add();
          }
        lval[0]=lval[2]=0;
        lval[1]=ptr[TYPE];
        k=1;
        }
      else if(match("(")) {           /* function(...) */
        if(ptr==0) callfunction(0);
        else if(ptr[IDENT]!=FUNCTION) {
          rvalue(lval);
          callfunction(0);
          }
        else callfunction(ptr);
        k=lval[0]=lval[3]=0;
        }
      else return k;
      }
    }
  if(ptr==0) return k;
  if(ptr[IDENT]==FUNCTION) {
    address(ptr);
    return 0;
    }
  return k;
  }

primary(lval)  int *lval; {
  char *ptr;
  int k;
  if(match("(")) {                    /* (expression) */
    k=heir1(lval);
    needtoken(")");
    return k;
    }
  putint(0, lval, 8<<LBPW); /* clear lval array */
  if(symname(ssname, YES)) {
    if(ptr=findloc(ssname)) {
#ifdef STGOTO
      if(ptr[IDENT]==LABEL) {
        experr();
        return 0;
        }
#endif
      getloc(ptr);
      lval[0]=ptr;
      lval[1]=ptr[TYPE];
      if(ptr[IDENT]==POINTER) {
        lval[1]=CINT;
        lval[2]=ptr[TYPE];
        }
      if(ptr[IDENT]==ARRAY) {
        lval[2]=ptr[TYPE];
        return 0;
        }
      else return 1;
      }
    if(ptr=findglb(ssname))
      if(ptr[IDENT]!=FUNCTION) {
        lval[0]=ptr;
        lval[1]=0;
        if(ptr[IDENT]!=ARRAY) {
          if(ptr[IDENT]==POINTER) lval[2]=ptr[TYPE];
          return 1;
          }
        address(ptr);
        lval[1]=lval[2]=ptr[TYPE];
        return 0;
        }
    ptr=addsym(ssname, FUNCTION, CINT, 0, &glbptr, STATIC);
    lval[0]=ptr;
    lval[1]=0;
    return 0;
    }
  if(constant(lval)==0) experr();
  return 0;
  }

experr() {
  error("invalid expression");
  const(0);
  junk();
  }
 
callfunction(ptr)  char *ptr; { /* symbol table entry or 0 */
  int nargs, const, val;
  nargs=0;
  blanks();               /* already saw open paren */
  if(ptr==0) push();      /* calling HL */
  while(streq(lptr,")")==0) {
    if(endst()) break;
    expression(&const, &val);
    if(ptr==0) swapstk(); /* don't push addr */
    push();               /* push argument */
    nargs=nargs+BPW;      /* count args*BPW */
    if (match(",")==0) break;
    }
  needtoken(")");
  if(streq(ptr+NAME, "CCARGC")==0) loadargc(nargs>>LBPW);
  if(ptr) call(ptr+NAME);
  else callstk();
  csp=modstk(csp+nargs, YES);
  }
//SYSIN DD SYSOUT=*
echo Extracting cc33.c
cat > cc33.c << "//SYSIN DD SYSOUT=*"
/*
** true if val1 -> int pointer or int array and val2 not ptr or array
*/
dbltest(val1,val2) int val1[], val2[]; {
  if(val1[2]!=CINT) return 0;
  if(val2[2]) return 0;
  return 1;
  }

/*
** determine type of binary operation
*/
result(lval, lval2) int lval[], lval2[]; {
  if((lval[2]!=0)&(lval2[2]!=0)) {
    lval[2]=0;
    }
  else if(lval2[2]) {
    lval[0]=lval2[0];
    lval[1]=lval2[1];
    lval[2]=lval2[2];
    }
  }

step(oper, lval) int oper, lval[]; {
  if(lval[1]) {
    if(lval[5]) {
      push();
      rvalue(lval);
      oper(lval[2]>>2);
      pop();
      store(lval);
      return;
      }
    else {
      move();
      lval[5]=1;
      }
    }
  rvalue(lval);
  oper(lval[2]>>2);
  store(lval);
  }

store(lval)  int lval[]; {
  if(lval[1]) putstk(lval);
  else        putmem(lval);
  }

rvalue(lval) int lval[]; {
  if ((lval[0]!=0)&(lval[1]==0)) getmem(lval);
  else                         indirect(lval);
  }

test(label, parens)  int label, parens;  {
  int lval[8];
  char *before, *start;
  if(parens) needtoken("(");
  while(1) {
    setstage(&before, &start);
    if(heir1(lval)) rvalue(lval);
    if(match(",")) clearstage(before, start);
    else break;
    }
  if(parens) needtoken(")");
  if(lval[3]) {  /* constant expression */
    clearstage(before, 0);
    if(lval[4]) return;
    jump(label);
    return;
    }
  if(lval[7]) {  /* stage address of "oper 0" code */
    oper=lval[6];/* operator function address */
         if((oper==eq)|
            (oper==ule)) zerojump(eq0, label, lval);
    else if((oper==ne)|
            (oper==ugt)) zerojump(ne0, label, lval);
    else if (oper==gt)   zerojump(gt0, label, lval);
    else if (oper==ge)   zerojump(ge0, label, lval);
    else if (oper==uge)  clearstage(lval[7],0);
    else if (oper==lt)   zerojump(lt0, label, lval);
    else if (oper==ult)  zerojump(ult0, label, lval);
    else if (oper==le)   zerojump(le0, label, lval);
    else                 testjump(label);
    }
  else testjump(label);
  clearstage(before, start);
  }

constexpr(val) int *val; {
  int const;
  char *before, *start;
  setstage(&before, &start);
  expression(&const, val);
  clearstage(before, 0);  /* scratch generated code */
  if(const==0) error("must be constant expression");
  return const;
  }

const(val) int val; {
  immed();
  outdec(val);
  nl();
  }

const2(val) int val; {
  immed2();
  outdec(val);
  nl();
  }

constant(lval)  int lval[]; {
  lval=lval+3;
  *lval=1;       /* assume it will be a constant */
  if (number(++lval)) immed();
  else if (pstr(lval)) immed();
  else if (qstr(lval)) {
    *(lval-1)=0; /* nope, it's a string address */
    immed();
    printlabel(litlab);
    outbyte('+');
    }
  else return 0;
  outdec(*lval);
  nl();
  return 1;
  }

number(val)  int val[]; {
  int k, minus;
  k=minus=0;
  while(1) {
    if(match("+")) ;
    else if(match("-")) minus=1;
    else break;
    }
  if(numeric(ch)==0)return 0;
  while (numeric(ch)) k=k*10+(inbyte()-'0');
  if (minus) k=(-k);
  val[0]=k;
  return 1;
  }

address(ptr) char *ptr; {
  immed();
  outstr(ptr+NAME);
  nl();
  }

pstr(val)  int val[]; {
  int k;
  k=0;
  if (match("'")==0) return 0;
  while(ch!=39)    k=(k&255)*256 + (litchar()&255);
  ++lptr;
  val[0]=k;
  return 1;
  }

qstr(val)  int val[]; {
  char c;
  if (match(quote)==0) return 0;
  val[0]=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=litptr+size;
  }

/*
** return current literal char & bump lptr
*/
litchar() {
  int i, oct;
  if((ch!=92)|(nch==0)) return gch();
  gch();
  if(ch=='n') {gch(); return 13;} /* CR */
  if(ch=='t') {gch(); return  9;} /* HT */
  if(ch=='b') {gch(); return  8;} /* BS */
  if(ch=='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;
  }
//SYSIN DD SYSOUT=*
echo Extracting cc4.c
cat > cc4.c << "//SYSIN DD SYSOUT=*"
/*
** Small-C Compiler Version 2.0
**
** Copyright 1982 J. E. Hendrix
**
** Part 4
*/
#include stdio.h,2
#include cc.def,2

/*
** external references in part 1
*/
extern char
#ifdef HASH
 *macn,
#endif
#ifdef OPTIMIZE
 optimize,
#endif
 *stagenext, ssname[NAMESIZE];
extern int
  beglab,  csp, output;

/*
** external references in part 2
*/
extern int
#ifdef HASH
  search(),
#else
  findmac(),
#endif
  clearstage(),  col(),  cout(),  getint(),  getlabel(),
  nl(),  numeric(),  ol(),  ot(),  printlabel(),
  lout(),  outdec(),  outstr(),  streq();

/*
** external references in part 3
*/
extern int const();

#include cc41.c,2
#include cc42.c,2
//SYSIN DD SYSOUT=*
echo Extracting cc41.c
cat > cc41.c << "//SYSIN DD SYSOUT=*"
/*
** print all assembler info before any code is generated
*/
header()  {
  beglab=getlabel();
#ifndef LINK
  if(beglab < 3)
#endif
    {
#ifdef SMALL_VM
    ol("LXI D,$+6");
    ol("JMP CC9998");
#endif
    jump(beglab);
    }
  }

/*
** print any assembler stuff needed at the end
*/
trailer()  {  
#ifdef SMALL_VM
#ifndef LINK
  if((beglab == 1)|(beglab > 9000))
#endif
    {
    ol("CC9997:JMP CCBOJ");
    ol("CC9998:DS 6");
    ol("PUSH D");
    ol("LXI D,$+6");
    ol("JMP CC9997");
    ol("ORG CC9998");
    ol("JMP $+6");
    }
#endif
  ol("END");
  }

/*
** load # args before function call
*/
loadargc(val) int val; {
#ifdef HASH
  if(search("NOCCARGC", macn, NAMESIZE+2, MACNEND, MACNBR, 0)==0) {
#else
  if(findmac("NOCCARGC")==0) {
#endif
    ot("MVI A,");
    outdec(val);
    nl();
    }
  }

/*
** declare entry point
*/
entry() {
  outstr(ssname);
  col();
#ifdef LINK
  ol("ENTRY");
#else
  nl();
#endif
  }

/*
** declare external reference
*/
external(name) char *name; {
#ifdef LINK
  outstr(name);
  col();
  ol("EXTRN");
#endif
  }

/*
** fetch object indirect to primary register
*/
indirect(lval) int lval[]; {
  if(lval[1]==CCHAR) call("CCGCHAR");
  else               call("CCGINT");
  }

/*
** fetch a static memory cell into primary register
*/
getmem(lval)  int lval[]; {
  char *sym;
  sym=lval[0];
  if((sym[IDENT]!=POINTER)&(sym[TYPE]==CCHAR)) {
    ot("LDA ");
    outstr(sym+NAME);
    nl();
    call("CCSXT");
    }
  else {
    ot("LHLD ");
    outstr(sym+NAME);
    nl();
    }
  }

/*
** fetch addr of the specified symbol into primary register
*/
getloc(sym)  char *sym; {
  const(getint(sym+OFFSET, OFFSIZE)-csp);
  ol("DAD SP");
  }

/*
** store primary register into static cell
*/
putmem(lval)  int lval[]; {
  char *sym;
  sym=lval[0];
  if((sym[IDENT]!=POINTER)&(sym[TYPE]==CCHAR)) {
    ol("MOV A,L");
    ot("STA ");
    }
  else ot("SHLD ");
  outstr(sym+NAME);
  nl();
  }

/*
** put on the stack the type object in primary register
*/
putstk(lval) int lval[]; {
  if(lval[1]==CCHAR) {
    ol("MOV A,L");
    ol("STAX D");
    }
  else call("CCPINT");
  }

/*
** move primary register to secondary
*/
move() {
  ol("MOV D,H");
  ol("MOV E,L");
  }

/*
** swap primary and secondary registers
*/
swap() {
  ol("XCHG;;");  /* peephole() uses trailing ";;" */
  }

/*
** partial instruction to get immediate value
** into the primary register
*/
immed() {
  ot("LXI H,");
  }

/*
** partial instruction to get immediate operand
** into secondary register
*/
immed2() {
  ot("LXI D,");
  }

/*
** push primary register onto stack
*/
push() {
  ol("PUSH H");
  csp=csp-BPW;
  }

/*
** unpush or pop as required
*/
smartpop(lval, start) int lval[]; char *start; {
  if(lval[5])  pop(); /* secondary was used */
  else unpush(start);
  }

/*
** replace a push with a swap
*/
unpush(dest) char *dest; {
  int i;
  char *sour;
#ifdef TAB
  sour="\tXCHG;;";  /* peephole() uses trailing ";;" */
#else
  sour="XCHG;;";  /* peephole() uses trailing ";;" */
#endif
  while(*sour) *dest++ = *sour++;
  sour=stagenext;
  while(--sour > dest) { /* adjust stack references */
#ifdef TAB
    if(streq(sour,"\tDAD SP")) {
#else
    if(streq(sour,"DAD SP")) {
#endif
      --sour;
      i=BPW;
      while(numeric(*(--sour))) {
        if((*sour=*sour-i) < '0') {
          *sour=*sour+10;
          i=1;
          }
        else i=0;
        }
      }
    }
  csp=csp+BPW;
  }

/*
** pop stack to the secondary register
*/
pop() {
  ol("POP D");
  csp=csp+BPW;
  }

/*
** swap primary register and stack
*/
swapstk() {
  ol("XTHL");
  }

/*
** process switch statement
*/
sw() {
  call("CCSWITCH");
  }

/*
** call specified subroutine name
*/
call(sname)  char *sname; {
  ot("CALL ");
  outstr(sname);
  nl();
  }

/*
** return from subroutine
*/
ret() {
  ol("RET");
  }

/*
** perform subroutine call to value on stack
*/
callstk() {
  immed();
  outstr("$+5");
  nl();
  swapstk();
  ol("PCHL");
  csp=csp+BPW;
  }

/*
** jump to internal label number
*/
jump(label)  int label; {
  ot("JMP ");
  printlabel(label);
  nl();
  }

/*
** test primary register and jump if false
*/
testjump(label)  int label; {
  ol("MOV A,H");
  ol("ORA L");
  ot("JZ ");
  printlabel(label);
  nl();
  }

/*
** test primary register against zero and jump if false
*/
zerojump(oper, label, lval) int oper, label, lval[]; {
  clearstage(lval[7], 0);  /* purge conventional code */
  oper(label);
  }

/*
** define storage according to size
*/
defstorage(size) int size; {
  if(size==1) ot("DB ");
  else        ot("DW ");
  }

/*
** point to following object(s)
*/
point() {
  ol("DW $+2");
  }

/*
** modify stack pointer to value given
*/
modstk(newsp, save)  int newsp, save; {
  int k;
  k=newsp-csp;
  if(k==0)return newsp;
  if(k>=0) {
    if(k<7) {
      if(k&1) {
        ol("INX SP");
        k--;
        }
      while(k) {
        ol("POP B");
        k=k-BPW;
        }
      return newsp;
      }
    }
  if(k<0) {
    if(k>-7) {
      if(k&1) {
        ol("DCX SP");
        k++;
        }
      while(k) {
        ol("PUSH B");
        k=k+BPW;
        }
      return newsp;
      }
    }
  if(save) swap();
  const(k);
  ol("DAD SP");
  ol("SPHL");
  if(save) swap();
  return newsp;
  }

/*
** double primary register
*/
doublereg() {ol("DAD H");}
//SYSIN DD SYSOUT=*
echo Extracting cc42.c
cat > cc42.c << "//SYSIN DD SYSOUT=*"
/*
** add primary and secondary registers (result in primary)
*/
add() {ol("DAD D");}

/*
** subtract primary from secondary register (result in primary)
*/
sub() {call("CCSUB");}

/*
** multiply primary and secondary registers (result in primary)
*/
mult() {call("CCMULT");}

/*
** divide secondary by primary register
** (quotient in primary, remainder in secondary)
*/
div() {call("CCDIV");}

/*
** remainder of secondary/primary
** (remainder in primary, quotient in secondary)
*/
mod() {div();swap();}

/*
** inclusive "or" primary and secondary registers
** (result in primary)
*/
or() {call("CCOR");}

/*
** exclusive "or" the primary and secondary registers
** (result in primary)
*/
xor() {call("CCXOR");}

/*
** "and" primary and secondary registers
** (result in primary)
*/
and() {call("CCAND");}

/*
** logical negation of primary register
*/
lneg() {call("CCLNEG");}

/*
** arithmetic shift right secondary register
** number of bits given in primary register
** (result in primary)
*/
asr() {call("CCASR");}

/*
** arithmetic shift left secondary register
** number of bits given in primary register
** (result in primary)
*/
asl() {call("CCASL");}

/*
** two's complement primary register
*/
neg() {call("CCNEG");}

/*
** one's complement primary register
*/
com() {call("CCCOM");}

/*
** increment primary register by one object of whatever size
*/
inc(n) int n; {
  while(1) {
    ol("INX H");
    if(--n < 1) break;
    }
  }

/*
** decrement primary register by one object of whatever size
*/
dec(n) int n; {
  while(1) {
    ol("DCX H");
    if(--n < 1) break;
    }
  }
 
/*
** test for equal to
*/
eq()  {call("CCEQ");}

/*
** test for equal to zero
*/
eq0(label) int label; {
  ol("MOV A,H");
  ol("ORA L");
  ot("JNZ ");
  printlabel(label);
  nl();
  }

/*
** test for not equal to
*/
ne()  {call("CCNE");}

/*
** test for not equal to zero
*/
ne0(label) int label; {
  ol("MOV A,H");
  ol("ORA L");
  ot("JZ ");
  printlabel(label);
  nl();
  }

/*
** test for less than (signed)
*/
lt()  {call("CCLT");}

/*
** test for less than to zero
*/
lt0(label) int label; {
  ol("XRA A");
  ol("ORA H");
  ot("JP ");
  printlabel(label);
  nl();
  }

/*
** test for less than or equal to (signed)
*/
le()  {call("CCLE");}

/*
** test for less than or equal to zero
*/
le0(label) int label; {
  ol("MOV A,H");
  ol("ORA L");
  ol("JZ $+8");
  ol("XRA A");
  ol("ORA H");
  ot("JP ");
  printlabel(label);
  nl();
  }

/*
** test for greater than (signed)
*/
gt()  {call("CCGT");}

/*
** test for greater than to zero
*/
gt0(label) int label; {
  ol("XRA A");
  ol("ORA H");
  ot("JM ");
  printlabel(label);
  nl();
  ol("ORA L");
  ot("JZ ");
  printlabel(label);
  nl();
  }

/*
** test for greater than or equal to (signed)
*/
ge()  {call("CCGE");}

/*
** test for gteater than or equal to zero
*/
ge0(label) int label; {
  ol("XRA A");
  ol("ORA H");
  ot("JM ");
  printlabel(label);
  nl();
  }

/*
** test for less than (unsigned)
*/
ult()  {call("CCULT");}

/*
** test for less than to zero (unsigned)
*/
ult0(label) int label; {
  ot("JMP ");
  printlabel(label);
  nl();
  }

/*
** test for less than or equal to (unsigned)
*/
ule()  {call("CCULE");}

/*
** test for greater than (unsigned)
*/
ugt()  {call("CCUGT");}

/*
** test for greater than or equal to (unsigned)
*/
uge()  {call("CCUGE");}

#ifdef OPTIMIZE
peephole(ptr) char *ptr; {
  while(*ptr) {
#ifdef TAB
    if(streq(ptr, "\tLXI H,0\n\tDAD SP\n\tCALL CCGINT")) {
      if(streq(ptr+31, "XCHG;;")) {pp2();ptr=ptr+38;}
      else                        {pp1();ptr=ptr+30;}
      }
    else if(streq(ptr, "\tLXI H,2\n\tDAD SP\n\tCALL CCGINT")) {
      if(streq(ptr+31, "XCHG;;")) {pp3(pp2);ptr=ptr+38;}
      else                        {pp3(pp1);ptr=ptr+30;}
      }
    else if(optimize) {
      if(streq(ptr, "\tDAD SP\n\tCALL CCGINT")) {
        ol("CALL CCDSGI");
        ptr=ptr+21;
        }
      else if(streq(ptr, "\tDAD D\n\tCALL CCGINT")) {
        ol("CALL CCDDGI");
        ptr=ptr+20;
        }
      else if(streq(ptr, "\tDAD SP\n\tCALL CCGCHAR")) {
        ol("CALL CCDSGC");
        ptr=ptr+22;
        }
      else if(streq(ptr, "\tDAD D\n\tCALL CCGCHAR")) {
        ol("CALL CCDDGC");
        ptr=ptr+21;
        }
      else if(streq(ptr,
"\tDAD SP\n\tMOV D,H\n\tMOV E,L\n\tCALL CCGINT\n\tINX H\n\tCALL CCPINT")) {
        ol("CALL CCINCI");
        ptr=ptr+59;
        }
      else if(streq(ptr,
"\tDAD SP\n\tMOV D,H\n\tMOV E,L\n\tCALL CCGINT\n\tDCX H\n\tCALL CCPINT")) {
        ol("CALL CCDECI");
        ptr=ptr+59;
        }
      else if(streq(ptr,
"\tDAD SP\n\tMOV D,H\n\tMOV E,L\n\tCALL CCGCHAR\n\tINX H\n\tMOV A,L\n\tSTAX D")) {
        ol("CALL CCINCC");
        ptr=ptr+64;
        }
      else if(streq(ptr,
"\tDAD SP\n\tMOV D,H\n\tMOV E,L\n\tCALL CCGCHAR\n\tDCX H\n\tMOV A,L\n\tSTAX D")) {
        ol("CALL CCDECC");
        ptr=ptr+64;
        }
      else if(streq(ptr, "\tDAD D\n\tPOP D\n\tCALL CCPINT")) {
        ol("CALL CCDDPDPI");
        ptr=ptr+27;
        }
      else if(streq(ptr, "\tDAD D\n\tPOP D\n\tMOV A,L\n\tSTAX D")) {
        ol("CALL CCDDPDPC");
        ptr=ptr+31;
        }
      else if(streq(ptr, "\tPOP D\n\tCALL CCPINT")) {
        ol("CALL CCPDPI");
        ptr=ptr+20;
        }
      else if(streq(ptr, "\tPOP D\n\tMOV A,L\n\tSTAX D")) {
        ol("CALL CCPDPC");
        ptr=ptr+24;
        }
      /* additional optimizing logic goes here */
#else
    if(streq(ptr,"LXI H,0\nDAD SP\nCALL CCGINT")) {
      if(streq(ptr+27, "XCHG;;")) {pp2();ptr=ptr+34;}
      else                        {pp1();ptr=ptr+27;}
      }
    else if(streq(ptr,"LXI H,2\nDAD SP\nCALL CCGINT")) {
      if(streq(ptr+27, "XCHG;;")) {pp3(pp2);ptr=ptr+34;}
      else                        {pp3(pp1);ptr=ptr+27;}
      }
    else if(optimize) {
      if(streq(ptr, "DAD SP\nCALL CCGINT")) {
        ol("CALL CCDSGI");
        ptr=ptr+19;
        }
      else if(streq(ptr, "DAD D\nCALL CCGINT")) {
        ol("CALL CCDDGI");
        ptr=ptr+18;
        }
      else if(streq(ptr, "DAD SP\nCALL CCGCHAR")) {
        ol("CALL CCDSGC");
        ptr=ptr+20;
          }
      else if(streq(ptr, "DAD D\nCALL CCGCHAR")) {
        ol("CALL CCDDGC");
        ptr=ptr+19;
        }
      else if(streq(ptr,
"DAD SP\nMOV D,H\nMOV E,L\nCALL CCGINT\nINX H\nCALL CCPINT")) {
        ol("CALL CCINCI");
        ptr=ptr+53;
        }
      else if(streq(ptr,
"DAD SP\nMOV D,H\nMOV E,L\nCALL CCGINT\nDCX H\nCALL CCPINT")) {
        ol("CALL CCDECI");
        ptr=ptr+53;
        }
      else if(streq(ptr,
"DAD SP\nMOV D,H\nMOV E,L\nCALL CCGCHAR\nINX H\nMOV A,L\nSTAX D")) {
        ol("CALL CCINCC");
        ptr=ptr+57;
        }
      else if(streq(ptr,
"DAD SP\nMOV D,H\nMOV E,L\nCALL CCGCHAR\nDCX H\nMOV A,L\nSTAX D")) {
        ol("CALL CCDECC");
        ptr=ptr+57;
        }
      else if(streq(ptr, "DAD D\nPOP D\nCALL CCPINT")) {
        ol("CALL CCDDPDPI");
        ptr=ptr+24;
        }
      else if(streq(ptr, "DAD D\nPOP D\nMOV A,L\nSTAX D")) {
        ol("CALL CCDDPDPC");
        ptr=ptr+27;
        }
      else if(streq(ptr, "POP D\nCALL CCPINT")) {
        ol("CALL CCPDPI");
        ptr=ptr+18;
        }
      else if(streq(ptr, "POP D\nMOV A,L\nSTAX D")) {
        ol("CALL CCPDPC");
        ptr=ptr+21;
        }
      /* additional optimizing logic goes here */
#endif
      else cout(*ptr++, output);
      }
    else cout(*ptr++, output);
    }
  }

pp1() {
  ol("POP H");
  ol("PUSH H");
  }

pp2() {
  ol("POP D");
  ol("PUSH D");
  }

pp3(pp) int pp; {
  ol("POP B");
  pp();
  ol("PUSH B");
  }

#endif
//SYSIN DD SYSOUT=*
echo Extracting crt.def
cat > crt.def << "//SYSIN DD SYSOUT=*"
Y



















-1
0
24,80
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
0,0,0
	




-1
//SYSIN DD SYSOUT=*
echo Extracting dtoi.c
cat > dtoi.c << "//SYSIN DD SYSOUT=*"
/*
** dtoi -- convert signed decimal string to integer nbr
**         returns field length, else ERR on error
*/
dtoi(decstr, nbr)  char *decstr;  int *nbr;  {
  int len, s;
  if((*decstr)=='-') {s=1; ++decstr;} else s=0;
  if((len=utoi(decstr, nbr))<0) return ERR;
  if(*nbr<0) return ERR;
  if(s) {*nbr = -*nbr; return ++len;} else return len;
  }
//SYSIN DD SYSOUT=*
echo Extracting itod.c
cat > itod.c << "//SYSIN DD SYSOUT=*"
/*
** itod -- convert nbr to signed decimal string of width sz
**         right adjusted, blank filled; returns str
**
**        if sz > 0 terminate with null byte
**        if sz = 0 find end of string
**        if sz < 0 use last byte for data
*/
itod(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  char sgn;
  if(nbr<0) {nbr = -nbr; sgn='-';}
  else sgn=' ';
  if(sz>0) str[--sz]=NULL;
  else if(sz<0) sz = -sz;
  else while(str[sz]!=NULL) ++sz;
  while(sz) {
    str[--sz]=(nbr%10+'0');
    if((nbr=nbr/10)==0) break;
    }
  if(sz) str[--sz]=sgn;
  while(sz>0) str[--sz]=' ';
  return str;
  }
//SYSIN DD SYSOUT=*
echo Extracting itou.c
cat > itou.c << "//SYSIN DD SYSOUT=*"
/*
** itou -- convert nbr to unsigned decimal string of width sz
**         right adjusted, blank filled; returns str
**
**        if sz > 0 terminate with null byte
**        if sz = 0 find end of string
**        if sz < 0 use last byte for data
*/
itou(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  int lowbit;
  if(sz>0) str[--sz]=NULL;
  else if(sz<0) sz = -sz;
  else while(str[sz]!=NULL) ++sz;
  while(sz) {
    lowbit=nbr&1;
    nbr=(nbr>>1)&32767;  /* divide by 2 */
    str[--sz]=((nbr%5)<<1)+lowbit+'0';
    if((nbr=nbr/5)==0) break;
    }
  while(sz) str[--sz]=' ';
  return str;
  }
//SYSIN DD SYSOUT=*
echo Extracting itox.c
cat > itox.c << "//SYSIN DD SYSOUT=*"
/*
** itox -- converts nbr to hex string of length sz
**         right adjusted and blank filled, returns str
**
**        if sz > 0 terminate with null byte
**        if sz = 0 find end of string
**        if sz < 0 use last byte for data
*/
itox(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  int digit, offset;
  if(sz>0) str[--sz]=NULL;
  else if(sz<0) sz = -sz;
  else while(str[sz]!=NULL) ++sz;
  while(sz) {
    digit=nbr&15; nbr=(nbr>>4)&4095;
    if(digit<10) offset=48; else offset=55;
    str[--sz]=digit+offset;
    if(nbr==0) break;
    }
  while(sz) str[--sz]=' ';
  return str;
  }
//SYSIN DD SYSOUT=*
echo Extracting left.c
cat > left.c << "//SYSIN DD SYSOUT=*"
/*
** left -- left adjust and null terminate a string
*/
left(str) char *str; {
  char *str2;
  str2=str;
  while(*str2==' ') ++str2;
  while(*str++ = *str2++);
  }
//SYSIN DD SYSOUT=*
echo Extracting lib.c
cat > lib.c << "//SYSIN DD SYSOUT=*"
/*
** lib.c -- function library
**
** Copyright 1982 J. E. Hendrix
*/
#define NOCCARGC /* don't pass arg count to functions */
                 /* called by these functions */
#include abs.c,2
#include dtoi.c,2
#include itod.c,2
#include itou.c,2
#include itox.c,2
#include left.c,2
#include printf.c,2
#include sign.c,2
#include strcmp.c,2
#include utoi.c,2
#include xtoi.c,2
#include out.c,2
//SYSIN DD SYSOUT=*
echo Extracting lib.h
cat > lib.h << "//SYSIN DD SYSOUT=*"
/*
** lib.h -- invoke a local copy of the function library
*/
#define PASSARGC /* pass arg count to called functions */
#asm
LIB.R:LIBRY
ABS:EXTRN
DTOI:EXTRN
ITOD:EXTRN
ITOU:EXTRN
ITOX:EXTRN
LEFT:EXTRN
PRINTF:EXTRN
SIGN:EXTRN
STRCMP:EXTRN
UTOI:EXTRN
XTOI:EXTRN
#endasm
//SYSIN DD SYSOUT=*
echo Extracting out.c
cat > out.c << "//SYSIN DD SYSOUT=*"
cout(c, fd) char c; int fd; {
  if(fputc(c, fd)==EOF) xout();
  }

sout(string, fd) char *string; int fd; {
  if(fputs(string, fd)==EOF) xout();
  }

lout(line, fd) char *line; int fd; {
  sout(line, fd);
  cout('\n', fd);
  }

xout() {
  fputs("output error\n", stderr);
  abort(ERRCODE);
  }

//SYSIN DD SYSOUT=*
echo Extracting printf.c
cat > printf.c << "//SYSIN DD SYSOUT=*"
/*
** printf(controlstring, arg, arg, ...) -- formatted print
**        operates as described by Kernighan & Ritchie
**        only d, x, c, s, and u specs are supported.
*/
printf(argc) int argc; {
  int i, width, prec, preclen, len, *nxtarg;
  char *ctl, *cx, c, right, str[7], *sptr, pad;
  i = CCARGC();   /* fetch arg count from A reg first */
  nxtarg = &argc + i - 1;
  ctl = *nxtarg;
  while(c=*ctl++) {
    if(c!='%') {cout(c, stdout); continue;}
    if(*ctl=='%') {cout(*ctl++, stdout); continue;}
    cx=ctl;
    if(*cx=='-') {right=0; ++cx;} else right=1;
    if(*cx=='0') {pad='0'; ++cx;} else pad=' ';
    if((i=utoi(cx, &width)) >= 0) cx=cx+i; else continue;
    if(*cx=='.') {
      if((preclen=utoi(++cx, &prec)) >= 0) cx=cx+preclen;
      else continue;
      }
    else preclen=0;
    sptr=str; c=*cx++; i=*(--nxtarg);
    if(c=='d') itod(i, str, 7);
    else if(c=='x') itox(i, str, 7);
    else if(c=='c') {str[0]=i; str[1]=NULL;}
    else if(c=='s') sptr=i;
    else if(c=='u') itou(i, str, 7);
    else continue;
    ctl=cx; /* accept conversion spec */
    if(c!='s') while(*sptr==' ') ++sptr;
    len=-1; while(sptr[++len]); /* get length */
    if((c=='s')&(len>prec)&(preclen>0)) len=prec;
    if(right) while(((width--)-len)>0) cout(pad, stdout);
    while(len) {cout(*sptr++, stdout); --len; --width;}
    while(((width--)-len)>0) cout(pad, stdout);
    }
  }
//SYSIN DD SYSOUT=*
echo Extracting sign.c
cat > sign.c << "//SYSIN DD SYSOUT=*"
/*
** sign -- return -1, 0, +1 depending on the sign of nbr
*/
sign(nbr)  int nbr;  {
  if(nbr>0) return 1;
  else if(nbr==0) return 0;
  else return -1;
  }
//SYSIN DD SYSOUT=*
echo Extracting stdio.h
cat > stdio.h << "//SYSIN DD SYSOUT=*"
/*
** stdio.h -- header for resident STDIO/CALL, and VM interfaces
*/
#define stdin 0
#define stdout 1
#define stderr 2
#define stdport 3
#define stdlist 4
#define CCEOM 45062
#define ERR -2
#define EOF -1
#define YES 1
#define NO 0
#define NULL 0
#define CR 13
#define LF 10
#asm
STDIO:EQU 0E00H;;STDIO BASE

CCBOJ:  EQU STDIO+0006H
CCEXIT: EQU STDIO+0009H
CCPOLL: EQU STDIO+000CH
CCHALT: EQU STDIO+000FH
CCOPEN: EQU STDIO+0012H
CCCLOSE:EQU STDIO+0015H
CCREAD: EQU STDIO+0018H
CCWRITE:EQU STDIO+001BH
CCSEEK: EQU STDIO+001EH
CCMODE: EQU STDIO+0021H
CCFILE: EQU STDIO+0024H
CCPURGE:EQU STDIO+0027H
CCFLUSH:EQU STDIO+002AH
CCALLOC:EQU STDIO+002DH
CCFREE: EQU STDIO+0030H
CCAVAIL:EQU STDIO+0033H
CCDELIM:EQU STDIO+0036H

CCDDGC: EQU STDIO+0039H
CCDSGC: EQU STDIO+003DH
CCGCHAR:EQU STDIO+0040H
CCARGC: EQU STDIO+0041H
CCSXT:  EQU STDIO+0041H
CCDDGI: EQU STDIO+0046H
CCDSGI: EQU STDIO+004AH
CCGINT: EQU STDIO+004DH
CCDECC: EQU STDIO+0052H
CCINCC: EQU STDIO+005EH
CCDDPDPC:EQU STDIO+006AH
CCPDPC: EQU STDIO+006BH
CCPCHAR:EQU STDIO+006EH
CCDECI: EQU STDIO+0071H
CCINCI: EQU STDIO+007DH
CCDDPDPI:EQU STDIO+0089H
CCPDPI: EQU STDIO+008AH
CCPINT: EQU STDIO+008DH
CCOR:   EQU STDIO+0093H
CCXOR:  EQU STDIO+009AH
CCAND:  EQU STDIO+00A1H
CCEQ:   EQU STDIO+00A8H
CCNE:   EQU STDIO+00AEH
CCGT:   EQU STDIO+00B4H
CCLE:   EQU STDIO+00BBH
CCGE:   EQU STDIO+00C2H
CCLT:   EQU STDIO+00C8H
CCCMP:  EQU STDIO+00CEH
CCUGE:  EQU STDIO+00DFH
CCULT:  EQU STDIO+00E5H
CCUGT:  EQU STDIO+00EBH
CCULE:  EQU STDIO+00F2H
CCUCMP: EQU STDIO+00F9H
CCASR:  EQU STDIO+0104H
CCASL:  EQU STDIO+0112H
CCSUB:  EQU STDIO+0119H
CCNEG:  EQU STDIO+0120H
CCCOM:  EQU STDIO+0125H
CCMULT: EQU STDIO+012CH
CCDIV:  EQU STDIO+014CH
CCLNEG: EQU STDIO+01AAH
CCSWITCH:EQU STDIO+01B6H

GETC:   EQU STDIO+01D0H
PUTC:   EQU STDIO+01D3H
FFLUSH: EQU STDIO+01D6H
ABORT:  EQU STDIO+01D9H
EXIT:   EQU STDIO+01DCH
UNLINK: EQU STDIO+01DFH
FGETC:  EQU STDIO+01E2H
GETCHAR:EQU STDIO+02D9H
FGETS:  EQU STDIO+02E2H
FPUTC:  EQU STDIO+050DH
PUTCHAR:EQU STDIO+0579H
FPUTS:  EQU STDIO+058AH
PUTS:   EQU STDIO+0699H
FOPEN:  EQU STDIO+06B5H
FCLOSE: EQU STDIO+078BH
GETARG: EQU STDIO+07E7H
#endasm
//SYSIN DD SYSOUT=*
echo Extracting stdiol.h
cat > stdiol.h << "//SYSIN DD SYSOUT=*"
/*
** stdiol.h -- header for local STDIO/CALL, and VM interfaces
*/
#define stdin 0
#define stdout 1
#define stderr 2
#define stdport 3
#define stdlist 4
#define ERR -2
#define EOF -1
#define YES 1
#define NO 0
#define NULL 0
#define CR 13
#define LF 10
#asm
STDIOL.R:LIBRY
; STD I/O ROUTINES
GETC:   EXTRN
GETCHAR:EXTRN
FGETC:  EXTRN
FGETS:  EXTRN
PUTC:   EXTRN
PUTCHAR:EXTRN
FPUTC:  EXTRN
FPUTS:  EXTRN
PUTS:   EXTRN
FOPEN:  EXTRN
FCLOSE: EXTRN
GETARG: EXTRN
; STD I/O ROUTINES MATCHING VM ROUTINES
FFLUSH: EXTRN
ABORT:  EXTRN
EXIT:   EXTRN
UNLINK: EXTRN
; ARITHMETIC & LOGICAL ROUTINES
CCARGC: EXTRN
CCSXT:  EXTRN
CCDSGI: EXTRN
CCDDGI: EXTRN
CCINCI: EXTRN
CCDECI: EXTRN
CCGINT: EXTRN
CCDDPDPI:EXTRN
CCPDPI: EXTRN
CCDSGC: EXTRN
CCDDGC: EXTRN
CCINCC: EXTRN
CCDECC: EXTRN
CCGCHAR:EXTRN
CCDDPDPC:EXTRN
CCPDPC: EXTRN
CCPCHAR:EXTRN
CCPINT: EXTRN
CCOR:   EXTRN
CCXOR:  EXTRN
CCAND:  EXTRN
CCEQ:   EXTRN
CCNE:   EXTRN
CCGT:   EXTRN
CCLE:   EXTRN
CCGE:   EXTRN
CCLT:   EXTRN
CCCMP:  EXTRN
CCUGE:  EXTRN
CCULT:  EXTRN
CCUGT:  EXTRN
CCULE:  EXTRN
CCUCMP: EXTRN
CCASR:  EXTRN
CCASL:  EXTRN
CCSUB:  EXTRN
CCNEG:  EXTRN
CCCOM:  EXTRN
CCMULT: EXTRN
CCDIV:  EXTRN
CCLNEG: EXTRN
CCSWITCH:EXTRN
; VM ROUTINES
VM.R:   LIBRY
CCBOJ:  EXTRN
CCEXIT: EXTRN
CCPOLL: EXTRN
CCHALT: EXTRN
CCOPEN: EXTRN
CCCLOSE:EXTRN
CCDELIM:EXTRN
CCREAD: EXTRN
CCWRITE:EXTRN
CCSEEK: EXTRN
CCMODE: EXTRN
CCFILE: EXTRN
CCPURGE:EXTRN
CCFLUSH:EXTRN
CCALLOC:EXTRN
CCFREE: EXTRN
CCAVAIL:EXTRN
#endasm
//SYSIN DD SYSOUT=*
echo Extracting strcmp.c
cat > strcmp.c << "//SYSIN DD SYSOUT=*"
/*
** strcmp -- return -1, 0, +1 depending on str1 <, =, > str2
*/
strcmp(str1, str2)  char *str1, *str2;  {
  char c1, c2;
  while((c1=*str1++)==(c2=*str2++)) if(c1==NULL) return 0;
  return sign(c1-c2);
  }
//SYSIN DD SYSOUT=*
echo Extracting utoi.c
cat > utoi.c << "//SYSIN DD SYSOUT=*"
/*
** utoi -- convert unsigned decimal string to integer nbr
**          returns field size, else ERR on error
*/
utoi(decstr, nbr)  char *decstr;  int *nbr;  {
  int d,t; d=0;
  *nbr=0;
  while((*decstr>='0')&(*decstr<='9')) {
    t=*nbr;t=(10*t) + (*decstr++ - '0');
    if ((t>=0)&(*nbr<0)) return ERR;
    d++; *nbr=t;
    }
  return d;
  }
//SYSIN DD SYSOUT=*
echo Extracting vm.h
cat > vm.h << "//SYSIN DD SYSOUT=*"
/*
** vm.h -- header for resident VM interface
*/
#asm
VM:     EQU 0B000H;;VIRTUAL MACHINE BASE
CCBOJ:  ENTRY
        JMP VM+08H
CCEXIT: ENTRY
        JMP VM+0BH
CCPOLL: ENTRY
        JMP VM+0EH
CCHALT: ENTRY
        JMP VM+11H
CCOPEN: ENTRY
        JMP VM+14H
CCCLOSE:ENTRY
        JMP VM+17H
CCREAD: ENTRY
        JMP VM+1AH
CCWRITE:ENTRY
        JMP VM+1DH
CCSEEK: ENTRY
        JMP VM+20H
CCMODE: ENTRY
        JMP VM+23H
CCFILE: ENTRY
        JMP VM+26H
CCPURGE:ENTRY
        JMP VM+29H
CCFLUSH:ENTRY
        JMP VM+2CH
CCALLOC:ENTRY
        JMP VM+2FH
CCFREE: ENTRY
        JMP VM+32H
CCAVAIL:ENTRY
        JMP VM+35H
CCDELIM:ENTRY
        JMP VM+38H
#endasm
//SYSIN DD SYSOUT=*
echo Extracting vml.h
cat > vml.h << "//SYSIN DD SYSOUT=*"
/*
** vml.h -- header for local VM interface
*/
#asm
VM.R:   LIBRY
CCBOJ:  EXTRN
CCEXIT: EXTRN
CCPOLL: EXTRN
CCHALT: EXTRN
CCOPEN: EXTRN
CCCLOSE:EXTRN
CCDELIM:EXTRN
CCREAD: EXTRN
CCWRITE:EXTRN
CCSEEK: EXTRN
CCMODE: EXTRN
CCFILE: EXTRN
CCPURGE:EXTRN
CCFLUSH:EXTRN
CCALLOC:EXTRN
CCFREE: EXTRN
CCAVAIL:EXTRN
#endasm
//SYSIN DD SYSOUT=*
echo Extracting xtoi.c
cat > xtoi.c << "//SYSIN DD SYSOUT=*"
/*
** xtoi -- convert hex string to integer nbr
**         returns field size, else ERR on error
*/
xtoi(hexstr, nbr)  char *hexstr;  int *nbr;  {
  int d,t; d=0;
  *nbr=0;
  while(1)
    {
    if((*hexstr>='0')&(*hexstr<='9')) t=48;
    else if((*hexstr>='A')&(*hexstr<='F')) t=55;
    else if((*hexstr>='a')&(*hexstr<='f')) t=87;
    else break;
    if(d<4) ++d; else return ERR;
    *nbr=*nbr<<4;
    *nbr=*nbr+(*hexstr++)-t;
    }
  return d;
  }
//SYSIN DD SYSOUT=*