summaryrefslogtreecommitdiff
path: root/bcc/exptree.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcc/exptree.c')
-rw-r--r--bcc/exptree.c1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/bcc/exptree.c b/bcc/exptree.c
new file mode 100644
index 0000000..c4da1c4
--- /dev/null
+++ b/bcc/exptree.c
@@ -0,0 +1,1087 @@
+/* exptree.c - expression tree routines for bcc */
+
+/* Copyright (C) 1992 Bruce Evans */
+
+#include "const.h"
+#include "types.h"
+#include "byteord.h"
+#include "gencode.h"
+#include "parse.h"
+#include "reg.h"
+#include "sc.h"
+#include "scan.h"
+#include "sizes.h"
+#include "type.h"
+
+#define ETREESIZE 1200
+#define errtype itype
+#define redtype ctype
+#define uredtype uctype
+
+PRIVATE struct nodestruct etree[ETREESIZE]; /* expression tree */
+PRIVATE struct nodestruct *ettop;
+
+FORWARD void badlvalue P((struct nodestruct *nodeptr));
+FORWARD void binconvert P((struct nodestruct *nodeptr));
+FORWARD void castiright P((struct nodestruct *nodeptr));
+FORWARD void etreefull P((void));
+FORWARD void fixnode P((struct nodestruct *nodeptr));
+FORWARD bool_pt isconst0 P((struct nodestruct *nodeptr));
+FORWARD bool_pt isnodecharconst P((struct nodestruct *nodeptr));
+FORWARD void needint P((struct nodestruct *nodeptr));
+FORWARD void neednonstruct P((struct nodestruct *nodeptr));
+FORWARD void needscalar P((struct nodestruct *nodeptr));
+FORWARD void needspv P((struct nodestruct *nodeptr));
+FORWARD struct typestruct *nodetype P((struct nodestruct *nodeptr));
+FORWARD int redscalar P((struct nodestruct *nodeptr));
+FORWARD struct nodestruct *unconvert P((struct nodestruct *nodeptr));
+
+PRIVATE void badlvalue(nodeptr)
+struct nodestruct *nodeptr;
+{
+ error("invalid lvalue");
+ fixnode(nodeptr);
+}
+
+PRIVATE void binconvert(nodeptr)
+register struct nodestruct *nodeptr;
+{
+ bool_t bothscalar;
+ value_t divisor;
+ scalar_t lscalar;
+ register struct nodestruct *right;
+ scalar_t rscalar;
+
+ rscalar = (right = nodeptr->right)->nodetype->scalar;
+ lscalar = nodeptr->left.nodeptr->nodetype->scalar;
+ if ((bothscalar = lscalar | rscalar) & RSCALAR)
+ {
+ nodeptr->nodetype = dtype;
+ if (!(lscalar & DOUBLE))
+ nodeptr->left.nodeptr = castnode(dtype, nodeptr->left.nodeptr);
+ if (!(rscalar & DOUBLE))
+ nodeptr->right = castnode(dtype, right);
+ }
+ else if (!(bothscalar & DLONG) && ((nodeptr->tag == ANDOP &&
+ (redscalar(nodeptr->left.nodeptr) | redscalar(right)) & CHAR) ||
+ ((nodeptr->tag == EOROP || nodeptr->tag == OROP) &&
+ redscalar(nodeptr->left.nodeptr) & redscalar(right) & CHAR) ||
+ (nodeptr->tag == MODOP && right->tag == LEAF &&
+ right->left.symptr->storage == CONSTANT &&
+ (divisor = right->left.symptr->offset.offv,
+ (uvalue_t) divisor <= MAXUCHTO + 1) &&
+ bitcount((uvalue_t) divisor) <= 1)))
+ {
+ /* result fits in char and extends correctly */
+ if (bothscalar & UNSIGNED)
+ nodeptr->nodetype = uredtype;
+ else
+ nodeptr->nodetype = redtype;
+ }
+ else if (bothscalar & LONG)
+ {
+ nodeptr->nodetype = ltype;
+ if (bothscalar & UNSIGNED)
+ nodeptr->nodetype = ultype;
+ if (bothscalar & (DLONG | SHORT | INT))
+ {
+ /* XXX - otherwise both are long, or one is long with the same
+ * size as int and the other is char, and we want the lower level
+ * routines to handle the char.
+ */
+ if (!(lscalar & LONG))
+ nodeptr->left.nodeptr = castnode(nodeptr->nodetype,
+ nodeptr->left.nodeptr);
+ if (!(rscalar & LONG))
+ nodeptr->right = castnode(nodeptr->nodetype, right);
+ }
+ }
+#ifdef I8088
+ else if (i386_32 && bothscalar & SHORT)
+ {
+ nodeptr->nodetype = itype;
+ if (bothscalar & UNSIGNED)
+ nodeptr->nodetype = uitype;
+ if (lscalar & SHORT)
+ nodeptr->left.nodeptr = castnode(nodeptr->nodetype,
+ nodeptr->left.nodeptr);
+ if (rscalar & SHORT)
+ nodeptr->right = castnode(nodeptr->nodetype, right);
+ }
+#endif
+ else if (bothscalar & UNSIGNED)
+ nodeptr->nodetype = uitype;
+ else
+ nodeptr->nodetype = itype;
+}
+
+PRIVATE void castiright(nodeptr)
+struct nodestruct *nodeptr;
+{
+ nodeptr->right = castnode(itype, nodeptr->right);
+}
+
+PUBLIC struct nodestruct *castnode(type, nodeptr)
+struct typestruct *type;
+struct nodestruct *nodeptr;
+{
+ struct symstruct *symptr;
+
+ (symptr = constsym((value_t) 0))->type = type;
+ return node(CASTOP, nodeptr, leafnode(symptr));
+}
+
+PRIVATE void etreefull()
+{
+ limiterror("expression too complex (1201 nodes)");
+}
+
+PUBLIC void etreeinit()
+{
+ ettop = (etptr = etree) + ETREESIZE;
+}
+
+PRIVATE void fixnode(nodeptr)
+register struct nodestruct *nodeptr;
+{
+ nodeptr->tag = LEAF;
+ nodeptr->flags = nodeptr->weight = 0;
+ nodeptr->left.symptr = constsym((value_t) 0); /* this has type errtype */
+ nodeptr->nodetype = errtype;
+}
+
+PRIVATE bool_pt isconst0(nodeptr)
+register struct nodestruct *nodeptr;
+{
+ register struct symstruct *symptr;
+
+ return nodeptr->tag == LEAF &&
+ (symptr = nodeptr->left.symptr)->storage == CONSTANT &&
+ symptr->offset.offv == 0 &&
+ symptr->type->scalar & ISCALAR;
+}
+
+PRIVATE bool_pt isnodecharconst(nodeptr)
+register struct nodestruct *nodeptr;
+{
+ register struct symstruct *symptr;
+
+ if (nodeptr->tag == LEAF &&
+ (symptr = nodeptr->left.symptr)->storage == CONSTANT &&
+ ischarconst(symptr->offset.offv) &&
+ symptr->type->scalar & ISCALAR)
+ return TRUE;
+ return FALSE;
+}
+
+PUBLIC struct nodestruct *leafnode(source)
+struct symstruct *source;
+{
+ register struct nodestruct *leafptr;
+
+ if ((leafptr = etptr++) >= ettop)
+ etreefull();
+ leafptr->tag = LEAF;
+ leafptr->flags = leafptr->weight = 0;
+ leafptr->nodetype = source->type;
+ leafptr->left.symptr = source;
+ leafptr->right = NULL;
+ return leafptr;
+}
+
+PRIVATE void needint(nodeptr)
+struct nodestruct *nodeptr;
+{
+ if (!(nodeptr->nodetype->scalar & ISCALAR))
+ {
+ error("need integral type");
+ fixnode(nodeptr);
+ }
+}
+
+PRIVATE void neednonstruct(nodeptr)
+struct nodestruct *nodeptr;
+{
+ if (nodeptr->nodetype->constructor & STRUCTU)
+ {
+ error("need non-structure type");
+ fixnode(nodeptr);
+ }
+}
+
+PRIVATE void needscalar(nodeptr)
+struct nodestruct *nodeptr;
+{
+ if (!nodeptr->nodetype->scalar)
+ {
+ error("need scalar");
+ fixnode(nodeptr);
+ }
+}
+
+PRIVATE void needspv(nodeptr)
+struct nodestruct *nodeptr;
+{
+ if (nodeptr->nodetype->constructor & (ARRAY | FUNCTION | STRUCTU))
+ {
+ error("need scalar or pointer or void");
+ fixnode(nodeptr);
+ }
+}
+
+PUBLIC struct nodestruct *node(t, p1, p2)
+op_pt t;
+struct nodestruct *p1;
+struct nodestruct *p2;
+{
+#if MAXREGS != 1
+ weight_t rightweight;
+#endif
+ double dsourceval = 0; /* for -Wall */
+ double dtargval = 0 ; /* for -Wall */
+ bool_t lflag;
+ scalar_t lscalar;
+ struct nodestruct *pswap;
+ struct symstruct *source = NULL; /* for -Wall */
+ value_t sourceval = 0 ; /* for -Wall */
+ struct symstruct *target;
+ offset_t targszdelta;
+ value_t targval = 0; /* for -Wall */
+ scalar_t rscalar = 0; /* for -Wall */
+ bool_t uflag;
+
+ switch ((op_t) t)
+ {
+ case ADDABOP:
+ if (p1->nodetype->constructor & (ARRAY | POINTER))
+ t = PTRADDABOP;
+ break;
+ case ADDOP:
+ if (p2->nodetype->constructor & (ARRAY | POINTER))
+ {
+ pswap = p1;
+ p1 = p2;
+ p2 = pswap;
+ }
+ if (p1->nodetype->constructor & (ARRAY | POINTER))
+ t = PTRADDOP;
+ break;
+ case CONDOP:
+ /* Change structs to struct pointers so condop() doesn't have to know
+ * about structs.
+ */
+ if (p2->nodetype->constructor & STRUCTU)
+ {
+ p2 = node(COLONOP, node(ADDRESSOP, p2->left.nodeptr, NULLNODE),
+ node(ADDRESSOP, p2->right, NULLNODE));
+ return node(INDIRECTOP, node(CONDOP, p1, p2), NULLNODE);
+ }
+ break;
+ case FUNCOP:
+ if (p1->nodetype->constructor & (ARRAY | POINTER))
+ p1 = node(INDIRECTOP, p1, NULLNODE);
+ break;
+ case SUBABOP:
+ if (p1->nodetype->constructor & (ARRAY | POINTER))
+ {
+ t = PTRADDABOP;
+ p2 = node(NEGOP, p2, NULLNODE);
+ break;
+ }
+ case SUBOP:
+#if 0
+ /* This works but sometimes pessimizes the code by converting small
+ * constants into large negative constants. It makes the most
+ * difference for longs by avoiding stack tangles. longop could be
+ * more careful. Only the case (regpair) - constant is naturally
+ * tangled.
+ */
+ if (p2->tag == LEAF && p2->nodetype->scalar
+ && (source = p2->left.symptr)->storage == CONSTANT)
+ {
+ if (source->type->scalar & RSCALAR)
+ *source->offset.offd = -*source->offset.offd;
+ else
+ source->offset.offv = -source->offset.offv;
+ return node((op_t) t == SUBOP ? ADDOP : ADDABOP, p1, p2);
+ }
+#endif
+ if (p1->nodetype->constructor & (ARRAY | POINTER))
+ {
+ if (p2->nodetype->nexttype == p1->nodetype->nexttype)
+ t = PTRSUBOP;
+ else
+ {
+ t = PTRADDOP;
+ p2 = node(NEGOP, p2, NULLNODE);
+ }
+ }
+ break;
+ }
+ if (((op_t) t == PTRADDABOP || (op_t) t == PTRADDOP) &&
+ p1->nodetype->nexttype->constructor & (FUNCTION | VOID))
+ error("arithmetic on pointer to function or void");
+ if (p1->tag != LEAF)
+ goto node1;
+ target = p1->left.symptr;
+ switch ((op_t) t)
+ {
+ case ADDRESSOP:
+ if (target->indcount == 0 && target->flags == REGVAR)
+ error("register variable addressed");
+ else if (target->type->constructor & ARRAY)
+ {
+ if (target->indcount != 0)
+ bugerror("botched array indirection count");
+ target->type = pointype(target->type);
+ }
+ else if (!(p1->flags & LVALUE))
+ badlvalue(p1);
+ else
+ {
+ address(target); /* change p1, no code generated */
+ if (target->indcount == 2) /* XXX - MAXINDIRECT? */
+ /* just became direct enough */
+ p1->weight = 1;
+ }
+ p1->flags &= ~LVALUE;
+ p1->nodetype = target->type;
+ return p1;
+ case CASTOP:
+ needspv(p2);
+ if (p1->nodetype == p2->nodetype)
+ {
+ p1->flags &= ~LVALUE;
+ return p1;
+ }
+ if ((rscalar = p2->nodetype->scalar) & ISCALAR)
+ neednonstruct(p1);
+ else if (rscalar & RSCALAR)
+ needscalar(p1);
+ else /* POINTER */
+ neednonstruct(p1); /* H & S say functions & arrays must match */
+ if (((lscalar = p1->nodetype->scalar) | rscalar) & RSCALAR)
+ {
+ if (target->storage != CONSTANT)
+ goto node1;
+ if (lscalar & RSCALAR && !(rscalar & RSCALAR))
+ {
+ double val;
+ static double MAXULONG = (double)0xFFFFFFFFL +1;
+
+ val = *target->offset.offd;
+ if (val > maxlongto)
+ val -= MAXULONG;
+ target->offset.offv = (value_t) val;
+ }
+ if (!(lscalar & RSCALAR) && rscalar & RSCALAR)
+ {
+ value_t val;
+
+ val = target->offset.offv;
+ target->offset.offd = qmalloc(sizeof *target->offset.offd);
+ if (lscalar & UNSIGNED)
+ *target->offset.offd = (uvalue_t) val;
+ else
+ *target->offset.offd = val;
+ }
+ }
+ if (target->storage == CONSTANT)
+ {
+ if (rscalar & CHAR)
+ target->offset.offv &= CHMASKTO;
+ else if (rscalar & SHORT)
+ {
+ target->offset.offv &= shortmaskto;
+ if (!(rscalar & UNSIGNED) && target->offset.offv > maxshortto)
+ target->offset.offv -= (maxushortto + 1);
+ }
+ else if (rscalar & INT)
+ {
+ target->offset.offv &= intmaskto;
+ if (!(rscalar & UNSIGNED) && target->offset.offv > maxintto)
+ target->offset.offv -= (maxuintto + 1);
+ }
+ else if (rscalar & FLOAT)
+ *target->offset.offd = (float) *target->offset.offd;
+ }
+ else if ((targszdelta =
+ ((p1->nodetype->constructor & (ARRAY | POINTER)) ?
+ ptypesize : p1->nodetype->typesize) -
+ p2->nodetype->typesize) == 0)
+ ;
+ else if (target->indcount == 1 && targszdelta > 0 &&
+ target->flags != REGVAR)
+ {
+#if DYNAMIC_LONG_ORDER
+ if (long_big_endian)
+#endif
+#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
+# if BIG_ENDIAN
+ target->offset.offi += targszdelta;
+# else
+ {
+ if (lscalar & DLONG)
+ target->offset.offi += itypesize; /* discard msword */
+ }
+# endif
+#endif
+#if DYNAMIC_LONG_ORDER
+ else
+#endif
+#if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
+# if BIG_ENDIAN
+ {
+ if (rscalar & CHAR)
+ target->offset.offi += ctypesize;
+ }
+# else
+ ;
+# endif
+#endif
+ }
+ else
+ goto node1;
+ p1->flags &= ~LVALUE;
+ p1->nodetype = target->type = p2->nodetype;
+ return p1;
+ case INDIRECTOP:
+ if (!(target->type->constructor & (ARRAY | POINTER)))
+ error("illegal indirection");
+ else
+ {
+ indirec(target);
+ if (target->indcount == 3) /* XXX - MAXINDIRECT + 1? */
+ /* just became too indirect */
+ p1->weight = 1;
+ p1->flags |= LVALUE;
+ p1->nodetype = target->type;
+ }
+ return p1;
+ case STRUCELTOP: /* p2 known leaf */
+ if (target->indcount != 1)
+ break; /* struc() would generate code */
+ struc(p2->left.symptr, target);
+ p1->flags |= LVALUE;
+ p1->nodetype = target->type;
+ return p1;
+ }
+ if (target->indcount != 0)
+ goto node1;
+ lscalar = target->type->scalar;
+ if (target->storage == CONSTANT)
+ {
+ if (lscalar & RSCALAR)
+ dtargval = *target->offset.offd;
+ else
+ targval = target->offset.offv;
+ switch ((op_t) t)
+ {
+ case COMMAOP:
+ return p2;
+ case CONDOP:
+ if ((lscalar & RSCALAR && dtargval != FALSE)
+ || (!(lscalar & RSCALAR) && targval != FALSE))
+ {
+ p2->left.nodeptr->nodetype = p2->nodetype;
+ return p2->left.nodeptr;
+ }
+ p2->right->nodetype = p2->nodetype;
+ return p2->right;
+ case LOGANDOP:
+ if ((lscalar & RSCALAR && dtargval != FALSE)
+ || (!(lscalar & RSCALAR) && targval != FALSE))
+ break;
+ p1->nodetype = target->type = itype;
+ return p1;
+ case LOGOROP:
+ if ((lscalar & RSCALAR && dtargval == FALSE)
+ || (!(lscalar & RSCALAR) && targval == FALSE))
+ break;
+ target->offset.offv = TRUE;
+ p1->nodetype = target->type = itype;
+ return p1;
+ }
+ }
+ switch ((op_t) t)
+ {
+ case COLONOP:
+ case FUNCOP:
+ case LISTOP:
+ case ROOTLISTOP:
+ goto node1;
+ case PTRADDOP:
+ if (p2->tag == LEAF &&
+ (source = p2->left.symptr)->storage == CONSTANT &&
+ source->type->scalar & ISCALAR)
+ {
+ indexadr(source, target);
+ p1->flags &= ~LVALUE;
+ p1->nodetype = target->type;
+ return p1;
+ }
+ }
+ if (target->storage != CONSTANT ||
+ !((lscalar & (ISCALAR | RSCALAR)) && (op_t) t != PTRSUBOP) ||
+ (p2 != NULL &&
+ (p2->tag != LEAF || (source = p2->left.symptr)->storage != CONSTANT ||
+ (!((rscalar = source->type->scalar) & (ISCALAR | RSCALAR))
+ && (op_t) t != PTRSUBOP))))
+ goto node1;
+ lflag = lscalar & LONG;
+ uflag = lscalar & UNSIGNED;
+ if (p2 != NULL)
+ {
+ if (rscalar & RSCALAR)
+ dsourceval = *source->offset.offd;
+ else
+ {
+ sourceval = source->offset.offv;
+ lflag |= rscalar & LONG;
+ uflag |= rscalar & UNSIGNED;
+ }
+ }
+ if (lscalar & RSCALAR || (p2 != NULL && rscalar & RSCALAR))
+ {
+ if (!(lscalar & RSCALAR))
+ {
+ if (uflag)
+ dtargval = (uvalue_t) targval;
+ else
+ dtargval = targval;
+ }
+ if (p2 != NULL && !(rscalar & RSCALAR))
+ {
+ if (rscalar & UNSIGNED)
+ dsourceval = (uvalue_t) sourceval;
+ else
+ dsourceval = sourceval;
+ }
+ switch ((op_t) t)
+ {
+ case ADDOP:
+ dtargval += dsourceval;
+ break;
+ case DIVOP:
+ if (dsourceval == 0)
+ {
+ error("divison by 0");
+ dsourceval = 1;
+ }
+ dtargval /= dsourceval;
+ break;
+ case EQOP:
+ targval = dtargval == dsourceval;
+ goto intconst;
+ case GEOP:
+ targval = dtargval >= dsourceval;
+ goto intconst;
+ case GTOP:
+ targval = dtargval > dsourceval;
+ goto intconst;
+ case LEOP:
+ targval = dtargval <= dsourceval;
+ goto intconst;
+ case LOGANDOP:
+ targval = dtargval && dsourceval;
+ goto intconst;
+ case LOGNOTOP:
+ targval = !dtargval;
+ goto intconst;
+ case LOGOROP:
+ targval = dtargval || dsourceval;
+ goto intconst;
+ case LTOP:
+ targval = dtargval < dsourceval;
+ goto intconst;
+ case MULOP:
+ dtargval *= dsourceval;
+ break;
+ case NEGOP:
+ dtargval = -dtargval;
+ break;
+ case NEOP:
+ targval = dtargval != dsourceval;
+ goto intconst;
+ case SUBOP:
+ dtargval -= dsourceval;
+ break;
+ }
+ /* XXX - leaks memory */
+ target->offset.offd = qmalloc(sizeof *target->offset.offd);
+ *target->offset.offd = dtargval;
+ p1->nodetype = target->type = dtype;
+ return p1;
+ }
+ switch ((op_t) t)
+ {
+ case ADDOP:
+ targval += sourceval;
+ break;
+ case ANDOP:
+ targval &= sourceval;
+ break;
+ case DIVOP:
+ if (sourceval == 0)
+ {
+ error("divison by 0");
+ sourceval = 1;
+ }
+ if (uflag)
+ targval = (uvalue_t) targval / sourceval;
+ else
+ targval /= sourceval;
+ break;
+ case EOROP:
+ targval ^= sourceval;
+ break;
+ case EQOP:
+ targval = targval == sourceval;
+ break;
+ case GEOP:
+ if (uflag)
+ targval = (uvalue_t) targval >= sourceval;
+ else
+ targval = targval >= sourceval;
+ goto intconst;
+ case GTOP:
+ if (uflag)
+ targval = (uvalue_t) targval > sourceval;
+ else
+ targval = targval > sourceval;
+ goto intconst;
+ case LEOP:
+ if (uflag)
+ targval = (uvalue_t) targval <= sourceval;
+ else
+ targval = targval <= sourceval;
+ goto intconst;
+ case LOGANDOP:
+ targval = targval && sourceval;
+ goto intconst;
+ case LOGNOTOP:
+ targval = !targval;
+ goto intconst;
+ case LOGOROP:
+ targval = targval || sourceval;
+ goto intconst;
+ case LTOP:
+ if (uflag)
+ targval = (uvalue_t) targval < sourceval;
+ else
+ targval = targval < sourceval;
+ goto intconst;
+ break;
+ case MODOP:
+ if (sourceval == 0)
+ {
+ error("modulo by 0");
+ sourceval = 1;
+ }
+ if (uflag)
+ targval = (uvalue_t) targval % sourceval;
+ else
+ targval %= sourceval;
+ break;
+ case MULOP:
+ targval *= sourceval;
+ break;
+ case NEGOP:
+ targval = -targval;
+ break;
+ case NEOP:
+ targval = targval != sourceval;
+ goto intconst;
+ case NOTOP:
+ targval = ~targval;
+ break;
+ case OROP:
+ targval |= sourceval;
+ break;
+ case PTRSUBOP:
+ if (targval < sourceval)
+ targval = -((uvalue_t) (sourceval - targval) /
+ target->type->nexttype->typesize);
+ else
+ targval = (uvalue_t) (targval - sourceval) /
+ target->type->nexttype->typesize;
+ uflag = FALSE;
+ break;
+ case SLOP:
+ targval <<= sourceval; /* assume shiftcount treated as unsigned */
+ lflag = lscalar & LONG;
+ uflag = lscalar & UNSIGNED;
+ break;
+ case SROP:
+ if (uflag)
+ targval = (uvalue_t) targval >> sourceval;
+ else
+ targval >>= sourceval;
+ lflag = lscalar & LONG;
+ uflag = lscalar & UNSIGNED;
+ break;
+ case SUBOP:
+ targval -= sourceval;
+ break;
+ }
+ if (lflag)
+ {
+ target->type = ltype;
+ if (uflag)
+ target->type = ultype;
+ }
+ else
+ {
+ targval &= intmaskto;
+ if (uflag)
+ target->type = uitype;
+ else
+ {
+ target->type = itype;
+ if (targval > maxintto)
+ targval -= (maxuintto + 1);
+ }
+ }
+ target->offset.offv = targval;
+ p1->nodetype = target->type;
+ return p1;
+
+intconst:
+ target->offset.offv = targval;
+ p1->nodetype = target->type = itype;
+ return p1;
+
+node1:
+ {
+ register struct nodestruct *nodeptr;
+ register struct nodestruct *regp2;
+
+ if ((nodeptr = etptr++) >= ettop)
+ etreefull();
+ regp2 = p2;
+ nodeptr->tag = t;
+ nodeptr->left.nodeptr = p1;
+ nodeptr->right = regp2;
+ if ((op_t) t == FUNCOP)
+ nodeptr->weight = MAXREGS + 1;
+ else
+ {
+#if MAXREGS == 1
+ if ((nodeptr->weight = p1->weight) <= MAXREGS &&
+ (regp2 == NULL ||
+ (nodeptr->weight = regp2->weight) < MAXREGS))
+ nodeptr->weight = MAXREGS;
+#else
+ nodeptr->weight = p1->weight;
+ if (regp2 == NULL)
+ rightweight = 1; /* could do POST-ops with 0 */
+ else /* 0 more approp for LIST-ops but 1 OK */
+ rightweight = regp2->weight;
+ if (nodeptr->weight < rightweight)
+ nodeptr->weight = rightweight;
+ else if (nodeptr->weight == rightweight &&
+ nodeptr->weight < MAXREGS)
+ ++nodeptr->weight;
+#endif
+ }
+ nodeptr->nodetype = nodetype(nodeptr);
+ return nodeptr;
+ }
+}
+
+PRIVATE struct typestruct *nodetype(nodeptr)
+struct nodestruct *nodeptr;
+{
+ scalar_t bothscalar;
+ scalar_t lscalar;
+ scalar_t rscalar;
+ struct nodestruct *left;
+ struct nodestruct *right;
+ struct typestruct *targtype;
+
+ if (nodeptr->tag == LEAF)
+ return nodeptr->left.symptr->type;
+ targtype = (left = nodeptr->left.nodeptr)->nodetype;
+ right = nodeptr->right;
+ switch (nodeptr->tag)
+ {
+ case FUNCOP:
+ if (!(targtype->constructor & FUNCTION))
+ {
+ error("call of non-function");
+ fixnode(nodeptr);
+ return errtype;
+ }
+ return targtype->nexttype;
+ case INDIRECTOP:
+ if (!(targtype->constructor & (ARRAY | POINTER)))
+ {
+ error("illegal indirection");
+ fixnode(nodeptr);
+ return errtype;
+ }
+ nodeptr->flags |= LVALUE;
+ return targtype->nexttype;
+ case LISTOP:
+ case ROOTLISTOP:
+ nodeptr->left.nodeptr = unconvert(left);
+ return promote(targtype);
+ case CASTOP:
+ needspv(right);
+ case COMMAOP:
+ case CONDOP:
+ return right->nodetype;
+
+ case STRUCELTOP:
+ nodeptr->flags |= LVALUE;
+ return right->nodetype;
+
+ case ADDRESSOP:
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+ return pointype(targtype);
+ case LOGNOTOP:
+ neednonstruct(left);
+ return redtype;
+ case NEGOP:
+ needscalar(left);
+ return promote(left->nodetype);
+ case NOTOP:
+ needint(left);
+ return promote(left->nodetype);
+ case PREDECOP:
+ case PREINCOP:
+ case POSTDECOP:
+ case POSTINCOP:
+ neednonstruct(left);
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+ break;
+
+ case ANDOP:
+ case EOROP:
+ case MODOP:
+ case OROP:
+ needint(left);
+ needint(right);
+ /* fall through to redundant check and code to cast to same types */
+ case ADDOP:
+ case DIVOP:
+ case MULOP:
+ case SUBOP:
+ needscalar(left);
+ needscalar(right);
+ binconvert(nodeptr);
+ return nodeptr->nodetype;
+
+ case PTRADDABOP:
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+ case PTRADDOP: /* right type conversion to same size as ptr */
+ needint(right);
+ if (right->nodetype->scalar & LONG)
+ castiright(nodeptr);
+ break;
+ case PTRSUBOP: /* already checked */
+ return itype;
+ case SLOP: /* right type conversion always to int */
+ case SROP: /* ulong strictly to unsigned but no matter */
+ needint(left);
+ needint(right);
+ if (right->nodetype->scalar & LONG)
+ castiright(nodeptr);
+ return promote(left->nodetype);
+
+ case LTOP:
+ case LEOP:
+ case GTOP:
+ case GEOP:
+ case EQOP:
+ case LOGOROP:
+ case LOGANDOP:
+ case NEOP:
+ neednonstruct(left);
+ neednonstruct(right);
+ nodeptr->left.nodeptr = left = unconvert(left);
+ nodeptr->right = right = unconvert(right);
+#ifdef MAYBE_DO_LATER /* OK if pointers fit in uitype */
+ if (left->nodetype->constructor & POINTER)
+ nodeptr->left.nodeptr = left = castnode(uitype, left);
+ if (right->nodetype->constructor & POINTER)
+ nodeptr->right = right = castnode(uitype, right);
+#endif
+ binconvert(nodeptr);
+ return redtype;
+
+ case COLONOP:
+ if (isnodecharconst(left) && isnodecharconst(right))
+ {
+ targtype = (targtype->scalar | right->nodetype->scalar) & UNSIGNED
+ ? uctype : ctype;
+ left = castnode(targtype, left);
+ right = castnode(targtype, right);
+ }
+ nodeptr->left.nodeptr = left = unconvert(left);
+ nodeptr->right = right = unconvert(right);
+ if ((targtype = left->nodetype) == right->nodetype)
+ return targtype; /* XXX - reduced from promote(targtype) */
+ if ((lscalar = targtype->scalar) != 0 &&
+ (rscalar = right->nodetype->scalar) != 0)
+ {
+ /* promote minimally without using binconvert for char/short */
+ if ((bothscalar = lscalar | rscalar) & (LONG | RSCALAR))
+ {
+ binconvert(nodeptr);
+ return nodeptr->nodetype;
+ }
+ if (bothscalar & INT || (lscalar ^ rscalar) & UNSIGNED)
+ targtype = itype;
+ else if (bothscalar & SHORT)
+ targtype = stype;
+ else
+ targtype = ctype;
+ if (bothscalar & UNSIGNED)
+ targtype = tounsigned(targtype);
+ if ((!(bothscalar & INT) || (left->tag == LEAF && lscalar & INT)) ||
+ (right->tag == LEAF && rscalar & INT))
+ {
+ /* this is correct even when the if fails (the casts have to */
+ /* be considered at a lower level) but gives worse code */
+ if (left->nodetype != targtype)
+ nodeptr->left.nodeptr = castnode(targtype, left);
+ if (right->nodetype != targtype)
+ nodeptr->right = castnode(targtype, right);
+ }
+ return targtype; /* XXX - reduced from promote(targtype) */
+ }
+ if (targtype->constructor & POINTER &&
+ (isconst0(right) || (right->nodetype->constructor & POINTER &&
+ right->nodetype->nexttype->constructor & VOID)))
+ return targtype;
+ if (right->nodetype->constructor & POINTER &&
+ (isconst0(left) || (targtype->constructor & POINTER &&
+ targtype->nexttype->constructor & VOID)))
+ return right->nodetype;
+ error("mismatched types");
+ fixnode(left); /* XXX - better to fix the CONDOP */
+ fixnode(right);
+ return errtype;
+
+ case ASSIGNOP:
+ if (right->nodetype->constructor & VOID)
+ {
+ error("assignment of void");
+ fixnode(right);
+ }
+ if (targtype->constructor & (ARRAY | FUNCTION | VOID))
+ {
+ error("assignment to array, function or void");
+ fixnode(nodeptr);
+ return errtype;
+ }
+ if ((targtype->constructor | right->nodetype->constructor)
+ & STRUCTU && targtype != right->nodetype)
+ {
+ error("assignment to/from struct/union of a different type");
+ fixnode(nodeptr);
+ return errtype;
+ }
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+#if 0
+ /* XXX - this is done at the lowest levels, with too many chances for
+ * errors.
+ */
+ if (targtype != right->nodetype)
+ nodeptr->right = castnode(left->nodetype, right);
+#endif
+ break;
+ case ANDABOP:
+ case EORABOP:
+ case MODABOP:
+ case ORABOP:
+ needint(right);
+ needint(left);
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+ /* fall through to redundant check and code to cast to same types */
+ case ADDABOP:
+ case SUBABOP:
+ case DIVABOP:
+ case MULABOP:
+ needscalar(right);
+ needscalar(left);
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+ rscalar = right->nodetype->scalar;
+ if ((lscalar = (targtype = left->nodetype)->scalar) & RSCALAR)
+ {
+ if (!(rscalar & DOUBLE))
+ nodeptr->right = castnode(dtype, right);
+ }
+ else if (lscalar & LONG)
+ {
+ if (!(rscalar & LONG))
+ nodeptr->right = castnode(rscalar & UNSIGNED
+ ? ultype : targtype, right);
+ }
+#ifdef I8088
+ else if (i386_32 && lscalar & INT)
+ {
+ if (rscalar & SHORT)
+ nodeptr->right = castnode(rscalar & UNSIGNED
+ ? uitype : targtype, right);
+ }
+#endif
+ break;
+ case SLABOP:
+ case SRABOP:
+ needint(right);
+ needint(left);
+ if (!(left->flags & LVALUE))
+ {
+ badlvalue(nodeptr);
+ return errtype;
+ }
+ if (!(right->nodetype->scalar & INT))
+ castiright(nodeptr);
+ break;
+ }
+ return left->nodetype;
+}
+
+PRIVATE int redscalar(nodeptr)
+register struct nodestruct *nodeptr;
+{
+ if (isnodecharconst(nodeptr))
+ return CHAR;
+ return nodeptr->nodetype->scalar;
+}
+
+PRIVATE struct nodestruct *unconvert(nodeptr)
+struct nodestruct *nodeptr;
+{
+ if (nodeptr->nodetype->constructor & (ARRAY | FUNCTION))
+ return castnode(pointype(nodeptr->nodetype->constructor & ARRAY ?
+ nodeptr->nodetype->nexttype :
+ nodeptr->nodetype), nodeptr);
+ return nodeptr;
+}