1967c25fac
git-svn-id: svn://kolibrios.org@718 a494cfbc-eb01-0410-851d-a64ba20cac60
912 lines
23 KiB
C
912 lines
23 KiB
C
/*
|
|
** 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);
|
|
}
|
|
|