/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* @(#)c04.c 1.2 */ /* * C compiler */ static char *Sccsid = "@(#)c04.c 3.0 (ULTRIX) 4/21/86"; #include "c0.h" /* * Reduce the degree-of-reference by one. * e.g. turn "ptr-to-int" into "int". */ decref(t) register int t; { 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) register int t; { return(((t&~TYPE)<<TYLEN) | (t&TYPE) | PTR); } /* * Make a tree that causes a branch to lbl * if the tree's value is non-zero together with the cond. */ cbranch(t, lbl, cond) union tree *t; { treeout(t, 0); outcode("BNNN", CBRANCH, lbl, cond, line); } /* * Write out a tree. */ rcexpr(tp) register union tree *tp; { /* * Special optimization */ if (tp->t.op==INIT && tp->t.tr1->t.op==CON) { if (tp->t.type==CHAR || tp->t.type==UNCHAR) { outcode("B1N0", BDATA, tp->t.tr1->c.value); return; } else if (tp->t.type==INT || tp->t.type==UNSIGN) { outcode("BN", SINIT, tp->t.tr1->c.value); return; } } treeout(tp, 0); outcode("BN", EXPR, line); } treeout(tp, isstruct) register union tree *tp; { register struct nmlist *hp; register nextisstruct; if (tp == NULL || tp->t.op==NULLOP) { outcode("B", XNULLOP); return; } nextisstruct = tp->t.type==STRUCT; if (tp->t.type==VOID) tp->t.type = INT; switch(tp->t.op) { case NAME: hp = &tp->t.tr1->n; if (hp->hclass==TYPEDEF) error("Illegal use of type name"); outcode("BNN", NAME, hp->hclass==0?STATIC:hp->hclass, tp->t.type); if (hp->hclass==EXTERN) outcode("S", hp->name); else outcode("N", hp->hoffset); break; case LCON: outcode("BNNN", tp->l.op, tp->l.type, tp->l.lvalue); break; case CON: outcode("BNN", tp->c.op, tp->c.type, tp->c.value); break; case FCON: outcode("BNF", tp->f.op, tp->f.type, tp->f.cstr); break; case STRING: outcode("BNNN", NAME, STATIC, tp->t.type, tp->t.tr1); break; case FSEL: treeout(tp->t.tr1, nextisstruct); outcode("BNNN", tp->t.op, tp->t.type, tp->t.tr2->fld.bitoffs, tp->t.tr2->fld.flen); break; case ETYPE: error("Illegal use of type"); break; case AMPER: treeout(tp->t.tr1, 1); outcode("BN", tp->t.op, tp->t.type); break; case CALL: treeout(tp->t.tr1, 1); treeout(tp->t.tr2, 0); outcode("BN", CALL, tp->t.type); break; default: treeout(tp->t.tr1, nextisstruct); if (opdope[tp->t.op]&BINARY) treeout(tp->t.tr2, nextisstruct); outcode("BN", tp->t.op, tp->t.type); break; } if (nextisstruct && isstruct==0) outcode("BNN", STRASG, STRUCT, tp->t.strp->S.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(p) register union tree *p; { register t, l; if (p==0 || ((t=p->t.type)&~TYPE) == 0) /* not a reference */ return(1); p->t.type = decref(t); l = length(p); p->t.type = t; return(l); } /* * return the number of bytes in the object * whose tree node is acs. */ length(cs) union tree *cs; { register t, elsz; long n; int nd; t = cs->t.type; n = 1; nd = 0; while ((t&XTYPE) == ARRAY) { t = decref(t); n *= cs->t.subsp[nd++]; } if ((t&~TYPE)==FUNC) return(0); if (t>=PTR) elsz = SZPTR; else switch(t&TYPE) { case VOID: error("Illegal use of void object"); return(2); case INT: case UNSIGN: elsz = SZINT; break; case CHAR: case UNCHAR: elsz = 1; break; case FLOAT: elsz = SZFLOAT; break; case LONG: elsz = SZLONG; break; case DOUBLE: elsz = SZDOUB; break; case STRUCT: if ((elsz = cs->t.strp->S.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) union tree *cs; { return((length(cs)+ALIGN) & ~ALIGN); } /* * After an "if (...) goto", look to see if the transfer * is to a simple label. */ simplegoto() { register struct nmlist *csp; if ((peeksym=symbol())==NAME && nextchar()==';') { csp = csym; if (csp->hblklev == 0) csp = 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 union tree *np; register char *st; st = starttree(); *cp++ = tree(0); build(STAR); chkw(np = *--cp, -1); rcexpr(block(JUMP, 0, (int *)NULL, (union str *)NULL, np, TNULL)); endtree(st); } /* * The return statement, which has to convert * the returned object to the function's type. */ doret() { register union tree *t; if (nextchar() != ';') { register char *st; st = starttree(); t = tree(0); *cp++ = (union tree *)&funcblk; *cp++ = t; build(ASSIGN); cp[-1] = cp[-1]->t.tr2; if (funcblk.type==CHAR) cp[-1] = block(ITOC, INT, (int *)NULL, (union str *)NULL, cp[-1], TNULL); build(RFORCE); rcexpr(*--cp); endtree(st); } 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 */ /* VARARGS1 */ 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 = (char *)*ap++; goto str; case 'S': n = NCPS; np = (char *)*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"); } } unsigned hash(sp) register char *sp; { register unsigned h; register c; h = 0; c = 7; do { if (*sp == 0) break; h += h; h += *sp++; } while (--c != 0); return(h%HSHSIZ); }