# /* C compiler * * */ #include "c0.h" /* * Process a single external definition */ extdef() { register o; int sclass, scflag, *cb; struct hshtab typer; register struct hshtab *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 = 0; parame = 0; if (sclass==TYPEDEF) { decl1(TYPEDEF, &typer, 0, NULL); continue; } decl1(EXTERN, &typer, 0, NULL); if ((ds=defsym)==0) return; funcsym = ds; if ((ds->type&XTYPE)==FUNC) { if ((peeksym=symbol())==LBRACE || peeksym==KEYW || (peeksym==NAME && csym->hclass==TYPEDEF)) { funcblk.type = decref(ds->type); funcblk.strp = ds->strp; 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(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) peeksym = o; setinit(ds); if (sclass==EXTERN) outcode("BS", SYMDEF, ds->name); outcode("BBS", DATA, NLABEL, ds->name); cb = funcbase; if (cinit(ds, 1, sclass) & ALIGN) outcode("B", EVEN); if (maxdecl > cb) cb = maxdecl; funcbase = cb; } } 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 int *cb; register sloc; sloc = isn; isn =+ 2; outcode("BBS", PROG, RLABEL, funcsym->name); if (proflg) outcode("BN", PROFIL, isn++); cb = curbase; regvar = 5; autolen = STAUTO; maxauto = STAUTO; blklev = 1; declist(ARG); outcode("B", SAVE); 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); outcode("BN", SETSTK, -maxauto); branch(sloc+1); if (cb < maxdecl) cb = maxdecl; curbase = funcbase = cb; } /* * Process the initializers for an external definition. */ cinit(anp, flex, sclass) struct hshtab *anp; { register struct phshtab *np; register nel, ninit; int width, isarray, o, brace, realtype, *cb; struct tnode *s; cb = funcbase; np = gblock(sizeof(*np)); funcbase = curbase; cpysymb(np, anp); realtype = np->type; isarray = 0; if ((realtype&XTYPE) == ARRAY) isarray++; else flex = 0; width = length(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->type = decref(realtype); np->subsp++; if (width==0 && flex==0) error("0-length row: %.8s", anp->name); o = length(np); /* nel = ldiv(0, width, o); */ nel = (unsigned)width/o; width = o; } brace = 0; if ((peeksym=symbol())==LBRACE && (isarray || np->type!=STRUCT)) { peeksym = -1; brace++; } ninit = 0; do { if ((o=symbol())==RBRACE) break; peeksym = o; if (o==STRING && realtype==ARRAY+CHAR) { if (sclass==AUTO) error("No strings in automatic"); peeksym = -1; putstr(0, flex?10000:nel); ninit =+ nchstr; o = symbol(); break; } else if (np->type==STRUCT) { strinit(np, sclass); } else if ((np->type&ARRAY)==ARRAY || peeksym==LBRACE) cinit(np, 0, sclass); else { initflg++; s = tree(); 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->op!=CON) error("Illegal enum constant for %.8s", anp->name); anp->hoffset = s->value; } else rcexpr(block(INIT,np->type,NULL,NULL,(*--cp)->tr2)); } ninit++; if ((ninit&077)==0 && sclass==EXTERN) outcode("BS", SYMDEF, ""); } while ((o=symbol())==COMMA && (ninitnel) { if (flex && nel==0) { np->subsp[-1] = ninit; } else error("Too many initializers: %.8s", anp->name); nel = ninit; } curbase = funcbase = cb; return(nel*width); } /* * Initialize a structure */ strinit(np, sclass) struct tnode *np; { register struct hshtab **mlp; static zerloc; register int o, brace; if ((mlp = np->strp->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(&funcblk, 0, sclass); } else cinit(*mlp++, 0, sclass); if (*mlp == &structhole) { outcode("B", EVEN); mlp++; } } while ((o=symbol())==COMMA && (*mlp || brace)); if (sclass!=AUTO && sclass!=REG) { if (*mlp) outcode("BN", SSPACE, np->strp->ssize - (*mlp)->hoffset); outcode("B", EVEN); } if (o!=RBRACE || brace==0) peeksym = o; } /* * Mark already initialized */ setinit(anp) struct hshtab *anp; { register struct hshtab *np; np = anp; if (np->hflag&FINIT) error("%s multiply defined", np->name); np->hflag =| FINIT; } /* * Process one statement in a function. */ statement() { register o, o1, o2; int o3; struct tnode *np; 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 IF: np = pexpr(); 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: o1 = contlab; o2 = brklab; label(contlab = isn++); cbranch(pexpr(), 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: o1 = contlab; o2 = brklab; contlab = isn++; brklab = isn++; label(o3 = isn++); statement(); label(contlab); contlab = o1; if ((o=symbol())==KEYW && cval==WHILE) { cbranch(tree(), 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: o1 = brklab; brklab = isn++; np = pexpr(); chkw(np, -1); rcexpr(block(RFORCE,0,NULL,NULL,np)); 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: o1 = contlab; o2 = brklab; contlab = isn++; brklab = isn++; if (o=forstmt()) goto syntax; label(brklab); contlab = o1; brklab = o2; return; case ELSE: error("Inappropriate 'else'"); statement(); return; } error("Unknown keyword"); goto syntax; case NAME: if (nextchar()==':') { peekc = 0; o1 = csym; if (o1->hclass>0) { if (o1->hblklev==0) { pushdecl(o1); o1->hoffset = 0; } else { defsym = o1; redec(); goto stmt; } } o1->hclass = STATIC; o1->htype = ARRAY; o1->hflag =| FLABL; if (o1->hoffset==0) o1->hoffset = isn++; label(o1->hoffset); goto stmt; } } peeksym = o; rcexpr(tree()); semi: if ((o=symbol())==SEMI) return; syntax: error("Statement syntax"); errflush(o); } /* * Process a for statement. */ forstmt() { register int l, o, sline; int sline1, *ss; struct tnode *st; if ((o=symbol()) != LPARN) return(o); if ((o=symbol()) != SEMI) { /* init part */ peeksym = o; rcexpr(tree()); if ((o=symbol()) != SEMI) return(o); } label(contlab); if ((o=symbol()) != SEMI) { /* test part */ peeksym = o; cbranch(tree(), brklab, 0); if ((o=symbol()) != SEMI) return(o); } if ((peeksym=symbol()) == RPARN) { /* incr part */ peeksym = -1; statement(); branch(contlab); return(0); } l = contlab; contlab = isn++; st = tree(); sline = line; if ((o=symbol()) != RPARN) return(o); ss = funcbase; funcbase = curbase; statement(); sline1 = line; line = sline; label(contlab); rcexpr(st); line = sline1; if (ss < maxdecl) ss = maxdecl; curbase = funcbase = ss; branch(l); return(0); } /* * A parenthesized expression, * as after "if". */ struct tnode * pexpr() { register o, t; if ((o=symbol())!=LPARN) goto syntax; t = tree(); if ((o=symbol())!=RPARN) goto syntax; 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 hshtab hreg { REG, 0, 0, NULL, NULL, 0 }; struct tnode areg { NAME, 0, NULL, NULL, &hreg}; funchead() { register pl; register struct hshtab *cs; struct tnode *bstack[2]; pl = STARG; while(paraml) { parame->hoffset = 0; cs = paraml; paraml = paraml->hoffset; if (cs->htype==FLOAT) cs->htype = DOUBLE; cs->hoffset = pl; if ((cs->htype&XTYPE) == ARRAY) { cs->htype =- (ARRAY-PTR); /* set ptr */ cs->subsp++; /* pop dims */ } pl =+ rlength(cs); if (cs->hclass==AREG && (hreg.hoffset=goodreg(cs))>=0) { bstack[0] = &areg; bstack[1] = nblock(cs); cp = &bstack[2]; areg.type = cs->htype; cs->hclass = AUTO; build(ASSIGN); rcexpr(bstack[0]); cs->hoffset = hreg.hoffset; cs->hclass = REG; } else cs->hclass = AUTO; prste(cs); } for (cs=hshtab; csname[0] == '\0') continue; if (cs->hclass == ARG || cs->hclass==AREG) error("Not an argument: %.8s", 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; save those that are external. * Also complain about undefined labels. */ blkend() { register struct hshtab *cs, *ncs; struct hshtab *endcs; register i; blklev--; for (cs=hshtab; cs->name[0] && csname[0]) { if (cs->hblklev <= blklev) continue; if ((cs->hclass!=EXTERN || blklev!=0) && ((cs->hflag&FLABL)==0 || blklev==0)) { if (cs->hclass==0) error("%.8s undefined", cs->name); if ((ncs = cs->hpdown)==NULL) { cs->name[0] = '\0'; hshused--; cs->hflag =& FKEYW; } else { cpysymb(cs, ncs); } continue; } /* * Retained name; must rehash. */ for (i=0; iname[i]; mossym = cs->hflag&FMOS; lookup(); if ((ncs=csym) != cs) { cs->name[0] = '\0'; hshused--; i = ncs->hflag; cpysymb(ncs, cs); ncs->hflag =| i&FKEYW; cs->hflag =& FKEYW; } if (ncs->hblklev>1 || (ncs->hblklev>0 && ncs->hclass==EXTERN)) ncs->hblklev--; } while ((cs = (cs<&hshtab[HSHSIZ-1])? ++cs: hshtab) != endcs); } /* * 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(acs) struct hshtab *acs; { register struct hshtab *cs; register nkind; cs = acs; 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) /* ; { } */ o = symbol(); peeksym = o; }