Appendix C:
Small C Compiler Listings
_____________________________________________________________________
notice.h
_____________________________________________________________________
/*
** NOTICE.H -- Small C Signon Notice.
*/
#define VERSION "Small C, Version 2.2, Revision Level 112\n"
#define CRIGHT1 "Copyright 1982, 1983, 1985, 1988 J. E. Hendrix\n\n"
_____________________________________________________________________
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 1) */
#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[] */
_____________________________________________________________________
stdio.h
______________________________________________________________________
/*
** STDIO.H -- Standard Small C Definitions.
*/
#define stdin 0 /* file descriptor for standard input file */
#define stdout 1 /* file descriptor for standard output file */
#define stderr 2 /* file descriptor for standard error file */
#define stdaux 3 /* file descriptor for standard auxiliary port */
#define stdprn 4 /* file descriptor for standard printer */
#define FILE char /* supports "FILE *fp;" declarations */
#define ERR (-2) /* return value for errors */
#define EOF (-1) /* return value for end-of-file */
#define YES 1 /* true */
#define NO 0 /* false */
#define NULL 0 /* zero */
#define CR 13 /* ASCII carriage return */
#define LF 10 /* ASCII line feed */
#define BELL 7 /* ASCII bell */
#define SPACE ' ' /* ASCII space */
#define NEWLINE LF /* Small C newline character */
_____________________________________________________________________
cc1.c
_____________________________________________________________________
/*
** Small-C Compiler -- Part 1 -- Top End.
** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
** 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, class);
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());
else error("bad label");
ns();
}
dolabel() {
char *savelptr;
blanks();
savelptr = lptr;
if(symname(ssname)) {
if(gch() == ':') {
gen(LABm, 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, 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] != '-') 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] == '-') 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. Hendrix
** 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) != 92)) {
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("/_S0",_T fp);
fputs("**** ", fp); lout(msg, fp);
}
_____________________________________________________________________
cc3.c
_____________________________________________________________________
/*
** Small-C Compiler -- Part 3 -- Expression Analyzer.
** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
** 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, level4, is);}
level4 (is) int is[]; {return skim("&&", NE10f, 0, 1, level5, 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, level12, is);}
level12(is) int is[]; {return down("* / %", 13, level13, 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 != '_S0'_T || 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. Hendrix
** 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 exists */
#define pfree 0x00FD /* matches if pri register free */
#define sfree 0x00FC /* matches if sec register free */
#define comm 0x00FB /* matches if registers are commutative */
/* -- 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 next 0 */
#define ifl 0x0700 /* if value < n do commands to next 0 */
#define swv 0x0800 /* swap value with value n entries away */
#define topop 0x0900 /* moves |code and current value 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, /* rINC1 or rDEC1 ? */
ifl|m2,0,ifl|0,rDEC1,neg,0,ifl|p3,rINC1,0,0},
seq02[] = {0,ADD2n,0, /* rINC2 or rDEC2 ? */
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,0, /* 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, /* PUSHm */
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, /* PUSHp */
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, /* GETw2s GETw1s */
go|p2,GETw1s,gv|m1,go|m1,GETw2s,gv|m1,0},
seq18[] = {0,GETw1s,MOVE21,0, /* GETw2s */
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, /* ADD1n */
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, /* ADDbpn or INCbp */
go|p2,ife|p1,INCbp,0,ADDbpn,0},
seq25[] = {0,rINC1,PUTwp1,rDEC1,0, /* ADDwpn 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 comm */
go|p1,GETw2n,0},
seq28[] = {0,POINT1m,GETw2n,ADD12,MOVE21,0, /* POINT2m_ PLUSn */
go|p3,PLUSn,gv|m2,go|m1,POINT2m_,gv|m2,0},
seq29[] = {0,POINT1m,MOVE21,pfree,0, /* POINT2m */
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,GETb1p,0, /* GETb1s */
sum|p1,go|p4,GETb1s,gv|m4,0},
seq32[] = {0,POINT1s,GETw2n,ADD12,MOVE21,GETb1pu,0,/* GETb1su */
sum|p1,go|p4,GETb1su,gv|m4,0},
seq33[] = {0,POINT1s,GETw2n,ADD12,MOVE21,GETw1p,0, /* GETw1s */
sum|p1,go|p4,GETw1s,gv|m4,0},
seq34[] = {0,POINT1s,PUSH1,MOVE21,0, /* POINT2s PUSH2 */
go|p1,POINT2s,gv|m1,go|p1,PUSH2,go|m1,0},
seq35[] = {0,POINT1s,PUSH1,pfree,_pop,0, /* ... POINT2s */
topop|POINT2s,go|p2,0},
seq36[] = {0,POINT1s,MOVE21,0, /* POINT2s */
go|p1,POINT2s,gv|m1,0},
seq37[] = {0,POINT2m,GETb1p,sfree,0, /* GETb1m */
go|p1,GETb1m,gv|m1,0},
seq38[] = {0,POINT2m,GETb1pu,sfree,0, /* GETb1mu */
go|p1,GETb1mu,gv|m1,0},
seq39[] = {0,POINT2m,GETw1p,sfree,0, /* GETw1m */
go|p1,GETw1m,gv|m1,0},
seq40[] = {0,POINT2m_,PLUSn,GETw1p,sfree,0, /* GETw1m_ PLUSn */
go|p2,gc|m1,gv|m1,go|m1,GETw1m_,gv|m1,0},
seq41[] = {0,POINT2s,GETb1p,sfree,0, /* GETb1s */
sum|p1,go|p1,GETb1s,gv|m1,0},
seq42[] = {0,POINT2s,GETb1pu,sfree,0, /* GETb1su */
sum|p1,go|p1,GETb1su,gv|m1,0},
seq43[] = {0,POINT2s,GETw1p,PUSH1,pfree,0, /* PUSHs */
sum|p1,go|p2,PUSHs,gv|m2,0},
seq44[] = {0,POINT2s,GETw1p,sfree,0, /* GETw1s */
sum|p1,go|p1,GETw1s,gv|m1,0},
seq45[] = {0,PUSH1,any,POP2,0, /* MOVE21 any */
go|p2,gc|m1,gv|m1,go|m1,MOVE21,0},
seq46[] = {0,PUSHm,_pop,0, /* ... GETw2m */
topop|GETw2m,go|p1,0},
seq47[] = {0,PUSHp,any,POP2,0, /* GETw2p ... */
go|p2,gc|m1,gv|m1,go|m1,GETw2p,gv|m1,0},
seq48[] = {0,PUSHs,_pop,0, /* ... GETw2s */
topop|GETw2s,go|p1,0},
seq49[] = {0,SUB1n,0, /* rDEC1 or rINC1 ? */
ifl|m2,0,ifl|0,rINC1,neg,0,ifl|p3,rDEC1,0,0};
#define HIGH_SEQ 49
int seq[HIGH_SEQ + 1];
setseq() {
seq[ 0] = seq00; seq[ 1] = seq01; seq[ 2] = seq02; seq[ 3] = seq03;
seq[ 4] = seq04; seq[ 5] = seq05; seq[ 6] = seq06; seq[ 7] = seq07;
seq[ 8] = seq08; seq[ 9] = seq09; seq[10] = seq10; 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[31] = 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;
seq[48] = seq48; seq[49] = seq49;
}
/***************** 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>\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"; /* 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>\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>\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";
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)]; goto 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(toupper(*ptr++), output);
}
outstr(ptr) char ptr[]; {
poll(1); /* allow program interruption */
while(*ptr >= ' ') fputc(*ptr++, output);
}
Go to Appendix D Return to Table of Contents