summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/ccom/trees.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/pcc/ccom/trees.c')
-rw-r--r--usr.bin/pcc/ccom/trees.c2466
1 files changed, 2466 insertions, 0 deletions
diff --git a/usr.bin/pcc/ccom/trees.c b/usr.bin/pcc/ccom/trees.c
new file mode 100644
index 00000000000..077d4b9d743
--- /dev/null
+++ b/usr.bin/pcc/ccom/trees.c
@@ -0,0 +1,2466 @@
+/* $Id: trees.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Some of the changes from 32V include:
+ * - Understand "void" as type.
+ * - Handle enums as ints everywhere.
+ * - Convert some C-specific ops into branches.
+ */
+
+# include "pass1.h"
+# include "pass2.h"
+
+# include <stdarg.h>
+
+static void chkpun(NODE *p);
+static int chkenum(int, int, NODE *p);
+static int opact(NODE *p);
+static int moditype(TWORD);
+static NODE *strargs(NODE *);
+static void rmcops(NODE *p);
+
+int lastloc = -1;
+
+/* some special actions, used in finding the type of nodes */
+# define NCVT 01
+# define PUN 02
+# define TYPL 04
+# define TYPR 010
+# define TYMATCH 040
+# define LVAL 0100
+# define CVTO 0200
+# define CVTL 0400
+# define CVTR 01000
+# define PTMATCH 02000
+# define OTHER 04000
+# define NCVTR 010000
+
+/* node conventions:
+
+ NAME: rval>0 is stab index for external
+ rval<0 is -inlabel number
+ lval is offset in bits
+ ICON: lval has the value
+ rval has the STAB index, or - label number,
+ if a name whose address is in the constant
+ rval = NONAME means no name
+ REG: rval is reg. identification cookie
+
+ */
+
+int bdebug = 0;
+
+NODE *
+buildtree(int o, NODE *l, NODE *r)
+{
+ NODE *p, *q;
+ int actions;
+ int opty;
+ struct symtab *sp = NULL; /* XXX gcc */
+ NODE *lr, *ll;
+ char *name;
+ struct symtab **elem;
+
+#ifdef PCC_DEBUG
+ if (bdebug) {
+ printf("buildtree(%s, %p, %p)\n", copst(o), l, r);
+ if (l) fwalk(l, eprint, 0);
+ if (r) fwalk(r, eprint, 0);
+ }
+#endif
+ opty = coptype(o);
+
+ /* check for constants */
+
+ if( opty == UTYPE && l->n_op == ICON ){
+
+ switch( o ){
+
+ case NOT:
+ case UMINUS:
+ case COMPL:
+ if( conval( l, o, l ) ) return(l);
+ break;
+ }
+ } else if (o == NOT && l->n_op == FCON) {
+ l = clocal(block(SCONV, l, NIL, INT, 0, MKSUE(INT)));
+ } else if( o == UMINUS && l->n_op == FCON ){
+ l->n_dcon = -l->n_dcon;
+ return(l);
+
+ } else if( o==QUEST && l->n_op==ICON ) {
+ CONSZ c = l->n_lval;
+ nfree(l);
+ if (c) {
+ tfree(r->n_right);
+ l = r->n_left;
+ nfree(r);
+ return(l);
+ } else {
+ tfree(r->n_left);
+ l = r->n_right;
+ nfree(r);
+ return(l);
+ }
+ } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){
+
+ switch( o ){
+
+ case PLUS:
+ case MINUS:
+ case MUL:
+ case DIV:
+ case MOD:
+ /*
+ * Do type propagation for simple types here.
+ * The constant value is correct anyway.
+ * Maybe this op shortcut should be removed?
+ */
+ if (l->n_sp == NULL && r->n_sp == NULL &&
+ l->n_type < BTMASK && r->n_type < BTMASK) {
+ if (l->n_type > r->n_type)
+ r->n_type = l->n_type;
+ else
+ l->n_type = r->n_type;
+ }
+ /* FALLTHROUGH */
+ case ULT:
+ case UGT:
+ case ULE:
+ case UGE:
+ case LT:
+ case GT:
+ case LE:
+ case GE:
+ case EQ:
+ case NE:
+ case ANDAND:
+ case OROR:
+ case AND:
+ case OR:
+ case ER:
+ case LS:
+ case RS:
+ if( conval( l, o, r ) ) {
+ nfree(r);
+ return(l);
+ }
+ break;
+ }
+ } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) &&
+ (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS ||
+ o == MUL || o == DIV)) {
+ switch(o){
+ case PLUS:
+ case MINUS:
+ case MUL:
+ case DIV:
+ if (l->n_op == ICON)
+ l->n_dcon = l->n_lval;
+ if (r->n_op == ICON)
+ r->n_dcon = r->n_lval;
+ switch (o) {
+ case PLUS:
+ l->n_dcon += r->n_dcon; break;
+ case MINUS:
+ l->n_dcon -= r->n_dcon; break;
+ case MUL:
+ l->n_dcon *= r->n_dcon; break;
+ case DIV:
+ if (r->n_dcon == 0)
+ uerror("division by 0.");
+ else
+ l->n_dcon /= r->n_dcon;
+ }
+ l->n_op = FCON;
+ l->n_type = DOUBLE;
+ l->n_sue = MKSUE(DOUBLE);
+ nfree(r);
+ return(l);
+ }
+ }
+
+ /* its real; we must make a new node */
+
+ p = block(o, l, r, INT, 0, MKSUE(INT));
+
+ actions = opact(p);
+
+ if (actions & LVAL) { /* check left descendent */
+ if (notlval(p->n_left)) {
+ uerror("lvalue required");
+#ifdef notyet
+ } else {
+ if ((l->n_type > BTMASK && ISCON(l->n_qual)) ||
+ (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT)))
+ if (blevel > 0)
+ uerror("lvalue is declared const");
+#endif
+ }
+ }
+
+ if( actions & NCVTR ){
+ p->n_left = pconvert( p->n_left );
+ }
+ else if( !(actions & NCVT ) ){
+ switch( opty ){
+
+ case BITYPE:
+ p->n_right = pconvert( p->n_right );
+ case UTYPE:
+ p->n_left = pconvert( p->n_left );
+
+ }
+ }
+
+ if ((actions&PUN) && (o!=CAST))
+ chkpun(p);
+
+ if( actions & (TYPL|TYPR) ){
+
+ q = (actions&TYPL) ? p->n_left : p->n_right;
+
+ p->n_type = q->n_type;
+ p->n_qual = q->n_qual;
+ p->n_df = q->n_df;
+ p->n_sue = q->n_sue;
+ }
+
+ if( actions & CVTL ) p = convert( p, CVTL );
+ if( actions & CVTR ) p = convert( p, CVTR );
+ if( actions & TYMATCH ) p = tymatch(p);
+ if( actions & PTMATCH ) p = ptmatch(p);
+
+ if( actions & OTHER ){
+ l = p->n_left;
+ r = p->n_right;
+
+ switch(o){
+
+ case NAME:
+ sp = spname;
+ if (sp->sflags & STNODE) {
+ /* Generated for optimizer */
+ p->n_op = TEMP;
+ p->n_type = sp->stype;
+ p->n_sue = sp->ssue;
+ p->n_df = sp->sdf;
+ p->n_lval = sp->soffset;
+ break;
+ }
+
+#ifdef GCC_COMPAT
+ /* Get a label name */
+ if (sp->sflags == SLBLNAME) {
+ p->n_type = VOID;
+ p->n_sue = MKSUE(VOID);
+ p->n_lval = 0;
+ p->n_sp = sp;
+ break;
+ } else
+#endif
+ if (sp->stype == UNDEF) {
+ uerror("%s undefined", sp->sname);
+ /* make p look reasonable */
+ p->n_type = INT;
+ p->n_sue = MKSUE(INT);
+ p->n_df = NULL;
+ p->n_sp = sp;
+ p->n_lval = 0;
+ defid(p, SNULL);
+ break;
+ }
+ p->n_type = sp->stype;
+ p->n_qual = sp->squal;
+ p->n_df = sp->sdf;
+ p->n_sue = sp->ssue;
+ p->n_lval = 0;
+ p->n_sp = sp;
+ /* special case: MOETY is really an ICON... */
+ if (p->n_type == MOETY) {
+ p->n_sp = NULL;
+ p->n_lval = sp->soffset;
+ p->n_df = NULL;
+ p->n_type = ENUMTY;
+ p->n_op = ICON;
+ }
+ break;
+
+ case STREF:
+ /* p->x turned into *(p+offset) */
+ /* rhs must be a name; check correctness */
+
+ /* Find member symbol struct */
+ if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){
+ uerror("struct or union required");
+ break;
+ }
+
+ if ((elem = l->n_sue->suelem) == NULL)
+ uerror("undefined struct or union");
+
+ name = r->n_name;
+ for (; *elem != NULL; elem++) {
+ sp = *elem;
+ if (sp->sname == name)
+ break;
+ }
+ if (*elem == NULL)
+ uerror("member '%s' not declared", name);
+
+ r->n_sp = sp;
+ p = stref(p);
+ break;
+
+ case UMUL:
+ if (l->n_op == ADDROF) {
+ nfree(p);
+ p = l->n_left;
+ nfree(l);
+ }
+ if( !ISPTR(l->n_type))uerror("illegal indirection");
+ p->n_type = DECREF(l->n_type);
+ p->n_qual = DECREF(l->n_qual);
+ p->n_df = l->n_df;
+ p->n_sue = l->n_sue;
+ break;
+
+ case ADDROF:
+ switch( l->n_op ){
+
+ case UMUL:
+ nfree(p);
+ p = l->n_left;
+ nfree(l);
+ case TEMP:
+ case NAME:
+ p->n_type = INCREF(l->n_type);
+ p->n_qual = INCQAL(l->n_qual);
+ p->n_df = l->n_df;
+ p->n_sue = l->n_sue;
+ break;
+
+ case COMOP:
+ nfree(p);
+ lr = buildtree(ADDROF, l->n_right, NIL);
+ p = buildtree( COMOP, l->n_left, lr );
+ nfree(l);
+ break;
+
+ case QUEST:
+ lr = buildtree( ADDROF, l->n_right->n_right, NIL );
+ ll = buildtree( ADDROF, l->n_right->n_left, NIL );
+ nfree(p); nfree(l->n_right);
+ p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) );
+ nfree(l);
+ break;
+
+ default:
+ uerror("unacceptable operand of &: %d", l->n_op );
+ break;
+ }
+ break;
+
+ case LS:
+ case RS: /* must make type size at least int... */
+ if (p->n_type == CHAR || p->n_type == SHORT) {
+ p->n_left = makety(l, INT, 0, 0, MKSUE(INT));
+ } else if (p->n_type == UCHAR || p->n_type == USHORT) {
+ p->n_left = makety(l, UNSIGNED, 0, 0,
+ MKSUE(UNSIGNED));
+ }
+ l = p->n_left;
+ p->n_type = l->n_type;
+ p->n_qual = l->n_qual;
+ p->n_df = l->n_df;
+ p->n_sue = l->n_sue;
+
+ /* FALLTHROUGH */
+ case LSEQ:
+ case RSEQ: /* ...but not for assigned types */
+ if(tsize(r->n_type, r->n_df, r->n_sue) > SZINT)
+ p->n_right = makety(r, INT, 0, 0, MKSUE(INT));
+ break;
+
+ case RETURN:
+ case ASSIGN:
+ case CAST:
+ /* structure assignment */
+ /* take the addresses of the two sides; then make an
+ * operator using STASG and
+ * the addresses of left and right */
+
+ {
+ struct suedef *sue;
+ TWORD t;
+ union dimfun *d;
+
+ if (l->n_sue != r->n_sue)
+ uerror("assignment of different structures");
+
+ r = buildtree(ADDROF, r, NIL);
+ t = r->n_type;
+ d = r->n_df;
+ sue = r->n_sue;
+
+ l = block(STASG, l, r, t, d, sue);
+
+ if( o == RETURN ){
+ nfree(p);
+ p = l;
+ break;
+ }
+
+ p->n_op = UMUL;
+ p->n_left = l;
+ p->n_right = NIL;
+ break;
+ }
+ case COLON:
+ /* structure colon */
+
+ if (l->n_sue != r->n_sue)
+ uerror( "type clash in conditional" );
+ break;
+
+ case CALL:
+ p->n_right = r = strargs(p->n_right);
+ case UCALL:
+ if (!ISPTR(l->n_type))
+ uerror("illegal function");
+ p->n_type = DECREF(l->n_type);
+ if (!ISFTN(p->n_type))
+ uerror("illegal function");
+ p->n_type = DECREF(p->n_type);
+ p->n_df = l->n_df;
+ p->n_sue = l->n_sue;
+ if (l->n_op == ADDROF && l->n_left->n_op == NAME &&
+ l->n_left->n_sp != NULL && l->n_left->n_sp != NULL &&
+ (l->n_left->n_sp->sclass == FORTRAN ||
+ l->n_left->n_sp->sclass == UFORTRAN)) {
+ p->n_op += (FORTCALL-CALL);
+ }
+ if (p->n_type == STRTY || p->n_type == UNIONTY) {
+ /* function returning structure */
+ /* make function really return ptr to str., with * */
+
+ p->n_op += STCALL-CALL;
+ p->n_type = INCREF(p->n_type);
+ p = clocal(p); /* before recursing */
+ p = buildtree(UMUL, p, NIL);
+
+ }
+ break;
+
+ default:
+ cerror( "other code %d", o );
+ }
+
+ }
+
+ /*
+ * Allow (void)0 casts.
+ * XXX - anything on the right side must be possible to cast.
+ * XXX - remove void types further on.
+ */
+ if (p->n_op == CAST && p->n_type == VOID &&
+ p->n_right->n_op == ICON)
+ p->n_right->n_type = VOID;
+
+ if (actions & CVTO)
+ p = oconvert(p);
+ p = clocal(p);
+
+#ifdef PCC_DEBUG
+ if (bdebug) {
+ printf("End of buildtree:\n");
+ fwalk(p, eprint, 0);
+ }
+#endif
+
+ return(p);
+
+ }
+
+/*
+ * Do a conditional branch.
+ */
+void
+cbranch(NODE *p, NODE *q)
+{
+ p = buildtree(CBRANCH, p, q);
+ if (p->n_left->n_op == ICON) {
+ if (p->n_left->n_lval != 0)
+ branch(q->n_lval); /* branch always */
+ tfree(p);
+ tfree(q);
+ return;
+ }
+ ecomp(p);
+}
+
+NODE *
+strargs( p ) register NODE *p; { /* rewrite structure flavored arguments */
+
+ if( p->n_op == CM ){
+ p->n_left = strargs( p->n_left );
+ p->n_right = strargs( p->n_right );
+ return( p );
+ }
+
+ if( p->n_type == STRTY || p->n_type == UNIONTY ){
+ p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_sue);
+ p->n_left = buildtree( ADDROF, p->n_left, NIL );
+ p = clocal(p);
+ }
+ return( p );
+}
+
+/*
+ * apply the op o to the lval part of p; if binary, rhs is val
+ */
+int
+conval(NODE *p, int o, NODE *q)
+{
+ int i, u;
+ CONSZ val;
+ U_CONSZ v1, v2;
+
+ val = q->n_lval;
+ u = ISUNSIGNED(p->n_type) || ISUNSIGNED(q->n_type);
+ if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE);
+
+ if (p->n_sp != NULL && q->n_sp != NULL)
+ return(0);
+ if (q->n_sp != NULL && o != PLUS)
+ return(0);
+ if (p->n_sp != NULL && o != PLUS && o != MINUS)
+ return(0);
+ v1 = p->n_lval;
+ v2 = q->n_lval;
+ switch( o ){
+
+ case PLUS:
+ p->n_lval += val;
+ if (p->n_sp == NULL) {
+ p->n_rval = q->n_rval;
+ p->n_type = q->n_type;
+ }
+ break;
+ case MINUS:
+ p->n_lval -= val;
+ break;
+ case MUL:
+ p->n_lval *= val;
+ break;
+ case DIV:
+ if (val == 0)
+ uerror("division by 0");
+ else {
+ if (u) {
+ v1 /= v2;
+ p->n_lval = v1;
+ } else
+ p->n_lval /= val;
+ }
+ break;
+ case MOD:
+ if (val == 0)
+ uerror("division by 0");
+ else {
+ if (u) {
+ v1 %= v2;
+ p->n_lval = v1;
+ } else
+ p->n_lval %= val;
+ }
+ break;
+ case AND:
+ p->n_lval &= val;
+ break;
+ case OR:
+ p->n_lval |= val;
+ break;
+ case ER:
+ p->n_lval ^= val;
+ break;
+ case LS:
+ i = val;
+ p->n_lval = p->n_lval << i;
+ break;
+ case RS:
+ i = val;
+ if (u) {
+ v1 = v1 >> i;
+ p->n_lval = v1;
+ } else
+ p->n_lval = p->n_lval >> i;
+ break;
+
+ case UMINUS:
+ p->n_lval = - p->n_lval;
+ break;
+ case COMPL:
+ p->n_lval = ~p->n_lval;
+ break;
+ case NOT:
+ p->n_lval = !p->n_lval;
+ break;
+ case LT:
+ p->n_lval = p->n_lval < val;
+ break;
+ case LE:
+ p->n_lval = p->n_lval <= val;
+ break;
+ case GT:
+ p->n_lval = p->n_lval > val;
+ break;
+ case GE:
+ p->n_lval = p->n_lval >= val;
+ break;
+ case ULT:
+ p->n_lval = v1 < v2;
+ break;
+ case ULE:
+ p->n_lval = v1 <= v2;
+ break;
+ case UGT:
+ p->n_lval = v1 > v2;
+ break;
+ case UGE:
+ p->n_lval = v1 >= v2;
+ break;
+ case EQ:
+ p->n_lval = p->n_lval == val;
+ break;
+ case NE:
+ p->n_lval = p->n_lval != val;
+ break;
+ case ANDAND:
+ p->n_lval = p->n_lval && val;
+ break;
+ case OROR:
+ p->n_lval = p->n_lval || val;
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+ }
+
+/*
+ * Checks p for the existance of a pun. This is called when the op of p
+ * is ASSIGN, RETURN, CAST, COLON, or relational.
+ * One case is when enumerations are used: this applies only to lint.
+ * In the other case, one operand is a pointer, the other integer type
+ * we check that this integer is in fact a constant zero...
+ * in the case of ASSIGN, any assignment of pointer to integer is illegal
+ * this falls out, because the LHS is never 0.
+ */
+void
+chkpun(NODE *p)
+{
+ union dimfun *d1, *d2;
+ NODE *q;
+ int t1, t2;
+
+ t1 = p->n_left->n_type;
+ t2 = p->n_right->n_type;
+
+ switch (p->n_op) {
+ case RETURN:
+ /* return of void allowed but nothing else */
+ if (t1 == VOID && t2 == VOID)
+ return;
+ if (t1 == VOID) {
+ werror("returning value from void function");
+ return;
+ }
+ if (t2 == VOID) {
+ uerror("using void value");
+ return;
+ }
+ case COLON:
+ if (t1 == VOID && t2 == VOID)
+ return;
+ break;
+ default:
+ if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) {
+ uerror("value of void expression used");
+ return;
+ }
+ break;
+ }
+
+ /* allow void pointer assignments in any direction */
+ if (BTYPE(t1) == VOID && (t2 & TMASK))
+ return;
+ if (BTYPE(t2) == VOID && (t1 & TMASK))
+ return;
+
+ /* check for enumerations */
+ if (t1 == ENUMTY || t2 == ENUMTY) {
+ if (clogop(p->n_op) && p->n_op != EQ && p->n_op != NE) {
+ werror("comparison of enums");
+ return;
+ }
+ if (chkenum(t1, t2, p))
+ return;
+ }
+
+ if (ISPTR(t1) || ISARY(t1))
+ q = p->n_right;
+ else
+ q = p->n_left;
+
+ if (!ISPTR(q->n_type) && !ISARY(q->n_type)) {
+ if (q->n_op != ICON || q->n_lval != 0)
+ werror("illegal combination of pointer and integer");
+ } else {
+ d1 = p->n_left->n_df;
+ d2 = p->n_right->n_df;
+ if (t1 == t2) {
+ if (p->n_left->n_sue != p->n_right->n_sue)
+ werror("illegal structure pointer combination");
+ return;
+ }
+ for (;;) {
+ if (ISARY(t1) || ISPTR(t1)) {
+ if (!ISARY(t2) && !ISPTR(t2))
+ break;
+ if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) {
+ werror("illegal array size combination");
+ return;
+ }
+ if (ISARY(t1))
+ ++d1;
+ if (ISARY(t2))
+ ++d2;
+ } else if (ISFTN(t1)) {
+ if (chkftn(d1->dfun, d2->dfun)) {
+ werror("illegal function "
+ "pointer combination");
+ return;
+ }
+ ++d1;
+ ++d2;
+ } else if (t1 == ENUMTY || t2 == ENUMTY) {
+ chkenum(t1, t2, p);
+ return;
+ } else
+ break;
+ t1 = DECREF(t1);
+ t2 = DECREF(t2);
+ }
+ werror("illegal pointer combination");
+ }
+}
+
+static int
+chkenum(int t1, int t2, NODE *p)
+{
+ if (t1 == ENUMTY && t2 == ENUMTY) {
+ if (p->n_left->n_sue != p->n_right->n_sue)
+ werror("enumeration type clash, operator %s", copst(p->n_op));
+ return 1;
+ }
+ if ((t1 == ENUMTY && !(t2 >= CHAR && t2 <= UNSIGNED)) ||
+ (t2 == ENUMTY && !(t1 >= CHAR && t1 <= UNSIGNED))) {
+ werror("illegal combination of enum and non-integer type");
+ return 1;
+ }
+ return 0;
+}
+
+NODE *
+stref(NODE *p)
+{
+ NODE *r;
+ struct suedef *sue;
+ union dimfun *d;
+ TWORD t, q;
+ int dsc;
+ OFFSZ off;
+ struct symtab *s;
+
+ /* make p->x */
+ /* this is also used to reference automatic variables */
+
+ s = p->n_right->n_sp;
+ nfree(p->n_right);
+ r = p->n_left;
+ nfree(p);
+ p = pconvert(r);
+
+ /* make p look like ptr to x */
+
+ if (!ISPTR(p->n_type))
+ p->n_type = PTR+UNIONTY;
+
+ t = INCREF(s->stype);
+ q = INCQAL(s->squal);
+ d = s->sdf;
+ sue = s->ssue;
+
+ p = makety(p, t, q, d, sue);
+
+ /* compute the offset to be added */
+
+ off = s->soffset;
+ dsc = s->sclass;
+
+ if (dsc & FIELD) { /* make fields look like ints */
+ off = (off/ALINT)*ALINT;
+ sue = MKSUE(INT);
+ }
+ if (off != 0) {
+ p = block(PLUS, p, offcon(off, t, d, sue), t, d, sue);
+ p->n_qual = q;
+ p = optim(p);
+ }
+
+ p = buildtree(UMUL, p, NIL);
+
+ /* if field, build field info */
+
+ if (dsc & FIELD) {
+ p = block(FLD, p, NIL, s->stype, 0, s->ssue);
+ p->n_qual = q;
+ p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%ALINT);
+ }
+
+ p = clocal(p);
+ return p;
+}
+
+int
+notlval(p) register NODE *p; {
+
+ /* return 0 if p an lvalue, 1 otherwise */
+
+ again:
+
+ switch( p->n_op ){
+
+ case FLD:
+ p = p->n_left;
+ goto again;
+
+ case NAME:
+ case OREG:
+ case UMUL:
+ if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1);
+ case TEMP:
+ case REG:
+ return(0);
+
+ default:
+ return(1);
+
+ }
+
+ }
+/* make a constant node with value i */
+NODE *
+bcon(int i)
+{
+ register NODE *p;
+
+ p = block(ICON, NIL, NIL, INT, 0, MKSUE(INT));
+ p->n_lval = i;
+ p->n_sp = NULL;
+ return(clocal(p));
+}
+
+NODE *
+bpsize(NODE *p)
+{
+ return(offcon(psize(p), p->n_type, p->n_df, p->n_sue));
+}
+
+/*
+ * p is a node of type pointer; psize returns the
+ * size of the thing pointed to
+ */
+OFFSZ
+psize(NODE *p)
+{
+
+ if (!ISPTR(p->n_type)) {
+ uerror("pointer required");
+ return(SZINT);
+ }
+ /* note: no pointers to fields */
+ return(tsize(DECREF(p->n_type), p->n_df, p->n_sue));
+}
+
+/*
+ * convert an operand of p
+ * f is either CVTL or CVTR
+ * operand has type int, and is converted by the size of the other side
+ * convert is called when an integer is to be added to a pointer, for
+ * example in arrays or structures.
+ */
+NODE *
+convert(NODE *p, int f)
+{
+ union dimfun *df;
+ TWORD ty, ty2;
+ NODE *q, *r, *s, *rv;
+
+ if (f == CVTL) {
+ q = p->n_left;
+ s = p->n_right;
+ } else {
+ q = p->n_right;
+ s = p->n_left;
+ }
+ ty2 = ty = DECREF(s->n_type);
+ while (ISARY(ty))
+ ty = DECREF(ty);
+
+ r = offcon(tsize(ty, s->n_df, s->n_sue), s->n_type, s->n_df, s->n_sue);
+ ty = ty2;
+ rv = bcon(1);
+ df = s->n_df;
+ while (ISARY(ty)) {
+ rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) :
+ tempnode(-df->ddim, INT, 0, MKSUE(INT)));
+ df++;
+ ty = DECREF(ty);
+ }
+ rv = clocal(block(PMCONV, rv, r, INT, 0, MKSUE(INT)));
+ rv = optim(rv);
+
+ r = block(PMCONV, q, rv, INT, 0, MKSUE(INT));
+ r = clocal(r);
+ /*
+ * Indexing is only allowed with integer arguments, so insert
+ * SCONV here if arg is not an integer.
+ * XXX - complain?
+ */
+ if (r->n_type != INT)
+ r = clocal(block(SCONV, r, NIL, INT, 0, MKSUE(INT)));
+ if (f == CVTL)
+ p->n_left = r;
+ else
+ p->n_right = r;
+ return(p);
+}
+
+/*
+ * change enums to ints, or appropriate types
+ */
+void
+econvert( p ) register NODE *p; {
+
+
+ register TWORD ty;
+
+ if( (ty=BTYPE(p->n_type)) == ENUMTY || ty == MOETY ) {
+ if (p->n_sue->suesize == SZCHAR)
+ ty = INT;
+ else if (p->n_sue->suesize == SZINT)
+ ty = INT;
+ else if (p->n_sue->suesize == SZSHORT)
+ ty = INT;
+ else if (p->n_sue->suesize == SZLONGLONG)
+ ty = LONGLONG;
+ else
+ ty = LONG;
+ ty = ctype(ty);
+ p->n_sue = MKSUE(ty);
+ MODTYPE(p->n_type,ty);
+ if (p->n_op == ICON && ty != LONG && ty != LONGLONG)
+ p->n_type = INT, p->n_sue = MKSUE(INT);
+ }
+}
+
+NODE *
+pconvert( p ) register NODE *p; {
+
+ /* if p should be changed into a pointer, do so */
+
+ if( ISARY( p->n_type) ){
+ p->n_type = DECREF( p->n_type );
+ ++p->n_df;
+ return( buildtree( ADDROF, p, NIL ) );
+ }
+ if( ISFTN( p->n_type) )
+ return( buildtree( ADDROF, p, NIL ) );
+
+ return( p );
+ }
+
+NODE *
+oconvert(p) register NODE *p; {
+ /* convert the result itself: used for pointer and unsigned */
+
+ switch(p->n_op) {
+
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+ if( ISUNSIGNED(p->n_left->n_type) || ISUNSIGNED(p->n_right->n_type) ) p->n_op += (ULE-LE);
+ case EQ:
+ case NE:
+ return( p );
+
+ case MINUS:
+ return( clocal( block( PVCONV,
+ p, bpsize(p->n_left), INT, 0, MKSUE(INT))));
+ }
+
+ cerror( "illegal oconvert: %d", p->n_op );
+
+ return(p);
+ }
+
+/*
+ * makes the operands of p agree; they are
+ * either pointers or integers, by this time
+ * with MINUS, the sizes must be the same
+ * with COLON, the types must be the same
+ */
+NODE *
+ptmatch(NODE *p)
+{
+ struct suedef *sue, *sue2;
+ union dimfun *d, *d2;
+ TWORD t1, t2, t, q1, q2, q;
+ int o;
+
+ o = p->n_op;
+ t = t1 = p->n_left->n_type;
+ q = q1 = p->n_left->n_qual;
+ t2 = p->n_right->n_type;
+ q2 = p->n_right->n_qual;
+ d = p->n_left->n_df;
+ d2 = p->n_right->n_df;
+ sue = p->n_left->n_sue;
+ sue2 = p->n_right->n_sue;
+
+ switch( o ){
+
+ case ASSIGN:
+ case RETURN:
+ case CAST:
+ { break; }
+
+ case MINUS:
+ { if( psize(p->n_left) != psize(p->n_right) ){
+ uerror( "illegal pointer subtraction");
+ }
+ break;
+ }
+ case COLON:
+ if (t1 != t2) {
+ /*
+ * Check for void pointer types. They are allowed
+ * to cast to/from any pointers.
+ */
+ if (ISPTR(t1) && ISPTR(t2) &&
+ (BTYPE(t1) == VOID || BTYPE(t2) == VOID))
+ break;
+ uerror("illegal types in :");
+ }
+ break;
+
+ default: /* must work harder: relationals or comparisons */
+
+ if( !ISPTR(t1) ){
+ t = t2;
+ q = q2;
+ d = d2;
+ sue = sue2;
+ break;
+ }
+ if( !ISPTR(t2) ){
+ break;
+ }
+
+ /* both are pointers */
+ if( talign(t2,sue2) < talign(t,sue) ){
+ t = t2;
+ q = q2;
+ sue = sue2;
+ }
+ break;
+ }
+
+ p->n_left = makety( p->n_left, t, q, d, sue );
+ p->n_right = makety( p->n_right, t, q, d, sue );
+ if( o!=MINUS && !clogop(o) ){
+
+ p->n_type = t;
+ p->n_qual = q;
+ p->n_df = d;
+ p->n_sue = sue;
+ }
+
+ return(clocal(p));
+ }
+
+int tdebug = 0;
+
+NODE *
+tymatch(p) register NODE *p; {
+
+ /* satisfy the types of various arithmetic binary ops */
+
+ /* rules are:
+ if assignment, type of LHS
+ if any doubles, make double
+ else if any float make float
+ else if any longlongs, make long long
+ else if any longs, make long
+ else etcetc.
+ if either operand is unsigned, the result is...
+ */
+
+ TWORD t1, t2, t, tu;
+ int o, lu, ru;
+
+ o = p->n_op;
+
+ t1 = p->n_left->n_type;
+ t2 = p->n_right->n_type;
+
+ lu = ru = 0;
+ if( ISUNSIGNED(t1) ){
+ lu = 1;
+ t1 = DEUNSIGN(t1);
+ }
+ if( ISUNSIGNED(t2) ){
+ ru = 1;
+ t2 = DEUNSIGN(t2);
+ }
+
+ if (t1 == ENUMTY || t1 == MOETY)
+ t1 = INT; /* XXX */
+ if (t2 == ENUMTY || t2 == MOETY)
+ t2 = INT; /* XXX */
+#if 0
+ if ((t1 == CHAR || t1 == SHORT) && o!= RETURN)
+ t1 = INT;
+ if (t2 == CHAR || t2 == SHORT)
+ t2 = INT;
+#endif
+
+ if (t1 == LDOUBLE || t2 == LDOUBLE)
+ t = LDOUBLE;
+ else if (t1 == DOUBLE || t2 == DOUBLE)
+ t = DOUBLE;
+ else if (t1 == FLOAT || t2 == FLOAT)
+ t = FLOAT;
+ else if (t1==LONGLONG || t2 == LONGLONG)
+ t = LONGLONG;
+ else if (t1==LONG || t2==LONG)
+ t = LONG;
+ else /* if (t1==INT || t2==INT) */
+ t = INT;
+#if 0
+ else if (t1==SHORT || t2==SHORT)
+ t = SHORT;
+ else
+ t = CHAR;
+#endif
+
+ if( casgop(o) ){
+ tu = p->n_left->n_type;
+ t = t1;
+ } else {
+ tu = ((ru|lu) && UNSIGNABLE(t))?ENUNSIGN(t):t;
+ }
+
+ /* because expressions have values that are at least as wide
+ as INT or UNSIGNED, the only conversions needed
+ are those involving FLOAT/DOUBLE, and those
+ from LONG to INT and ULONG to UNSIGNED */
+
+
+ if (t != t1 || (ru && !lu))
+ p->n_left = makety( p->n_left, tu, 0, 0, MKSUE(tu));
+
+ if (t != t2 || o==CAST || (lu && !ru))
+ p->n_right = makety(p->n_right, tu, 0, 0, MKSUE(tu));
+
+ if( casgop(o) ){
+ p->n_type = p->n_left->n_type;
+ p->n_df = p->n_left->n_df;
+ p->n_sue = p->n_left->n_sue;
+ }
+ else if( !clogop(o) ){
+ p->n_type = tu;
+ p->n_df = NULL;
+ p->n_sue = MKSUE(t);
+ }
+
+#ifdef PCC_DEBUG
+ if (tdebug) {
+ printf("tymatch(%p): ", p);
+ tprint(stdout, t1, 0);
+ printf(" %s ", copst(o));
+ tprint(stdout, t2, 0);
+ printf(" => ");
+ tprint(stdout, tu, 0);
+ printf("\n");
+ }
+#endif
+
+ return(p);
+ }
+
+/*
+ * make p into type t by inserting a conversion
+ */
+NODE *
+makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct suedef *sue)
+{
+
+ if (p->n_type == ENUMTY && p->n_op == ICON)
+ econvert(p);
+ if (t == p->n_type) {
+ p->n_df = d;
+ p->n_sue = sue;
+ p->n_qual = q;
+ return(p);
+ }
+
+ if ((p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE)
+ && (t == FLOAT || t == DOUBLE || t == LDOUBLE) && p->n_op == FCON) {
+ p->n_type = t;
+ p->n_qual = q;
+ p->n_df = d;
+ p->n_sue = sue;
+ return(p);
+ }
+
+ if (t & TMASK) {
+ /* non-simple type */
+ p = block(PCONV, p, NIL, t, d, sue);
+ p->n_qual = q;
+ return clocal(p);
+ }
+
+ if (p->n_op == ICON) {
+ if (t == DOUBLE || t == FLOAT) {
+ p->n_op = FCON;
+ if (ISUNSIGNED(p->n_type))
+ p->n_dcon = (U_CONSZ) p->n_lval;
+ else
+ p->n_dcon = p->n_lval;
+ p->n_type = t;
+ p->n_qual = q;
+ p->n_sue = MKSUE(t);
+ return (clocal(p));
+ }
+ }
+ p = block(SCONV, p, NIL, t, d, sue);
+ p->n_qual = q;
+ return clocal(p);
+
+}
+
+NODE *
+block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct suedef *sue)
+{
+ register NODE *p;
+
+ p = talloc();
+ p->n_rval = 0;
+ p->n_op = o;
+ p->n_lval = 0; /* Protect against large lval */
+ p->n_left = l;
+ p->n_right = r;
+ p->n_type = t;
+ p->n_qual = 0;
+ p->n_df = d;
+ p->n_sue = sue;
+#if !defined(MULTIPASS)
+ /* p->n_reg = */p->n_su = 0;
+ p->n_regw = 0;
+#endif
+ return(p);
+ }
+
+int
+icons(p) register NODE *p; {
+ /* if p is an integer constant, return its value */
+ int val;
+
+ if( p->n_op != ICON ){
+ uerror( "constant expected");
+ val = 1;
+ }
+ else {
+ val = p->n_lval;
+ if( val != p->n_lval ) uerror( "constant too big for cross-compiler" );
+ }
+ tfree( p );
+ return(val);
+}
+
+/*
+ * the intent of this table is to examine the
+ * operators, and to check them for
+ * correctness.
+ *
+ * The table is searched for the op and the
+ * modified type (where this is one of the
+ * types INT (includes char and short), LONG,
+ * DOUBLE (includes FLOAT), and POINTER
+ *
+ * The default action is to make the node type integer
+ *
+ * The actions taken include:
+ * PUN check for puns
+ * CVTL convert the left operand
+ * CVTR convert the right operand
+ * TYPL the type is determined by the left operand
+ * TYPR the type is determined by the right operand
+ * TYMATCH force type of left and right to match,by inserting conversions
+ * PTMATCH like TYMATCH, but for pointers
+ * LVAL left operand must be lval
+ * CVTO convert the op
+ * NCVT do not convert the operands
+ * OTHER handled by code
+ * NCVTR convert the left operand, not the right...
+ *
+ */
+
+# define MINT 01 /* integer */
+# define MDBI 02 /* integer or double */
+# define MSTR 04 /* structure */
+# define MPTR 010 /* pointer */
+# define MPTI 020 /* pointer or integer */
+# define MENU 040 /* enumeration variable or member */
+
+int
+opact(NODE *p)
+{
+ int mt12, mt1, mt2, o;
+
+ mt1 = mt2 = mt12 = 0;
+
+ switch (coptype(o = p->n_op)) {
+ case BITYPE:
+ mt12=mt2 = moditype(p->n_right->n_type);
+ case UTYPE:
+ mt12 &= (mt1 = moditype(p->n_left->n_type));
+ break;
+ }
+
+ switch( o ){
+
+ case NAME :
+ case ICON :
+ case FCON :
+ case CALL :
+ case UCALL:
+ case UMUL:
+ { return( OTHER ); }
+ case UMINUS:
+ if( mt1 & MDBI ) return( TYPL );
+ break;
+
+ case COMPL:
+ if( mt1 & MINT ) return( TYPL );
+ break;
+
+ case ADDROF:
+ return( NCVT+OTHER );
+ case NOT:
+/* case INIT: */
+ case CM:
+ case CBRANCH:
+ case ANDAND:
+ case OROR:
+ return( 0 );
+
+ case MUL:
+ case DIV:
+ if ((mt1&MDBI) && (mt2&MENU)) return( TYMATCH );
+ if ((mt2&MDBI) && (mt1&MENU)) return( TYMATCH );
+ if( mt12 & MDBI ) return( TYMATCH );
+ break;
+
+ case MOD:
+ case AND:
+ case OR:
+ case ER:
+ if( mt12 & MINT ) return( TYMATCH );
+ break;
+
+ case LS:
+ case RS:
+ if( mt12 & MINT ) return( TYPL+OTHER );
+ break;
+
+ case EQ:
+ case NE:
+ case LT:
+ case LE:
+ case GT:
+ case GE:
+ if( mt12 & MDBI ) return( TYMATCH+CVTO );
+ else if( mt12 & MPTR ) return( PTMATCH+PUN );
+ else if( mt12 & MPTI ) return( PTMATCH+PUN );
+ else break;
+
+ case QUEST:
+ case COMOP:
+ if( mt2&MENU ) return( TYPR+NCVTR );
+ return( TYPR );
+
+ case STREF:
+ return( NCVTR+OTHER );
+
+ case FORCE:
+ return( TYPL );
+
+ case COLON:
+ if( mt12 & MDBI ) return( TYMATCH );
+ else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN );
+ else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN );
+ else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN );
+ else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER );
+ break;
+
+ case ASSIGN:
+ case RETURN:
+ if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER );
+ case CAST:
+ if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH );
+#if 0
+ else if(mt1&MENU && mt2&MDBI) return( TYPL+LVAL+TYMATCH );
+ else if(mt2&MENU && mt1&MDBI) return( TYPL+LVAL+TYMATCH );
+ else if( (mt1&MENU)||(mt2&MENU) )
+ return( LVAL+NCVT+TYPL+PTMATCH+PUN );
+#endif
+ else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN );
+ else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN );
+ break;
+
+ case LSEQ:
+ case RSEQ:
+ if( mt12 & MINT ) return( TYPL+LVAL+OTHER );
+ break;
+
+ case MULEQ:
+ case DIVEQ:
+ if( mt12 & MDBI ) return( LVAL+TYMATCH );
+ break;
+
+ case MODEQ:
+ case ANDEQ:
+ case OREQ:
+ case EREQ:
+ if (mt12 & MINT)
+ return(LVAL+TYMATCH);
+ break;
+
+ case PLUSEQ:
+ case MINUSEQ:
+ case INCR:
+ case DECR:
+ if (mt12 & MDBI)
+ return(TYMATCH+LVAL);
+ else if ((mt1&MPTR) && (mt2&MINT))
+ return(TYPL+LVAL+CVTR);
+ break;
+
+ case MINUS:
+ if (mt12 & MPTR)
+ return(CVTO+PTMATCH+PUN);
+ if (mt2 & MPTR)
+ break;
+ /* FALLTHROUGH */
+ case PLUS:
+ if (mt12 & MDBI)
+ return(TYMATCH);
+ else if ((mt1&MPTR) && (mt2&MINT))
+ return(TYPL+CVTR);
+ else if ((mt1&MINT) && (mt2&MPTR))
+ return(TYPR+CVTL);
+
+ }
+ uerror("operands of %s have incompatible types", copst(o));
+ return(NCVT);
+}
+
+int
+moditype(TWORD ty)
+{
+ switch (ty) {
+
+ case ENUMTY:
+ case MOETY:
+ return( MENU|MINT|MDBI|MPTI );
+
+ case STRTY:
+ case UNIONTY:
+ return( MSTR );
+
+ case BOOL:
+ case CHAR:
+ case SHORT:
+ case UCHAR:
+ case USHORT:
+ case UNSIGNED:
+ case ULONG:
+ case ULONGLONG:
+ case INT:
+ case LONG:
+ case LONGLONG:
+ return( MINT|MDBI|MPTI );
+ case FLOAT:
+ case DOUBLE:
+ case LDOUBLE:
+ return( MDBI );
+ default:
+ return( MPTR|MPTI );
+
+ }
+}
+
+int tvaloff = 100;
+
+/*
+ * Returns a TEMP node with temp number nr.
+ * If nr == 0, return a node with a new number.
+ */
+NODE *
+tempnode(int nr, TWORD type, union dimfun *df, struct suedef *sue)
+{
+ NODE *r;
+
+ r = block(TEMP, NIL, NIL, type, df, sue);
+ r->n_lval = nr ? nr : tvaloff;
+ tvaloff += szty(type);
+ return r;
+}
+
+/*
+ * Do sizeof on p.
+ */
+NODE *
+doszof(NODE *p)
+{
+ union dimfun *df;
+ TWORD ty;
+ NODE *rv;
+
+ if (p->n_op == FLD)
+ uerror("can't apply sizeof to bit-field");
+
+ /*
+ * Arrays may be dynamic, may need to make computations.
+ */
+
+ rv = bcon(1);
+ df = p->n_df;
+ ty = p->n_type;
+ while (ISARY(ty)) {
+ rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) :
+ tempnode(-df->ddim, INT, 0, MKSUE(INT)));
+ df++;
+ ty = DECREF(ty);
+ }
+ rv = buildtree(MUL, rv, bcon(tsize(ty, p->n_df, p->n_sue)/SZCHAR));
+ tfree(p);
+ return rv;
+}
+
+#ifdef PCC_DEBUG
+void
+eprint(NODE *p, int down, int *a, int *b)
+{
+ int ty;
+
+ *a = *b = down+1;
+ while( down > 1 ){
+ printf( "\t" );
+ down -= 2;
+ }
+ if( down ) printf( " " );
+
+ ty = coptype( p->n_op );
+
+ printf("%p) %s, ", p, copst(p->n_op));
+ if (ty == LTYPE) {
+ printf(CONFMT, p->n_lval);
+ printf(", %d, ", p->n_rval);
+ }
+ tprint(stdout, p->n_type, p->n_qual);
+ printf( ", %p, %p\n", p->n_df, p->n_sue );
+}
+# endif
+
+void
+prtdcon(NODE *p)
+{
+ int o = p->n_op, i;
+
+ if (o != FCON)
+ return;
+
+ /* Write float constants to memory */
+ /* Should be volontary per architecture */
+
+ setloc1(RDATA);
+ defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ?
+ ALDOUBLE : ALLDOUBLE );
+ deflab1(i = getlab());
+ ninval(0, btdims[p->n_type].suesize, p);
+ p->n_op = NAME;
+ p->n_lval = 0;
+ p->n_sp = tmpalloc(sizeof(struct symtab_hdr));
+ p->n_sp->sclass = ILABEL;
+ p->n_sp->soffset = i;
+}
+
+extern int negrel[];
+
+/*
+ * Walk up through the tree from the leaves,
+ * removing constant operators.
+ */
+static void
+logwalk(NODE *p)
+{
+ int o = coptype(p->n_op);
+ NODE *l, *r;
+
+ l = p->n_left;
+ r = p->n_right;
+ switch (o) {
+ case LTYPE:
+ return;
+ case BITYPE:
+ logwalk(r);
+ case UTYPE:
+ logwalk(l);
+ }
+ if (!clogop(p->n_op))
+ return;
+ if (p->n_op == NOT && l->n_op == ICON) {
+ p->n_lval = l->n_lval == 0;
+ nfree(l);
+ p->n_op = ICON;
+ }
+ if (l->n_op == ICON && r->n_op == ICON) {
+ if (conval(l, p->n_op, r) == 0) {
+ /*
+ * people sometimes tend to do really odd compares,
+ * like "if ("abc" == "def")" etc.
+ * do it runtime instead.
+ */
+ } else {
+ p->n_lval = l->n_lval;
+ p->n_op = ICON;
+ nfree(l);
+ nfree(r);
+ }
+ }
+}
+
+/*
+ * Removes redundant logical operators for branch conditions.
+ */
+static void
+fixbranch(NODE *p, int label)
+{
+
+ logwalk(p);
+
+ if (p->n_op == ICON) {
+ if (p->n_lval != 0)
+ branch(label);
+ nfree(p);
+ } else {
+ if (!clogop(p->n_op)) /* Always conditional */
+ p = buildtree(NE, p, bcon(0));
+ ecode(buildtree(CBRANCH, p, bcon(label)));
+ }
+}
+
+/*
+ * Write out logical expressions as branches.
+ */
+static void
+andorbr(NODE *p, int true, int false)
+{
+ NODE *q;
+ int o, lab;
+
+ lab = -1;
+ switch (o = p->n_op) {
+ case EQ:
+ case NE:
+ /*
+ * Remove redundant EQ/NE nodes.
+ */
+ while (((o = p->n_left->n_op) == EQ || o == NE) &&
+ p->n_right->n_op == ICON) {
+ o = p->n_op;
+ q = p->n_left;
+ if (p->n_right->n_lval == 0) {
+ nfree(p->n_right);
+ *p = *q;
+ nfree(q);
+ if (o == EQ)
+ p->n_op = negrel[p->n_op - EQ];
+// p->n_op = NE; /* toggla */
+ } else if (p->n_right->n_lval == 1) {
+ nfree(p->n_right);
+ *p = *q;
+ nfree(q);
+ if (o == NE)
+ p->n_op = negrel[p->n_op - EQ];
+// p->n_op = EQ; /* toggla */
+ } else
+ break; /* XXX - should always be false */
+
+ }
+ /* FALLTHROUGH */
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+calc: if (true < 0) {
+ p->n_op = negrel[p->n_op - EQ];
+ true = false;
+ false = -1;
+ }
+
+ rmcops(p->n_left);
+ rmcops(p->n_right);
+ fixbranch(p, true);
+ if (false >= 0)
+ branch(false);
+ break;
+
+ case ULE:
+ case UGT:
+ /* Convert to friendlier ops */
+ if (p->n_right->n_op == ICON && p->n_right->n_lval == 0)
+ p->n_op = o == ULE ? EQ : NE;
+ goto calc;
+
+ case UGE:
+ case ULT:
+ /* Already true/false by definition */
+ if (p->n_right->n_op == ICON && p->n_right->n_lval == 0) {
+ if (true < 0) {
+ o = o == ULT ? UGE : ULT;
+ true = false;
+ }
+ rmcops(p->n_left);
+ ecode(p->n_left);
+ rmcops(p->n_right);
+ ecode(p->n_right);
+ nfree(p);
+ if (o == UGE) /* true */
+ branch(true);
+ break;
+ }
+ goto calc;
+
+ case ANDAND:
+ lab = false<0 ? getlab() : false ;
+ andorbr(p->n_left, -1, lab);
+ andorbr(p->n_right, true, false);
+ if (false < 0)
+ plabel( lab);
+ nfree(p);
+ break;
+
+ case OROR:
+ lab = true<0 ? getlab() : true;
+ andorbr(p->n_left, lab, -1);
+ andorbr(p->n_right, true, false);
+ if (true < 0)
+ plabel( lab);
+ nfree(p);
+ break;
+
+ case NOT:
+ andorbr(p->n_left, false, true);
+ nfree(p);
+ break;
+
+ default:
+ rmcops(p);
+ if (true >= 0)
+ fixbranch(p, true);
+ if (false >= 0) {
+ if (true >= 0)
+ branch(false);
+ else
+ fixbranch(buildtree(EQ, p, bcon(0)), false);
+ }
+ }
+}
+
+/*
+ * Massage the output trees to remove C-specific nodes:
+ * COMOPs are split into separate statements.
+ * QUEST/COLON are rewritten to branches.
+ * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation.
+ * CBRANCH conditions are rewritten for lazy-evaluation.
+ */
+static void
+rmcops(NODE *p)
+{
+ TWORD type;
+ NODE *q, *r;
+ int o, ty, lbl, lbl2, tval = 0;
+
+again:
+ o = p->n_op;
+ ty = coptype(o);
+ switch (o) {
+ case QUEST:
+
+ /*
+ * Create a branch node from ?:
+ * || and && must be taken special care of.
+ */
+ type = p->n_type;
+ andorbr(p->n_left, -1, lbl = getlab());
+
+ /* Make ASSIGN node */
+ /* Only if type is not void */
+ q = p->n_right->n_left;
+ if (type != VOID) {
+ r = tempnode(0, q->n_type, q->n_df, q->n_sue);
+ tval = r->n_lval;
+ q = buildtree(ASSIGN, r, q);
+ }
+ rmcops(q);
+ ecode(q); /* Done with assign */
+ branch(lbl2 = getlab());
+ plabel( lbl);
+
+ q = p->n_right->n_right;
+ if (type != VOID) {
+ r = tempnode(tval, q->n_type, q->n_df, q->n_sue);
+ q = buildtree(ASSIGN, r, q);
+ }
+ rmcops(q);
+ ecode(q); /* Done with assign */
+
+ plabel( lbl2);
+
+ nfree(p->n_right);
+ if (p->n_type != VOID) {
+ r = tempnode(tval, p->n_type, p->n_df, p->n_sue);
+ *p = *r;
+ nfree(r);
+ } else
+ p->n_op = ICON;
+ break;
+
+ case ULE:
+ case ULT:
+ case UGE:
+ case UGT:
+ case EQ:
+ case NE:
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+ case ANDAND:
+ case OROR:
+ case NOT:
+#ifdef SPECIAL_CCODES
+#error fix for private CCODES handling
+#else
+ r = talloc();
+ *r = *p;
+ andorbr(r, -1, lbl = getlab());
+ q = tempnode(0, p->n_type, p->n_df, p->n_sue);
+ tval = q->n_lval;
+ r = tempnode(tval, p->n_type, p->n_df, p->n_sue);
+ ecode(buildtree(ASSIGN, q, bcon(1)));
+ branch(lbl2 = getlab());
+ plabel( lbl);
+ ecode(buildtree(ASSIGN, r, bcon(0)));
+ plabel( lbl2);
+ r = tempnode(tval, p->n_type, p->n_df, p->n_sue);
+ *p = *r;
+ nfree(r);
+#endif
+ break;
+ case CBRANCH:
+ andorbr(p->n_left, p->n_right->n_lval, -1);
+ nfree(p->n_right);
+ p->n_op = ICON; p->n_type = VOID;
+ break;
+ case COMOP:
+ rmcops(p->n_left);
+ ecode(p->n_left);
+ /* Now when left tree is dealt with, rm COMOP */
+ q = p->n_right;
+ *p = *p->n_right;
+ nfree(q);
+ goto again;
+
+ default:
+ if (ty == LTYPE)
+ return;
+ rmcops(p->n_left);
+ if (ty == BITYPE)
+ rmcops(p->n_right);
+ }
+}
+
+/*
+ * Return 1 if an assignment is found.
+ */
+static int
+has_se(NODE *p)
+{
+ if (cdope(p->n_op) & ASGFLG)
+ return 1;
+ if (coptype(p->n_op) == LTYPE)
+ return 0;
+ if (has_se(p->n_left))
+ return 1;
+ if (coptype(p->n_op) == BITYPE)
+ return has_se(p->n_right);
+ return 0;
+}
+
+/*
+ * Find and convert asgop's to separate statements.
+ * Be careful about side effects.
+ * assign tells whether ASSIGN should be considered giving
+ * side effects or not.
+ */
+static NODE *
+delasgop(NODE *p)
+{
+ NODE *q, *r;
+ int tval;
+
+ if (p->n_op == INCR || p->n_op == DECR) {
+ /*
+ * Rewrite x++ to (x += 1) -1; and deal with it further down.
+ * Pass2 will remove -1 if unneccessary.
+ */
+ q = ccopy(p);
+ tfree(p->n_left);
+ q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ;
+ p->n_op = (p->n_op==INCR)?MINUS:PLUS;
+ p->n_left = delasgop(q);
+
+ } else if ((cdope(p->n_op)&ASGOPFLG) &&
+ p->n_op != RETURN && p->n_op != CAST) {
+ NODE *l = p->n_left;
+ NODE *ll = l->n_left;
+
+ if (has_se(l)) {
+ q = tempnode(0, ll->n_type, ll->n_df, ll->n_sue);
+ tval = q->n_lval;
+ r = tempnode(tval, ll->n_type, ll->n_df,ll->n_sue);
+ l->n_left = q;
+ /* Now the left side of node p has no side effects. */
+ /* side effects on the right side must be obeyed */
+ p = delasgop(p);
+
+ r = buildtree(ASSIGN, r, ll);
+ r = delasgop(r);
+ ecode(r);
+ } else {
+#if 0 /* Cannot call buildtree() here, it would invoke double add shifts */
+ p->n_right = buildtree(UNASG p->n_op, ccopy(l),
+ p->n_right);
+#else
+ p->n_right = block(UNASG p->n_op, ccopy(l),
+ p->n_right, p->n_type, p->n_df, p->n_sue);
+#endif
+ p->n_op = ASSIGN;
+ p->n_right = delasgop(p->n_right);
+ p->n_right = clocal(p->n_right);
+ }
+
+ } else {
+ if (coptype(p->n_op) == LTYPE)
+ return p;
+ p->n_left = delasgop(p->n_left);
+ if (coptype(p->n_op) == BITYPE)
+ p->n_right = delasgop(p->n_right);
+ }
+ return p;
+}
+
+int edebug = 0;
+void
+ecomp(NODE *p)
+{
+
+#ifdef PCC_DEBUG
+ if (edebug)
+ fwalk(p, eprint, 0);
+#endif
+ if (!reached) {
+ werror("statement not reached");
+ reached = 1;
+ }
+ p = optim(p);
+ rmcops(p);
+ p = delasgop(p);
+ setloc1(PROG);
+ if (p->n_op == ICON && p->n_type == VOID)
+ tfree(p);
+ else
+ ecode(p);
+}
+
+#if defined(MULTIPASS)
+void
+p2tree(NODE *p)
+{
+ struct symtab *q;
+ int ty;
+
+# ifdef MYP2TREE
+ MYP2TREE(p); /* local action can be taken here; then return... */
+# endif
+
+ ty = coptype(p->n_op);
+
+ printf("%d\t", p->n_op);
+
+ if (ty == LTYPE) {
+ printf(CONFMT, p->n_lval);
+ printf("\t");
+ }
+ if (ty != BITYPE) {
+ if (p->n_op == NAME || p->n_op == ICON)
+ printf("0\t");
+ else
+ printf("%d\t", p->n_rval);
+ }
+
+ printf("%o\t", p->n_type);
+
+ /* handle special cases */
+
+ switch (p->n_op) {
+
+ case NAME:
+ case ICON:
+ /* print external name */
+ if ((q = p->n_sp) != NULL) {
+ if ((q->sclass == STATIC && q->slevel > 0) ||
+ q->sclass == ILABEL) {
+ printf(LABFMT, q->soffset);
+ } else
+ printf("%s\n", exname(q->sname));
+ } else
+ printf("\n");
+ break;
+
+ case STARG:
+ case STASG:
+ case STCALL:
+ case USTCALL:
+ /* print out size */
+ /* use lhs size, in order to avoid hassles
+ * with the structure `.' operator
+ */
+
+ /* note: p->left not a field... */
+ printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df,
+ p->n_left->n_sue));
+ printf("\t%d\t\n", talign(STRTY, p->n_left->n_sue));
+ break;
+
+ default:
+ printf( "\n" );
+ }
+
+ if (ty != LTYPE)
+ p2tree(p->n_left);
+ if (ty == BITYPE)
+ p2tree(p->n_right);
+}
+#else
+void
+p2tree(NODE *p)
+{
+ struct symtab *q;
+ int ty;
+
+# ifdef MYP2TREE
+ MYP2TREE(p); /* local action can be taken here; then return... */
+# endif
+
+ ty = coptype(p->n_op);
+
+ switch( p->n_op ){
+
+ case NAME:
+ case ICON:
+ if ((q = p->n_sp) != NULL) {
+ if ((q->sclass == STATIC && q->slevel > 0) ||
+#ifdef GCC_COMPAT
+ q->sflags == SLBLNAME ||
+#endif
+ q->sclass == ILABEL) {
+ char *cp = (isinlining ?
+ permalloc(32) : tmpalloc(32));
+ int n = q->soffset;
+ if (n < 0)
+ n = -n;
+ snprintf(cp, 32, LABFMT, n);
+ p->n_name = cp;
+ } else {
+#ifdef GCC_COMPAT
+ p->n_name = gcc_findname(q);
+#else
+ p->n_name = exname(q->sname);
+#endif
+ }
+ } else
+ p->n_name = "";
+ break;
+
+ case STASG:
+ /* STASG used for stack array init */
+ if (ISARY(p->n_type)) {
+ int size1 = tsize(p->n_type, p->n_left->n_df,
+ p->n_left->n_sue)/SZCHAR;
+ p->n_stsize = tsize(p->n_type, p->n_right->n_df,
+ p->n_right->n_sue)/SZCHAR;
+ if (size1 < p->n_stsize)
+ p->n_stsize = size1;
+ p->n_stalign = talign(p->n_type,
+ p->n_left->n_sue)/SZCHAR;
+ break;
+ }
+ /* FALLTHROUGH */
+ case STARG:
+ case STCALL:
+ case USTCALL:
+ /* set up size parameters */
+ p->n_stsize = (tsize(STRTY, p->n_left->n_df,
+ p->n_left->n_sue)+SZCHAR-1)/SZCHAR;
+ p->n_stalign = talign(STRTY,p->n_left->n_sue)/SZCHAR;
+ break;
+
+ default:
+ p->n_name = "";
+ }
+
+ if( ty != LTYPE ) p2tree( p->n_left );
+ if( ty == BITYPE ) p2tree( p->n_right );
+ }
+
+#endif
+
+/*
+ * Change void data types into char.
+ */
+static void
+delvoid(NODE *p)
+{
+ /* Convert "PTR undef" (void *) to "PTR uchar" */
+ if (BTYPE(p->n_type) == VOID)
+ p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+ if (BTYPE(p->n_type) == BOOL) {
+ if (p->n_op == SCONV && p->n_type == BOOL) {
+ /* create a jump and a set */
+ NODE *q, *r, *s;
+ int l, val;
+
+ q = talloc();
+ *q = *p;
+ q->n_type = BOOL_TYPE;
+ r = tempnode(0, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE));
+ val = r->n_lval;
+ s = tempnode(val, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE));
+ *p = *s;
+ q = buildtree(ASSIGN, r, q);
+ cbranch(buildtree(EQ, q, bcon(0)), bcon(l = getlab()));
+ ecode(buildtree(ASSIGN, s, bcon(1)));
+ plabel(l);
+ } else
+ p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE;
+ }
+
+}
+
+void
+ecode(NODE *p)
+{
+ /* walk the tree and write out the nodes.. */
+
+ if (nerrors)
+ return;
+
+ p = optim(p);
+ p = delasgop(p);
+ walkf(p, prtdcon);
+ walkf(p, delvoid);
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("Fulltree:\n");
+ fwalk(p, eprint, 0);
+ }
+#endif
+ p2tree(p);
+#if !defined(MULTIPASS)
+ send_passt(IP_NODE, p);
+#endif
+}
+
+/*
+ * Send something further on to the next pass.
+ */
+void
+send_passt(int type, ...)
+{
+ struct interpass *ip;
+ struct interpass_prolog *ipp;
+ extern int crslab;
+ va_list ap;
+ int sz;
+
+ va_start(ap, type);
+ if (type == IP_PROLOG || type == IP_EPILOG)
+ sz = sizeof(struct interpass_prolog);
+ else
+ sz = sizeof(struct interpass);
+
+ ip = isinlining ? permalloc(sz) : tmpalloc(sz);
+ ip->type = type;
+ ip->lineno = lineno;
+ switch (type) {
+ case IP_NODE:
+ if (lastloc != PROG)
+ setloc1(PROG);
+ ip->ip_node = va_arg(ap, NODE *);
+ break;
+ case IP_EPILOG:
+ case IP_PROLOG:
+ setloc1(PROG);
+ ipp = (struct interpass_prolog *)ip;
+ ipp->ipp_regs = va_arg(ap, int);
+ ipp->ipp_autos = va_arg(ap, int);
+ ipp->ipp_name = va_arg(ap, char *);
+ ipp->ipp_type = va_arg(ap, TWORD);
+ ipp->ipp_vis = va_arg(ap, int);
+ ip->ip_lbl = va_arg(ap, int);
+ ipp->ip_tmpnum = tvaloff;
+ ipp->ip_lblnum = crslab;
+ if (type == IP_PROLOG)
+ ipp->ip_lblnum--;
+ break;
+ case IP_DEFLAB:
+ ip->ip_lbl = va_arg(ap, int);
+ break;
+ case IP_ASM:
+ if (blevel == 0) { /* outside function */
+ printf("\t%s\n", va_arg(ap, char *));
+ va_end(ap);
+ lastloc = -1;
+ return;
+ }
+ ip->ip_asm = va_arg(ap, char *);
+ break;
+ default:
+ cerror("bad send_passt type %d", type);
+ }
+ va_end(ap);
+ if (isinlining)
+ inline_addarg(ip);
+ else
+ pass2_compile(ip);
+ if (type == IP_EPILOG)
+ lastloc = PROG;
+}
+
+char *
+copst(int op)
+{
+ if (op <= MAXOP)
+ return opst[op];
+#define SNAM(x,y) case x: return #y;
+ switch (op) {
+ SNAM(QUALIFIER,QUALIFIER)
+ SNAM(CLASS,CLASS)
+ SNAM(RB,])
+ SNAM(DOT,.)
+ SNAM(ELLIPSIS,...)
+ SNAM(LB,[)
+ SNAM(TYPE,TYPE)
+ SNAM(COMOP,COMOP)
+ SNAM(QUEST,?)
+ SNAM(COLON,:)
+ SNAM(ANDAND,&&)
+ SNAM(OROR,||)
+ SNAM(NOT,!)
+ SNAM(CAST,CAST)
+ SNAM(PLUSEQ,+=)
+ SNAM(MINUSEQ,-=)
+ SNAM(MULEQ,*=)
+ SNAM(DIVEQ,/=)
+ SNAM(MODEQ,%=)
+ SNAM(ANDEQ,&=)
+ SNAM(OREQ,|=)
+ SNAM(EREQ,^=)
+ SNAM(LSEQ,<<=)
+ SNAM(RSEQ,>>=)
+ SNAM(INCR,++)
+ SNAM(DECR,--)
+ default:
+ cerror("bad copst %d", op);
+ }
+ return 0; /* XXX gcc */
+}
+
+int
+cdope(int op)
+{
+ if (op <= MAXOP)
+ return dope[op];
+ switch (op) {
+ case QUALIFIER:
+ case CLASS:
+ case RB:
+ case DOT:
+ case ELLIPSIS:
+ case TYPE:
+ return LTYPE;
+ case COMOP:
+ case QUEST:
+ case COLON:
+ case LB:
+ return BITYPE;
+ case ANDAND:
+ case OROR:
+ return BITYPE|LOGFLG;
+ case NOT:
+ return UTYPE|LOGFLG;
+ case CAST:
+ return BITYPE|ASGFLG|ASGOPFLG;
+ case PLUSEQ:
+ return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG;
+ case MINUSEQ:
+ return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG;
+ case MULEQ:
+ return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG;
+ case OREQ:
+ case EREQ:
+ case ANDEQ:
+ return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG;
+ case DIVEQ:
+ return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG;
+ case MODEQ:
+ return BITYPE|DIVFLG|ASGFLG|ASGOPFLG;
+ case LSEQ:
+ case RSEQ:
+ return BITYPE|SHFFLG|ASGFLG|ASGOPFLG;
+ case INCR:
+ case DECR:
+ return BITYPE|ASGFLG;
+ }
+ return 0; /* XXX gcc */
+}
+
+/*
+ * make a fresh copy of p
+ */
+NODE *
+ccopy(NODE *p)
+{
+ NODE *q;
+
+ q = talloc();
+ *q = *p;
+
+ switch (coptype(q->n_op)) {
+ case BITYPE:
+ q->n_right = ccopy(p->n_right);
+ case UTYPE:
+ q->n_left = ccopy(p->n_left);
+ }
+
+ return(q);
+}
+
+/*
+ * set PROG-seg label.
+ */
+void
+plabel(int label)
+{
+ setloc1(PROG);
+ reached = 1; /* Will this always be correct? */
+ send_passt(IP_DEFLAB, label);
+}