Interdata_v6/usr/source/c/c04.c
#
/*
* 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)<<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)
struct tnode *t;
{
treeout(t);
outcode("BNNN", CBRANCH, lbl, cond, line);
}
/*
* Write out a tree.
*/
rcexpr(atp)
struct tnode *atp;
{
register struct tnode *tp;
/*
* Special optimization
*/
if ((tp=atp)->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);
outcode("BN", EXPR, line);
}
treeout(atp)
struct tnode *atp;
{
register struct tnode *tp;
register struct hshtab *hp;
if ((tp = atp) == 0) {
outcode("B", NULLOP);
return;
}
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);
return;
case LCON:
outcode("BNNN", tp->op, tp->type, tp->lvalue);
return;
case CON:
outcode("BNN", tp->op, tp->type, tp->value);
return;
case FCON:
outcode("BNF", tp->op, tp->type, tp->cstr);
return;
case STRING:
outcode("BNNN", NAME, STATIC, tp->type, tp->tr1);
return;
case FSEL:
treeout(tp->tr1);
outcode("BNNN",tp->op,tp->type,tp->tr2->bitoffs,tp->tr2->flen);
return;
case ETYPE:
error("Illegal use of type");
return;
default:
treeout(tp->tr1);
if (opdope[tp->op]&BINARY)
treeout(tp->tr2);
outcode("BN", tp->op, tp->type);
return;
}
}
/*
* 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 tnode *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, 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)
return(SZPTR*n);
switch(t&TYPE) {
case INT:
case UNSIGN:
return(SZINT*n);
case CHAR:
return(n);
/***/ case SHORT:
/***/ return(SZSHORT*n);
case FLOAT:
return(SZFLOAT*n);
case LONG:
return(SZLONG*n);
case DOUBLE:
return(SZDOUB*n);
case STRUCT:
if ((t = cs->strp->ssize) == 0)
error("Undefined structure");
return(n * t);
}
error("Compiler error (length)");
return(0);
}
/*
* 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;
build(RFORCE);
rcexpr(*--cp);
}
branch(retlab);
}
/*
* Write a character on the error output.
*/
putchar(c)
{
/***/ char sc;
sc = c&0177;
write(1, &sc, 1);
}
/*
* 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;
{
extern errno;
register *ap, *bufp;
int n, anyerr;
register char *np;
bufp = obuf;
if (strflg)
bufp = sbuf;
ap = &a;
errno = 0;
anyerr = 0;
for (;;) switch(*s++) {
case 'B':
putw(*ap++ | (0376<<8), bufp);
anyerr =| errno;
continue;
case 'N':
putw(*ap++, bufp);
anyerr =| errno;
continue;
case 'F':
n = 1000;
goto str;
case 'S':
n = NCPS;
str:
np = *ap++;
while (n-- && *np) {
putc(*np++&0177, bufp);
}
putc(0, bufp);
anyerr =| errno;
continue;
case '1':
putw(1, bufp);
anyerr =| errno;
continue;
case '0':
putw(0, bufp);
anyerr =| errno;
continue;
case '\0':
if (anyerr) {
error("Write error on temp");
exit(1);
}
return;
default:
error("Botch in outcode");
}
}