#define EXTERN /**/
#include "mc.h"
void ntable_consistency();
static void adecl();
static int alpha();
static int binop();
int caddr();
int cadr();
int car();
static void compatible();
static void decl();
static void def();
static int digit();
static void docase();
static void docomp();
static void dodefault();
static void dodo();
static void dofor();
static void dogoto();
static void doif();
static void dolabel();
static void doswitch();
static void doreturn();
static void dowhile();
static void errmsg();
static void copy();
void error();
static int expr();
static int expr0();
static int expr1();
static int expr2();
static int expr3();
static int expr4();
static int expr5();
static int expr6();
static int expr7();
static int expr8();
static int expr9();
static int expr10();
static int expr11();
static int expr12();
static int expr13();
static int expr14();
static int expr15();
static int expr16();
static void fcheck();
static void fdecl();
static int getch();
static int getfree();
static void getline();
static void getstring();
static int getsym();
static int indop();
static void init();
static int integral();
static void lcheck();
int list2();
int list3();
int list4();
static int macroeq();
static int ndecl0();
static int ndecl1();
static int neqname();
static void newfile();
static int postequ();
static void reserve();
static void reverse();
static int rplacad();
static int rvalue();
static int scalar();
static int sdecl();
static int skipspc();
static void statement();
static int strop();
static int typeid();
static int typename();
static int typespec();
static int cexpr();
extern void exit();
extern void closing();
extern void opening();
extern void gen_gdecl();
extern void enter();
extern void enter1();
extern void leave();
extern void ret();
extern void jmp();
extern void gexpr();
extern void bexpr();
extern int fwdlabel();
extern void fwddef();
extern int backdef();
extern int def_label();
extern void jmp_label();
extern void cmpdimm();
extern void jcond();
extern void jmp_eq_label();
extern void gen_comment();
extern void gen_source();
extern void code_init();
int
main(argc,argv)
int argc;
char **argv;
{
NMTBL *nptr;
int i;
char *ccout;
if(argc==1) exit(1);
lsrc = chk = asmf = 0;
ccout = OUTPUT_FILE_NAME;
ac=argc;
av=argv;
for (ac2=1; (ac2 < ac) && (*av[ac2] == '-'); ++ac2) {
switch (*(av[ac2]+1)) {
case 'S': case 's':
lsrc = 1;
break;
case 'O': case 'o':
ccout = av[ac2]+2;
break;
case 'C': case 'c':
chk = 1;
break;
case 'D': case 'd':
debug = 1;
break;
default:
error(OPTION);
exit(1);
}
}
fclose(stdout);
if (!chk)
if ( (obuf = fopen(ccout,"w")) == NULL ) error(FILERR);
init();
while(1) {
for (nptr = &ntable[GSYMS],i=LSYMS; i--;)
(nptr++)->sc = 0;
mode=TOP;
while(getsym()==SM);
mode=GDECL;
args=0;
decl();
}
/*NOTREACHED*/
}
void
error(n)
int n;
{
if(n == EOFERR) {
if(filep!=filestack) {
fclose(filep->fcb);
fprintf(stderr,"End of inclusion.\n");
lineno=filep->ln;
--filep;
return;
} else if(ac2!=ac) {
fclose(filep->fcb);
newfile();
return;
} else if(mode == TOP) {
fprintf(stderr,"\nCompiled %u lines.\n",glineno-1);
if (!chk) fprintf(stderr,
"Total internal labels : %u.\n",labelno-1);
fprintf(stderr,
"Total global variables : %u bytes.\n\n",gpc);
closing();
exit(0);
}
}
fprintf(stderr,"%5d:%s.\n",lineno,
(n==FILERR) ? "Can't open specified file" :
(n==DCERR) ? "Declaration syntax" :
(n==STERR) ? "Statement syntax" :
(n==EXERR) ? "Expression syntax" :
(n==CNERR) ? "Constant required" :
(n==CHERR) ? "Illegal character" :
(n==GSERR) ? "Too many global symbols" :
(n==LSERR) ? "Too many local symbols" :
(n==STRERR) ? "Too many strings or macros" :
(n==LNERR) ? "Line too long" :
(n==EOFERR) ? "Unexpected end of file" :
(n==MCERR) ? "Macro syntax" :
(n==INCERR) ? "Include syntax" :
(n==HPERR) ? "Too long expression" :
(n==TYERR) ? "Type mismatch" :
(n==LVERR) ? "Lvalue required" :
(n==UDERR) ? "Undeclared identifier" :
(n==OPTION) ? "Illegal option" :
"Bug of compiler");
errmsg();
exit(1);
}
void
errmsg()
{
char *p,*lim;
if(lineno==0) return;
fprintf(stderr,"%s",linebuf);
lim=(mflag?chptrsave:chptr);
for (p=linebuf; p < lim;)
fprintf(stderr,(*p++ == '\t') ? "\t" : " ");
fprintf (stderr,"^\n");
}
void
checksym(s)
int s;
{
char *p;
if (sym != s) {
p=(s==RPAR) ? "')'": (s==RBRA) ? "']'": (s==SM) ? "';'":
(s==LPAR) ? "'('": (s==WHILE) ? "'while'":
(s==COLON) ? "':'": "Identifier";
fprintf(stderr,"%d:%s expected.\n",lineno,p);
errmsg();
} else
getsym();
}
void
init()
{
NMTBL *nptr;
int i;
cheapp=cheap;
for(nptr = ntable,i = GSYMS; i--;) (nptr++)->sc = 0;
reserve("int",INT);
reserve("void",INT);
reserve("char",CHAR);
reserve("struct",STRUCT);
reserve("union",UNION);
reserve("unsigned",UNSIGNED);
reserve("static",STATIC);
reserve("goto",GOTO);
reserve("return",RETURN);
reserve("break",BREAK);
reserve("continue",CONTINUE);
reserve("if",IF);
reserve("else",ELSE);
reserve("for",FOR);
reserve("do",DO);
reserve("while",WHILE);
reserve("switch",SWITCH);
reserve("case",CASE);
reserve("default",DEFAULT);
reserve("typedef",TYPEDEF);
reserve("sizeof",SIZEOF);
reserve("long",LONG);
reserve("short",SHORT);
reserve("extern",EXTRN);
gpc=glineno=mflag=0;
gfree=ilabel=1;
labelno=2;
lfree=HEAPSIZE;
filep=filestack;
code_init();
newfile();
getline();
getch();
}
void
newfile()
{
lineno=0;
fprintf(stderr,"%s:\n",av[ac2]);
opening(av[ac2]);
if ( (filep->fcb = fopen(av[ac2++],"r")) == NULL ) error(FILERR);
}
void
reserve(s,d)
char *s;
int d;
{
NMTBL *nptr;
int i;
hash=0; name=namebuf; i=0;
while((name[i++] = *s)) {
hash=((7*hash) ^ *s++);
}
if (cheapp+i >= cheap+CHEAPSIZE) error(STRERR);
name[i++] = 0;
(nptr = gsearch())->sc = RESERVE;
nptr->dsp = d;
}
void
decl()
{
NMTBL *n;
int t;
stmode = 0;
if(sym==STATIC) {
if(mode==LDECL) {
getsym();
mode=STADECL;
stmode=LDECL;
} else if(mode==GDECL) {
getsym();
stmode=STATIC;
} else
error(DCERR);
} else if(sym==EXTRN) {
getsym();
stmode=EXTRN;
} else if(sym==TYPEDEF) {
if(mode==GDECL) {
getsym();
mode=GTDECL;
} else if(mode==LDECL) {
getsym();
mode=LTDECL;
} else
error(DCERR);
}
if((t=typespec())==0) return;
if(sym==SM) return;
type=t;
n=decl0();
reverse(t);
if(args||sym==LC) {
fdecl(n);return;
}
def(n);
while(sym==COMMA) {
getsym();
type=t;
n=decl0();
reverse(t);
if(args) error(DCERR);
def(n);
}
if(sym!=SM) error(DCERR);
if(mode==GTDECL)
mode=GDECL;
if(mode==STADECL||mode==LTDECL)
mode=LDECL;
}
int
typespec()
{
int t;
switch(sym) {
case INT:
case CHAR:
t= sym;
getsym();
break;
case STRUCT:
case UNION:
t=sdecl(sym);
break;
case UNSIGNED:
t = UNSIGNED;
if(getsym()==INT) getsym();
break;
case SHORT:
t=CHAR;
if(getsym()==INT) getsym();
break;
case LONG:
t=INT;
if(getsym()==INT) getsym();
break;
default:
if(sym==IDENT) {
if(nptr->sc==TYPE) {
t=nptr->ty;
getsym();
break;
} else if(nptr->sc==EMPTY && gnptr->sc==TYPE) {
t=gnptr->ty;
getsym();
break;
}
}
if(mode==LDECL) return 0;
t= INT;
}
return t;
}
struct nametable *
decl0()
{
NMTBL *n;
if(sym==MUL) {
getsym();
n=decl0();
type=list2(POINTER,type);
return n;
}
return decl1();
}
NMTBL *
decl1()
{
NMTBL *n;
int i,t;
if(sym==LPAR) {
getsym();
n=decl0();
checksym(RPAR);
} else if (sym == IDENT) {
n=nptr;
getsym();
}
else error(DCERR);
while(1) {
if(sym==LBRA) {
if(getsym()==RBRA) {
getsym();
if(mode!=ADECL) error(DCERR);
t=type;
type=list2(POINTER,type);
} else {
t=type;
i=cexpr(expr());
checksym(RBRA);
type=list3(ARRAY,t,i);
}
} else if(sym==LPAR) {
if(mode==GDECL) {
mode=ADECL;getsym();mode=GDECL;
}
else
getsym();
if(sym==RPAR)
getsym();
else {
n->sc=FUNCTION;
adecl();
n->sc=EMPTY;
}
type=list2(FUNCTION,type);
} else
return n;
}
}
void
adecl()
{
if(mode!=GDECL) error(DCERR);
mode=ADECL;
args= arg_offset;
while(1) {
if(sym!=IDENT) error(DCERR);
nptr->ty = INT;
nptr->sc = LVAR;
nptr->dsp = (args += int_size);
if(getsym()!=COMMA) break;
getsym();
}
checksym(RPAR);
mode=GDECL;
return;
}
void
reverse(t1)
int t1;
{
int t2,t3;
t2=t1;
while(type!=t1) {
t3=cadr(type);
rplacad(type,t2);
t2=type;
type=t3;
}
type=t2;
}
int
size(t)
int t;
{
if(t==CHAR) return 1;
if(scalar(t)) return int_size;
if(car(t)==STRUCT||car(t)==UNION) {
if(cadr(t)==-1) error(DCERR);
return(cadr(t));
}
if(car(t)==ARRAY)
return(size(cadr(t))*caddr(t));
else
error(DCERR);
return 0;
}
void
def(n)
NMTBL *n;
{
int sz,nsc,ndsp,slfree,t,e;
char *p;
if(car(type)==FUNCTION) {
fcheck(n);
return;
}
if (n->sc!=EMPTY &&
!(n->sc==GVAR&&n->dsp==EXTRN) &&
!(n->sc==FUNCTION&&n->dsp==EXTRN) &&
(mode!=ADECL || n->sc!=LVAR || n->ty!=INT) &&
((mode!=GSDECL&&mode!=LSDECL) || n->sc!=FIELD || n->dsp!=disp) &&
((mode!=GUDECL&&mode!=LUDECL) || n->sc!=FIELD || n->dsp!=0) )
error(DCERR);
sz = size(n->ty = type);
switch(mode) {
case GDECL:
gen_gdecl(n->nm,gpc);
case STADECL:
nsc = GVAR;
ndsp = gpc;
if (stmode==EXTRN)
n->dsp = EXTRN;
else
n->dsp = ndsp; /* emit_data will override this */
n->sc = nsc;
if (stmode==LDECL) {
copy(n,n->nm);
cheapp[-1] = '.';
ndsp = ++stat_no;
while(ndsp>0) {
*cheapp++ = ndsp%10+'0';
ndsp /= 10;
}
*cheapp++ = 0;
}
if(sym==ASS) {
t=type;
if(!scalar(t))
error(TYERR);
getsym();
slfree=lfree;
e=expr1();
if(car(e)!=CONST && t==CHAR)
error(TYERR);
emit_data(e,t,n);
lfree=slfree;
type=t;
}
gpc +=sz;
return;
case GSDECL:
nsc = FIELD;
ndsp = disp;
disp += sz;
break;
case GUDECL:
nsc = FIELD;
ndsp = 0;
if (disp < sz) disp = sz;
break;
case GTDECL:
nsc = TYPE;
break;
case ADECL:
if(type==CHAR) {
if (endian)
n->dsp += int_size-1;
} else if (!scalar(type)) error(TYERR);
return;
case LDECL:
nsc = LVAR;
ndsp = (disp -= sz) + disp_offset;
break;
case LSDECL:
nsc = FIELD;
ndsp = disp;
disp += sz;
break;
case LUDECL:
nsc = FIELD;
ndsp = 0;
if (disp < sz) disp = sz;
break;
case LTDECL:
nsc = TYPE;
break;
default:
error(DCERR);
}
n->sc = nsc;
if (stmode==EXTRN)
n->dsp = EXTRN;
else
n->dsp = ndsp;
}
int
sdecl(s)
int s;
{
int smode,sdisp,type;
NMTBL *nptr0;
smode=mode;
if (mode==GDECL || mode==GSDECL || mode==GUDECL || mode==GTDECL)
mode=(s==STRUCT?GSDECL:GUDECL);
else
mode=(s==STRUCT?LSDECL:LUDECL);
sdisp=disp;
disp=0;
if (getsym() == IDENT) {
nptr0 = nptr;
if (getsym() == LC) {
if (nptr0->sc != EMPTY) error(DCERR);
nptr0->sc = TAG;
nptr0->ty = list2(s,-1);
while (getsym() != RC) decl();
getsym();
rplacad(type = nptr0->ty,disp);
} else {
if(nptr0->sc == EMPTY) nptr0=gnptr;
if(nptr0->sc == EMPTY) error(UDERR);
if(nptr0->sc != TAG) error(TYERR);
type = nptr0->ty;
}
} else if(sym==LC) {
while(getsym() != RC) decl();
getsym();
type = list2(s,disp);
}
else error(DCERR);
disp=sdisp;
mode=smode;
return type;
}
void
fdecl(n)
NMTBL *n;
{
int sretlabel;
enter(n->nm);
retlabel=fwdlabel();
args=0;
fcheck(n);
mode=ADECL;
lfree= HEAPSIZE;
while (sym!=LC) {
decl(); getsym();
}
disp=0;
mode=STAT;
while (typeid(getsym()) || sym==STATIC || sym==EXTRN || sym==TYPEDEF) {
mode=LDECL;
decl();
mode=STAT;
}
control=1;
enter1(disp);
lvar= -disp;
while(sym!=RC) statement();
leave(control,n->nm);
retpending = 0;
control=0;
retlabel=sretlabel;
}
void
fcheck(n)
NMTBL *n;
{
if(mode!=GDECL||car(type)!=FUNCTION) error(DCERR);
if(n->sc==FUNCTION) compatible(n->ty,cadr(type));
else if(n->sc!=EMPTY) error(DCERR);
n->sc=FUNCTION;
n->ty=cadr(type);
}
void
compatible(t1,t2)
int t1,t2;
{
if(integral(t1)) {
if(t1!=t2) error(TYERR);
}
else if(car(t1)!=car(t2))
error(TYERR);
else if((car(t1)==STRUCT || car(t1)==UNION) && cadr(t1)!=cadr(t2))
error(TYERR);
else if(car(t1)==POINTER || car(t1)==ARRAY ||car(t1)==FUNCTION)
compatible(cadr(t1),cadr(t2));
}
int
scalar(t)
int t;
{
return(integral(t)||car(t)==POINTER);
}
int
integral(t)
int t;
{
return(t==INT||t==CHAR||t==UNSIGNED);
}
void
checkret()
{
if (retpending) {
ret();retpending=0;
}
}
void
statement()
{
int slfree;
if(sym==SM) {
getsym(); return;
}
checkret();
switch(sym) {
case IF:
doif();
return;
case WHILE:
dowhile();
return;
case DO:
dodo();
return;
case FOR:
dofor();
return;
case SWITCH:
doswitch();
return;
case LC:
docomp();
return;
case BREAK:
jmp(blabel);
getsym();
checksym(SM);
return;
case CONTINUE:
jmp(clabel);
getsym();
checksym(SM);
return;
case CASE:
docase();
statement();
return;
case DEFAULT:
dodefault();
statement();
return;
case RETURN:
doreturn();
return;
case GOTO:
dogoto();
return;
default:
if(sym==IDENT&&skipspc()==':') {
dolabel();
statement();
} else {
slfree=lfree;
gexpr(expr());
lfree=slfree;
checksym(SM);
}
}
}
void
doif()
{
int l1,l2,slfree;
getsym();
checksym(LPAR);
slfree=lfree;
bexpr(expr(),0,l1=fwdlabel());
lfree=slfree;
checksym(RPAR);
statement();
checkret();
if(sym==ELSE) {
if ((l2 = control))
jmp(l2=fwdlabel());
fwddef(l1);
getsym();
statement();
checkret();
if (l2) fwddef(l2);
}
else fwddef(l1);
}
void
dowhile()
{
int sbreak,scontinue,slfree,e;
sbreak=blabel;
scontinue=clabel;
blabel=fwdlabel();
clabel=backdef();
getsym();
checksym(LPAR);
slfree=lfree;
e=expr();
checksym(RPAR);
if(sym==SM) {
bexpr(e,1,clabel);
lfree=slfree;
getsym();
} else {
bexpr(e,0,blabel);
lfree=slfree;
statement();
checkret();
if(control)
jmp(clabel);
}
fwddef(blabel);
clabel=scontinue;
blabel=sbreak;
}
void
dodo()
{
int sbreak,scontinue,l,slfree;
sbreak=blabel;
scontinue=clabel;
blabel=fwdlabel();
clabel=fwdlabel();
l=backdef();
getsym();
statement();
checkret();
fwddef(clabel);
checksym(WHILE);
checksym(LPAR);
slfree=lfree;
bexpr(expr(),1,l);
lfree=slfree;
checksym(RPAR);
checksym(SM);
fwddef(blabel);
clabel=scontinue;
blabel=sbreak;
}
void
dofor()
{
int sbreak,scontinue,l,e,slfree;
sbreak=blabel;
scontinue=clabel;
blabel=fwdlabel();
getsym();
checksym(LPAR);
slfree=lfree;
if(sym!=SM) {
gexpr(expr());
checksym(SM);
}
else getsym();
lfree=slfree;
l=backdef();
if(sym!=SM) {
bexpr(expr(),0,blabel);
checksym(SM);
}
else getsym();
lfree=slfree;
if(sym==RPAR) {
clabel=l;
getsym();
statement();
checkret();
} else {
clabel=fwdlabel();
e=expr();
checksym(RPAR);
statement();
checkret();
fwddef(clabel);
gexpr(e);
lfree=slfree;
}
jmp(l);
fwddef(blabel);
clabel=scontinue;
blabel=sbreak;
}
void
doswitch()
{
int sbreak,scase,sdefault,slfree,svalue;
sbreak=blabel; /* save parents break label */
blabel=fwdlabel();
sdefault=dlabel; /* save parents default label */
dlabel=0;
scase=cslabel; /* save parents next case label */
getsym();
checksym(LPAR);
slfree=lfree;
svalue=csvalue1; /* save parents switch value */
gexpr(expr());
csvalue1=csvalue ;
lfree=slfree;
checksym(RPAR);
cslabel = control = 0;
/* should be case statement but... */
statement();
checkret();
if(dlabel) def_label(cslabel,dlabel);
else fwddef(cslabel);
csvalue1=svalue;
cslabel=scase;
dlabel=sdefault;
fwddef(blabel);
blabel=sbreak;
}
void
docomp()
{
getsym();
while(sym!=RC) { statement(); checkret();}
getsym();
}
void
docase()
{
int c,l,slfree;
c=0;
slfree=lfree;
while(sym==CASE) {
getsym();
c=list2(cexpr(expr()),c);
checksym(COLON);
}
l=fwdlabel();
if (control) {
control=0;
jmp(l);
}
if (cslabel) fwddef(cslabel);
while(cadr(c)) {
cmpdimm(car(c),csvalue1);
jcond(l,0);
c=cadr(c);
}
lfree=slfree;
cmpdimm(car(c),csvalue1);
jcond(cslabel=fwdlabel(),1);
fwddef(l);
}
void
dodefault()
{
getsym();
checksym(COLON);
if (dlabel) error(STERR);
if (!cslabel) jmp(cslabel = fwdlabel());
dlabel = backdef();
}
void
doreturn()
{
int slfree;
if(getsym()==SM) {
getsym();
control=0;
retpending = 1;
return;
}
slfree=lfree;
gexpr(expr());
lfree=slfree;
checksym(SM);
control=0;
retpending = 1;
}
void
dogoto()
{
NMTBL *nptr0;
getsym();
nptr0=nptr;
checksym(IDENT);
if(nptr0->sc == BLABEL || nptr0->sc == FLABEL)
jmp(nptr0->dsp);
else if(nptr0->sc == EMPTY) {
nptr0->sc = FLABEL;
jmp(nptr0->dsp = fwdlabel());
}
else error(STERR);
checksym(SM);
}
void
dolabel()
{
if(nptr->sc == FLABEL)
fwddef(nptr->dsp);
else if(nptr->sc != EMPTY)
error(TYERR);
nptr->sc = BLABEL;
nptr->dsp = backdef();
getsym();
checksym(COLON);
}
int
expr()
{
return(rvalue(expr0()));
}
int
expr0()
{
int e;
e=expr1();
while(sym==COMMA) {
getsym();e=list3(COMMA,e,rvalue(expr1()));
}
return e;
}
int
expr1()
{
int e1,e2,t,op;
e1=expr2();
switch (sym) {
case ASS:
lcheck(e1);
t=type;
getsym();
e2=rvalue(expr1());
if(t==CHAR) {
type= INT;return(list3(CASS,e1,e2));
}
type=t;
return(list3(ASS,e1,e2));
case ADD+AS: case SUB+AS: case MUL+AS: case DIV+AS: case MOD+AS:
case RSHIFT+AS: case LSHIFT+AS: case BAND+AS: case EOR+AS: case BOR+AS:
op = sym-AS;
lcheck(e1);
t=type;
getsym();
e2=rvalue(expr1());
if(!integral(type)) error(TYERR);
if((t==UNSIGNED||type==UNSIGNED)&&
(op==MUL||op==DIV||op==MOD||op==RSHIFT||op==LSHIFT))
op=op+US;
if(t==CHAR) {
type= INT;
return(list4(CASSOP,e1,e2,op));
}
type=t;
if(integral(t)) return(list4(ASSOP,e1,e2,op));
if((op!=ADD&&op!=SUB)||car(t)!=POINTER) error(TYERR);
e2=binop(MUL,e2,list2(CONST,size(cadr(t))),INT,UNSIGNED);
type=t;
return list4(ASSOP,e1,e2,op);
default:
return(e1);
}
}
int
expr2()
{
int e1,e2,e3,t;
e1=expr3();
if(sym==COND) {
e1=rvalue(e1);
getsym();
e2=rvalue(expr2());
t=type;
checksym(COLON);
e3=rvalue(expr2());
if(car(e1)==CONST) {
if(cadr(e1)) {
type=t;return e2;
} else
return e3;
}
if(type==INT||(t!=INT&&type==UNSIGNED))
type=t;
return(list4(COND,e1,e2,e3));
}
return(e1);
}
int
expr3()
{
int e;
e=expr4();
while(sym==LOR) {
e=rvalue(e);
getsym();
e=list3(LOR,e,rvalue(expr4()));
type= INT;
}
return(e);
}
int
expr4()
{
int e;
e=expr5();
while(sym==LAND) {
e=rvalue(e);
getsym();
e=list3(LAND,e,rvalue(expr5()));
type= INT;
}
return(e);
}
int
expr5()
{
int e1,e2,t;
e1=expr6();
while(sym==BOR) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr6());
e1=binop(BOR,e1,e2,t,type);
}
return(e1);
}
int
expr6()
{
int e1,e2,t;
e1=expr7();
while(sym==EOR) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr7());
e1=binop(EOR,e1,e2,t,type);
}
return(e1);
}
int
expr7()
{
int e1,e2,t;
e1=expr8();
while(sym==BAND) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr8());
e1=binop(BAND,e1,e2,t,type);
}
return(e1);
}
int
expr8()
{
int e,op;
e=expr9();
while((op=sym)==EQ||op==NEQ) {
e=rvalue(e);
getsym();
e=list3(op,e,rvalue(expr9()));
type= INT;
}
return e;
}
int
expr9()
{
int e1,e2,t,op;
e1=expr10();
while((op=sym)==GT||op==GE||op==LT||op==LE) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr10());
if(t==INT&&type==INT)
e1=list3(op,e1,e2);
else
e1=list3(op+US,e1,e2);
type= INT;
}
return e1;
}
int
expr10()
{
int e1,e2,t,op;
e1=expr11();
while((op=sym)==RSHIFT||op==LSHIFT) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr11());
e1=binop(op,e1,e2,t,type);
}
return e1;
}
int
expr11()
{
int e1,e2,t,op;
e1=expr12();
while((op=sym)==ADD||op==SUB) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr12());
e1=binop(op,e1,e2,t,type);
}
return e1;
}
int
expr12()
{
int e1,e2,t,op;
e1=expr13();
while((op=sym)==MUL||op==DIV||op==MOD) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr13());
e1=binop(op,e1,e2,t,type);
}
return e1;
}
int
expr13()
{
int e,op;
switch (op = sym) {
case INC: case DEC:
getsym();
lcheck(e=expr13());
if(type==CHAR) {
type= INT;
return(list2(op==INC?CPREINC:CPREDEC,e));
}
if(integral(type))
return(list3(PREINC,e,op==INC?1:-1));
if(car(type)!=POINTER)
error(TYERR);
return(list3(PREINC,e,
op==INC?size(cadr(type)):-size(cadr(type)) ));
case MUL:
getsym();
e=rvalue(expr13());
return(indop(e));
case BAND:
getsym();
switch(car(e=expr13())) {
case INDIRECT:
e=cadr(e);
break;
case GVAR:
case LVAR:
e=list2(ADDRESS,e);
break;
case FNAME:
return e;
default:error(LVERR);
}
type=list2(POINTER,type);
return e;
case SUB:
getsym();
e=rvalue(expr13());
if(!integral(type))
error(TYERR);
return(car(e)==CONST?list2(CONST,-cadr(e)):list2(MINUS,e));
case BNOT:
getsym();
e=rvalue(expr13());
if(!integral(type))
error(TYERR);
return(car(e)==CONST?list2(CONST,~cadr(e)):list2(BNOT,e));
case LNOT:
getsym();
return(list2(LNOT,rvalue(expr13())));
case SIZEOF:
if(getsym()==LPAR) {
if(typeid(getsym())) {
e=list2(CONST,size(typename()));
type=INT;
checksym(RPAR);
return e;
} else {
e=expr0();
checksym(RPAR);
expr16(e);
if(sym==INC||sym==DEC) {
getsym();
if(type==CHAR) type=INT;
else if(!scalar(type))
error(TYERR);
}
}
} else
expr13();
e=list2(CONST,size(type));
type=INT;
return e;
}
e=expr14();
if((op=sym)==INC||op==DEC) {
lcheck(e);
getsym();
if(type==CHAR) {
type= INT;
return(list2(op==INC?CPOSTINC:CPOSTDEC,e));
}
if(integral(type))
return(list3(POSTINC,e,op==INC?1:-1));
if(car(type)!=POINTER)
error(TYERR);
return (list3(POSTINC,e,
op == INC ? size(cadr(type)): -size(cadr(type)) ));
}
return e;
}
int
expr14()
{
int e1,t;
switch(sym) {
case IDENT:
switch(nptr->sc) {
case GVAR:
e1=list3(GVAR,nptr->dsp,nptr->nm);
type=nptr->ty;
getsym();
break;
case LVAR:
e1=list2(LVAR,nptr->dsp);
type=nptr->ty;
getsym();
break;
case FUNCTION:
e1=list2(FNAME,(int)nptr);
type=list2(FUNCTION,nptr->ty);
getsym();
break;
case EMPTY:
if(getsym()==LPAR) {
nptr->sc = FUNCTION;
nptr->ty= INT;
type= list2(FUNCTION,INT);
e1=expr15(list2(FNAME,(int)nptr));
break;
}
default:error(UDERR);
}
break;
case STRING:
e1=list3(STRING,(int)sptr,symval);
type=list3(ARRAY,CHAR,symval);
getsym();
break;
case CONST:
type= INT;
e1=list2(CONST,symval);
getsym();
break;
case LPAR:
if(typeid(getsym())) {
t=typename();
checksym(RPAR);
e1=expr13();
type=t;
return e1;
}
e1=expr0();
checksym(RPAR);
break;
default:error(EXERR);
}
return expr16(e1);
}
int
expr16(e1)
int e1;
{
int e2,t;
while(1) {
if(sym==LBRA) {
e1=rvalue(e1);
t=type;
getsym();
e2=rvalue(expr0());
checksym(RBRA);
e1=binop(ADD,e1,e2,t,type);
e1=indop(e1);
} else if(sym==LPAR) e1=expr15(e1);
else if(sym==PERIOD) e1=strop(e1);
else if(sym==ARROW) e1=strop(indop(rvalue(e1)));
else break;
}
if(car(e1)==FNAME) type=list2(POINTER,type);
return e1;
}
int
rvalue(e)
int e;
{
if(type==CHAR) {
type= INT;
switch(car(e)) {
case GVAR:
return(list3(CRGVAR,cadr(e),caddr(e)));
case LVAR:
return(list2(CRLVAR,cadr(e)));
case INDIRECT:
return(list2(CRINDIRECT,cadr(e)));
default:return(e);
}
}
if(!integral(type)) {
if(car(type)==ARRAY) {
type=list2(POINTER,cadr(type));
if(car(e)==INDIRECT) return cadr(e);
return list2(ADDRESS,e);
}
else if(car(type)!=POINTER) error(TYERR);
}
switch(car(e)) {
case GVAR:
return(list3(RGVAR,cadr(e),caddr(e)));
case LVAR:
return(list2(RLVAR,cadr(e)));
case INDIRECT:
return(list2(RINDIRECT,cadr(e)));
default:return(e);
}
}
void
lcheck(e)
int e;
{
if(!scalar(type)||(car(e)!=GVAR&&car(e)!=LVAR&&car(e)!=INDIRECT))
error(LVERR);
}
int
indop(e)
int e;
{
if(type!=INT&&type!=UNSIGNED) {
if(car(type)==POINTER)
type=cadr(type);
else error(TYERR);
} else
type= CHAR;
if(car(e)==ADDRESS)
return(cadr(e));
return(list2(INDIRECT,e));
}
int
strop(e)
{
getsym();
if (sym!=IDENT||nptr->sc!=FIELD) error(TYERR);
if (integral(type)||(car(type)!=STRUCT && car(type)!=UNION))
e=rvalue(e);
type = nptr->ty;
switch(car(e)) {
case GVAR:
e=list2(INDIRECT,list3(ADD,e,list2(CONST,nptr->dsp)));
break;
case LVAR:
e=list2(car(e),cadr(e) + nptr->dsp);
break;
case INDIRECT:
if(!nptr->dsp) break;
e=list2(INDIRECT,list3(ADD,cadr(e),list2(CONST,nptr->dsp)));
break;
default:
e=list2(INDIRECT,list3(ADD,e,list2(CONST,nptr->dsp)));
}
getsym();
return e;
}
int
binop(op,e1,e2,t1,t2)
int op,e1,e2,t1,t2;
{
int e;
if(car(e1)==CONST&&car(e2)==CONST) {
e1=cadr(e1);
e2=cadr(e2);
type= INT;
switch(op) {
case BOR:
e=e1|e2;break;
case EOR:
e=e1^e2;break;
case BAND:
e=e1&e2;break;
case ADD:
if(integral(t1)) {
if(integral(t2)) {
e=e1+e2;
} else {
if(car(t2)!=POINTER) error(TYERR);
e=size(cadr(t2))*e1+e2;
type=t2;
}
} else {
if(car(t1)!=POINTER) error(TYERR);
e=e1+size(cadr(t1))*e2;
type=t1;
}
break;
case SUB:
if(integral(t1)) {
e=e1-e2;
} else {
if(car(t1)!=POINTER) error(TYERR);
e=e1-size(cadr(t1))*e2;
type=t1;
}
break;
case MUL:
e=e1*e2;break;
case DIV:
if(!e2) error(EXERR);e=e1/e2;break;
case MOD:
if(!e2) error(EXERR);e=e1%e2;break;
case RSHIFT:
e=e1>>e2;break;
case LSHIFT:
e=e1<<e2;
}
return list2(CONST,e);
}
if((op==ADD||op==MUL||op==BOR||op==EOR||op==BAND)&&
(car(e1)==CONST||(car(e2)!=CONST&&
(car(e1)==RGVAR||car(e1)==RLVAR)))) {
e=e1;e1=e2;e2=e;e=t1;t1=t2;t2=e;
}
if(op==ADD) {
if(integral(t1)) {
if(integral(t2)) {
if(t1==INT) type=t2;else type=t1;
return(list3(ADD,e1,e2));
}
if(car(t2)!=POINTER) error(TYERR);
e=binop(MUL,e1,list2(CONST,size(cadr(t2))),t1,INT);
type=t2;
return(list3(ADD,e,e2));
}
if(car(t1)!=POINTER||!integral(t2)) error(TYERR);
e=binop(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT);
type=t1;
if(car(e1)==ADDRESS&&car(e)==CONST&&car(cadr(e1))!=GVAR)
return(list2(ADDRESS,list2(car(cadr(e1)),
cadr(cadr(e1))+cadr(e))));
return(list3(ADD,e1,e));
}
if(op==SUB) {
if(integral(t1)) {
if(!integral(t2)) error(TYERR);
if(t1==INT) type=t2;else type=t1;
return(list3(SUB,e1,e2));
}
if(car(t1)!=POINTER) error(TYERR);
if(integral(t2)) {
e=binop(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT);
type=t1;
return(list3(SUB,e1,e));
}
if(car(t2)!=POINTER)
error(TYERR);
compatible(t1,t2);
e=list3(SUB,e1,e2);
e=binop(DIV,e,list2(CONST,size(cadr(t1))),UNSIGNED,INT);
type= INT;
return e;
}
if(!integral(t1)||!integral(t2)) error(TYERR);
if(t1==INT) type=t2;else type=t1;
if((op==MUL||op==DIV)&&car(e2)==CONST&&cadr(e2)==1) return e1;
if(op==BOR||op==EOR||op==BAND) return(list3(op,e1,e2));
return(list3(type==UNSIGNED?op+US:op,e1,e2));
}
int
expr15(e1)
int e1;
{
int t,args;
t=type;
if(integral(t)||car(t)!=FUNCTION)
error(TYERR);
t=cadr(t);
getsym();
args=0;
while(sym!=RPAR) {
args=list2(rvalue(expr1()),args);
if(sym!=COMMA) break;
getsym();
}
checksym(RPAR);
if(t==CHAR) type= INT;else type=t;
return list3(FUNCTION,e1,args);
}
int
typeid(s)
int s;
{
return (integral(s) || s==SHORT || s==LONG || s==STRUCT || s==UNION ||
(s==IDENT && nptr->sc==TYPE));
}
int
typename()
{
int t;
type=t=typespec();
ndecl0();
reverse(t);
return type;
}
int
ndecl0()
{
if(sym==MUL) {
getsym();
return type=list2(POINTER,ndecl0());
}
return ndecl1();
}
int
ndecl1()
{
int i,t;
if(sym==LPAR) {
if(getsym()==RPAR) {
type=list2(FUNCTION,type); getsym();
} else {
ndecl0();
checksym(RPAR);
}
}
while(1) {
if(sym==LBRA) {
getsym();
t=type;
i=cexpr(expr());
checksym(RBRA);
type=list3(ARRAY,t,i);
} else if(sym==LPAR) {
getsym();
checksym(RPAR);
type=list2(FUNCTION,type);
}
else return type;
}
}
int
cexpr(e)
int e;
{
if (car(e) != CONST) error(CNERR);
return (cadr(e));
}
int
getsym()
{
NMTBL *nptr0,*nptr1;
int i;
char c;
if (alpha(skipspc())) {
i = hash = 0;
name = namebuf;
while (alpha(ch) || digit(ch)) {
if (i < LBUFSIZE-1)
hash=(7*hash ^ (name[i++]=ch));
getch();
}
name[i++] = '\0';
nptr0 = gsearch();
if (nptr0->sc == RESERVE) return sym = nptr0->dsp;
if (nptr0->sc == MACRO && !mflag) {
mflag++;
chsave = ch;
chptrsave = chptr;
chptr = (char *)nptr0->dsp;
getch();
return getsym();
}
sym = IDENT;
gnptr=nptr=nptr0;
if (mode==GDECL || mode==GSDECL || mode==GUDECL ||
mode==GTDECL || mode==TOP) {
return sym;
}
nptr1=lsearch(nptr0->nm);
if (mode==STAT)
if (nptr1->sc == EMPTY) return sym;
else { nptr=nptr1; return sym;}
nptr=nptr1;
return sym;
} else if (digit(ch)) {
symval=0;
if (ch == '0') {
if (getch() == 'x' || ch == 'X') {
while(1) {
if(digit(getch()))
symval=symval*16+ch-'0';
else if('a'<=ch&&ch<='f')
symval=symval*16+ch-'a'+10;
else if('A'<=ch&&ch<='F')
symval=symval*16+ch-'A'+10;
else break;
}
} else {
while (digit(ch)) {
symval=symval*8+ch-'0';getch();
}
}
} else {
while(digit(ch)) {
symval=symval*10+ch-'0';getch();
}
}
return sym=CONST;
} else if(ch=='\'') {
getch();
symval=escape();
if(ch!='\'') error(CHERR);
getch();
return sym=CONST;
} else if(ch=='"') {
getstring();
return sym= STRING;
}
c=ch;
getch();
switch(c) {
case '*':
return postequ(MUL,MUL+AS);
case '&':
if(ch=='&') {getch();return sym=LAND;}
return postequ(BAND,BAND+AS);
case '-':
if(ch=='>') {getch();return sym=ARROW;}
if(ch=='-') {getch();return sym=DEC;}
return postequ(SUB,SUB+AS);
case '!':
return postequ(LNOT,NEQ);
case '~':
return sym=BNOT;
case '+':
if(ch=='+') {getch();return sym=INC;}
return postequ(ADD,ADD+AS);
case '%':
return postequ(MOD,MOD+AS);
case '^':
return postequ(EOR,EOR+AS);
case '|':
if(ch=='|') {getch();return sym=LOR;}
return postequ(BOR,BOR+AS);
case '=':
return postequ(ASS,EQ);
case '>':
if(ch=='>') {getch();return postequ(RSHIFT,RSHIFT+AS);}
return postequ(GT,GE);
case '<':
if(ch=='<') {getch();return postequ(LSHIFT,LSHIFT+AS);}
return postequ(LT,LE);
case '(':
return sym=LPAR;
case ')':
return sym=RPAR;
case '[':
return sym=LBRA;
case ']':
return sym=RBRA;
case '{':
return sym=LC;
case '}':
return sym=RC;
case ',':
return sym=COMMA;
case ';':
return sym=SM;
case ':':
return sym=COLON;
case '?':
return sym=COND;
case '.':
return sym=PERIOD;
case '/':
if(ch!='*') return postequ(DIV,DIV+AS);
getch();
while(ch=='*'?getch()!='/':getch());
getch();
return getsym();
default:
error(CHERR);
return getsym();
}
}
int
postequ(s1,s2)
int s1,s2;
{
if(ch=='=') {getch();return sym=s2;}
return sym=s1;
}
int
alpha(c)
char c;
{
return(('a'<=c&&c<='z')||('A'<=c&&c<='Z')||c=='_');
}
int
digit(c)
char c;
{
return('0'<=c&&c<='9');
}
NMTBL *
gsearch()
{
NMTBL *nptr,*iptr;
iptr=nptr= &ntable[hash % GSYMS];
while(nptr->sc!=0 && neqname(nptr->nm)) {
if (++nptr== &ntable[GSYMS])
nptr=ntable;
if (nptr==iptr) error(GSERR);
}
if (nptr->sc == 0) {
copy(nptr,name);
nptr->sc=EMPTY;
}
return nptr;
}
NMTBL *
lsearch(name)
char *name;
{
NMTBL *nptr,*iptr;
iptr=nptr= &ntable[hash%LSYMS+GSYMS];
while(nptr->sc!=0 && neqname(nptr->nm)) {
if (++nptr== &ntable[LSYMS+GSYMS])
nptr= &ntable[GSYMS];
if (nptr==iptr) error(LSERR);
}
if (nptr->sc == 0) {
nptr->nm=name; /* already saved in gsearch */
nptr->sc=EMPTY;
}
return nptr;
}
void
copy(nptr,s)
NMTBL *nptr;
char *s;
{
nptr->nm = cheapp;
while(*cheapp++ = *s++);
}
int
neqname(p)
char *p;
{
char *q;
if (!p)
return 0;
q=name;
while(*p && *p!='.')
if(*p++ != *q++) return 1;
return (*q!=0);
}
void
getstring()
{
getch();
symval = 0;
sptr = cheapp;
while (ch != '"') {
*cheapp++ = escape();
symval++;
if (cheapp >= cheap+CHEAPSIZE) error(STRERR);
}
getch();
*cheapp++ = '\0';
symval++;
}
int
skipspc()
{
while(ch=='\t'||ch=='\n'||ch==' '||ch=='\r')
getch();
return ch;
}
int
getch()
{
if(*chptr) return ch= *chptr++;
if(mflag) {
mflag=0;chptr=chptrsave;return ch=chsave;
}
getline();
return getch();
}
char
escape()
{
char c;
if ((c=ch) == '\\') {
if (digit(c=getch())) {
c = ch-'0';
if (digit(getch())) {
c = c*8+ch-'0';
if (digit(getch())) {
c=c*8+ch-'0';getch();
}
}
return c;
}
getch();
switch(c) {
case 'n':
return '\n';
case 't':
return '\t';
case 'b':
return '\b';
case 'r':
return '\r';
case 'f':
return '\f';
case '\n':
return escape();
default:
return c;
}
}
if (c == '\n') error(EXERR);
getch();
return c;
}
FILE *
getfname()
{
int i;
char name[LBUFSIZE];
FILE *fp;
getch();
if(skipspc()!='"') error(INCERR);
for(i=0;(getch()!='"' && ch!='\n');) {
if(i<LBUFSIZE-1) name[i++]=ch;
}
if(ch=='\n') error(INCERR);
name[i]=0;
fp = fopen(name,"r") ;
return ( (filep+1)->fcb = fp );
}
void
getline()
{
int i;
int c;
lineno++;
glineno++;
chptr=linebuf;
i=0;
/* while ((*chptr++ = c = getc(filep->fcb)) != '\n') {
we cannot handle unsaved register in library call
so make it easy for the compiler
*/
while ((c=getc(filep->fcb)),(*chptr++=c)!='\n') {
if (++i > LBUFSIZE-2) error(LNERR);
if (c==EOF) {
error(EOFERR);
--chptr;
}
}
*chptr = '\0';
if (lsrc && !asmf) gen_comment(linebuf);
if (*(chptr = linebuf) == '#') {
++chptr;
if (macroeq("define")) {
i=mode;
mode=GDECL;
ch= *chptr;
if (getsym() == IDENT) {
if (nptr->sc == EMPTY) {
nptr->sc = MACRO;
nptr->dsp = (int)cheapp;
while ((*cheapp++ = c = *chptr++)
&& c != '\n');
*cheapp++ = '\0';
if (cheapp >= cheap+CHEAPSIZE)
error(STRERR);
if (!c) error(EOFERR);
} else error(MCERR);
} else error(MCERR);
mode=i;
*(chptr = linebuf) = '\0';
} else if (macroeq("include")) {
fprintf(stderr,"%s",linebuf);
if(filep+1 >= filestack + FILES) error(FILERR);
if ( ((filep+1)->fcb=getfname()) == NULL) error(FILERR);
(filep+1)->ln=lineno;
lineno=0;
++filep;
*(chptr = linebuf) = '\0';
} else if (macroeq("asm")) {
if (asmf) error(MCERR);
asmf = 1;
getline();
while (asmf) {
gen_source(linebuf);
getline();
}
} else if (macroeq("endasm")) {
if (!asmf) error(MCERR);
asmf = 0;
} else if (macroeq(" "))
getline();
else error(MCERR);
}
}
int
macroeq(s)
char *s;
{
char *p;
for (p = chptr; *s;) if (*s++ != *p++) return 0;
chptr = p;
return 1;
}
int
car(e)
int e;
{
return heap[e];
}
int
cadr(e)
int e;
{
return heap[e+1];
}
int
caddr(e)
int e;
{
return heap[e+2];
}
int
cadddr(e)
int e;
{
return heap[e+3];
}
int
list2(e1,e2)
int e1,e2;
{
int e;
e=getfree(2);
heap[e]=e1;
heap[e+1]=e2;
return e;
}
int
list3(e1,e2,e3)
int e1,e2,e3;
{
int e;
e=getfree(3);
heap[e]=e1;
heap[e+1]=e2;
heap[e+2]=e3;
return e;
}
int
list4(e1,e2,e3,e4)
int e1,e2,e3,e4;
{
int e;
e=getfree(4);
heap[e]=e1;
heap[e+1]=e2;
heap[e+2]=e3;
heap[e+3]=e4;
return e;
}
int
getfree(n)
int n;
{
int e;
switch (mode) {
case GDECL: case GSDECL: case GUDECL: case GTDECL:
e=gfree;
gfree+=n;
break;
default:
lfree-=n;
e=lfree;
}
if(lfree<gfree) error(HPERR);
return e;
}
int
rplacad(e,n)
int e,n;
{
heap[e+1]=n;
return e;
}
display_ntable(n,s)
NMTBL *n;
char *s;
{
fprintf(stderr,"\n%s %0x %0x ",s,n,ntable);
fprintf(stderr,"nptr->sc %d ",n->sc);
fprintf(stderr,"nptr->dsp %d ",n->dsp);
fprintf(stderr,"nptr->ty %d ",n->ty);
fprintf(stderr,"nptr->nm %s\n",n->nm);
}
/* end */