/* @(#)c04.c 2.1 SCCS id keyword */ # /* * C compiler * * */ #include "c0.h" /* * Reduce the degree-of-reference by one. * e.g. turn "ptr-to-int" into "int". */ decref(at) { register t; t = at; if ((t & ~TYPE) == 0) { error("Illegal indirection"); return(t); } return((t>>TYLEN) & ~TYPE | t&TYPE); } /* * Increase the degree of reference by * one; e.g. turn "int" to "ptr-to-int". */ incref(t) { return(((t&~TYPE)<op==INIT && tp->tr1->op==CON) { if (tp->type==CHAR) { outcode("B1N0", BDATA, tp->tr1->value); return; } else if (tp->type==INT || tp->type==UNSIGN) { outcode("BN", SINIT, tp->tr1->value); return; } } treeout(tp, 0); outcode("BN", EXPR, line); } treeout(atp, isstruct) struct tnode *atp; { register struct tnode *tp; register struct hshtab *hp; register nextisstruct; if ((tp = atp) == 0) { outcode("B", NULLOP); return; } nextisstruct = tp->type==STRUCT; switch(tp->op) { case NAME: hp = tp->tr1; if (hp->hclass==TYPEDEF) error("Illegal use of type name"); outcode("BNN", NAME, hp->hclass==0?STATIC:hp->hclass, tp->type); if (hp->hclass==EXTERN) outcode("S", hp->name); else outcode("N", hp->hoffset); break; case LCON: outcode("BNNN", tp->op, tp->type, tp->lvalue); break; case CON: outcode("BNN", tp->op, tp->type, tp->value); break; case FCON: outcode("BNF", tp->op, tp->type, tp->cstr); break; case STRING: outcode("BNNN", NAME, STATIC, tp->type, tp->tr1); break; case FSEL: treeout(tp->tr1, nextisstruct); outcode("BNNN",tp->op,tp->type,tp->tr2->bitoffs,tp->tr2->flen); break; case ETYPE: error("Illegal use of type"); break; case AMPER: treeout(tp->tr1, 1); outcode("BN", tp->op, tp->type); break; case CALL: treeout(tp->tr1, 1); treeout(tp->tr2, 0); outcode("BN", CALL, tp->type); break; default: treeout(tp->tr1, nextisstruct); if (opdope[tp->op]&BINARY) treeout(tp->tr2, nextisstruct); outcode("BN", tp->op, tp->type); break; } if (nextisstruct && isstruct==0) outcode("BNN", STRASG, STRUCT, tp->strp->ssize); } /* * Generate a branch */ branch(lab) { outcode("BN", BRANCH, lab); } /* * Generate a label */ label(l) { outcode("BN", LABEL, l); } /* * ap is a tree node whose type * is some kind of pointer; return the size of the object * to which the pointer points. */ plength(ap) struct tname *ap; { register t, l; register struct tnode *p; p = ap; if (p==0 || ((t=p->type)&~TYPE) == 0) /* not a reference */ return(1); p->type = decref(t); l = length(p); p->type = t; return(l); } /* * return the number of bytes in the object * whose tree node is acs. */ length(acs) struct tnode *acs; { register t, elsz; long n; register struct tnode *cs; int nd; cs = acs; t = cs->type; n = 1; nd = 0; while ((t&XTYPE) == ARRAY) { t = decref(t); n =* cs->subsp[nd++]; } if ((t&~TYPE)==FUNC) return(0); if (t>=PTR) elsz = SZPTR; else switch(t&TYPE) { case INT: case UNSIGN: elsz = SZINT; break; case CHAR: elsz = 1; break; case FLOAT: elsz = SZFLOAT; break; case LONG: elsz = SZLONG; break; case DOUBLE: elsz = SZDOUB; break; case STRUCT: if ((elsz = cs->strp->ssize) == 0) error("Undefined structure"); break; default: error("Compiler error (length)"); return(0); } n *= elsz; if (n >= (unsigned)50000) { error("Warning: very large data structure"); nerror--; } return(n); } /* * The number of bytes in an object, rounded up to a word. */ rlength(cs) struct tnode *cs; { return((length(cs)+ALIGN) & ~ALIGN); } /* * After an "if (...) goto", look to see if the transfer * is to a simple label. */ simplegoto() { register struct hshtab *csp; if ((peeksym=symbol())==NAME && nextchar()==';') { csp = csym; if (csp->hblklev == 0) pushdecl(csp); if (csp->hclass==0 && csp->htype==0) { csp->htype = ARRAY; csp->hflag =| FLABL; if (csp->hoffset==0) csp->hoffset = isn++; } if ((csp->hclass==0||csp->hclass==STATIC) && csp->htype==ARRAY) { peeksym = -1; return(csp->hoffset); } } return(0); } /* * Return the next non-white-space character */ nextchar() { while (spnextchar()==' ') peekc = 0; return(peekc); } /* * Return the next character, translating all white space * to blank and handling line-ends. */ spnextchar() { register c; if ((c = peekc)==0) c = getchar(); if (c=='\t' || c=='\014') /* FF */ c = ' '; else if (c=='\n') { c = ' '; if (inhdr==0) line++; inhdr = 0; } else if (c=='\001') { /* SOH, insert marker */ inhdr++; c = ' '; } peekc = c; return(c); } /* * is a break or continue legal? */ chconbrk(l) { if (l==0) error("Break/continue error"); } /* * The goto statement. */ dogoto() { register struct tnode *np; *cp++ = tree(); build(STAR); chkw(np = *--cp, -1); rcexpr(block(JUMP,0,NULL,NULL,np)); } /* * The return statement, which has to convert * the returned object to the function's type. */ doret() { register struct tnode *t; if (nextchar() != ';') { t = tree(); *cp++ = &funcblk; *cp++ = t; build(ASSIGN); cp[-1] = cp[-1]->tr2; if (funcblk.type==CHAR) cp[-1] = block(ITOC, INT, NULL, NULL, cp[-1]); build(RFORCE); rcexpr(*--cp); } branch(retlab); } /* * Write a character on the error output. */ /* * Coded output: * B: beginning of line; an operator * N: a number * S: a symbol (external) * 1: number 1 * 0: number 0 */ outcode(s, a) char *s; { register *ap; register FILE *bufp; int n; register char *np; bufp = stdout; if (strflg) bufp = sbufp; ap = &a; for (;;) switch(*s++) { case 'B': putc(*ap++, bufp); putc(0376, bufp); continue; case 'N': putc(*ap, bufp); putc(*ap++>>8, bufp); continue; case 'F': n = 1000; np = *ap++; goto str; case 'S': n = NCPS; np = *ap++; if (*np) putc('_', bufp); str: while (n-- && *np) { putc(*np++&0177, bufp); } putc(0, bufp); continue; case '1': putc(1, bufp); putc(0, bufp); continue; case '0': putc(0, bufp); putc(0, bufp); continue; case '\0': if (ferror(bufp)) { error("Write error on temp"); exit(1); } return; default: error("Botch in outcode"); } }