kolibrios/programs/develop/scc/cc1.c

912 lines
23 KiB
C
Raw Normal View History

/*
** Small-C Compiler -- Part 1 -- Top End.
** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix
** Copyright 1998 H T Walheim
** 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 = 0, /* 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, stdout);
fputs(CRIGHT1, stdout);
fputs(CRIGHT2, stdout);
argcs = argc;
argvs = argv;
swnext = calloc(SWTABSZ, 1);
swend = swnext+(SWTABSZ-SWSIZ);
stage = calloc(STAGESIZE, 2*INTSIZE);
wqptr =
wq = calloc(WQTABSZ, INTSIZE);
litq = calloc(LITABSZ, 1);
macn = calloc(MACNSIZE, 1);
macq = calloc(MACQSIZE, 1);
pline = calloc(LINESIZE, 1);
mline = calloc(LINESIZE, 1);
slast = stage+(STAGESIZE*2*INTSIZE);
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, PTRSIZE, 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 = PTRSIZE);
}
/* FASM */
public(ident);
if(litptr>0) dumplits(size);
else if(dim>0)
{/*In FASM: "<variable>: TIMES <number> D<type> 0" */
fputc(':',output);
}
dumpzero(size, dim); /* only if dim > 0 */
/* FASM */
}
/*
** 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;
}
/*
puts (msname);
puts (" is #defined\n");
*/
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 /*INTSIZE*/);
while(white()) gch();
while(putmac(gch()));
if(macptr >= MACMAX) {
error("macro string queue full");
exit(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 += INTSIZE;
}
}
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+INTSIZE; /* 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, INTSIZE);
putint(argtop-getint(ptr+OFFSET, INTSIZE), ptr+OFFSET, INTSIZE);
}
else error("not an argument");
}
argstk = argstk - INTSIZE; /* 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;
int mod;
if(match("(")) p = 1;
else p = 0;
if(match("*")) {*id = POINTER; *sz = PTRSIZE;}
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 = PTRSIZE; /* size of pointer argument */
}
}
mod = *sz % ALIGN;
if (mod)
{
*sz = *sz + (ALIGN-mod);
}
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++);
#ifdef INT32
gen(DWORDn, *swptr++); /* case value */
#else
gen(WORDn, *swptr++); /* case value */
#endif
}
#ifdef INT32
gen(DWORDn, 0);
#else
gen(WORDn, 0);
#endif
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, INTSIZE));
}
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 constant, val;
int *before, *start;
usexpr = use; /* tell isfree() whether expr value is used */
while(1) {
setstage(&before, &start);
expression(&constant, &val);
clearstage(before, start);
if(ch != ',') break;
bump(1);
}
usexpr = YES; /* return to normal value */
}
/******************** miscellaneous functions *******************/
/*
** get run options
*/
ask()
{
int i;
int j;
i = listfp = nxtlab = 0;
output = stdout;
#ifdef LATER
optimize = YES; // Not working for 32 bit int's yer
#else
optimize = NO;
#endif
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' // List
&& isdigit(line[2])
&& line[3] <= ' ')
{
listfp = line[2]-'0';
continue;
}
if(toupper(line[1]) == 'N' // No optimize
&& toupper(line[2]) == 'O'
&& line[3] <= ' ')
{
optimize = NO;
continue;
}
if(toupper(line[1]) == 'D')
{
j = 0;
ch = line[j+2];
lptr = line + j+2;
/*
while (line[j+2] != ' ')
{
if (j < (NAMEMAX-1))
{
msname[j] = line[j+1];
++j;
}
else
{
break;
}
}
msname[j] = '\0';
*/
dodefine ();
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] [-d<id>]\n", stderr);
fputs(" -m monitor\n", stderr);
fputs(" -a alarm\n", stderr);
fputs(" -p pause\n", stderr);
fputs(" -l# list\n", stderr);
fputs(" -no no optimize\n", stderr);
fputs(" -d<id> pre-#define id\n", stderr);
exit(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");
#ifdef _MSC_VER
if(!files) {
strcpy(outfn + j, ".ASM");
output = mustopen(outfn, "w");
}
#else
if(!files /* && iscons(stdout)*/) {
strcpy(outfn + j, ".ASM");
output = mustopen(outfn, "w");
}
#endif
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);
exit(ERRCODE);
}