#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 */