sob (03/13/83)
this an archive file: place in a directory, chmod +x, then run to extract the files echo x - Makefile cat >Makefile <<'!Funky!Stuff!' SMALLH = cc.def LIBDIR = /usr/lib/smallc BINDIR = /usr/bin CFLAGS = -w -DLIBDIR=\"$(LIBDIR)\" OBJS = cc1.o cc11.o cc12.o cc13.o cc2.o cc21.o cc22.o cc3.o cc31.o cc32.o cc33.o cc4.o cc41.o cc42.o SRCS = cc1.c cc11.c cc12.c cc13.c cc2.c cc21.c cc22.c cc3.c cc31.c cc32.c cc33.c cc4.c cc41.c cc42.c smallc: ${OBJS} cc -o smallc ${OBJS} ${OBJS}: $(SMALLH) install: smallc stdio.c asm.8085.c libsmc.c cp smallc $(BINDIR) cp stdio.c libasm.c libsmc.c $(LIBDIR) clean: rm smallc ${OBJS} !Funky!Stuff! echo x - READ_ME cat >READ_ME <<'!Funky!Stuff!' Over All description of Implementation ====================================== The major change to be made in this system is how to do "includes". If the include statement file name has surrounding quotes ( " " ), then the file is searched for in the current directory only, and if not found results in an error. If the file name specified in the "include" statement is surrounded by "<" and ">", then that indicates to the compiler that the file is a library file, so it will not search the current directory for the file, but a system defined directory, that can be defined when "making" Smallc. In order to do this, simply go into the Makefile, and where it says "LIBDIR= ...", substitute the directory pathname your system wishes to use. Re-make the file, and you have defined a library dir- ectory. There are three different libraries that come with Smallc V2. libsmc.c : Contains Smallc functions for Output (utilizing putc et. al.), and arithmetic operations and string functions. Can either be "included" or , as it was meant to be used, can be passed on the command line as a library function. libasm.c : Contains 8085 library routines for arithmetic operations and register transfers and shifts. The routines in this file are called by the Smallc-compiled 8085 code very frequently, so it may be necessary to include this file with all Smallc programs. (This file may be included as is because of the #asm statements) stdio.c : Contains I/O parameters for the Smallc system We hope very soon for there to be a way to pass a file with 8085 code to the command line, and have it only append to the output file those functions that are called for in the code. Also included in this package is a manual page, based as much on the UNIXtm manual pages as possible, as well as the Makefile described above. !Funky!Stuff! echo x - cc.def cat >cc.def <<'!Funky!Stuff!' /* %W% %G% */ /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Macro Definitions */ #include <stdio.h> /* ** compile options */ #define PHASE2 /* 2nd and later compiles */ #define OPTIMIZE /* compile output optimizer */ #define NOCCARGC /* no calls to CCARGC */ /* #define CMD_LINE /* command line run options */ /* #define HASH /* use hash search for macros */ /* #define SMALL_VM /* uses Small-VM interface */ /* #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 /* ** Filestack size (for input files) */ #define FILESTACKMAX 30 #define INCLUDESTACKMAX 30 #define CHARSTACKMAX 128 /* ** 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 */ #define SWSIZ (2*BPW) #define SWTABSZ (25*SWSIZ) /* ** "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 */ #define MACNBR 90 #define MACNSIZE 990 /* 90*(NAMESIZE+2) */ #define MACNEND (macn+MACNSIZE) #define MACQSIZE 450 /* 90*5 */ #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 */ /* ** I/O parameters, logical flags */ /* #define stdin 0 #define stdout 1 #define stderr 2 */ #define stdport 3 #define stdlist 4 #define ERR -2 #define EOL 10 /* #define EOF -1 */ #define YES 1 #define NO 0 /* #define NULL 0 */ #define CR 13 #define LF 10 !Funky!Stuff! echo x - smallc.1 cat >smallc.1 <<'!Funky!Stuff!' .TH SMALLC 1 PDP11 .SH NAME smallc \- A subset C compiler .SH SYNOPSIS .B smallc [ option ] ... file ... .PP .SH DESCRIPTION Smallc is a subset C compiler that compiles pseudo-C code into 8085 micro-computer assembler language. It accepts several types of arguments: .PP Arguments whose names end with `.c' are taken to be Smallc source programs; they are compiled, and each assembler-language program is left on the file whose name is that of the source with `.8085' substituted for `.c'. If multiple source files are supplied, then the output file name will be the lastfilename.8085. .PP It is not possible to produce object code for the 8085 with the Smallc compiler; It produces only assembly code. Object code must be produced from this assembly code with an 8085 assembler. .PP The following options are interpreted by .IR smallc . .TP 8 .B \-p Causes the compiler to pause after each error it finds in the source. The compilation will proceed only after the user has hit a carriage return. .TP .SM .B \-O Invoke a machine-code optimizer. .TP .SM .B \-e Utilize 'pointer' type error messages. The compiler outputs the line at which the error occurred as well as a 'pointer' to the illegal component of the line. .TP .BI \-o " output" Name the final output file .IR output . If this option is used the file inputfile.8085 will not be created. .TP .SM .B \-m Function monitor. Displays function names and arguments as the compiler parses each function. .TP .SM .BI \-l " libfile" After parsing the input file(s), will look up in the symbol table for unresolved (undefined) functions and then search through libfile looking for the function definitions, whereupon it parses them to the output file. .TP .SM .B \-a Error alarm. Outputs a bell (^G) to stderr after each error found. .TP .SM .BI \-b " number" Specify a starting number for assembler-language labels. Used so that when appending compiled modules, there are no multiply defined labels. number is taken in decimal. .SH EXAMPLE To compile a program and specify the output file name. .br $ smallc -o fname fname.c .SH FILES .ta \w'/usr/c/oc[102] 'u file.c input file .br file.8085 assembler-language file .SH DIAGNOSTICS The diagnostics produced by Smallc itself are intended to be self-explanatory. For a more detailed diagnostic error message, use the '-e' option. .SH BRIEF OPTIONS .br .B \-p Pauses after each error; waits for <cr> to continue. .B \-O Invoke a machine-code optimizer. .B \-e Produce "pointer" type error messages. .br .B \-o output Name final output file output. .br .B \-m Prints out function names and args as they are parsed. .B \-l libfile Search for unresolved functions in libfile. .B \-a Sound error alarm after each error. .B \-b number Specify a starting label for assembler code. !Funky!Stuff! echo x - cc1.c cat >cc1.c <<'!Funky!Stuff!' /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 1 */ #include "cc.def" /* ** miscellaneous storage */ char optimize, /* optimize output of staging buffer */ alarm, /* audible alarm on errors? */ monitor, /* monitor function headers? */ library, /* look up unresolved functions in user library */ pause, /* pause for operator on errors? */ errorptr, /* print out line and error pointer on error */ stage[STAGESIZE], symtab[SYMTBSZ], litq[LITABSZ], macn[MACNSIZE], macq[MACQSIZE], pline[LINESIZE], mline[LINESIZE], swq[SWTABSZ], *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 nogo, /* > 0 disables goto statements */ noloc, /* > 0 disables block locals */ 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 */ wq[WQTABSZ], *wqptr, /* ptr to next entry */ litptr, /* ptr to next entry */ macptr, /* macro buffer index */ mack, /* variable k for findmac routine */ argcs, /* static argc */ *argvs, /* static argv */ filestack[FILESTACKMAX], /* stack of input files */ filebuffer[LINESIZE], /* holds the current processing file */ charstack[CHARSTACKMAX], /* holds included file names */ charcount, /* # of chars in charstack */ includectr, /* counter, indicating # of records in stack */ filecount, /* counter, accessing files in filestack */ pptr, /* ptr to parsing buffer */ oper, /* address of binary operator function */ 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 */ ch, /* current character of line being scanned */ nch, /* next character of line being scanned */ csp, /* compiler relative stk ptr */ argstk, /* function arg sp */ argtop, ncmp, /* # open compound statements */ errflag, /* non-zero after 1st error in statement */ outflg, /* specifies whether or not to open a default output file */ eof, /* set non-zero on final input eof */ input, /* fd # for input file */ input2, /* fd # for "include" file */ output, /* fd # for output file */ linectr, /* # of parsed lines in current 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 */ long includestack[INCLUDESTACKMAX]; /* holds info for included files */ 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 gt(), and(), asl(), asr(), defstora(), div(), eq(), entry(), external(), ge(), add(), header(), jump(), le(), lt(), mod(), modstk(), mult(), ne(), or(), point(), ret(), sub(), sw(), trailer(), uge(), ugt(), ule(), ult(), xor(); !Funky!Stuff! echo x - cc11.c cat >cc11.c <<'!Funky!Stuff!' /* ** execution begins here */ #include "cc1.c" main(argc, argv) int argc; char *argv; { swend=(swnext=swq)+SWTABSZ-SWSIZ; stagelast=stage+STAGELIMIT; 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= linectr= filecount= quote[1]=0; func1= /* first function */ ccode=1; /* enable preprocessing */ wqptr=wq; /* clear while queue */ quote[0]='"'; /* fake a quote literal */ charstack[0] = NULL; /* initialize charstack */ charcount = 1; /* chars in character stack */ input = input2 = EOF; options(argc,argv); /* get user options */ openin(); /* get first input file from command line */ preprocess(); /* fetch first line */ cptr = STARTGLB - 1; while (++cptr < ENDGLB) *cptr = 0; /* initialize globla symtab */ glbptr=STARTGLB; glbflag=1; ctext=0; header(); /* intro code */ setops(); /* set values in op arrays */ parse(); /* process ALL input */ outside(); /* verify outside any function */ dumpglbs(); 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) { 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) { 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 options from user ** */ options(argc, argv) int argc; char *argv[]; { int k; char *foo; linectr = k = listfp = nxtlab = 0; includectr = 1; output = stdout; library = optimize = errorptr = alarm = monitor = pause = NO; line = mline; /* ???? */ /* ** ** get options from command line ** */ while (++k < argc) { foo = argv[k]; if( *foo == '-' ) { foo++; switch(*foo) { /* Command line switches */ case 'C': ctext = 1; break; case 'o': /* user names the output file */ foo++; if (*foo == 0) foo = argv[++k]; /* foo gets output filename */ openout(foo); /* open file */ outflg = 1; /* set output flag */ break; case 'l': foo++; if (*foo == 0) foo = argv[++k]; /* foo gets output filename */ filecount = FILESTACKMAX - 2; storefile(foo); filecount = 0; library = YES; break; case 'a': alarm=YES; break; case 'm': monitor=YES; break; case 'O': optimize=YES; break; case 'p': pause=YES; break; case 'e': errorptr=YES; break; case 'b': foo++; if (*foo == 0) foo = argv[++k]; /* foo gets output filename */ if(sscanf(foo, "%d", &nxtlab) != 1) { printf("smallc: must be a number after -b option\n"); exit(1); } else break; default: /* unknown option */ printf("%s: unknown option: %s\n", argv[0], foo); exit(1); } } else storefile(foo); /* store input files */ } if (argc == 1) exit(1); /* no input file supplied -- exit */ if (outflg == 0) opendef(foo); /* no output file specified -- open one */ /* default is lastfilename.8085 */ kill(); } /* pushes each input file it gets onto a filestack */ storefile(name) char *name; { if (filecount > (FILESTACKMAX - 2) && library == YES) { /* save one space on filestack */ sout("Too many input files: system error\n",stdout); exit(1); } filestack[++filecount] = name; } /* pops into it's argument array the top file name on the filestack */ restorefile(array) char array[]; { char *foo; int i; i = 0; foo = filestack[filecount--]; if (foo == NULL) return 0; while (*foo != NULL) array[i++] = *foo++; array[i] = NULL; return i; } /* ** get next input file */ openin() { int i,k,j; char temp[LINESIZE],*pt; k = j = 0; input = EOF; pt = &temp[0]; if (i = restorefile(temp)) { if ((temp[i-2] != '.') & (temp[i-1] != 'c')) { fprintf(stdout,"Open failure for input file %s (must be appended with '.c')\n",pt); abort(); } if ((input = fopen(temp, "r")) == NULL) { fprintf(stdout,"Open failure for input file %s\n",pt); abort(); } files = YES; linectr = 0; while (j < i) filebuffer[j] = temp[j++]; filebuffer[j] = NULL; kill(); /* erase line */ return; } if (files++) eof = YES; else input = stdin; kill(); } /* open a specified-by-name output file */ openout(filname) char *filname; { int i; i = 0; /* while((line[i++] = *filname++) != NULL) ; line[i] = NULL; */ if ((output = fopen(filname,"w")) == NULL) { output = 0; /* can't open */ error("Open error for output file\n"); } } /* construct default */ /* output filename */ /* append '.8085' to filname */ opendef(filname) char *filname; { int i; i = output = 0; /* start with none */ while (((line[i++] = *filname++) != '.')); line[i++] = '8'; line[i++] = '0'; line[i++] = '8'; line[i++] = '5'; line[i] = NULL; /* make .asciz string */ if ((output=fopen(line,"w")) == NULL) { output = 0; /* can't open */ error("Open failure for output file\n"); } kill(); /* erase line */ } setops() { op2[0]= op[0]= or; /* heir5 */ op2[1]= op[1]= xor; /* heir6 */ op2[2]= op[2]= and; /* heir7 */ op2[3]= op[3]= eq; /* heir8 */ op2[4]= op[4]= ne; op2[5]=ule; op[5]= le; /* heir9 */ op2[6]=uge; op[6]= ge; op2[7]=ult; op[7]= lt; op2[8]=ugt; op[8]=gt; op2[9]= op[9]= 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; } !Funky!Stuff! echo x - cc12.c cat >cc12.c <<'!Funky!Stuff!' static char *cc12_id = "%W% %G%"; #include "cc1.c" #ifndef LIBDIR #define LIBDIR ="." #endif char *LIB = LIBDIR; /* ** open an include file */ doinclude() { int i,j; char name[LINESIZE]; int c; i = j = 0; pushfile(input); /* save fd, filename and linecount in stack */ blanks(); /* skip over to name and read between quotes */ if (*lptr == '<') { while (*LIB != NULL) name[i++] = *LIB++; name[i++] = '/'; while (*++lptr != '>') name[i++] = *lptr; } else if (*lptr++ == '"') while (*lptr != '"') name[i++] = *lptr++; else error("Bad include syntax"); name[i] =(char) NULL; i = 0; while ((c = (int) name[i]) != NULL) filebuffer[i++] = c; filebuffer[i] = c; if ((input = fopen(name,"r")) == NULL ) { i = 0; input = EOF; printf("open failure on include file "); while(filebuffer[i]) printf("%c",filebuffer[i++]); printf("\n"); if (alarm) putc(7,stderr); } kill(); /* clear rest of line */ } /* ** 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; if(noloc) error("not allowed with goto"); 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; nogo = /* enable goto statements */ noloc = 0; /* enable block-local declarations */ lastst= /* no statement yet */ litptr=0; /* clear lit pool */ litlab=getlabel(); /* label next lit pool */ locptr=STARTLOC; /* clear local variables */ if(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"); } } pushfile(fd) int fd; { char name[LINESIZE]; int i; i = 0; if (includectr > INCLUDESTACKMAX) error("Too many nested includes"); includestack[includectr++] = fd; includestack[includectr++] = linectr; while (filebuffer[i]){ charstack[charcount++] = filebuffer[i++]; } charstack[charcount++] = NULL; linectr = 0; /* reset line count for new file */ } popfile() { int i; i = 0; if (includectr != YES) { /* if inside an include */ if (charstack[--charcount]){ /* and stack is set up correctly */ printf("System Error\n"); exit(1); } while (charstack[--charcount]) /* while char on stack is good */ filebuffer[i++] = charstack[charcount]; /* copy into filebuffer */ filebuffer[i] = NULL; charcount++; /* next open pos. in stack */ reversearray(filebuffer); linectr = includestack[--includectr]; /* restore line count */ return(includestack[--includectr]); } else return(EOF); } copyarray(array1,array2) /* returns a pointer to a copy of its first arg */ int array1[],array2[]; { int i; i = 0; while (array1[i]) array2[i] = array1[i++]; array2[i] = NULL; return &array2[i]; } reversearray(array) int array[]; { int i,j; int array2[LINESIZE]; i = j = 0; while (array[i++]); --i; while (i) array2[j++] = array[--i]; array2[j] = NULL; copyarray(array2,array); } !Funky!Stuff! echo x - cc13.c cat >cc13.c <<'!Funky!Stuff!' static char *cc13_id = "%W% %G%"; #include "cc1.c" /* ** 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) { if(ncmp > 1) nogo=declared; /* disable goto if any */ 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;} else if(amatch("do",2)) {dodo();lastst=STDO;} else if(amatch("for",3)) {dofor();lastst=STFOR;} else if(amatch("switch",6)) {doswitch();lastst=STSWITCH;} else if(amatch("case",4)) {docase();lastst=STCASE;} else if(amatch("default",7)) {dodefault();lastst=STDEF;} else if(amatch("goto", 4)) {dogoto(); lastst=STGOTO;} else if(dolabel()) ; 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 */ cptr=savloc; /* retain labels */ while(cptr < locptr) { cptr2=nextsym(cptr); if(cptr[IDENT] == LABEL) { while(cptr < cptr2) *savloc++ = *cptr++; } else cptr=cptr2; } locptr=savloc; /* delete local symbols */ declared = -1; /* may not declare variables */ } doif() { int flab1,flab2; 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(); if((lastst != STRETURN)&(lastst != STGOTO)) jump(flab2); 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 */ } 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(); } 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(); } doswitch() { int wq[4], endlab, swact, swdef, *swnex, *swptr; swact=swactive; swdef=swdefault; swnex=swptr=swnext; addwhile(wq); *(wqptr + WQLOOP - WQSIZ) = 0; 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()); } 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)); } doreturn() { if(endst()==0) { doexpr(); modstk(0, YES); } else modstk(0, NO); ret(); } dobreak() { int *ptr; if ((ptr = readwhile(wqptr))==0) return; /* no loops open */ modstk((ptr[WQSP]), NO); /* clean up stk ptr */ jump(ptr[WQEXIT]); /* jump to exit label */ } docont() { int *ptr; ptr = wqptr; while(1) { if ((ptr=readwhile(ptr))==0) return; /* no loops open */ if (ptr[WQLOOP]) break; } 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; sout(line, output); } kill(); ccode=1; } !Funky!Stuff! echo x - cc2.c cat >cc2.c <<'!Funky!Stuff!' static char *cc2_id = "%W% %G%"; /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 2 */ #include "cc.def" /* ** external references in parts 1 & 2 */ extern char symtab[SYMTBSZ], stage[STAGESIZE], macn[MACNSIZE], macq[MACQSIZE], pline[LINESIZE], mline[LINESIZE], alarm, *glbptr, *line, *lptr, *cptr, *cptr2, *cptr3, *locptr, msname[NAMESIZE], optimize, pause, library, quote[2], *stagelast, *stagenext; extern int wq[WQTABSZ], mack, linectr, includectr, charcount, filecount, includestack[INCLUDESTACKMAX], charstack[LINESIZE], filestack[FILESTACKMAX], filebuffer[LINESIZE], ccode, ch, csp, eof, errflag, iflevel, errorptr, input, input2, listfp, macptr, nch, nxtlab, op[16], opindex, opsize, output, pptr, skiplevel, *wqptr; extern int openin(), popfile(),reversearray(); /* ** external references in part 4 */ #ifdef OPTIMIZE extern int peephole(); #endif !Funky!Stuff! echo x - cc21.c cat >cc21.c <<'!Funky!Stuff!' #include "cc2.c" 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; { if (search( sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; return 0; } findloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptr > STARTLOC) { cptr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1; } return 0; } addsym(sname, id, typ, value, lgptrptr, class) char *sname, id, typ; int value, class, *lgptrptr; { if(lgptrptr == &glbptr) { if(cptr2=findglb(sname)) return cptr2; if (cptr == 0) { error("global symbol table overflow"); return 0; } } else { if(locptr > (ENDLOC-SYMMAX)) { error("local symbol table overflow"); abort(ERRCODE); } cptr = *lgptrptr; } cptr[IDENT]=id; cptr[TYPE]=typ; cptr[CLASS]=class; putint(value, cptr+OFFSET, OFFSIZE); cptr3 = cptr2 = cptr + NAME; while(an(*sname)) *cptr2++ = *sname++; if (lgptrptr == &locptr) { *cptr2 = cptr2 - cptr3; /* set length */ *lgptrptr = ++cptr2; } return cptr; } nextsym(entry) char *entry; { entry = entry + NAME; while(*entry++ >= ' '); /* find length byte */ return entry; } /* ** 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)) { if(ucase) sname[k]=upper(gch()); else sname[k]=gch(); if(k<NAMEMAX) ++k; } sname[k]=0; return 1; } /* ** force upper case alphabetics */ upper(c) char c; { if((c >= 'a') & (c <= 'z')) return (c - 32); else return c; } /* ** force upper case alphabetics */ lower(c) char c; { if((c >= 'A') & (c <= 'Z')) return (c + 32); else return c; } /* ** 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(wqptr > wq) wqptr=wqptr-WQSIZ; } readwhile(ptr) int *ptr; { if (ptr <= wq) { error("out of context"); return 0; } else return (ptr-WQSIZ); } white() { /* test for stack/program overlap */ /* primary -> symname -> blanks -> white */ 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; while(1) { if (input==EOF) openin(); if (eof && library) appendlib(); /* append user library */ if (eof) return; if(fgets(line, LINEMAX, input)==NULL) { fclose(input); input = popfile(); } else { bump(0); linectr++; return; } } } undefined(sname) char *sname; { char c; if (errflag) return; if (errorptr) /* if user wants pointer to variable */ error("Undefined variable"); else { while(*sname) { c = lower(*sname++); printf("%c",c); } printf(" in "); error("Undefined variable"); if ((ch == ')') || (ch == ',' )) bump(1); /* if in function call */ } } appendlib() { int index,i,j; long tempstack[50]; char c,str[LINESIZE]; filecount = FILESTACKMAX - 1; openin(); /* get library file from filestack[FILESTACKMAX] */ eof = library = NO; /* no nested appendlibs */ j = 0; preprocess(); /* get first line */ unresolved(tempstack); while (eof == NO) { cptr = STARTGLB; while ((index = tempstack[j++]) != YES) { i = 0; while((c = cptr[index + NAME + i]) != NULL) str[i++] = lower(c); str[i] = NULL; if(match(str)) { bump(0); newfunc(); /* parses and resolves functions on symtab */ break; } } ch = EOL; /* force blanks to get new line */ j = 0; blanks(); } } unresolved(array) long array[]; { int index,i; cptr = STARTGLB; index = i = 0; while(&cptr[index] < ENDGLB) { if (cptr[index + IDENT]) if (cptr[index + OFFSET] == NULL){ array[i++] = index; } index = index + SYMMAX; } array[i] = YES; /* end-of-stack marker */ } abort(n) int n; { exit(1); } !Funky!Stuff! echo x - cc22.c cat >cc22.c <<'!Funky!Stuff!' static char *cc22_id = "%W% %G%"; #include "cc2.c" ifline() { while(1) { inline(); if(eof) return; if(match("#ifdef")) { ++iflevel; if(skiplevel) continue; blanks(); if (search(lptr, macn, NAMESIZE + 2, MACNEND, MACNBR, 0) == 0) skiplevel=iflevel; continue; } if(match("#ifndef")) { ++iflevel; if(skiplevel) continue; blanks(); if (search(lptr, macn, NAMESIZE + 2, MACNEND, MACNBR, 0)) skiplevel=iflevel; continue; } if(match("#else")) { if(iflevel) { if(skiplevel==iflevel) skiplevel=0; else if(skiplevel==0) skiplevel=iflevel; } else noiferr(); continue; } if(match("#endif")) { if(iflevel) { if(skiplevel==iflevel) skiplevel=0; --iflevel; } else noiferr(); continue; } if(skiplevel) continue; if(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; if (search(msname, macn, NAMESIZE + 2, MACNEND, MACNBR, 0)) { k = getint(cptr + NAMESIZE, 2); while (c = macq[k++]) keepch(c); } 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; char c; if(symname(msname, NO)==0) { illname(); kill(); return; } k=0; if (search(msname, macn, NAMESIZE + 2, MACNEND, MACNBR, 0) == 0) { if (cptr2 = cptr) while (*cptr2++ = msname[k++]); else { error("macro name table full"); return; } } putint(macptr, cptr + NAMESIZE, 2); while(white()) gch(); while((c = gch()) != EOL) putmac(c); putmac(0); if(macptr>=MACMAX) { error("macro string queue full"); abort(ERRCODE); } } putmac(c) char c; { macq[macptr]=c; if(macptr<MACMAX) ++macptr; return c; } /* ** 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; } 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[]; { /* 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[]; { int i; i = 0; if (errflag) return; else errflag=1; if (errorptr == NO) { while (filebuffer[i]) printf("%c",filebuffer[i++]); printf(", %s %d: %s\n","line",linectr,msg); } else { lout(line, stderr); errout(msg, stderr); } if(alarm) fputc(7, stderr); if(pause) while(fgetc(stdin)!='\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 != EOL) && (ch != NULL)) { if(white()) gch(); else return; } if(line==mline) return; preprocess(); if(eof)break; } } dumpglbs() { int index,i; char c,*pointer,*pointer1,temp[LINESIZE]; cptr = STARTGLB; index = 0; while(&cptr[index] < ENDGLB) { if (cptr[index + IDENT]) { if (cptr[index + OFFSET] == NULL) { i = 0; printf("Undefined function: "); while (cptr[index + NAME + i]) { c = lower(cptr[index + NAME + i++]); printf("%c",c); } printf("\n"); } } index = index + SYMMAX; } } !Funky!Stuff! echo x - cc3.c cat >cc3.c <<'!Funky!Stuff!' static char *cc3_id = "%W% %G%"; /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 3 */ #include "cc.def" /* ** external references in part 1 */ extern char stage[STAGESIZE], litq[LITABSZ], *glbptr, *lptr, ssname[NAMESIZE], quote[2], *stagenext; extern int ch, csp, litlab, litptr, nch, op[16], op2[16], oper, opindex, opsize; extern int heir1(), heir3(), heir4(), heir5(), heir6(), heir7(), heir8(), heir9(), heir10(), heir11(), heir12(), heir13(); /* ** 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(); !Funky!Stuff! echo x - cc31.c cat >cc31.c <<'!Funky!Stuff!' static char *cc31_id = "%W% %G%"; #include "cc3.c" /* ** 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, lval[]; int (*heir)(); { 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, exit1, lval[]; int (*testfunc)(); { 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, lval[]; int (*heir)(); { 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 lval[]; int (*heir)(); { 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)(); int (*oper2)(); int lval[], lval2[]; int (*heir)(); { 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); } !Funky!Stuff! echo x - cc32.c cat >cc32.c <<'!Funky!Stuff!' static char *cc32_id = "%W% %G%"; #include "cc3.c" 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)) { if(ptr[IDENT]==LABEL) { experr(); return 0; } 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; } if (match("(")) { /* if user defined function */ ptr=addsym(ssname, FUNCTION, CINT, 0, &glbptr, STATIC); lval[0] = ptr; lval[1] = 0; nch = ch; /* these next statements are similar to */ ch = '('; /* 'ungetting' a char from the input line */ --lptr; return 0; } undefined(ssname); /* outputs the otherwise undefined name */ 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); } !Funky!Stuff! echo x - cc33.c cat >cc33.c <<'!Funky!Stuff!' static char *cc33_id = "%W% %G%"; #include "cc3.c" /* ** 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('"')==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; } !Funky!Stuff! echo x - cc4.c cat >cc4.c <<'!Funky!Stuff!' static char *cc4_id = "%W% %G%"; /* ** Small-C Compiler Version 2.0 ** ** Copyright 1982 J. E. Hendrix ** ** Part 4 */ #include "cc.def" /* ** external references in part 1 */ extern char *macn, optimize, *stagenext, ssname[NAMESIZE]; extern int beglab, csp, output; /* ** external references in part 2 */ extern int search(), clearstage(), col(), cout(), getint(), getlabel(), nl(), numeric(), ol(), ot(), printlabel(), lout(), outdec(), outstr(), streq(); /* ** external references in part 3 */ extern int const(); !Funky!Stuff! echo x - cc41.c cat >cc41.c <<'!Funky!Stuff!' static char *cc41_id = "%w% %g%"; #include "cc4.c" /* ** print all assembler info before any code is generated */ header() { beglab=getlabel(); if(beglab < 3) jump(beglab); } /* ** print any assembler stuff needed at the end */ trailer() { if((beglab == 1)|(beglab > 9000)) ol("end"); } /* ** load # args before function call */ loadargc(val) int val; { if (search("NOCCARGC", macn, NAMESIZE + 2, MACNEND, MACNBR, 0) == 0) { ot("mvi a,"); outdec(val); nl(); } } /* ** declare entry point */ entry() { outstr(ssname); col(); nl(); } /* ** declare external reference */ external(name) char *name; { } /* ** 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; sour="\txchg;;"; /* peephole() uses trailing ";;" */ while(*sour) *dest++ = *sour++; sour=stagenext; while(--sour > dest) { /* adjust stack references */ if(streq(sour,"\tdad sp")) { --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");} !Funky!Stuff! echo x - cc42.c cat >cc42.c <<'!Funky!Stuff!' static char *cc42_id = "%w% %g%"; #include "cc4.c" /* ** 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) { 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();ptr=ptr+38;} else {pp4();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 cout(*ptr++, output); } else cout(*ptr++, output); } } pp1() { ol("pop h"); ol("push h"); } pp2() { ol("pop d"); ol("push d"); } pp3() { ol("pop b"); pp2(); ol("push b"); } pp4() { ol("pop b"); pp1(); ol("push b"); } #endif !Funky!Stuff! echo x - libasm.c cat >libasm.c <<'!Funky!Stuff!' #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 !Funky!Stuff! echo x - libsmc.c cat >libsmc.c <<'!Funky!Stuff!' /* ** 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; } /* ** 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; } /* ** 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; } /* ** 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; } /* ** abs -- returns absolute value of nbr */ abs(nbr) int nbr; { if(nbr<0) return -nbr; else return stdout; } /* ** left -- left adjust and null terminate a string */ left(str) char *str; { char *str2; str2=str; while(*str2==' ') ++str2; while(*str++ = *str2++); } 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); } /* ** 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); } } /* ** 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; } /* ** 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); } /* ** 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; } /* ** 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; } !Funky!Stuff! echo x - stdio.c cat >stdio.c <<'!Funky!Stuff!' /* ** stdio.c -- header for local I/O */ #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 !Funky!Stuff!
schrein (03/14/83)
#R:wjh12:-18000:uiucdcs:12600005:000:128 uiucdcs!schrein Mar 13 17:01:00 1983 There is, unfortunately, an old limit of about 64K for the length of a note.... Therefore, these smallc sources are incomplete.