CRACK LOCATOR

The Way We Find The Cracks
 
Small C Compiler - Small Assembler v2.2
  1. Download the crack/serial/keygen for "Small C Compiler - Small Assembler v2.2".
  2. Download with DSL speed using USENExT.
  3.  

  4. View text files (.nfo & .diz) autoextracted from the zip.
  5. If you like the software, please support the author and buy it! Every good job should be paid.

Previous cracks Next cracks
Related cracks Alternative possible spelling

Auto .NFO Viewer
AR.C: /* ** AR -- File Archiver ** ** usage: ar -{dptux} arcfile [file...] ** ** Ar collects text files into a single archive file. ** Files can be extracted, new ones added, ** old ones replaced or deleted, and ** a list of the archive contents produced. ** ** The first argument is a switch from the following set. ** The second argument is the name of the archive file. ** The third and subsequent arguments are file names. ** ** -d delete named files from the library. ** -p print named, or all, files on stdout. ** -t table of contents of named, or all, files to stdout. ** -u update the archive by adding/replacing files ** (used to create a new library). ** If no file names are specified in the command line, ** they are obtained from stdin. ** -x extract named, or all, files. ** ** Control-S to pause execution and control-C to abort. ** ** This program was given as a class assignment in the ** Computer Science Department at the University of Arizona. ** It was contributed by Ernext Payne. Orignially it was ** written to work with tape archives, but this version has ** been modified for higher speed operation with diskette ** archives under CP/M. */ #include <stdio.h> #define NAMESIZE 30 #define MAXLINE 500 #define MAXFILES 20 #define HDR ">>>" #define AUXSIZE 4096 char tname[]=" ar.$$$"; int fnptr[MAXFILES]; int fstat[MAXFILES]; int nfiles; int errchk; main(argc, argv) int argc, argv[]; { char cmd[3], aname[NAMESIZE]; if(getarg(1, cmd, 3,argc,argv) == EOF) usage(); if(getarg(2,aname,NAMESIZE,argc,argv) == EOF) usage(); if(aname[1] == ':') { tname[0] = aname[0]; tname[1] = aname[1]; } else left(tname); getfns(argc,argv); switch(toupper(cmd[1])) { case 'D': drop(aname); break; case 'T': table(aname); break; case 'U': update(aname); break; case 'X': case 'P': extract(aname, toupper(cmd[1])); break; default: usage(); } } /* acopy - copy size characters from fpi to fpo */ acopy(fpi,fpo,size) int fpi, fpo; int size; { int c; while(size-- > 0) { poll(YES); if((c = getc(fpi)) == EOF) break; putc(c,fpo); } } /* addfile - add file "name" to archive */ addfile(name,fp) char *name; int fp; { int nfp; if((nfp = fopen(name,"r")) == NULL) { fprintf(stderr,"%s: can't open\n",name); errchk = 1; } if (errchk == 0) { if(name[1] == ':') name += 2; fprintf(fp,"%s %s %d\n",HDR,name,fsize(nfp)); fcopy(nfp,fp); fclose(nfp); fprintf(stderr, " copied new %s\n", name); } } /* amove - move file1 to file2 */ amove(file1,file2) char *file1, *file2; { if(errchk) { printf("fatal errors - archive not altered\n"); unlink(file1); exit(7); } unlink(file2); if(file2[1] == ':') file2 += 2; if(rename(file1, file2)) { printf("can't rename %s to %s\n", file1, file2); exit(7); } } /* cant - print file name and die */ cant(name) char *name; { fprintf(stderr,"%s: can't open\n",name); exit(7); } /* drop - delete files from archive */ drop(aname) char *aname; { int afp, tfp; if(nfiles <= 0) /* protect innocents */ error("delete by name only"); afp = mustopen(aname,"r"); tfp = mustopen(tname,"w"); auxbuf(tfp, AUXSIZE); replace(afp,tfp,'d'); notfound(); fclose(afp); fclose(tfp); amove(tname,aname); } /* error - print message and die */ error(msg) char *msg; { fprintf(stderr,"%s\n",msg); exit(7); } /* extract - extract files from archive */ extract(aname,cmd) char *aname, cmd; { int afp, efp; char ename[NAMESIZE], in[MAXLINE]; int size; afp = mustopen(aname,"r"); auxbuf(afp, AUXSIZE); if(cmd == 'P') efp = stdout; else efp = NULL; while((size = gethdr(afp,in,ename)) >= 0) if(!fmatch(ename, YES)) fskip(afp,size); else { if(efp != stdout) efp = fopen(ename,"w"); if(efp == NULL) { fprintf(stderr,"%s: can't create\n",ename); errchk = 1; fskip(afp,size); } else { if(cmd == 'P') { fprintf(efp, "\n───────────────────────────────────"); fprintf(efp, "───────────────────────────────────\n"); fprintf(efp, " %s", ename); fprintf(efp, "\n───────────────────────────────────"); fprintf(efp, "───────────────────────────────────\n"); } acopy(afp,efp,size); if(cmd == 'P') fprintf(stderr, "printed %s\n", ename); else fprintf(stderr, "created %s\n", ename); if(efp != stdout) fclose(efp); } } notfound(); fclose(afp); } /* fcopy - copy file in to file out */ fcopy(in,out) int in, out; { int c; while((c = getc(in)) != EOF) { poll(YES); putc(c,out); } } /* fmatch - check if name matches argument list */ fmatch(name, quit) char *name; int quit; { int i, done; char *fnp; if(nfiles <= 0) return(1); done = YES; for(i=0;i<nfiles;++i) { fnp = fnptr[i]; if(fnp[1] == ':') fnp += 2; if(same(name,fnp) == 0) { fstat[i] = 1; return(1); } if(fstat[i] == 0) done = NO; } if(quit && done) exit(0); return(0); } /* fsize - size of file in characters */ fsize(fp) int fp; { int i; for(i=0; getc(fp) != EOF; ++i) ; rewind(fp); return(i); } /* fskip - skip n characters on file fp */ fskip(fp,n) int fp, n; { while(n-- > 0) { poll(YES); if(fgetc(fp) == EOF) break; } } /* getfns - get file names into fname, check for duplicates */ getfns(argc,argv) int argc, argv[]; { int i, j; nfiles = argc - 3; if(nfiles > MAXFILES) error("too many file names"); for(i=0,j=3; i<nfiles; i++,j++) fnptr[i] = argv[j]; for(i = 0; i < nfiles-1; ++i) for(j = i+1; j < nfiles; ++j) { if(same(fnptr[i],fnptr[j]) == 0) { fprintf(stderr,"%s:duplicate file names\n",fnptr[i]); exit(7); } } } /* gethdr - get header info from fp */ gethdr(fp,buf,name) int fp; char *buf, *name; { if(fgets(buf,MAXLINE,fp) == NULL) return(-1); buf = getwrd(buf,name); if(strcmp(name,HDR) != 0) error("archive not in proper format"); buf = getwrd(buf,name); return(atoi(buf)); } /* getwrd - copy first word of s to t */ getwrd(s,t) char *s, *t; { while(isspace(*s)) ++s; while(*s != '\0' && !isspace(*s)) *t++ = *s++; *t = '\0'; return(s); } /* mustopen - open file or die */ mustopen(name,mode) char *name, *mode; { int fp; if(fp = fopen(name,mode)) return(fp); cant(name); } /* notfound - print "not found" message */ notfound() { int i; for(i=0;i<nfiles;++i) if(fstat[i] == 0) { fprintf(stderr,"%s not in archive\n",fnptr[i]); errchk = 1; } } /* replace - replace or delete files */ replace(afp,tfp,cmd) int afp, tfp; char cmd; { char in[MAXLINE], uname[NAMESIZE]; int size; while((size = gethdr(afp,in,uname)) >= 0) { if(fmatch(uname, NO)) { if(cmd == 'u') /* add new one */ addfile(uname,tfp); fskip(afp,size); /* discard old one */ fprintf(stderr, "dropped old %s\n", uname); } else { fputs(in,tfp); acopy(afp,tfp,size); } } } /* table - print table of archive contents */ table(aname) char *aname; { char in[MAXLINE], lname[NAMESIZE]; int afp, size; afp = mustopen(aname,"r"); while((size = gethdr(afp,in,lname)) >= 0) { poll(YES); if(fmatch(lname, YES)) printf("%s\n", lname); fskip(afp,size); } notfound(); fclose(afp); } /* update - update existing files, add new ones at end */ update(aname) char *aname; { int afp, i, tfp; char fn[NAMESIZE]; if((afp = fopen(aname,"r+")) == NULL) /* maybe archive does not exist yet */ afp = mustopen(aname,"w+"); tfp = mustopen(tname,"w+"); auxbuf(tfp, AUXSIZE); replace(afp,tfp,'u'); /* update existing */ if(nfiles > 0) { for(i=0;i<nfiles;++i) /* add new ones */ if(fstat[i] == 0) { addfile(fnptr[i],tfp); if(errchk) break; fstat[i] = 1; } } else while(1) { poll(YES); if(iscons(stdin)) fprintf(stdout,"file - "); if(!fgets(fn, NAMESIZE, stdin) || *fn == '\n') break; for(i=0; fn[i]; i++) if((fn[i] = toupper(fn[i])) == '\n') fn[i] = NULL; addfile(&fn[0], tfp); if(errchk) break; } fclose(afp); fclose(tfp); amove(tname,aname); } /* return <0, 0, >0 according to s<t, s=t, s>t*/ same(s, t) char *s, *t; { while(toupper(*s) == toupper(*t)) { if(toupper(*s) == 0) return (0); ++s; ++t; } return (toupper(*s) - toupper(*t)); } /* usage - abort with a usage message */ usage() { error("usage: ar -{dptux} arcfile [file...]"); } C.TXT: Small C Compiler Version 2.2 The Small C compiler translates a subset of the C language into assembly language. It runs under PC/MS-DOS 2.1 and later. Small C is compatible with both Small Assembler and the Microsoft assembler MASM. Small C supports a small memory model with one code and one data/stack segment. Small C supports arrays of one dimension. Functions always return integer values. External functions are automatically declared. Initialization of global variables is supported. The preprocessor supports #include, #define, #ifdef, #ifndef, #else, #endif, #asm, #endasm commands . The following control statements are supported: if, switch, case, default, break, continue, while, for, and do/while. All expression operators are supported. Only signed and unsigned integer and character data types are supported. The following standard C features are not supported: structures, fields, unions, arrays of pointers, and casts. Small C supports UNIX-like I/O redirection and command-line argument passing. The Small C library includes over 80 functions -- a nearly complete set of the standard UNIX/C repertoire. Binary as well as character stream I/O is supported. The formatted I/O functions printf() and scanf() are included. Random access to files is provided. Programs can request additional file buffering. The compiler itself is written in Small C and is distributed with both object and source code. As a self compiler, Small C can be modified to work in other environments and to meet special needs. Since everything is revealed and fully documented, Small C has tremendous value as an educational device. Small C uses a single pass, recursive descent parsing algorithm. It generates p-codes for internal use, and optimizes its output. The Small C language and compiler are fully described in "A Small C Compiler: Language, Usage, Theory, and Design" by James E. Hendrix. Copies are available from: M&T Publishing, Inc. 501 Galveston Dr. Redwood City, CA 94063 Phone: 1 (800) 533-4372 J. E. Hendrix P.O. Box 1435 Oxford, MS 38655 CC.H: /* ** CC.H -- Symbol Definitions for Small-C compiler. */ /* ** machine dependent parameters */ #define BPW 2 /* bytes per word */ #define LBPW 1 /* log2(BPW) */ #define SBPC 1 /* stack bytes per character */ #define ERRCODE 7 /* op sys return code */ /* ** symbol table format */ #define IDENT 0 #define TYPE 1 #define CLASS 2 #define SIZE 3 #define OFFSET 5 #define NAME 7 #define SYMAVG 12 #define SYMMAX 16 /* ** symbol table parameters */ #define NUMLOCS 25 #define STARTLOC symtab #define ENDLOC (symtab+NUMLOCS*SYMAVG) #define NUMGLBS 200 #define STARTGLB ENDLOC #define ENDGLB (ENDLOC+(NUMGLBS-1)*SYMMAX) #define SYMTBSZ 3050 /* (NUMLOCS*SYMAVG + NUMGLBS*SYMMAX) */ /* ** system wide name size (for symbols) */ #define NAMESIZE 9 #define NAMEMAX 8 /* ** values for "IDENT" */ #define LABEL 0 #define VARIABLE 1 #define ARRAY 2 #define POINTER 3 #define FUNCTION 4 /* ** values for "TYPE" ** high order 14 bits give length of object ** low order 2 bits make type unique within length */ /* LABEL 0 */ #define CHR ( 1 << 2) #define INT (BPW << 2) #define UCHR (( 1 << 2) + 1) #define UINT ((BPW << 2) + 1) #define UNSIGNED 1 /* ** values for "CLASS" */ /* LABEL 0 */ #define AUTOMATIC 1 #define STATIC 2 #define EXTERNAL 3 #define AUTOEXT 4 /* ** segment types */ #define DATASEG 1 #define CODESEG 2 /* ** "switch" table */ #define SWSIZ (2*BPW) #define SWTABSZ (90*SWSIZ) /* ** "while" queue */ #define WQTABSZ 30 #define WQSIZ 3 #define WQMAX (wq+WQTABSZ-WQSIZ) /* ** field offsets in "while" queue */ #define WQSP 0 #define WQLOOP 1 #define WQEXIT 2 /* ** literal pool */ #define LITABSZ 2000 #define LITMAX (LITABSZ-1) /* ** input line */ #define LINEMAX 127 #define LINESIZE 128 /* ** entries in staging buffer */ #define STAGESIZE 200 /* ** macro (#define) pool */ #define MACNBR 300 #define MACNSIZE (MACNBR*(NAMESIZE+2)) #define MACNEND (macn+MACNSIZE) #define MACQSIZE (MACNBR*7) #define MACMAX (MACQSIZE-1) /* ** statement types */ #define STIF 1 #define STWHILE 2 #define STRETURN 3 #define STBREAK 4 #define STCONT 5 #define STASM 6 #define STEXPR 7 #define STDO 8 #define STFOR 9 #define STSWITCH 10 #define STCASE 11 #define STDEF 12 #define STGOTO 13 #define STLABEL 14 /* ** p-code symbols ** ** legend: ** 1 = primary register (pr in comments) ** 2 = secondary register (sr in comments) ** b = byte ** f = jump on false condition ** l = current literal pool label number ** m = memory reference by label ** n = numeric constant ** p = indirect reference thru pointer in sr ** r = repeated r times ** s = stack frame reference ** u = unsigned ** w = word ** _ (tail) = another p-code completes this one */ /* compiler-generated */ #define ADD12 1 /* add sr to pr */ #define ADDSP 2 /* add to stack pointer */ #define AND12 3 /* AND sr to pr */ #define ANEG1 4 /* arith negate pr */ #define ARGCNTn 5 /* pass arg count to function */ #define ASL12 6 /* arith shift left sr by pr into pr */ #define ASR12 7 /* arith shift right sr by pr into pr */ #define CALL1 8 /* call function thru pr */ #define CALLm 9 /* call function directly */ #define BYTE_ 10 /* define bytes (part 1) */ #define BYTEn 11 /* define byte of value n */ #define BYTEr0 12 /* define r bytes of value 0 */ #define COM1 13 /* ones complement pr */ #define DBL1 14 /* double pr */ #define DBL2 15 /* double sr */ #define DIV12 16 /* div pr by sr */ #define DIV12u 17 /* div pr by sr unsigned */ #define ENTER 18 /* set stack frame on function entry */ #define EQ10f 19 /* jump if (pr == 0) is false */ #define EQ12 20 /* set pr TRUE if (sr == pr) */ #define GE10f 21 /* jump if (pr >= 0) is false */ #define GE12 22 /* set pr TRUE if (sr >= pr) */ #define GE12u 23 /* set pr TRUE if (sr >= pr) unsigned */ #define POINT1l 24 /* point pr to function's literal pool */ #define POINT1m 25 /* point pr to mem item thru label */ #define GETb1m 26 /* get byte into pr from mem thru label */ #define GETb1mu 27 /* get unsigned byte into pr from mem thru label */ #define GETb1p 28 /* get byte into pr from mem thru sr ptr */ #define GETb1pu 29 /* get unsigned byte into pr from mem thru sr ptr */ #define GETw1m 30 /* get word into pr from mem thru label */ #define GETw1n 31 /* get word of value n into pr */ #define GETw1p 32 /* get word into pr from mem thru sr ptr */ #define GETw2n 33 /* get word of value n into sr */ #define GT10f 34 /* jump if (pr > 0) is false */ #define GT12 35 /* set pr TRUE if (sr > pr) */ #define GT12u 36 /* set pr TRUE if (sr > pr) unsigned */ #define WORD_ 37 /* define word (part 1) */ #define WORDn 38 /* define word of value n */ #define WORDr0 39 /* define r words of value 0 */ #define JMPm 40 /* jump to label */ #define LABm 41 /* define label m */ #define LE10f 42 /* jump if (pr <= 0) is false */ #define LE12 43 /* set pr TRUE if (sr <= pr) */ #define LE12u 44 /* set pr TRUE if (sr <= pr) unsigned */ #define LNEG1 45 /* logical negate pr */ #define LT10f 46 /* jump if (pr < 0) is false */ #define LT12 47 /* set pr TRUE if (sr < pr) */ #define LT12u 48 /* set pr TRUE if (sr < pr) unsigned */ #define MOD12 49 /* modulo pr by sr */ #define MOD12u 50 /* modulo pr by sr unsigned */ #define MOVE21 51 /* move pr to sr */ #define MUL12 52 /* multiply pr by sr */ #define MUL12u 53 /* multiply pr by sr unsigned */ #define NE10f 54 /* jump if (pr != 0) is false */ #define NE12 55 /* set pr TRUE if (sr != pr) */ #define NEARm 56 /* define near pointer thru label */ #define OR12 57 /* OR sr onto pr */ #define POINT1s 58 /* point pr to stack item */ #define POP2 59 /* pop stack into sr */ #define PUSH1 60 /* push pr onto stack */ #define PUTbm1 61 /* put pr byte in mem thru label */ #define PUTbp1 62 /* put pr byte in mem thru sr ptr */ #define PUTwm1 63 /* put pr word in mem thru label */ #define PUTwp1 64 /* put pr word in mem thru sr ptr */ #define rDEC1 65 /* dec pr (may repeat) */ #define REFm 66 /* finish instruction with label */ #define RETURN 67 /* restore stack and return */ #define rINC1 68 /* inc pr (may repeat) */ #define SUB12 69 /* sub sr from pr */ #define SWAP12 70 /* swap pr and sr */ #define SWAP1s 71 /* swap pr and top of stack */ #define SWITCH 72 /* find switch case */ #define XOR12 73 /* XOR pr with sr */ /* optimizer-generated */ #define ADD1n 74 /* add n to pr */ #define ADD21 75 /* add pr to sr */ #define ADD2n 76 /* add immediate to sr */ #define ADDbpn 77 /* add n to mem byte thru sr ptr */ #define ADDwpn 78 /* add n to mem word thru sr ptr */ #define ADDm_ 79 /* add n to mem byte/word thru label (part 1) */ #define COMMAn 80 /* finish instruction with ,n */ #define DECbp 81 /* dec mem byte thru sr ptr */ #define DECwp 82 /* dec mem word thru sr ptr */ #define POINT2m 83 /* point sr to mem thru label */ #define POINT2m_ 84 /* point sr to mem thru label (part 1) */ #define GETb1s 85 /* get byte into pr from stack */ #define GETb1su 86 /* get unsigned byte into pr from stack */ #define GETw1m_ 87 /* get word into pr from mem thru label (part 1) * / #define GETw1s 88 /* get word into pr from stack */ #define GETw2m 89 /* get word into sr from mem (label) */ #define GETw2p 90 /* get word into sr thru sr ptr */ #define GETw2s 91 /* get word into sr from stack */ #define INCbp 92 /* inc byte in mem thru sr ptr */ #define INCwp 93 /* inc word in mem thru sr ptr */ #define PLUSn 94 /* finish instruction with +n */ #define POINT2s 95 /* point sr to stack */ #define PUSH2 96 /* push sr */ #define PUSHm 97 /* push word from mem thru label */ #define PUSHp 98 /* push word from mem thru sr ptr */ #define PUSHs 99 /* push word from stack */ #define PUT_m_ 100 /* put byte/word into mem thru label (part  9;) */ #define rDEC2 101 /* dec sr (may repeat) */ #define rINC2 102 /* inc sr (may repeat) */ #define SUB_m_ 103 /* sub from mem byte/word thru label (part 1) */ #define SUB1n 104 /* sub n from pr */ #define SUBbpn 105 /* sub n from mem byte thru sr ptr */ #define SUBwpn 106 /* sub n from mem word thru sr ptr */ #define PCODES 107 /* size of code[] */ CC1.C: /* ** Small-C Compiler -- Part 1 -- Top End. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendri x ** All rights reserved. */ #include <stdio.h> #include "notice.h" #include "cc.h" /* ** miscellaneous storage */ int nogo, /* disable goto statements? */ noloc, /* disable block locals? */ opindex, /* index to matched operator */ opsize, /* size of operator in characters */ swactive, /* inside a switch? */ swdefault,/* default label #, else 0 */ *swnext, /* address of next entry */ *swend, /* address of last entry */ *stage, /* staging buffer address */ *wq, /* while queue */ argcs, /* static argc */ *argvs, /* static argv */ *wqptr, /* ptr to next entry */ litptr, /* ptr to next entry */ macptr, /* macro buffer index */ pptr, /* ptr to parsing buffer */ ch, /* current character of input line */ nch, /* next character of input line */ declared, /* # of local bytes to declare, -1 when declared */ iflevel, /* #if... nest level */ skiplevel,/* level at which #if... skipping started */ nxtlab, /* next avail label # */ litlab, /* label # assigned to literal pool */ csp, /* compiler relative stk ptr */ argstk, /* function arg sp */ argtop, /* highest formal argument offset */ ncmp, /* # open compound statements */ errflag, /* true after 1st error in statement */ eof, /* true on final input eof */ output, /* fd for output file */ files, /* true if file list specified on cmd line */ filearg, /* cur file arg index */ input = EOF, /* fd for input file */ input2 = EOF, /* fd for "#include" file */ usexpr = YES, /* true if value of expression is used */ ccode = YES, /* true while parsing C code */ *snext, /* next addr in stage */ *stail, /* last addr of data in stage */ *slast, /* last addr in stage */ listfp, /* file pointer to list device */ lastst, /* last parsed statement type */ oldseg; /* current segment (0, DATASEG, CODESEG) */ char optimize, /* optimize output of staging buffer? */ alarm, /* audible alarm on errors? */ monitor, /* monitor function headers? */ pause, /* pause for operator on errors? */ *symtab, /* symbol table */ *litq, /* literal pool */ *macn, /* macro name buffer */ *macq, /* macro string buffer */ *pline, /* parsing buffer */ *mline, /* macro buffer */ *line, /* ptr to pline or mline */ *lptr, /* ptr to current character in "line" */ *glbptr, /* global symbol table */ *locptr, /* next local symbol table entry */ quote[2] = {'"'}, /* literal string for '"' */ *cptr, /* work ptrs to any char buffer */ *cptr2, *cptr3, msname[NAMESIZE], /* macro symbol name */ ssname[NAMESIZE]; /* static symbol name */ int op[16] = { /* p-codes of signed binary operators */ OR12, /* level5 */ XOR12, /* level6 */ AND12, /* level7 */ EQ12, NE12, /* level8 */ LE12, GE12, LT12, GT12, /* level9 */ ASR12, ASL12, /* level10 */ ADD12, SUB12, /* level11 */ MUL12, DIV12, MOD12 /* level12 */ }; int op2[16] = { /* p-codes of unsigned binary operators */ OR12, /* level5 */ XOR12, /* level6 */ AND12, /* level7 */ EQ12, NE12, /* level8 */ LE12u, GE12u, LT12u, GT12u, /* level9 */ ASR12, ASL12, /* level10 */ ADD12, SUB12, /* level11 */ MUL12u, DIV12u, MOD12u /* level12 */ }; /* ** execution begins here */ main(argc, argv) int argc, *argv; { fputs(VERSION, stderr); fputs(CRIGHT1, stderr); argcs = argc; argvs = argv; swnext = calloc(SWTABSZ, 1); swend = swnext+(SWTABSZ-SWSIZ); stage = calloc(STAGESIZE, 2*BPW); wqptr = wq = calloc(WQTABSZ, BPW); litq = calloc(LITABSZ, 1); macn = calloc(MACNSIZE, 1); macq = calloc(MACQSIZE, 1); pline = calloc(LINESIZE, 1); mline = calloc(LINESIZE, 1); slast = stage+(STAGESIZE*2*BPW); symtab = calloc((NUMLOCS*SYMAVG + NUMGLBS*SYMMAX), 1); locptr = STARTLOC; glbptr = STARTGLB; ask(); /* get user options */ openfile(); /* and initial input file */ preprocess(); /* fetch first line */ header(); /* intro code */ setcodes(); /* initialize code pointer array */ parse(); /* process ALL input */ trailer(); /* follow-up code */ fclose(output); /* explicitly close output */ } /******************** high level parsing *******************/ /* ** process all input text ** ** At this level, only static declarations, ** defines, includes and function ** definitions are legal... */ parse() { while (eof == 0) { if (amatch("extern", 6)) dodeclare(EXTERNAL); else if(dodeclare(STATIC)) ; else if( match("#asm")) doasm(); else if( match("#include")) doinclude(); else if( match("#define")) dodefine(); else dofunction(); blanks(); /* force eof if pending */ } } /* ** test for global declarations */ dodeclare(class) int class; { if (amatch("char", 4)) declglb(CHR, class); else if(amatch("unsigned", 8)) { if (amatch("char", 4)) declglb(UCHR, class); else {amatch("int", 3); declglb(UINT, class);} } else if(amatch("int", 3) || class == EXTERNAL) declglb(INT, class); else return 0; ns(); return 1; } /* ** declare a static variable */ declglb(type, class) int type, class; { int id, dim; while(1) { if(endst()) return; /* do line */ if(match("*")) {id = POINTER; dim = 0;} else {id = VARIABLE; dim = 1;} if(symname(ssname) == 0) illname(); if(findglb(ssname)) multidef(ssname); if(id == VARIABLE) { if (match("(")) {id = FUNCTION; need(")");} else if(match("[")) {id = ARRAY; dim = needsub();} } if (class == EXTERNAL) external(ssname, type >> 2, id); else if( id != FUNCTION) initials(type >> 2, id, dim); if(id == POINTER) addsym(ssname, id, type, BPW, 0, &glbptr, class); else addsym(ssname, id, type, dim * (type >> 2), 0, &glbptr, cla ss); if(match(",") == 0) return; } } /* ** initialize global objects */ initials(size, ident, dim) int size, ident, dim; { int savedim; litptr = 0; if(dim == 0) dim = -1; /* *... or ...[] */ savedim = dim; public(ident); if(match("=")) { if(match("{")) { while(dim) { init(size, ident, &dim); if(match(",") == 0) break; } need("}"); } else init(size, ident, &dim); } if(savedim == -1 && dim == -1) { if(ident == ARRAY) error("need array size"); stowlit(0, size = BPW); } dumplits(size); dumpzero(size, dim); /* only if dim > 0 */ } /* ** evaluate one initializer */ init(size, ident, dim) int size, ident, *dim; { int value; if(string(&value)) { if(ident == VARIABLE || size != 1) error("must assign to char pointer or char array"); *dim -= (litptr - value); if(ident == POINTER) point(); } else if(constexpr(&value)) { if(ident == POINTER) error("cannot assign to pointer"); stowlit(value, size); *dim -= 1; } } /* ** get required array size */ needsub() { int val; if(match("]")) return 0; /* null size */ if(constexpr(&val) == 0) val = 1; if(val < 0) { error("negative size illegal"); val = -val; } need("]"); /* force single dimension */ return val; /* and return size */ } /* ** open an include file */ doinclude() { int i; char str[30]; blanks(); /* skip over to name */ if(*lptr == '"' || *lptr == '<') ++lptr; i = 0; while(lptr[i] && lptr[i] != '"' && lptr[i] != '>' && lptr[i] != '\n') { str[i] = lptr[i]; ++i; } str[i] = NULL; if((input2 = fopen(str,"r")) == NULL) { input2 = EOF; error("open failure on include file"); } kill(); /* make next read come from new file (if open) */ } /* ** define a macro symbol */ dodefine() { int k; if(symname(msname) == 0) { illname(); kill(); return; } k = 0; if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) { if(cptr2 = cptr) while(*cptr2++ = msname[k++]) ; else { error("macro name table full"); return; } } putint(macptr, cptr+NAMESIZE, 2); while(white()) gch(); while(putmac(gch())); if(macptr >= MACMAX) { error("macro string queue full"); abort(ERRCODE); } } putmac(c) char c; { macq[macptr] = c; if(macptr < MACMAX) ++macptr; return c; } /* ** begin a function ** ** called from "parse" and tries to make a function ** out of the following text */ dofunction() { char *ptr; nogo = /* enable goto statements */ noloc = /* enable block-local declarations */ lastst = /* no statement yet */ litptr = 0; /* clear lit pool */ litlab = getlabel(); /* label next lit pool */ locptr = STARTLOC; /* clear local variables */ if(match("void")) blanks(); /* skip "void" & locate header * / if(monitor) lout(line, stderr); if(symname(ssname) == 0) { error("illegal function or declaration"); errflag = 0; kill(); /* invalidate line */ return; } if(ptr = findglb(ssname)) { /* already in symbol table? */ if(ptr[CLASS] == AUTOEXT) ptr[CLASS] = STATIC; else multidef(ssname); } else addsym(ssname, FUNCTION, INT, 0, 0, &glbptr, STATIC); public(FUNCTION); argstk = 0; /* init arg count */ if(match("(") == 0) error("no open paren"); while(match(")") == 0) { /* then count args */ if(symname(ssname)) { if(findloc(ssname)) multidef(ssname); else { addsym(ssname, 0, 0, 0, argstk, &locptr, AUTOMATIC); argstk += BPW; } } else { error("illegal argument name"); skip(); } blanks(); if(streq(lptr,")") == 0 && match(",") == 0) error("no comma"); if(endst()) break; } csp = 0; /* preset stack ptr */ argtop = argstk+BPW; /* account for the pushed BP */ while(argstk) { if (amatch("char", 4)) {doargs(CHR); ns();} else if(amatch("int", 3)) {doargs(INT); ns();} else if(amatch("unsigned", 8)) { if (amatch("char", 4)) {doargs(UCHR); ns();} else {amatch("int", 3); doargs(UINT); ns();} } else {error("wrong number of arguments"); break;} } gen(ENTER, 0); statement(); if(lastst != STRETURN && lastst != STGOTO) gen(RETURN, 0); if(litptr) { toseg(DATASEG); gen(REFm, litlab); dumplits(1); /* dump literals */ } } /* ** declare argument types */ doargs(type) int type; { int id, sz; char c, *ptr; while(1) { if(argstk == 0) return; /* no arguments */ if(decl(type, POINTER, &id, &sz)) { if(ptr = findloc(ssname)) { ptr[IDENT] = id; ptr[TYPE] = type; putint(sz, ptr+SIZE, 2); putint(argtop-getint(ptr+OFFSET, 2), ptr+OFFSET, 2); } else error("not an argument"); } argstk = argstk - BPW; /* cnt down */ if(endst()) return; if(match(",") == 0) error("no comma"); } } /* ** parse next local or argument declaration */ decl(type, aid, id, sz) int type, aid, *id, *sz; { int n, p; if(match("(")) p = 1; else p = 0; if(match("*")) {*id = POINTER; *sz = BPW;} else {*id = VARIABLE; *sz = type >> 2;} if((n = symname(ssname)) == 0) illname(); if(p && match(")")) ; if(match("(")) { if(!p || *id != POINTER) error("try (*...)()"); need(")"); } else if(*id == VARIABLE && match("[")) { *id = aid; if((*sz *= needsub()) == 0) { if(aid == ARRAY) error("need array size"); *sz = BPW; /* size of pointer argument */ } } return n; } /******************** start 2nd level parsing *******************/ /* ** statement parser */ statement() { if(ch == 0 && eof) return; else if(amatch("char", 4)) {declloc(CHR); ns();} else if(amatch("int", 3)) {declloc(INT); ns();} else if(amatch("unsigned", 8)) { if (amatch("char", 4)) {declloc(UCHR); ns();} else {amatch("int", 3); declloc(UINT); ns();} } else { if(declared >= 0) { if(ncmp > 1) nogo = declared; /* disable goto */ gen(ADDSP, csp - declared); declared = -1; } if(match("{")) compound(); else if(amatch("if", 2)) {doif(); lastst = STIF;} else if(amatch("while", 5)) {dowhile(); lastst = STWHILE;} else if(amatch("do", 2)) {dodo(); lastst = STDO;} else if(amatch("for", 3)) {dofor(); lastst = STFOR;} else if(amatch("switch", 6)) {doswitch(); lastst = STSWITCH; } else if(amatch("case", 4)) {docase(); lastst = STCASE;} else if(amatch("default", 7)) {dodefault(); lastst = STDEF;} else if(amatch("goto", 4)) {dogoto(); lastst = STGOTO;} else if(dolabel()) lastst = STLABEL; else if(amatch("return", 6)) {doreturn(); ns(); lastst = STRETURN; } else if(amatch("break", 5)) {dobreak(); ns(); lastst = STBREAK;} else if(amatch("continue", 8)) {docont(); ns(); lastst = STCONT;} else if(match(";")) errflag = 0; else if(match("#asm")) {doasm(); lastst = STASM;} else {doexpr(NO); ns(); lastst = STEXPR;} } return lastst; } /* ** declare local variables */ declloc(type) int type; { int id, sz; if(swactive) error("not allowed in switch"); if(noloc) error("not allowed with goto"); if(declared < 0) error("must declare first in block"); while(1) { if(endst()) return; decl(type, ARRAY, &id, &sz); declared += sz; addsym(ssname, id, type, sz, csp - declared, &locptr, AUTOMATIC); if(match(",") == 0) return; } } compound() { int savcsp; char *savloc; savcsp = csp; savloc = locptr; declared = 0; /* may now declare local variables */ ++ncmp; /* new level open */ while (match("}") == 0) if(eof) { error("no final }"); break; } else statement(); /* do one */ if(--ncmp /* close current level */ && lastst != STRETURN && lastst != STGOTO) gen(ADDSP, savcsp); /* delete local variable space */ cptr = savloc; /* retain labels */ while(cptr < locptr) { cptr2 = nextsym(cptr); if(cptr[IDENT] == LABEL) { while(cptr < cptr2) *savloc++ = *cptr++; } else cptr = cptr2; } locptr = savloc; /* delete local symbols */ declared = -1; /* may not declare variables */ } doif() { int flab1, flab2; test(flab1 = getlabel(), YES); /* get expr, and branch false */ statement(); /* if true, do a statement */ if(amatch("else", 4) == 0) { /* if...else ? */ /* simple "if"...print false label */ gen(LABm, flab1); return; /* and exit */ } flab2 = getlabel(); if(lastst != STRETURN && lastst != STGOTO) gen(JMPm, flab2); gen(LABm, flab1); /* print false label */ statement(); /* and do "else" clause */ gen(LABm, flab2); /* print true label */ } dowhile() { int wq[4]; /* allocate local queue */ addwhile(wq); /* add entry to queue for "break" */ gen(LABm, wq[WQLOOP]); /* loop label */ test(wq[WQEXIT], YES); /* see if true */ statement(); /* if so, do a statement */ gen(JMPm, wq[WQLOOP]); /* loop to label */ gen(LABm, wq[WQEXIT]); /* exit label */ delwhile(); /* delete queue entry */ } dodo() { int wq[4]; addwhile(wq); gen(LABm, wq[WQLOOP]); statement(); need("while"); test(wq[WQEXIT], YES); gen(JMPm, wq[WQLOOP]); gen(LABm, wq[WQEXIT]); delwhile(); ns(); } dofor() { int wq[4], lab1, lab2; addwhile(wq); lab1 = getlabel(); lab2 = getlabel(); need("("); if(match(";") == 0) { doexpr(NO); /* expr 1 */ ns(); } gen(LABm, lab1); if(match(";") == 0) { test(wq[WQEXIT], NO); /* expr 2 */ ns(); } gen(JMPm, lab2); gen(LABm, wq[WQLOOP]); if(match(")") == 0) { doexpr(NO); /* expr 3 */ need(")"); } gen(JMPm, lab1); gen(LABm, lab2); statement(); gen(JMPm, wq[WQLOOP]); gen(LABm, wq[WQEXIT]); delwhile(); } doswitch() { int wq[4], endlab, swact, swdef, *swnex, *swptr; swact = swactive; swdef = swdefault; swnex = swptr = swnext; addwhile(wq); *(wqptr + WQLOOP - WQSIZ) = 0; need("("); doexpr(YES); /* evaluate switch expression */ need(")"); swdefault = 0; swactive = 1; gen(JMPm, endlab = getlabel()); statement(); /* cases, etc. */ gen(JMPm, wq[WQEXIT]); gen(LABm, endlab); gen(SWITCH, 0); /* match cases */ while(swptr < swnext) { gen(NEARm, *swptr++); gen(WORDn, *swptr++); /* case value */ } gen(WORDn, 0); if(swdefault) gen(JMPm, swdefault); gen(LABm, wq[WQEXIT]); delwhile(); swnext = swnex; swdefault = swdef; swactive = swact; } docase() { if(swactive == 0) error("not in switch"); if(swnext > swend) { error("too many cases"); return; } gen(LABm, *swnext++ = getlabel()); constexpr(swnext++); need(":"); } dodefault() { if(swactive) { if(swdefault) error("multiple defaults"); } else error("not in switch"); need(":"); gen(LABm, swdefault = getlabel()); } dogoto() { if(nogo > 0) error("not allowed with block-locals"); else noloc = 1; if(symname(ssname)) gen(JMPm, addlabel(NO)); else error("bad label"); ns(); } dolabel() { char *savelptr; blanks(); savelptr = lptr; if(symname(ssname)) { if(gch() == ':') { gen(LABm, addlabel(YES)); return 1; } else bump(savelptr-lptr); } return 0; } addlabel(def) int def; { if(cptr = findloc(ssname)) { if(cptr[IDENT] != LABEL) error("not a label"); else if(def) { if(cptr[TYPE]) error("duplicate label"); else cptr[TYPE] = YES; } } else cptr = addsym(ssname, LABEL, def, 0, getlabel(), &locptr, LABEL); return (getint(cptr+OFFSET, 2)); } doreturn() { int savcsp; if(endst() == 0) doexpr(YES); savcsp = csp; gen(RETURN, 0); csp = savcsp; } dobreak() { int *ptr; if((ptr = readwhile(wqptr)) == 0) return; gen(ADDSP, ptr[WQSP]); gen(JMPm, ptr[WQEXIT]); } docont() { int *ptr; ptr = wqptr; while (1) { if((ptr = readwhile(ptr)) == 0) return; if(ptr[WQLOOP]) break; } gen(ADDSP, ptr[WQSP]); gen(JMPm, ptr[WQLOOP]); } doasm() { ccode = 0; /* mark mode as "asm" */ while (1) { inline(); if(match("#endasm")) break; if(eof)break; fputs(line, output); } kill(); ccode = 1; } doexpr(use) int use; { int const, val; int *before, *start; usexpr = use; /* tell isfree() whether expr value is used */ while(1) { setstage(&before, &start); expression(&const, &val); clearstage(before, start); if(ch != ',') break; bump(1); } usexpr = YES; /* return to normal value */ } /******************** miscellaneous functions *******************/ /* ** get run options */ ask() { int i; i = listfp = nxtlab = 0; output = stdout; optimize = YES; alarm = monitor = pause = NO; line = mline; while(getarg(++i, line, LINESIZE, argcs, argvs) != EOF) { if(line[0] != '-' && line[0] != '/') continue; if(toupper(line[1]) == 'L' && isdigit(line[2]) && line[3] <= ' ') { listfp = line[2]-'0'; continue; } if(toupper(line[1]) == 'N' && toupper(line[2]) == 'O' && line[3] <= ' ') { optimize = NO; continue; } if(line[2] <= ' ') { if(toupper(line[1]) == 'A') {alarm = YES; continue;} if(toupper(line[1]) == 'M') {monitor = YES; continue;} if(toupper(line[1]) == 'P') {pause = YES; continue;} } fputs("usage: cc [file]... [-m] [-a] [-p] [-l#] [-no]\n", stderr); abort(ERRCODE); } } /* ** input and output file opens */ openfile() { /* entire function revised */ char outfn[15]; int i, j, ext; input = EOF; while(getarg(++filearg, pline, LINESIZE, argcs, argvs) != EOF) { if(pline[0] == '-' || pline[0] == '/') continue; ext = NO; i = -1; j = 0; while(pline[++i]) { if(pline[i] == '.') { ext = YES; break; } if(j < 10) outfn[j++] = pline[i]; } if(!ext) strcpy(pline + i, ".C"); input = mustopen(pline, "r"); if(!files && iscons(stdout)) { strcpy(outfn + j, ".ASM"); output = mustopen(outfn, "w"); } files = YES; kill(); return; } if(files++) eof = YES; else input = stdin; kill(); } /* ** open a file with error checking */ mustopen(fn, mode) char *fn, *mode; { int fd; if(fd = fopen(fn, mode)) return fd; fputs("open error on ", stderr); lout(fn, stderr); abort(ERRCODE); } CC2.C: /* ** Small-C Compiler -- Part 2 -- Front End and Miscellaneous. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendri x ** All rights reserved. */ #include <stdio.h> #include "cc.h" extern char *symtab, *macn, *macq, *pline, *mline, optimize, alarm, *glbptr, *line, *lptr, *cptr, *cptr2, *cptr3, *locptr, msname[NAMESIZE], pause, quote[2]; extern int *wq, ccode, ch, csp, eof, errflag, iflevel, input, input2, listfp, macptr, nch, nxtlab, op[16], opindex, opsize, output, pptr, skiplevel, *wqptr; /********************** input functions **********************/ preprocess() { int k; char c; if(ccode) { line = mline; ifline(); if(eof) return; } else { inline(); return; } pptr = -1; while(ch != NEWLINE && ch) { if(white()) { keepch(' '); while(white()) gch(); } else if(ch == '"') { keepch(ch); gch(); while(ch != '"' || (*(lptr-1) == 92 && *(lptr-2) != &# 57;2)) { if(ch == NULL) { error("no quote"); break; } keepch(gch()); } gch(); keepch('"'); } else if(ch == 39) { keepch(39); gch(); while(ch != 39 || (*(lptr-1) == 92 && *(lptr-2) != 92)) { if(ch == NULL) { error("no apostrophe"); break; } keepch(gch()); } gch(); keepch(39); } else if(ch == '/' && nch == '*') { bump(2); while((ch == '*' && nch == '/') == 0) { if(ch) bump(1); else { ifline(); if(eof) break; } } bump(2); } else if(an(ch)) { k = 0; while(an(ch) && k < NAMEMAX) { msname[k++] = ch; gch(); } msname[k] = NULL; if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) { k = getint(cptr+NAMESIZE, 2); while(c = macq[k++]) keepch(c); while(an(ch)) gch(); } else { k = 0; while(c = msname[k++]) keepch(c); } } else keepch(gch()); } if(pptr >= LINEMAX) error("line too long"); keepch(NULL); line = pline; bump(0); } keepch(c) char c; { if(pptr < LINEMAX) pline[++pptr] = c; } ifline() { while(1) { inline(); if(eof) return; if(match("#ifdef")) { ++iflevel; if(skiplevel) continue; symname(msname); if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0) == 0) skiplevel = iflevel; continue; } if(match("#ifndef")) { ++iflevel; if(skiplevel) continue; symname(msname); if(search(msname, macn, NAMESIZE+2, MACNEND, MACNBR, 0)) skiplevel = iflevel; continue; } if(match("#else")) { if(iflevel) { if(skiplevel == iflevel) skiplevel = 0; else if(skiplevel == 0) skiplevel = iflevel; } else noiferr(); continue; } if(match("#endif")) { if(iflevel) { if(skiplevel == iflevel) skiplevel = 0; --iflevel; } else noiferr(); continue; } if(skiplevel) continue; if(ch == 0) continue; break; } } inline() { /* numerous revisions */ int k, unit; poll(1); /* allow operator interruption */ if(input == EOF) openfile(); if(eof) return; if((unit = input2) == EOF) unit = input; if(fgets(line, LINEMAX, unit) == NULL) { fclose(unit); if(input2 != EOF) input2 = EOF; else input = EOF; *line = NULL; } else if(listfp) { if(listfp == output) fputc(';', output); fputs(line, listfp); } bump(0); } inbyte() { while(ch == 0) { if(eof) return 0; preprocess(); } return gch(); } /********************* scanning functions ********************/ /* ** test if next input string is legal symbol name */ symname(sname) char *sname; { int k;char c; blanks(); if(alpha(ch) == 0) return (*sname = 0); k = 0; while(an(ch)) { sname[k] = gch(); if(k < NAMEMAX) ++k; } sname[k] = 0; return 1; } need(str) char *str; { if(match(str) == 0) error("missing token"); } ns() { if(match(";") == 0) error("no semicolon"); else errflag = 0; } match(lit) char *lit; { int k; blanks(); if(k = streq(lptr, lit)) { bump(k); return 1; } return 0; } streq(str1, str2) char str1[], str2[]; { int k; k = 0; while (str2[k]) { if(str1[k] != str2[k]) return 0; ++k; } return k; } amatch(lit, len) char *lit; int len; { int k; blanks(); if(k = astreq(lptr, lit, len)) { bump(k); return 1; } return 0; } astreq(str1, str2, len) char str1[], str2[]; int len; { int k; k = 0; while (k < len) { if(str1[k] != str2[k]) break; /* ** must detect end of symbol table names terminated by ** symbol length in binary */ if(str2[k] < ' ') break; if(str1[k] < ' ') break; ++k; } if(an(str1[k]) || an(str2[k])) return 0; return k; } nextop(list) char *list; { char op[4]; opindex = 0; blanks(); while(1) { opsize = 0; while(*list > ' ') op[opsize++] = *list++; op[opsize] = 0; if(opsize = streq(lptr, op)) if(*(lptr+opsize) != '=' && *(lptr+opsize) != *(lptr+opsize-1)) return 1; if(*list) { ++list; ++opindex; } else return 0; } } blanks() { while(1) { while(ch) { if(white()) gch(); else return; } if(line == mline) return; preprocess(); if(eof) break; } } white() { avail(YES); /* abort on stack/symbol table overflow */ return (*lptr <= ' ' && *lptr); } gch() { int c; if(c = ch) bump(1); return c; } bump(n) int n; { if(n) lptr += n; else lptr = line; if(ch = nch = *lptr) nch = *(lptr+1); } kill() { *line = 0; bump(0); } skip() { if(an(inbyte())) while(an(ch)) gch(); else while(an(ch) == 0) { if(ch == 0) break; gch(); } blanks(); } endst() { blanks(); return (streq(lptr, ";") || ch == 0); } /*********** symbol table management functions ***********/ addsym(sname, id, type, size, value, lgpp, class) char *sname, id, type; int size, value, *lgpp, class; { if(lgpp == &glbptr) { if(cptr2 = findglb(sname)) return cptr2; if(cptr == 0) { error("global symbol table overflow"); return 0; } } else { if(locptr > (ENDLOC-SYMMAX)) { error("local symbol table overflow"); abort(ERRCODE); } cptr = *lgpp; } cptr[IDENT] = id; cptr[TYPE] = type; cptr[CLASS] = class; putint(size, cptr + SIZE, 2); putint(value, cptr + OFFSET, 2); cptr3 = cptr2 = cptr + NAME; while(an(*sname)) *cptr2++ = *sname++; if(lgpp == &locptr) { *cptr2 = cptr2 - cptr3; /* set length */ *lgpp = ++cptr2; } return cptr; } /* ** search for symbol match ** on return cptr points to slot found or empty slot */ search(sname, buf, len, end, max, off) char *sname, *buf, *end; int len, max, off; { cptr = cptr2 = buf+((hash(sname)%(max-1))*len); while(*cptr != NULL) { if(astreq(sname, cptr+off, NAMEMAX)) return 1; if((cptr = cptr+len) >= end) cptr = buf; if(cptr == cptr2) return (cptr = 0); } return 0; } hash(sname) char *sname; { int i, c; i = 0; while(c = *sname++) i = (i << 1) + c; return i; } findglb(sname) char *sname; { if(search(sname, STARTGLB, SYMMAX, ENDGLB, NUMGLBS, NAME)) return cptr; return 0; } findloc(sname) char *sname; { cptr = locptr - 1; /* search backward for block locals */ while(cptr > STARTLOC) { cptr = cptr - *cptr; if(astreq(sname, cptr, NAMEMAX)) return (cptr - NAME); cptr = cptr - NAME - 1; } return 0; } nextsym(entry) char *entry; { entry = entry + NAME; while(*entry++ >= ' '); /* find length byte */ return entry; } /******** while queue management functions *********/ addwhile(ptr) int ptr[]; { int k; ptr[WQSP] = csp; /* and stk ptr */ ptr[WQLOOP] = getlabel(); /* and looping label */ ptr[WQEXIT] = getlabel(); /* and exit label */ if(wqptr == WQMAX) { error("control statement nesting limit"); abort(ERRCODE); } k = 0; while (k < WQSIZ) *wqptr++ = ptr[k++]; } readwhile(ptr) int *ptr; { if(ptr <= wq) { error("out of context"); return 0; } else return (ptr - WQSIZ); } delwhile() { if(wqptr > wq) wqptr -= WQSIZ; } /****************** utility functions ********************/ /* ** test if c is alphabetic */ alpha(c) char c; { return (isalpha(c) || c == '_'); } /* ** test if given character is alphanumeric */ an(c) char c; { return (alpha(c) || isdigit(c)); } /* ** return next avail internal label number */ getlabel() { return(++nxtlab); } /* ** get integer of length len from address addr ** (byte sequence set by "putint") */ getint(addr, len) char *addr; int len; { int i; i = *(addr + --len); /* high order byte sign extended */ while(len--) i = (i << 8) | *(addr + len) & 255; return i; } /* ** put integer i of length len into address addr ** (low byte first) */ putint(i, addr, len) char *addr; int i, len; { while(len--) { *addr++ = i; i = i >> 8; } } lout(line, fd) char *line; int fd; { fputs(line, fd); fputc(NEWLINE, fd); } /******************* error functions *********************/ illname() { error("illegal symbol"); skip(); } multidef(sname) char *sname; { error("already defined"); } needlval() { error("must be lvalue"); } noiferr() { error("no matching #if..."); errflag = 0; } error(msg) char msg[]; { if(errflag) return; else errflag = 1; lout(line, stderr); errout(msg, stderr); if(alarm) fputc(7, stderr); if(pause) while(fgetc(stderr) != NEWLINE); if(listfp > 0) errout(msg, listfp); } errout(msg, fp) char msg[]; int fp; { int k; k = line+2; while(k++ <= lptr) fputc(' ', fp); lout("/\\", fp); fputs("**** ", fp); lout(msg, fp); } CC3.C: /* ** Small-C Compiler -- Part 3 -- Expression Analyzer. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendri x ** All rights reserved. */ #include <stdio.h> #include "cc.h" #define ST 0 /* is[ST] - symbol table address, else 0 */ #define TI 1 /* is[TI] - type of indirect obj to fetch, else 0 */ #define TA 2 /* is[TA] - type of address, else 0 */ #define TC 3 /* is[TC] - type of constant (INT or UINT), else 0 */ #define CV 4 /* is[CV] - value of constant (+ auxiliary uses) */ #define OP 5 /* is[OP] - code of highest/last binary operator */ #define SA 6 /* is[SA] - stage address of "op 0" code, else 0 */ extern char *litq, *glbptr, *lptr, ssname[NAMESIZE], quote[2]; extern int ch, csp, litlab, litptr, nch, op[16], op2[16], opindex, opsize, *snext; /***************** lead-in functions *******************/ constexpr(val) int *val; { int const; int *before, *start; setstage(&before, &start); expression(&const, val); clearstage(before, 0); /* scratch generated code */ if(const == 0) error("must be constant expression"); return const; } expression(con, val) int *con, *val; { int is[7]; if(level1(is)) fetch(is); *con = is[TC]; *val = is[CV]; } test(label, parens) int label, parens; { int is[7]; int *before, *start; if(parens) need("("); while(1) { setstage(&before, &start); if(level1(is)) fetch(is); if(match(",")) clearstage(before, start); else break; } if(parens) need(")"); if(is[TC]) { /* constant expression */ clearstage(before, 0); if(is[CV]) return; gen(JMPm, label); return; } if(is[SA]) { /* stage address of "oper 0" code */ switch(is[OP]) { /* operator code */ case EQ12: case LE12u: zerojump(EQ10f, label, is); break; case NE12: case GT12u: zerojump(NE10f, label, is); break; case GT12: zerojump(GT10f, label, is); break; case GE12: zerojump(GE10f, label, is); break; case GE12u: clearstage(is[SA], 0); break; case LT12: zerojump(LT10f, label, is); break; case LT12u: zerojump(JMPm, label, is); break; case LE12: zerojump(LE10f, label, is); break; default: gen(NE10f, label); break; } } else gen(NE10f, label); clearstage(before, start); } /* ** test primary register against zero and jump if false */ zerojump(oper, label, is) int oper, label, is[]; { clearstage(is[SA], 0); /* purge conventional code */ gen(oper, label); } /***************** precedence levels ******************/ level1(is) int is[]; { int k, is2[7], is3[2], oper, oper2; k = down1(level2, is); if(is[TC]) gen(GETw1n, is[CV]); if(match("|=")) {oper = oper2 = OR12;} else if(match("^=")) {oper = oper2 = XOR12;} else if(match("&=")) {oper = oper2 = AND12;} else if(match("+=")) {oper = oper2 = ADD12;} else if(match("-=")) {oper = oper2 = SUB12;} else if(match("*=")) {oper = MUL12; oper2 = MUL12u;} else if(match("/=")) {oper = DIV12; oper2 = DIV12u;} else if(match("%=")) {oper = MOD12; oper2 = MOD12u;} else if(match(">>=")) {oper = oper2 = ASR12;} else if(match("<<=")) {oper = oper2 = ASL12;} else if(match("=")) {oper = oper2 = 0;} else return k; /* have an assignment operator */ if(k == 0) { needlval(); return 0; } is3[ST] = is[ST]; is3[TI] = is[TI]; if(is[TI]) { /* indirect target */ if(oper) { /* ?= */ gen(PUSH1, 0); /* save address */ fetch(is); /* fetch left side */ } down2(oper, oper2, level1, is, is2); /* parse right side */ if(oper) gen(POP2, 0); /* retrieve address */ } else { /* direct target */ if(oper) { /* ?= */ fetch(is); /* fetch left side */ down2(oper, oper2, level1, is, is2); /* parse right side */ } else { /* = */ if(level1(is2)) fetch(is2); /* parse right side */ } } store(is3); /* store result */ return 0; } level2(is1) int is1[]; { int is2[7], is3[7], k, flab, endlab, *before, *after; k = down1(level3, is1); /* expression 1 */ if(match("?") == 0) return k; dropout(k, NE10f, flab = getlabel(), is1); if(down1(level2, is2)) fetch(is2); /* expression 2 */ else if(is2[TC]) gen(GETw1n, is2[CV]); need(":"); gen(JMPm, endlab = getlabel()); gen(LABm, flab); if(down1(level2, is3)) fetch(is3); /* expression 3 */ else if(is3[TC]) gen(GETw1n, is3[CV]); gen(LABm, endlab); is1[TC] = is1[CV] = 0; if(is2[TC] && is3[TC]) { /* expr1 ? const2 : const3 */ is1[TA] = is1[TI] = is1[SA] = 0; } else if(is3[TC]) { /* expr1 ? var2 : const3 */ is1[TA] = is2[TA]; is1[TI] = is2[TI]; is1[SA] = is2[SA]; } else if((is2[TC]) /* expr1 ? const2 : var3 */ || (is2[TA] == is3[TA])) { /* expr1 ? same2 : same3 */ is1[TA] = is3[TA]; is1[TI] = is3[TI]; is1[SA] = is3[SA]; } else error("mismatched expressions"); return 0; } level3 (is) int is[]; {return skim("||", EQ10f, 1, 0, le vel4, is);} level4 (is) int is[]; {return skim("&&", NE10f, 0, 1, le vel5, is);} level5 (is) int is[]; {return down("|", 0, level6, is);} level6 (is) int is[]; {return down("^", 1, level7, is);} level7 (is) int is[]; {return down("&", 2, level8, is);} level8 (is) int is[]; {return down("== !=", 3, level9, is);} level9 (is) int is[]; {return down("<= >= < >", 5 , level10, is);} level10(is) int is[]; {return down(">> <<", 9, level11, is);} level11(is) int is[]; {return down("+ -", 11, le vel12, is);} level12(is) int is[]; {return down("* / %", 13, level1 3, is);} level13(is) int is[]; { int k; char *ptr; if(match("++")) { /* ++lval */ if(level13(is) == 0) { needlval(); return 0; } step(rINC1, is, 0); return 0; } else if(match("--")) { /* --lval */ if(level13(is) == 0) { needlval(); return 0; } step(rDEC1, is, 0); return 0; } else if(match("~")) { /* ~ */ if(level13(is)) fetch(is); gen(COM1, 0); is[CV] = ~ is[CV]; return (is[SA] = 0); } else if(match("!")) { /* ! */ if(level13(is)) fetch(is); gen(LNEG1, 0); is[CV] = ! is[CV]; return (is[SA] = 0); } else if(match("-")) { /* unary - */ if(level13(is)) fetch(is); gen(ANEG1, 0); is[CV] = -is[CV]; return (is[SA] = 0); } else if(match("*")) { /* unary * */ if(level13(is)) fetch(is); if(ptr = is[ST]) is[TI] = ptr[TYPE]; else is[TI] = INT; is[SA] = /* no (op 0) stage address */ is[TA] = /* not an address */ is[TC] = 0; /* not a constant */ is[CV] = 1; /* omit fetch() on func call */ return 1; } else if(amatch("sizeof", 6)) { /* sizeof() */ int sz, p; char *ptr, sname[NAMESIZE]; if(match("(")) p = 1; else p = 0; sz = 0; if (amatch("unsigned", 8)) sz = BPW; if (amatch("int", 3)) sz = BPW; else if(amatch("char", 4)) sz = 1; if(sz) {if(match("*")) sz = BPW;} else if(symname(sname) && ((ptr = findloc(sname)) || (ptr = findglb(sname))) && ptr[IDENT] != FUNCTION && ptr[IDENT] != LABEL) sz = getint(ptr+SIZE, 2); else if(sz == 0) error("must be object or type"); if(p) need(")"); is[TC] = INT; is[CV] = sz; is[TA] = is[TI] = is[ST] = 0; return 0; } else if(match("&")) { /* unary & */ if(level13(is) == 0) { error("illegal address"); return 0; } ptr = is[ST]; is[TA] = ptr[TYPE]; if(is[TI]) return 0; gen(POINT1m, ptr); is[TI] = ptr[TYPE]; return 0; } else { k = level14(is); if(match("++")) { /* lval++ */ if(k == 0) { needlval(); return 0; } step(rINC1, is, rDEC1); return 0; } else if(match("--")) { /* lval-- */ if(k == 0) { needlval(); return 0; } step(rDEC1, is, rINC1); return 0; } else return k; } } level14(is) int *is; { int k, const, val; char *ptr, *before, *start; k = primary(is); ptr = is[ST]; blanks(); if(ch == '[' || ch == '(') { int is2[7]; /* allocate only if needed */ while(1) { if(match("[")) { /* [subscript] */ if(ptr == 0) { error("can't subscript"); skip(); need("]"); return 0; } if(is[TA]) {if(k) fetch(is);} else {error("can't subscript"); k = 0;} setstage(&before, &start); is2[TC] = 0; down2(0, 0, level1, is2, is2); need("]"); if(is2[TC]) { clearstage(before, 0); if(is2[CV]) { /* only add if non-zero */ if(ptr[TYPE] >> 2 == BPW) gen(GETw2n, is2[CV] << LBPW); else gen(GETw2n, is2[CV]); gen(ADD12, 0); } } else { if(ptr[TYPE] >> 2 == BPW) gen(DBL1, 0); gen(ADD12, 0); } is[TA] = 0; is[TI] = ptr[TYPE]; k = 1; } else if(match("(")) { /* function(...) */ if(ptr == 0) callfunc(0); else if(ptr[IDENT] != FUNCTION) { if(k && !is[CV]) fetch(is); callfunc(0); } else callfunc(ptr); k = is[ST] = is[TC] = is[CV] = 0; } else return k; } } if(ptr && ptr[IDENT] == FUNCTION) { gen(POINT1m, ptr); is[ST] = 0; return 0; } return k; } primary(is) int *is; { char *ptr, sname[NAMESIZE]; int k; if(match("(")) { /* (subexpression) */ do k = level1(is); while(match(",")); need(")"); return k; } putint(0, is, 7 << LBPW); /* clear "is" array */ if(symname(sname)) { /* is legal symbol */ if(ptr = findloc(sname)) { /* is local */ if(ptr[IDENT] == LABEL) { experr(); return 0; } gen(POINT1s, getint(ptr+OFFSET, 2)); is[ST] = ptr; is[TI] = ptr[TYPE]; if(ptr[IDENT] == ARRAY) { is[TA] = ptr[TYPE]; return 0; } if(ptr[IDENT] == POINTER) { is[TI] = UINT; is[TA] = ptr[TYPE]; } return 1; } if(ptr = findglb(sname)) { /* is global */ is[ST] = ptr; if(ptr[IDENT] != FUNCTION) { if(ptr[IDENT] == ARRAY) { gen(POINT1m, ptr); is[TI] = is[TA] = ptr[TYPE]; return 0; } if(ptr[IDENT] == POINTER) is[TA] = ptr[TYPE]; return 1; } } else is[ST] = addsym(sname, FUNCTION, INT, 0, 0, &glbptr, AUTOEXT); return 0; } if(constant(is) == 0) experr(); return 0; } experr() { error("invalid expression"); gen(GETw1n, 0); skip(); } callfunc(ptr) char *ptr; { /* symbol table entry or 0 */ int nargs, const, val; nargs = 0; blanks(); /* already saw open paren */ while(streq(lptr, ")") == 0) { if(endst()) break; if(ptr) { expression(&const, &val); gen(PUSH1, 0); } else { gen(PUSH1, 0); expression(&const, &val); gen(SWAP1s, 0); /* don't push addr */ } nargs = nargs + BPW; /* count args*BPW */ if(match(",") == 0) break; } need(")"); if(streq(ptr + NAME, "CCARGC") == 0) gen(ARGCNTn, nargs >> LBPW); if(ptr) gen(CALLm, ptr); else gen(CALL1, 0); gen(ADDSP, csp + nargs); } /* ** true if is2's operand should be doubled */ double(oper, is1, is2) int oper, is1[], is2[]; { if((oper != ADD12 && oper != SUB12) || (is1[TA] >> 2 != BPW) || (is2[TA])) return 0; return 1; } step(oper, is, oper2) int oper, is[], oper2; { fetch(is); gen(oper, is[TA] ? (is[TA] >> 2) : 1); store(is); if(oper2) gen(oper2, is[TA] ? (is[TA] >> 2) : 1); } store(is) int is[]; { char *ptr; if(is[TI]) { /* putstk */ if(is[TI] >> 2 == 1) gen(PUTbp1, 0); else gen(PUTwp1, 0); } else { /* putmem */ ptr = is[ST]; if(ptr[IDENT] != POINTER && ptr[TYPE] >> 2 == 1) gen(PUTbm1, ptr); else gen(PUTwm1, ptr); } } fetch(is) int is[]; { char *ptr; ptr = is[ST]; if(is[TI]) { /* indirect */ if(is[TI] >> 2 == BPW) gen(GETw1p, 0); else { if(ptr[TYPE] & UNSIGNED) gen(GETb1pu, 0); else gen(GETb1p, 0); } } else { /* direct */ if(ptr[IDENT] == POINTER || ptr[TYPE] >> 2 == BPW) gen(GETw1m, ptr); else { if(ptr[TYPE] & UNSIGNED) gen(GETb1mu, ptr); else gen(GETb1m, ptr); } } } constant(is) int is[]; { int offset; if (is[TC] = number(is + CV)) gen(GETw1n, is[CV]); else if(is[TC] = chrcon(is + CV)) gen(GETw1n, is[CV]); else if(string(&offset)) gen(POINT1l, offset); else return 0; return 1; } number(value) int *value; { int k, minus; k = minus = 0; while(1) { if(match("+")) ; else if(match("-")) minus = 1; else break; } if(isdigit(ch) == 0) return 0; if(ch == '0') { while(ch == '0') inbyte(); if(toupper(ch) == 'X') { inbyte(); while(isxdigit(ch)) { if(isdigit(ch)) k = k*16 + (inbyte() - '0'); else k = k*16 + 10 + (toupper(inbyte()) - 'A'); } } else while (ch >= '0' && ch <= '7') k = k*8 + (inbyte() - '0'); } else while (isdigit(ch)) k = k*10 + (inbyte() - '0'); if(minus) { *value = -k; return (INT); } if((*value = k) < 0) return (UINT); else return (INT); } chrcon(value) int *value; { int k; k = 0; if(match("'") == 0) return 0; while(ch != '\'') k = (k << 8) + (litchar() & 255); gch(); *value = k; return (INT); } string(offset) int *offset; { char c; if(match(quote) == 0) return 0; *offset = litptr; while (ch != '"') { if(ch == 0) break; stowlit(litchar(), 1); } gch(); litq[litptr++] = 0; return 1; } stowlit(value, size) int value, size; { if((litptr+size) >= LITMAX) { error("literal queue overflow"); abort(ERRCODE); } putint(value, litq+litptr, size); litptr += size; } litchar() { int i, oct; if(ch != '\\' || nch == 0) return gch(); gch(); switch(ch) { case 'n': gch(); return NEWLINE; case 't': gch(); return 9; /* HT */ case 'b': gch(); return 8; /* BS */ case 'f': gch(); return 12; /* FF */ } i = 3; oct = 0; while((i--) > 0 && ch >= '0' && ch <= '7') oct = (oct << 3) + gch() - '0'; if(i == 2) return gch(); else return oct; } /***************** pipeline functions ******************/ /* ** skim over terms adjoining || and && operators */ skim(opstr, tcode, dropval, endval, level, is) char *opstr; int tcode, dropval, endval, (*level)(), is[]; { int k, droplab, endlab; droplab = 0; while(1) { k = down1(level, is); if(nextop(opstr)) { bump(opsize); if(droplab == 0) droplab = getlabel(); dropout(k, tcode, droplab, is); } else if(droplab) { dropout(k, tcode, droplab, is); gen(GETw1n, endval); gen(JMPm, endlab = getlabel()); gen(LABm, droplab); gen(GETw1n, dropval); gen(LABm, endlab); is[TI] = is[TA] = is[TC] = is[CV] = is[SA] = 0; return 0; } else return k; } } /* ** test for early dropout from || or && sequences */ dropout(k, tcode, exit1, is) int k, tcode, exit1, is[]; { if(k) fetch(is); else if(is[TC]) gen(GETw1n, is[CV]); gen(tcode, exit1); /* jumps on false */ } /* ** drop to a lower level */ down(opstr, opoff, level, is) char *opstr; int opoff, (*level)(), is[]; { int k; k = down1(level, is); if(nextop(opstr) == 0) return k; if(k) fetch(is); while(1) { if(nextop(opstr)) { int is2[7]; /* allocate only if needed */ bump(opsize); opindex += opoff; down2(op[opindex], op2[opindex], level, is, is2); } else return 0; } } /* ** unary drop to a lower level */ down1(level, is) int (*level)(), is[]; { int k, *before, *start; setstage(&before, &start); k = (*level)(is); if(is[TC]) clearstage(before, 0); /* load constant later */ return k; } /* ** binary drop to a lower level */ down2(oper, oper2, level, is, is2) int oper, oper2, (*level)(), is[], is2[]; { int *before, *start; char *ptr; setstage(&before, &start); is[SA] = 0; /* not "... op 0" syntax */ if(is[TC]) { /* consant op unknown */ if(down1(level, is2)) fetch(is2); if(is[CV] == 0) is[SA] = snext; gen(GETw2n, is[CV] << double(oper, is2, is)); } else { /* variable op unknown */ gen(PUSH1, 0); /* at start in the buffer */ if(down1(level, is2)) fetch(is2); if(is2[TC]) { /* variable op constant */ if(is2[CV] == 0) is[SA] = start; csp += BPW; /* adjust stack and */ clearstage(before, 0); /* discard the PUSH */ if(oper == ADD12) { /* commutative */ gen(GETw2n, is2[CV] << double(oper, is, is2)); } else { /* non-commutative */ gen(MOVE21, 0); gen(GETw1n, is2[CV] << double(oper, is, is2)); } } else { /* variable op variable */ gen(POP2, 0); if(double(oper, is, is2)) gen(DBL1, 0); if(double(oper, is2, is)) gen(DBL2, 0); } } if(oper) { if(nosign(is) || nosign(is2)) oper = oper2; if(is[TC] = is[TC] & is2[TC]) { /* constant result */ is[CV] = calc(is[CV], oper, is2[CV]); clearstage(before, 0); if(is2[TC] == UINT) is[TC] = UINT; } else { /* variable result */ gen(oper, 0); if(oper == SUB12 && is [TA] >> 2 == BPW && is2[TA] >> 2 == BPW) { /* difference of two word addresses */ gen(SWAP12, 0); gen(GETw1n, 1); gen(ASR12, 0); /* div by 2 */ } is[OP] = oper; /* identify the operator */ } if(oper == SUB12 || oper == ADD12) { if(is[TA] && is2[TA]) /* addr +/- addr */ is[TA] = 0; else if(is2[TA]) { /* value +/- addr */ is[ST] = is2[ST]; is[TI] = is2[TI]; is[TA] = is2[TA]; } } if(is[ST] == 0 || ((ptr = is2[ST]) && (ptr[TYPE] & UNSIGNED))) is[ST] = is2[ST]; } } /* ** unsigned operand? */ nosign(is) int is[]; { char *ptr; if(is[TA] || is[TC] == UINT || ((ptr = is[ST]) && (ptr[TYPE] & UNSIGNED)) ) return 1; return 0; } /* ** calcualte signed constant result */ calc(left, oper, right) int left, oper, right; { switch(oper) { case ADD12: return (left + right); case SUB12: return (left - right); case MUL12: return (left * right); case DIV12: return (left / right); case MOD12: return (left % right); case EQ12: return (left == right); case NE12: return (left != right); case LE12: return (left <= right); case GE12: return (left >= right); case LT12: return (left < right); case GT12: return (left > right); case AND12: return (left & right); case OR12: return (left | right); case XOR12: return (left ^ right); case ASR12: return (left >> right); case ASL12: return (left << right); } return (calc2(left, oper, right)); } /* ** calcualte unsigned constant result */ calc2(left, oper, right) unsigned left, right; int oper; { switch(oper) { case MUL12u: return (left * right); case DIV12u: return (left / right); case MOD12u: return (left % right); case LE12u: return (left <= right); case GE12u: return (left >= right); case LT12u: return (left < right); case GT12u: return (left > right); } return (0); } CC4.C: /* ** Small-C Compiler -- Part 4 -- Back End. ** Copyright 1982, 1983, 1985, 1988 J. E. Hendri x ** All rights reserved. */ #include <stdio.h> #include "cc.h" /* #define DISOPT */ /* display optimizations values */ /*************************** externals ****************************/ extern char *cptr, *macn, *litq, *symtab, optimize, ssname[NAMESIZE]; extern int *stage, litlab, litptr, csp, output, oldseg, usexpr, *snext, *stail, *slast; /***************** optimizer command definitions ******************/ /* -- p-codes must not overlap these */ #define any 0x00FF /* matches any p-code */ #define _pop 0x00FE /* matches if corresponding POP2 e 0;ists */ #define pfree 0x00FD /* matches if pri register free */ #define sfree 0x00FC /* matches if sec register free */ #define comm 0x00FB /* matches if registers are commutativ e */ /* -- these digits are reserved for n */ #define go 0x0100 /* go n entries */ #define gc 0x0200 /* get code from n entries away */ #define gv 0x0300 /* get value from n entries away * / #define sum 0x0400 /* add value from nth entry away * / #define neg 0x0500 /* negate the value */ #define ife 0x0600 /* if value == n do commands to ne xt 0 */ #define ifl 0x0700 /* if value < n do commands t o next 0 */ #define swv 0x0800 /* swap value with value n entries away */ #define topop 0x0900 /* moves |code and current val ue to POP2 */ #define p1 0x0001 /* plus 1 */ #define p2 0x0002 /* plus 2 */ #define p3 0x0003 /* plus 3 */ #define p4 0x0004 /* plus 4 */ #define m1 0x00FF /* minus 1 */ #define m2 0x00FE /* minus 2 */ #define m3 0x00FD /* minus 3 */ #define m4 0x00FC /* minus 4 */ #define PRI 0030 /* primary register bits */ #define SEC 0003 /* secondary register bits */ #define USES 0011 /* use register contents */ #define ZAPS 0022 /* zap register contents */ #define PUSHES 0100 /* pushes onto the stack */ #define COMMUTES 0200 /* commutative p-code */ /******************** optimizer command lists *********************/ int seq00[] = {0,ADD12,MOVE21,0, /* ADD21 */ go|p1,ADD21,0}, seq01[] = {0,ADD1n,0, /* rINC 1 or rDEC1 ? */ ifl|m2,0,ifl|0,rDEC1,neg,0,ifl|p3,rINC1,0,& #48;}, seq02[] = {0,ADD2n,0, /* rINC2 or rDE C2 ? */ ifl|m2,0,ifl|0,rDEC2,neg,0,ifl|p3,rINC2,0,0}, seq03[] = {0,rDEC1,PUTbp1,rINC1,0, /* SUBbpn or DECbp */ go|p2,ife|p1,DECbp,0,SUBbpn,0}, seq04[] = {0,rDEC1,PUTwp1,rINC1,0, /* SUBwpn or DECwp */ go|p2,ife|p1,DECwp,0,SUBwpn,0}, seq05[] = {0,rDEC1,PUTbm1,rINC1,0, /* SUB_m_ COMMAn */ go|p1,SUB_m_,go|p1,COMMAn,go|m1,0}, seq06[] = {0,rDEC1,PUTwm1,rINC1,0, /* SUB_m_ COMMAn */ go|p1,SUB_m_,go|p1,COMMAn,go|m1,0}, seq07[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1p,0, /* GETw2m GETb1p */ go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, seq08[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1pu,0, /* GETw2m GETb1pu */ go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, seq09[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETw1p, 8;, /* GETw2m GETw1p */ go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, seq10[] = {0,GETw1m,GETw2m,SWAP12,0, /* GETw2m GETw1m */ go|p2,GETw1m,gv|m1,go|m1,gv|m1,0}, seq11[] = {0,GETw1m,MOVE21,0, /* GETw2m */ go|p1,GETw2m,gv|m1,0}, seq12[] = {0,GETw1m,PUSH1,pfree,0, /* PUSH m */ go|p1,PUSHm,gv|m1,0}, seq13[] = {0,GETw1n,PUTbm1,pfree,0, /* PUT_ m_ COMMAn */ PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0}, seq14[] = {0,GETw1n,PUTwm1,pfree,0, /* PUT_ m_ COMMAn */ PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0}, seq15[] = {0,GETw1p,PUSH1,pfree,0, /* PUSH p */ go|p1,PUSHp,gv|m1,0}, seq16[] = {0,GETw1s,GETw2n,ADD12,MOVE21,0, /* GETw2s ADD2n */ go|p3,ADD2n,gv|m2,go|m1,GETw2s,gv|m2,0}, seq17[] = {0,GETw1s,GETw2s,SWAP12,0, /* GETw 2s GETw1s */ go|p2,GETw1s,gv|m1,go|m1,GETw2s,gv|m1,0}, seq18[] = {0,GETw1s,MOVE21,0, /* GETw 2s */ go|p1,GETw2s,gv|m1,0}, seq19[] = {0,GETw2m,GETw1n,SWAP12,SUB12,0, /* GETw1m SUB1n */ go|p3,SUB1n,gv|m2,go|m1,GETw1m,gv|m2,0}, seq20[] = {0,GETw2n,ADD12,0, /* ADD1 n */ go|p1,ADD1n,gv|m1,0}, seq21[] = {0,GETw2s,GETw1n,SWAP12,SUB12,0, /* GETw1s SUB1n */ go|p3,SUB1n,gv|m2,go|m1,GETw1s,gv|m2,0}, seq22[] = {0,rINC1,PUTbm1,rDEC1,0, /* ADDm _ COMMAn */ go|p1,ADDm_,go|p1,COMMAn,go|m1,0}, seq23[] = {0,rINC1,PUTwm1,rDEC1,0, /* ADDm _ COMMAn */ go|p1,ADDm_,go|p1,COMMAn,go|m1,0}, seq24[] = {0,rINC1,PUTbp1,rDEC1,0, /* ADDb pn or INCbp */ go|p2,ife|p1,INCbp,0,ADDbpn,0}, seq25[] = {0,rINC1,PUTwp1,rDEC1,0, /* ADDw pn or INCwp */ go|p2,ife|p1,INCwp,0,ADDwpn,0}, seq26[] = {0,MOVE21,GETw1n,SWAP12,SUB12,0, /* SUB1n */ go|p3,SUB1n,gv|m2,0}, seq27[] = {0,MOVE21,GETw1n,comm,0, /* GETw2n c omm */ go|p1,GETw2n,0}, seq28[] = {0,POINT1m,GETw2n,ADD12,MOVE21,0, /* POIN T2m_ PLUSn */ go|p3,PLUSn,gv|m2,go|m1,POINT2m_,gv|m2,0}, seq29[] = {0,POINT1m,MOVE21,pfree,0, /* POIN T2m */ go|p1,POINT2m,gv|m1,0}, seq30[] = {0,POINT1m,PUSH1,pfree,_pop,0, /* ... POINT2m */ topop|POINT2m,go|p2,0}, seq31[] = {0,POINT1s,GETw2n,ADD12,MOVE21,0, /* POINT2s */ sum|p1,go|p3,POINT2s,gv|m3,0}, seq32[] = {0,POINT1s,PUSH1,MOVE21,0, /* POIN T2s PUSH2 */ go|p1,POINT2s,gv|m1,go|p1,PUSH2,go|m1,0}, seq33[] = {0,POINT1s,PUSH1,pfree,_pop,0, /* ... POIN T2s */ topop|POINT2s,go|p2,0}, seq34[] = {0,POINT1s,MOVE21,0, /* POINT2s */ go|p1,POINT2s,gv|m1,0}, seq35[] = {0,POINT2m,GETb1p,sfree,0, /* GETb1m * / go|p1,GETb1m,gv|m1,0}, seq36[] = {0,POINT2m,GETb1pu,sfree,0, /* GETb1mu */ go|p1,GETb1mu,gv|m1,0}, seq37[] = {0,POINT2m,GETw1p,sfree,0, /* GETw1m * / go|p1,GETw1m,gv|m1,0}, seq38[] = {0,POINT2m_,PLUSn,GETw1p,sfree,0, /* GETw1m_ PLUSn */ go|p2,gc|m1,gv|m1,go|m1,GETw1m_,gv|m1,0}, seq39[] = {0,POINT2s,GETb1p,sfree,0, /* GETb1 ;s */ sum|p1,go|p1,GETb1s,gv|m1,0}, seq40[] = {0,POINT2s,GETb1pu,sfree,0, /* GETb1 ;su */ sum|p1,go|p1,GETb1su,gv|m1,0}, seq41[] = {0,POINT2s,GETw1p,PUSH1,pfree,0, /* PUSH s */ sum|p1,go|p2,PUSHs,gv|m2,0}, seq42[] = {0,POINT2s,GETw1p,sfree,0, /* GETw1s * / sum|p1,go|p1,GETw1s,gv|m1,0}, seq43[] = {0,PUSH1,any,POP2,0, /* MOVE21 a ny */ go|p2,gc|m1,gv|m1,go|m1,MOVE21,0}, seq44[] = {0,PUSHm,_pop,0, /* ... GETw2m */ topop|GETw2m,go|p1,0}, seq45[] = {0,PUSHp,any,POP2,0, /* GETw2p ... */ go|p2,gc|m1,gv|m1,go|m1,GETw2p,gv|m1,0}, seq46[] = {0,PUSHs,_pop,0, /* ... GETw2s */ topop|GETw2s,go|p1,0}, seq47[] = {0,SUB1n,0, /* rDEC1 or rINC1 ? */ ifl|m2,0,ifl|0,rINC1,neg,0,ifl|p3,rDEC1,0,& #48;}; #define HIGH_SEQ 47 int seq[HIGH_SEQ + 1]; setseq() { seq[ 0] = seq00; seq[ 1] = seq01; seq[ 2] = seq0 2; seq[ 3] = seq03; seq[ 4] = seq04; seq[ 5] = seq05; seq[ 6] = seq06; seq[ 7] = se q07; seq[ 8] = seq08; seq[ 9] = seq09; seq[10] = seq1 0; seq[11] = seq11; seq[12] = seq12; seq[13] = seq13; seq[14] = seq14; seq[15] = seq15; seq[16] = seq16; seq[17] = seq17; seq[18] = seq18; seq[19] = seq19; seq[20] = seq20; seq[21] = seq21; seq[22] = seq22; seq[23] = seq23; seq[24] = seq24; seq[25] = seq25; seq[26] = seq26; seq[27] = seq27; seq[28] = seq28; seq[29] = seq29; seq[30] = seq30; seq[3 9;] = seq31; seq[32] = seq32; seq[33] = seq33; seq[34] = seq34; seq[35] = seq35; seq[36] = seq36; seq[37] = seq37; seq[38] = seq38; seq[39] = seq39; seq[40] = seq40; seq[41] = seq41; seq[42] = seq42; seq[43] = seq43; seq[44] = seq44; seq[45] = seq45; seq[46] = seq46; seq[47] = seq47; } /***************** assembly-code strings ******************/ int code[PCODES]; /* ** First byte contains flag bits indicating: ** the value in ax is needed (010) or zapped (020) ** the value in bx is needed (001) or zapped (002) */ setcodes() { setseq(); code[ADD12] = "\211ADD AX,BX\n"; code[ADD1n] = "\010?ADD AX,<n>\n??"; code[ADD21] = "\211ADD BX,AX\n"; code[ADD2n] = "\010?ADD BX,<n>\n??"; code[ADDbpn] = "\001ADD BYTE PTR [BX],<n>\n"; code[ADDwpn] = "\001ADD WORD PTR [BX],<n>\n"; code[ADDm_] = "\000ADD <m>"; code[ADDSP] = "\000?ADD SP,<n>\n??"; code[AND12] = "\211AND AX,BX\n"; code[ANEG1] = "\010NEG AX\n"; code[ARGCNTn] = "\000?MOV CL,<n>?XOR CL,CL?\n"; code[ASL12] = "\011MOV CX,AX\nMOV AX,BX\nSAL AX,CL\n" ;; code[ASR12] = "\011MOV CX,AX\nMOV AX,BX\nSAR AX,CL\n" ;; code[CALL1] = "\010CALL AX\n"; code[CALLm] = "\020CALL <m>\n"; code[BYTE_] = "\000 DB "; code[BYTEn] = "\000 DB <n>\n"; code[BYTEr0] = "\000 DB <n> DUP(0)\n"; code[COM1] = "\010NOT AX\n"; code[COMMAn] = "\000,<n>\n"; code[DBL1] = "\010SHL AX,1\n"; code[DBL2] = "\001SHL BX,1\n"; code[DECbp] = "\001DEC BYTE PTR [BX]\n"; code[DECwp] = "\001DEC WORD PTR [BX]\n"; code[DIV12] = "\011CWD\nIDIV BX\n"; /* see gen() */ code[DIV12u] = "\011XOR DX,DX\nDIV BX\n"; /* see gen() */ code[ENTER] = "\100PUSH BP\nMOV BP,SP\n"; code[EQ10f] = "\010OR AX,AX\nJE $+5\nJMP _<n> ;\n"; code[EQ12] = "\211CALL __eq\n"; code[GE10f] = "\010OR AX,AX\nJGE $+5\nJMP _<n 2;\n"; code[GE12] = "\011CALL __ge\n"; code[GE12u] = "\011CALL __uge\n"; code[GETb1m] = "\020MOV AL,<m>\nCBW\n"; code[GETb1mu] = "\020MOV AL,<m>\nXOR AH,AH\n"; code[GETb1p] = "\021MOV AL,?<n>??[BX]\nCBW\n"; /* see gen() */ code[GETb1pu] = "\021MOV AL,?<n>??[BX]\nXOR AH,AH\n 4;; /* see gen() */ code[GETb1s] = "\020MOV AL,<n>[BP]\nCBW\n"; code[GETb1su] = "\020MOV AL,<n>[BP]\nXOR AH,AH\n"; code[GETw1m] = "\020MOV AX,<m>\n"; code[GETw1m_] = "\020MOV AX,<m>"; code[GETw1n] = "\020?MOV AX,<n>?XOR AX,AX?\n"; code[GETw1p] = "\021MOV AX,?<n>??[BX]\n"; /* see gen() */ code[GETw1s] = "\020MOV AX,<n>[BP]\n"; code[GETw2m] = "\002MOV BX,<m>\n"; code[GETw2n] = "\002?MOV BX,<n>?XOR BX,BX?\n"; code[GETw2p] = "\021MOV BX,?<n>??[BX]\n"; code[GETw2s] = "\002MOV BX,<n>[BP]\n"; code[GT10f] = "\010OR AX,AX\nJG $+5\nJMP _<n> ;\n"; code[GT12] = "\010CALL __gt\n"; code[GT12u] = "\011CALL __ugt\n"; code[INCbp] = "\001INC BYTE PTR [BX]\n"; code[INCwp] = "\001INC WORD PTR [BX]\n"; code[WORD_] = "\000 DW "; code[WORDn] = "\000 DW <n>\n"; code[WORDr0] = "\000 DW <n> DUP(0)\n"; code[JMPm] = "\000JMP _<n>\n"; code[LABm] = "\000_<n>:\n"; code[LE10f] = "\010OR AX,AX\nJLE $+5\nJMP _<n 2;\n"; code[LE12] = "\011CALL __le\n"; code[LE12u] = "\011CALL __ule\n"; code[LNEG1] = "\010CALL __lneg\n"; code[LT10f] = "\010OR AX,AX\nJL $+5\nJMP _<n> ;\n"; code[LT12] = "\011CALL __lt\n"; code[LT12u] = "\011CALL __ult\n"; code[MOD12] = "\011CWD\nIDIV BX\nMOV AX,DX\n"; /* see gen() */ code[MOD12u] = "\011XOR DX,DX\nDIV BX\nMOV AX,DX\n"; /* see gen() */ code[MOVE21] = "\012MOV BX,AX\n"; code[MUL12] = "\211IMUL BX\n"; code[MUL12u] = "\211MUL BX\n"; code[NE10f] = "\010OR AX,AX\nJNE $+5\nJMP _<n 2;\n"; code[NE12] = "\211CALL __ne\n"; code[NEARm] = "\000 DW _<n>\n"; code[OR12] = "\211OR AX,BX\n"; code[PLUSn] = "\000?+<n>??\n"; code[POINT1l] = "\020MOV AX,OFFSET _<l>+<n>\n& #34;; code[POINT1m] = "\020MOV AX,OFFSET <m>\n"; code[POINT1s] = "\020LEA AX,<n>[BP]\n"; code[POINT2m] = "\002MOV BX,OFFSET <m>\n"; code[POINT2m_]= "\002MOV BX,OFFSET <m>"; code[POINT2s] = "\002LEA BX,<n>[BP]\n"; code[POP2] = "\002POP BX\n"; code[PUSH1] = "\110PUSH AX\n"; code[PUSH2] = "\101PUSH BX\n"; code[PUSHm] = "\100PUSH <m>\n"; code[PUSHp] = "\100PUSH ?<n>??[BX]\n"; code[PUSHs] = "\100PUSH ?<n>??[BP]\n"; code[PUT_m_] = "\000MOV <m>"; code[PUTbm1] = "\010MOV <m>,AL\n"; code[PUTbp1] = "\011MOV [BX],AL\n"; code[PUTwm1] = "\010MOV <m>,AX\n"; code[PUTwp1] = "\011MOV [BX],AX\n"; code[rDEC1] = "\010#DEC AX\n#"; code[rDEC2] = "\010#DEC BX\n#"; code[REFm] = "\000_<n>"; code[RETURN] = "\000?MOV SP,BP\n??POP BP\nRET\n"; code[rINC1] = "\010#INC AX\n#"; code[rINC2] = "\010#INC BX\n#"; code[SUB_m_] = "\000SUB <m>"; code[SUB12] = "\011SUB AX,BX\n"; /* see gen() */ code[SUB1n] = "\010?SUB AX,<n>\n??"; code[SUBbpn] = "\001SUB BYTE PTR [BX],<n>\n"; code[SUBwpn] = "\001SUB WORD PTR [BX],<n>\n"; code[SWAP12] = "\011XCHG AX,BX\n"; code[SWAP1s] = "\012POP BX\nXCHG AX,BX\nPUSH BX\n"; code[SWITCH] = "\012CALL __switch\n"; code[XOR12] = "\211XOR AX,BX\n"; } /***************** code generation functions *****************/ /* ** print all assembler info before any code is generated ** and ensure that the segments appear in the correct order. */ header() { toseg(CODESEG); outline("extrn __eq: near"); outline("extrn __ne: near"); outline("extrn __le: near"); outline("extrn __lt: near"); outline("extrn __ge: near"); outline("extrn __gt: near"); outline("extrn __ule: near"); outline("extrn __ult: near"); outline("extrn __uge: near"); outline("extrn __ugt: near"); outline("extrn __lneg: near"); outline("extrn __switch: near"); outline("dw 0"); /* force non-zero code pointers, word alignment * / toseg(DATASEG); outline("dw 0"); /* force non-zero data pointers, word alignment * / } /* ** print any assembler stuff needed at the end */ trailer() { char *cp; cptr = STARTGLB; while(cptr < ENDGLB) { if(cptr[IDENT] == FUNCTION && cptr[CLASS] == AUTOEXT) external(cptr + NAME, 0, FUNCTION); cptr += SYMMAX; } if((cp = findglb("main")) && cp[CLASS]==STATIC) external("_main", 0, FUNCTION); toseg(NULL); outline("END"); #ifdef DISOPT { int i, *count; printf(";opt count\n"); for(i = -1; ++i <= HIGH_SEQ; ) { count = seq[i]; printf("; %2u %5u\n", i, *count); poll(YES); } } #endif } /* ** remember where we are in the queue in case we have to back up. */ setstage(before, start) int *before, *start; { if((*before = snext) == 0) snext = stage; *start = snext; } /* ** generate code in staging buffer. */ gen(pcode, value) int pcode, value; { int newcsp; switch(pcode) { case GETb1pu: case GETb1p: case GETw1p: gen(MOVE21, 0); break; case SUB12: case MOD12: case MOD12u: case DIV12: case DIV12u: gen(SWAP12, 0); break; case PUSH1: csp -= BPW; break; case POP2: csp += BPW; break; case ADDSP: case RETURN: newcsp = value; value -= csp; csp = newcsp; } if(snext == 0) { outcode(pcode, value); return; } if(snext >= slast) { error("staging buffer overflow"); return; } snext[0] = pcode; snext[1] = value; snext += 2; } /* ** dump the contents of the queue. ** If start = 0, throw away contents. ** If before != 0, don't dump queue yet. */ clearstage(before, start) int *before, *start; { if(before) { snext = before; return; } if(start) dumpstage(); snext = 0; } /* ** dump the staging buffer */ dumpstage() { int i; stail = snext; snext = stage; while(snext < stail) { if(optimize) { restart: i = -1; while(++i <= HIGH_SEQ) if(peep(seq[i])) { #ifdef DISOPT if(isatty(output)) fprintf(stderr, " optimized %2u\n", i); #endif goto restart; } } outcode(snext[0], snext[1]); snext += 2; } } /* ** change to a new segment ** may be called with NULL, CODESEG, or DATASEG */ toseg(newseg) int newseg; { if(oldseg == newseg) return; if(oldseg == CODESEG) outline("CODE ENDS"); else if(oldseg == DATASEG) outline("DATA ENDS"); if(newseg == CODESEG) { outline("CODE SEGMENT PUBLIC"); outline("ASSUME CS:CODE, SS:DATA, DS:DATA"); } else if(newseg == DATASEG) outline("DATA SEGMENT PUBLIC"); oldseg = newseg; } /* ** declare entry point */ public(ident) int ident;{ if(ident == FUNCTION) toseg(CODESEG); else toseg(DATASEG); outstr("PUBLIC "); outname(ssname); newline(); outname(ssname); if(ident == FUNCTION) { colon(); newline(); } } /* ** declare external reference */ external(name, size, ident) char *name; int size, ident; { if(ident == FUNCTION) toseg(CODESEG); else toseg(DATASEG); outstr("EXTRN "); outname(name); colon(); outsize(size, ident); newline(); } /* ** output the size of the object pointed to. */ outsize(size, ident) int size, ident; { if(size == 1 && ident != POINTER && ident != FUNCTION) outstr("BYTE"); else if(ident != FUNCTION) outstr("WORD"); else outstr("NEAR"); } /* ** point to following object(s) */ point() { outline(" DW $+2"); } /* ** dump the literal pool */ dumplits(size) int size; { int j, k; k = 0; while (k < litptr) { poll(1); /* allow program interruption */ if(size == 1) gen(BYTE_, NULL); else gen(WORD_, NULL); j = 10; while(j--) { outdec(getint(litq + k, size)); k += size; if(j == 0 || k >= litptr) { newline(); break; } fputc(',', output); } } } /* ** dump zeroes for default initial values */ dumpzero(size, count) int size, count; { if(count > 0) { if(size == 1) gen(BYTEr0, count); else gen(WORDr0, count); } } /******************** optimizer functions ***********************/ /* ** Try to optimize sequence at snext in the staging buffer. */ peep(seq) int *seq; { int *next, *count, *pop, n, skip, tmp, reply; char c; next = snext; count = seq++; while(*seq) { switch(*seq) { case any: if(next < stail) break; return (NO); case pfree: if(isfree(PRI, next)) break; return (NO); case sfree: if(isfree(SEC, next)) break; return (NO); case comm: if(*next & COMMUTES) break; return (NO); case _pop: if(pop = getpop(next)) break; return (NO); default: if(next >= stail || *next != *seq) return (NO); } next += 2; ++seq; } /****** have a match, now optimize it ******/ *count += 1; reply = skip = NO; while(*(++seq) || skip) { if(skip) { if(*seq == 0) skip = NO; continue; } if(*seq >= PCODES) { c = *seq & 0xFF; /* get low byte of command */ n = c; /* and sign extend into n */ switch(*seq & 0xFF00) { case ife: if(snext[1] != n) skip = YES; break; case ifl: if(snext[1] >= n) skip = YES; break; case go: snext += (n<<1); break; case gc: snext[0] = snext[(n<<1)]; got o done; case gv: snext[1] = snext[(n<<1)+1]; goto done; case sum: snext[1] += snext[(n<<1)+1]; goto done; case neg: snext[1] = -snext[1]; goto done; case topop: pop[0] = n; pop[1] = snext[1]; goto done; case swv: tmp = snext[1]; snext[1] = snext[(n<<1)+1]; snext[(n<<1)+1] = tmp; done: reply = YES; break; } } else snext[0] = *seq; /* set p-code */ } return (reply); } /* ** Is the primary or secondary register free? ** Is it zapped or unused by the p-code at pp ** or a successor? If the primary register is ** unused by it still may not be free if the ** context uses the value of the expression. */ isfree(reg, pp) int reg, *pp; { char *cp; while(pp < stail) { cp = code[*pp]; if(*cp & USES & reg) return (NO); if(*cp & ZAPS & reg) return (YES); pp += 2; } if(usexpr) return (reg & 001); /* PRI => NO, SEC => YES at end */ else return (YES); } /* ** Get place where the currently pushed value is popped? ** NOTE: Function arguments are not popped, they are ** wasted with an ADDSP. */ getpop(next) int *next; { char *cp; int level; level = 0; while(YES) { if(next >= stail) /* compiler error */ return 0; if(*next == POP2) if(level) --level; else return next; /* have a matching POP2 */ else if(*next == ADDSP) { /* after func call */ if((level -= (next[1]>>LBPW)) < 0) return 0; } else { cp = code[*next]; /* code string ptr */ if(*cp & PUSHES) ++level; /* must be a push */ } next += 2; } } /******************* output functions *********************/ colon() { fputc(':', output); } newline() { fputc(NEWLINE, output); } /* ** output assembly code. */ outcode(pcode, value) int pcode, value; { int part, skip, count; char *cp, *back; part = back = 0; skip = NO; cp = code[pcode] + 1; /* skip 1st byte of code string */ while(*cp) { if(*cp == '<') { ++cp; /* skip to action code */ if(skip == NO) switch(*cp) { case 'm': outname(value+NAME); break; /* mem ref by label */ case 'n': outdec(value); break; /* numeric constant */ case 'l': outdec(litlab); break; /* current literal label * / } cp += 2; /* skip past > */ } else if(*cp == '?') { /* ?..if value...?...if not value...? * / switch(++part) { case 1: if(value == 0) skip = YES; break; case 2: skip = !skip; break; case 3: part = 0; skip = NO; break; } ++cp; /* skip past ? */ } else if(*cp == '#') { /* repeat #...# value times */ ++cp; if(back == 0) { if((count = value) < 1) { while(*cp && *cp++ != '#') ; continue; } back = cp; continue; } if(--count > 0) cp = back; else back = 0; } else if(skip == NO) fputc(*cp++, output); else ++cp; } } outdec(number) int number; { int k, zs; char c, *q, *r; zs = 0; k = 10000; if(number < 0) { number = -number; fputc('-', output); } while (k >= 1) { q = 0; r = number; while(r >= k) {++q; r = r - k;} c = q + '0'; if(c != '0' || k == 1 || zs) { zs = 1; fputc(c, output); } number = r; k /= 10; } } outline(ptr) char ptr[]; { outstr(ptr); newline(); } outname(ptr) char ptr[]; { outstr("_"); while(*ptr >= ' ') fputc(*ptr++, output); } outstr(ptr) char ptr[]; { poll(1); /* allow program interruption */ while(*ptr >= ' ') fputc(*ptr++, output); } CCC.BAT: cc cc1 -m -a -p if errorlevel 1 goto exit asm cc1 /p if errorlevel 1 goto exit : del cc1.asm cc cc2 -m -a -p if errorlevel 1 goto exit asm cc2 /p if errorlevel 1 goto exit : del cc2.asm cc cc3 -m -a -p if errorlevel 1 goto exit asm cc3 /p if errorlevel 1 goto exit : del cc3.asm cc cc4 -m -a -p if errorlevel 1 goto exit asm cc4 /p if errorlevel 1 goto exit : del cc4.asm link cc1 cc2 cc3 cc4,cc,cc,clib.lib :exit CLIB.ARC: >>> CLIB.H 1617 /* ** CLIB.H -- Definitions for Small-C library functions. ** ** Copyright 1983 L. E. Payne and J. E. Hendrix */ /* ** Misc parameters */ #define MAXFILES 20 /* maximum open files */ #define DOSEOF 26 /* DOS end-of-file byte */ #define ARCHIVE 32 /* file archive bit */ /* ** DOS function calls */ #define CREATE 60 /* make file */ #define OPEN 61 /* open file */ #define CLOSE 62 /* close file or device */ #define READ 63 /* read from a file */ #define WRITE 64 /* write to a file */ #define DELETE 65 /* delete file */ #define SEEK 66 /* seek within a file */ #define CONTROL 68 /* control device */ #define FORCE 70 /* force use of a handle */ #define RETDOS 76 /* close files and return to DOS */ #define FNDFIL 78 /* find first occurrence of a file */ #define FNDNXT 79 /* find next occurrence of a file */ #define RENAME 86 /* rename file */ /* ** File status bits */ #define OPNBIT 1 /* open condition */ #define EOFBIT 2 /* end-of-file condition */ #define ERRBIT 4 /* error condition */ /* ** File positioning origins */ #define FROM_BEG 0 /* from beginning of file */ #define FROM_CUR 1 /* from current position */ #define FROM_END 2 /* from end of file */ /* ** Buffer usage codes ** NULL means the buffer is not used. */ #define EMPTY 1 /* buffer is currently empty */ #define IN 2 /* buffer is currently holding input data */ #define OUT 3 /* buffer is currently holding output data */ /* ** ASCII characters */ #define ABORT 3 #define RUB 8 #define PAUSE 19 #define WIPE 24 #define DEL 127 >>> ABS.C 117 /* ** abs -- returns absolute value of nbr */ abs(nbr) int nbr; { if(nbr < 0) return (-nbr); return (nb