Research V6 development
[unix-history] / usr / source / c / c04.c
#
/*
* C compiler
*
*
*/
#include "c0h.c"
/*
* 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(tree, lbl, cond)
struct tnode *tree;
{
rcexpr(block(1,CBRANCH,tree,lbl,cond));
}
/*
* Write out a tree.
*/
rcexpr(tree)
struct tnode *tree;
{
treeout(tree);
outcode("BN", EXPR, line);
}
treeout(atree)
struct tnode *atree;
{
register struct tnode *tree;
if ((tree = atree) == 0)
return;
switch(tree->op) {
case 0:
outcode("B", NULL);
return;
case NAME:
outcode("BNN", NAME, tree->class, tree->type);
if (tree->class==EXTERN)
outcode("S", tree->nname);
else
outcode("N", tree->nloc);
return;
case CON:
case FCON:
case SFCON:
outcode("BNN", tree->op, tree->type, tree->value);
return;
case FSEL:
treeout(tree->tr1);
outcode("BNN", tree->op, tree->type, tree->tr2);
return;
case CBRANCH:
treeout(tree->btree);
outcode("BNN", tree->op, tree->lbl, tree->cond);
return;
default:
treeout(tree->tr1);
if (opdope[tree->op]&BINARY)
treeout(tree->tr2);
outcode("BN", tree->op, tree->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 tname *ap;
{
register t, l;
register struct tname *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;
cs = acs;
t = cs->type;
n = 1;
while ((t&XTYPE) == ARRAY) {
t = decref(t);
n = dimtab[cs->ssp&0377];
}
if ((t&~TYPE)==FUNC)
return(0);
if (t>=PTR)
return(2*n);
switch(t&TYPE) {
case INT:
return(2*n);
case CHAR:
return(n);
case FLOAT:
case LONG:
return(4*n);
case DOUBLE:
return(8*n);
case STRUCT:
return(n * dimtab[cs->lenp&0377]);
case RSTRUCT:
error("Bad structure");
return(0);
}
error("Compiler error (length)");
}
/*
* 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->hclass==0 && csp->htype==0) {
csp->htype = ARRAY;
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 = ' ';
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(1,JUMP,0,0,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 out a character to the usual output
* or to the string file
*/
putchar(c)
{
write(1, &c, 1);
}
outcode(s, a)
char *s;
{
register char *sp;
register *ap, *bufp;
int n;
char *np;
bufp = obuf;
if (strflg)
bufp = sbuf;
ap = &a;
for (;;) switch(*s++) {
case 'B':
putw(*ap++ | (0376<<8), bufp);
continue;
case 'N':
putw(*ap++, bufp);
continue;
case 'S':
np = *ap++;
n = ncps;
while (n-- && *np) {
putc(*np++, bufp);
}
putc(0, bufp);
continue;
case '1':
putw(1, bufp);
continue;
case '0':
putw(0, bufp);
continue;
case '\0':
return;
}
error("Botch in outcode");
}