/* * C compiler */ #include "c0.h" /* * Process a single external definition */ extdef() { register o; int sclass, scflag; struct nmlist typer; register struct nmlist *ds; if(((o=symbol())==EOFC) || o==SEMI) return; peeksym = o; sclass = 0; blklev = 0; if (getkeywords(&sclass, &typer)==0) { sclass = EXTERN; if (peeksym!=NAME) goto syntax; } scflag = 0; if (sclass==DEFXTRN) { scflag++; sclass = EXTERN; } if (sclass!=EXTERN && sclass!=STATIC && sclass!=TYPEDEF) error("Illegal storage class"); do { defsym = 0; paraml = NULL; parame = NULL; if (sclass==TYPEDEF) { decl1(TYPEDEF, &typer, 0, (struct nmlist *)NULL); continue; } decl1(EXTERN, &typer, 0, (struct nmlist *)NULL); if ((ds=defsym)==0) return; funcsym = ds; if ((ds->htype&XTYPE)==FUNC) { if ((peeksym=symbol())==LBRACE || peeksym==KEYW || (peeksym==NAME && csym->hclass==TYPEDEF)) { funcblk.type = decref(ds->htype); funcblk.strp = ds->hstrp; setinit(ds); outcode("BS", SYMDEF, sclass==EXTERN?ds->name:""); cfunc(); return; } if (paraml) error("Inappropriate parameters"); } else if ((o=symbol())==COMMA || o==SEMI) { peeksym = o; o = (length((union tree *)ds)+ALIGN) & ~ALIGN; if (sclass==STATIC) { setinit(ds); outcode("BSBBSBN", SYMDEF, "", BSS, NLABEL, ds->name, SSPACE, o); } else if (scflag) outcode("BSN", CSPACE, ds->name, o); } else { if (o!=ASSIGN) { error("Declaration syntax"); peeksym = o; } setinit(ds); if (sclass==EXTERN) outcode("BS", SYMDEF, ds->name); outcode("BBS", DATA, NLABEL, ds->name); if (cinit(ds, 1, sclass) & ALIGN) outcode("B", EVEN); } } while ((o=symbol())==COMMA); if (o==SEMI) return; syntax: if (o==RBRACE) { error("Too many }'s"); peeksym = 0; return; } error("External definition syntax"); errflush(o); statement(); } /* * Process a function definition. */ cfunc() { register char *cb; register sloc; sloc = isn; isn += 2; outcode("BBS", PROG, RLABEL, funcsym->name); regvar = 5; autolen = STAUTO; maxauto = STAUTO; blklev = 1; cb = locbase; declist(ARG); outcode("B", SAVE); if (proflg) outcode("BNS", PROFIL, isn++, funcsym->name); funchead(); branch(sloc); label(sloc+1); retlab = isn++; blklev = 0; if ((peeksym = symbol()) != LBRACE) error("Compound statement required"); statement(); outcode("BNB", LABEL, retlab, RETRN); label(sloc); /* add STAUTO; overlay bug fix, coupled with section in c11.c */ outcode("BN", SETSTK, -maxauto+STAUTO); branch(sloc+1); locbase = cb; } /* * Process the initializers for an external definition. */ cinit(anp, flex, sclass) struct nmlist *anp; { struct nmlist np; register nel, ninit; int width, isarray, o, brace, realtype; union tree *s; np = *anp; realtype = np.htype; isarray = 0; if ((realtype&XTYPE) == ARRAY) isarray++; else flex = 0; width = length((union tree *)&np); nel = 1; /* * If it's an array, find the number of elements. * temporarily modify to look like kind of thing it's * an array of. */ if (sclass==AUTO) if (isarray || realtype==STRUCT) error("No auto. aggregate initialization"); if (isarray) { np.htype = decref(realtype); np.hsubsp++; if (width==0 && flex==0) error("0-length row: %s", anp->name); o = length((union tree *)&np); nel = (unsigned)width/o; width = o; } brace = 0; if ((peeksym=symbol())==LBRACE && (isarray || np.htype!=STRUCT)) { peeksym = -1; brace++; } ninit = 0; do { if ((o=symbol())==RBRACE) break; peeksym = o; if (o==STRING && (realtype==ARRAY+CHAR || realtype==ARRAY+UNCHAR)) { if (sclass==AUTO) error("No strings in automatic"); peeksym = -1; putstr(0, flex?10000:nel); ninit += nchstr; o = symbol(); break; } else if (np.htype==STRUCT) { strinit(&np, sclass); } else if ((np.htype&ARRAY)==ARRAY || peeksym==LBRACE) cinit(&np, 0, sclass); else { char *st; initflg++; st = starttree(); s = tree(0); initflg = 0; if (np.hflag&FFIELD) error("No field initialization"); *cp++ = nblock(&np); *cp++ = s; build(ASSIGN); if (sclass==AUTO||sclass==REG) rcexpr(*--cp); else if (sclass==ENUMCON) { if (s->t.op!=CON) error("Illegal enum constant for %s", anp->name); anp->hoffset = s->c.value; } else rcexpr(block(INIT,np.htype,(int *)NULL, (union str *)NULL, (*--cp)->t.tr2, TNULL)); endtree(st); } ninit++; if ((ninit&077)==0 && sclass==EXTERN) outcode("BS", SYMDEF, ""); } while ((o=symbol())==COMMA && (ninitnel) { if (flex && nel==0) { np.hsubsp[-1] = ninit; } else error("Too many initializers: %s", anp->name); nel = ninit; } return(nel*width); } /* * Initialize a structure */ strinit(np, sclass) struct nmlist *np; { static struct nmlist junk; register struct nmlist **mlp; static struct nmlist *zerloc = NULL; register int o, brace; if ((mlp = np->hstrp->S.memlist)==NULL) { mlp = &zerloc; error("Undefined structure initialization"); } brace = 0; if ((o = symbol()) == LBRACE) brace++; else peeksym = o; do { if ((o=symbol()) == RBRACE) break; peeksym = o; if (*mlp==0) { error("Too many structure initializers"); cinit(&junk, 0, sclass); } else cinit(*mlp++, 0, sclass); if (*mlp == &structhole) { outcode("B", EVEN); mlp++; } /* DAG -- union initialization bug fix */ if (*mlp && mlp[-1]->hoffset == (*mlp)->hoffset) { werror("union initialization non-portable"); while (*mlp) /* will NOT be &structhole */ mlp++; /* skip other members of union */ } } while ((o=symbol())==COMMA && (*mlp || brace)); if (sclass!=AUTO && sclass!=REG) { if (*mlp) outcode("BN", SSPACE, np->hstrp->S.ssize - (*mlp)->hoffset); outcode("B", EVEN); } if (o!=RBRACE || brace==0) peeksym = o; } /* * Mark already initialized */ setinit(np) register struct nmlist *np; { if (np->hflag&FINIT) error("%s multiply defined", np->name); np->hflag |= FINIT; } /* * Process one statement in a function. */ statement() { register o, o1; int sauto, sreg; stmt: switch(o=symbol()) { case EOFC: error("Unexpected EOF"); case SEMI: return; case LBRACE: sauto = autolen; sreg = regvar; blockhead(); while (!eof) { if ((o=symbol())==RBRACE) { autolen = sauto; if (sreg!=regvar) outcode("BN", SETREG, sreg); regvar = sreg; blkend(); return; } peeksym = o; statement(); } error("Missing '}'"); return; case KEYW: switch(cval) { case GOTO: if (o1 = simplegoto()) branch(o1); else dogoto(); goto semi; case RETURN: doret(); goto semi; case ASM: { char tmp[80], /* tmp for line buffer */ *p; if (symbol() != LPARN || (o1 = symbol()) != STRING) goto syntax; for (p = tmp; (o1 = mapch('"')) >= 0; ) *p++ = o1&0177; *p = '\0'; if (symbol() != RPARN) goto syntax; outcode("BF", ASSEM, tmp); goto semi; } case IF: { register o2; register union tree *np; np = pexpr(1); o2 = 0; if ((o1=symbol())==KEYW) switch (cval) { case GOTO: if (o2=simplegoto()) goto simpif; cbranch(np, o2=isn++, 0); dogoto(); label(o2); goto hardif; case RETURN: if (nextchar()==';') { o2 = retlab; goto simpif; } cbranch(np, o1=isn++, 0); doret(); label(o1); o2++; goto hardif; case BREAK: o2 = brklab; goto simpif; case CONTIN: o2 = contlab; simpif: chconbrk(o2); cbranch(np, o2, 1); hardif: if ((o=symbol())!=SEMI) goto syntax; if ((o1=symbol())==KEYW && cval==ELSE) goto stmt; peeksym = o1; return; } peeksym = o1; cbranch(np, o1=isn++, 0); statement(); if ((o=symbol())==KEYW && cval==ELSE) { o2 = isn++; branch(o2); label(o1); statement(); label(o2); return; } peeksym = o; label(o1); return; } case WHILE: { register o2; o1 = contlab; o2 = brklab; label(contlab = isn++); cbranch(pexpr(1), brklab=isn++, 0); statement(); branch(contlab); label(brklab); contlab = o1; brklab = o2; return; } case BREAK: chconbrk(brklab); branch(brklab); goto semi; case CONTIN: chconbrk(contlab); branch(contlab); goto semi; case DO: { register int o2, o3; o1 = contlab; o2 = brklab; contlab = isn++; brklab = isn++; label(o3 = isn++); statement(); label(contlab); contlab = o1; if ((o=symbol())==KEYW && cval==WHILE) { cbranch(tree(1), o3, 1); label(brklab); brklab = o2; goto semi; } goto syntax; } case CASE: o1 = conexp(); if ((o=symbol())!=COLON) goto syntax; if (swp==0) { error("Case not in switch"); goto stmt; } if(swp>=swtab+SWSIZ) { error("Switch table overflow"); } else { swp->swlab = isn; (swp++)->swval = o1; label(isn++); } goto stmt; case SWITCH: { register union tree *np; register char *st; o1 = brklab; brklab = isn++; st = starttree(); np = pexpr(0); chkw(np, -1); rcexpr(block(RFORCE,0,(int *)NULL,(union str *)NULL,np,TNULL)); endtree(st); pswitch(); brklab = o1; return; } case DEFAULT: if (swp==0) error("Default not in switch"); if (deflab) error("More than 1 'default'"); if ((o=symbol())!=COLON) goto syntax; label(deflab = isn++); goto stmt; case FOR: { register int o2; o1 = contlab; o2 = brklab; contlab = isn++; brklab = isn++; if (o=forstmt()) goto syntax; contlab = o1; brklab = o2; return; } case ELSE: error("Inappropriate 'else'"); statement(); return; } error("Unknown keyword"); goto syntax; case NAME: { register struct nmlist *np; if (nextchar()==':') { peekc = 0; np = csym; if (np->hclass>0) { if (np->hblklev==0) { np = pushdecl(np); np->hoffset = 0; } else { defsym = np; redec(); goto stmt; } } np->hclass = STATIC; np->htype = ARRAY; np->hflag |= FLABL; if (np->hoffset==0) np->hoffset = isn++; label(np->hoffset); goto stmt; } } } peeksym = o; rcexpr(tree(1)); semi: if ((o=symbol())==SEMI) return; syntax: error("Statement syntax"); errflush(o); } /* * Process a for statement. */ forstmt() { register int o; register union tree *st; register l; char *ss; if ((o=symbol()) != LPARN) return(o); if ((o=symbol()) != SEMI) { /* init part */ peeksym = o; rcexpr(tree(1)); if ((o=symbol()) != SEMI) return(o); } l = isn; isn += 3; branch(l+0); label(l+1); branch(l+2); label(contlab); st = NULL; if ((o=symbol()) != SEMI) { /* test part */ peeksym = o; ss = starttree(); st = tree(0); if ((o=symbol()) != SEMI) { endtree(ss); return(o); } } if ((o=symbol()) != RPARN) { /* incr part */ peeksym = o; rcexpr(tree(1)); if ((o=symbol()) != RPARN) { if (st) endtree(ss); return(o); } } label(l+0); if (st) { cbranch(st, l+1, 1); endtree(ss); } else branch(l+1); branch(brklab); label(l+2); statement(); branch(contlab); label(brklab); return(0); } /* * A parenthesized expression, * as after "if". */ union tree * pexpr(eflag) { register o; register union tree *t; if ((o=symbol())!=LPARN) goto syntax; t = tree(eflag); if ((o=symbol())!=RPARN) goto syntax; if (t->t.type==VOID) error("Illegal use of void"); return(t); syntax: error("Statement syntax"); errflush(o); return(0); } /* * The switch statement, which involves collecting the * constants and labels for the cases. */ pswitch() { register struct swtab *cswp, *sswp; int dl, swlab; cswp = sswp = swp; if (swp==0) cswp = swp = swtab; branch(swlab=isn++); dl = deflab; deflab = 0; statement(); branch(brklab); label(swlab); if (deflab==0) deflab = brklab; outcode("BNN", SWIT, deflab, line); for (; cswp < swp; cswp++) outcode("NN", cswp->swlab, cswp->swval); outcode("0"); label(brklab); deflab = dl; swp = sswp; } /* * funchead is called at the start of each function * to process the arguments, which have been linked in a list. * This list is necessary because in * f(a, b) float b; int a; ... * the names are seen before the types. */ /* * Structure resembling a block for a register variable. */ struct nmlist hreg = { REG, 0, 0, NULL, NULL, 0 }; struct tnode areg = { NAME, 0, NULL, NULL, (union tree *)&hreg}; funchead() { register pl; register struct nmlist *cs; register char *st; pl = STARG; while(paraml) { parame->sparent = NULL; cs = paraml; paraml = ¶ml->sparent->P; if (cs->htype==FLOAT) cs->htype = DOUBLE; cs->hoffset = pl; if ((cs->htype&XTYPE) == ARRAY) { cs->htype -= (ARRAY-PTR); /* set ptr */ cs->hsubsp++; /* pop dims */ } pl += rlength((union tree *)cs); if (cs->hclass==AREG && (hreg.hoffset=goodreg(cs))>=0) { st = starttree(); *cp++ = (union tree *)&areg; *cp++ = nblock(cs); areg.type = cs->htype; areg.strp = cs->hstrp; cs->hclass = AUTO; build(ASSIGN); rcexpr(*--cp); cs->hoffset = hreg.hoffset; cs->hclass = REG; endtree(st); } else cs->hclass = AUTO; prste(cs); } for (pl=0; plnextnm) { if (cs->hclass == ARG || cs->hclass==AREG) error("Not an argument: %s", cs->name); } } outcode("BN", SETREG, regvar); } blockhead() { register r; r = regvar; blklev++; declist(0); if (r != regvar) outcode("BN", SETREG, regvar); } /* * After the end of a block, delete local * symbols; * Also complain about undefined labels. */ blkend() { register struct nmlist *cs, **lcs; register i; blklev--; for (i = 0; i < HSHSIZ; i++) { lcs = &hshtab[i]; cs = *lcs; while (cs) { if (cs->hblklev > blklev && (((cs->hflag&FLABL)==0 && cs->hclass!=EXTERN) || blklev<=0)) { if (cs->hclass==0) error("%s undefined", cs->name); if (cs->hclass==EXTERN) nameconflict(hshtab[i], cs); *lcs = cs->nextnm; } else lcs = &cs->nextnm; cs = cs->nextnm; } } } nameconflict(ocs, cs) register struct nmlist *ocs, *cs; { for (; ocs!=NULL; ocs = ocs->nextnm) if (ocs!=cs && ocs->hclass==EXTERN && strncmp(cs->name, ocs->name, MAXCPS-1) == 0) error("names %s and %s conflict", cs->name, ocs->name); } /* * write out special definitions of local symbols for * benefit of the debugger. None of these are used * by the assembler except to save them. */ prste(cs) struct nmlist *cs; { register nkind; switch (cs->hclass) { case REG: nkind = RNAME; break; case AUTO: nkind = ANAME; break; case STATIC: nkind = SNAME; break; default: return; } outcode("BSN", nkind, cs->name, cs->hoffset); } /* * In case of error, skip to the next * statement delimiter. */ errflush(ao) { register o; o = ao; while(o>RBRACE) { /* ; { } */ if (o==STRING) putstr(0, 0); o = symbol(); } peeksym = o; }