Logo Search packages:      
Sourcecode: pcc version File versions  Download package

trees.c

/*    $Id: trees.c,v 1.279 2011/04/19 16:38:12 ragge 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>
# include <string.h>

static void chkpun(NODE *p);
static int opact(NODE *p);
static int moditype(TWORD);
static NODE *strargs(NODE *);
static void rmcops(NODE *p);
void putjops(NODE *, void *);
static struct symtab *findmember(struct symtab *, char *);
int inftn; /* currently between epilog/prolog */

static char *tnames[] = {
      "undef",
      "farg",
      "char",
      "unsigned char",
      "short",
      "unsigned short",
      "int",
      "unsigned int",
      "long",
      "unsigned long",
      "long long",
      "unsigned long long",
      "float",
      "double",
      "long double",
      "strty",
      "unionty",
      "enumty",
      "moety",
      "void",
      "signed", /* pass1 */
      "bool", /* pass1 */
      "fimag", /* pass1 */
      "dimag", /* pass1 */
      "limag", /* pass1 */
      "fcomplex", /* pass1 */
      "dcomplex", /* pass1 */
      "lcomplex", /* pass1 */
      "enumty", /* pass1 */
      "?", "?"
};

/*    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
# define PROML 020000   /* promote left operand */

/* 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;
extern int negrel[];

NODE *
buildtree(int o, NODE *l, NODE *r)
{
      NODE *p, *q;
      int actions;
      int opty;
      struct symtab *sp = NULL; /* XXX gcc */
      NODE *lr, *ll;

#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 (o == ANDAND || o == OROR || o == NOT) {
            if (l->n_op == FCON) {
                  p = bcon(!FLOAT_ISZERO(l->n_dcon));
                  nfree(l);
                  l = p;
            }
            if (o != NOT && r->n_op == FCON) {
                  p = bcon(!FLOAT_ISZERO(r->n_dcon));
                  nfree(r);
                  r = p;
            }
      }

      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, 0));
      } else if( o == UMINUS && l->n_op == FCON ){
                  l->n_dcon = FLOAT_NEG(l->n_dcon);
                  return(l);

      } else if( o==QUEST && l->n_op==ICON ) {
            CONSZ c = l->n_lval;
            nfree(l);
            if (c) {
                  walkf(r->n_right, putjops, 0);
                  tfree(r->n_right);
                  l = r->n_left;
            } else {
                  walkf(r->n_left, putjops, 0);
                  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 (!ISPTR(l->n_type) && !ISPTR(r->n_type)) {
                        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 || (o >= EQ && o <= GT) )) {
            TWORD t;
#ifndef CC_DIV_0
            if (o == DIV &&
                ((r->n_op == ICON && r->n_lval == 0) ||
                 (r->n_op == FCON && r->n_dcon == 0.0)))
                        goto runtime; /* HW dependent */
#endif
            if (l->n_op == ICON)
                  l->n_dcon = FLOAT_CAST(l->n_lval, l->n_type);
            if (r->n_op == ICON)
                  r->n_dcon = FLOAT_CAST(r->n_lval, r->n_type);
            switch(o){
            case PLUS:
            case MINUS:
            case MUL:
            case DIV:
                  switch (o) {
                  case PLUS:
                        l->n_dcon = FLOAT_PLUS(l->n_dcon, r->n_dcon);
                        break;
                  case MINUS:
                        l->n_dcon = FLOAT_MINUS(l->n_dcon, r->n_dcon);
                        break;
                  case MUL:
                        l->n_dcon = FLOAT_MUL(l->n_dcon, r->n_dcon);
                        break;
                  case DIV:
                        l->n_dcon = FLOAT_DIV(l->n_dcon, r->n_dcon);
                        break;
                  }
                  t = (l->n_type > r->n_type ? l->n_type : r->n_type);
                  l->n_op = FCON;
                  l->n_type = t;
                  nfree(r);
                  return(l);
            case EQ:
            case NE:
            case LE:
            case LT:
            case GE:
            case GT:
                  switch (o) {
                  case EQ:
                        l->n_lval = FLOAT_EQ(l->n_dcon, r->n_dcon);
                        break;
                  case NE:
                        l->n_lval = FLOAT_NE(l->n_dcon, r->n_dcon);
                        break;
                  case LE:
                        l->n_lval = FLOAT_LE(l->n_dcon, r->n_dcon);
                        break;
                  case LT:
                        l->n_lval = FLOAT_LT(l->n_dcon, r->n_dcon);
                        break;
                  case GE:
                        l->n_lval = FLOAT_GE(l->n_dcon, r->n_dcon);
                        break;
                  case GT:
                        l->n_lval = FLOAT_GT(l->n_dcon, r->n_dcon);
                        break;
                  }
                  nfree(r);
                  r = bcon(l->n_lval);
                  nfree(l);
                  return r;
            }
      }
#ifndef CC_DIV_0
runtime:
#endif
      /* its real; we must make a new node */

      p = block(o, l, r, INT, 0, 0);

      actions = opact(p);

      if (actions & PROML)
            p->n_left = intprom(p->n_left);

      if (actions & LVAL) { /* check left descendent */
            if (notlval(p->n_left)) {
                  uerror("lvalue required");
                  nfree(p);
                  return l;
#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_ap = q->n_ap;
            }

      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 ){
            struct symtab *sp1;

            l = p->n_left;
            r = p->n_right;

            switch(o){

            case NAME:
                  cerror("buildtree NAME");

            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 ((sp1 = strmemb(l->n_ap)) == NULL) {
                        uerror("undefined struct or union");
                        break;
                  }

                  if ((sp = findmember(sp1, r->n_name)) == NULL) {
                        uerror("member '%s' not declared", r->n_name);
                        break;
                  }

                  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_ap = l->n_ap;
                  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_ap = l->n_ap;
                        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, 0);
                  } else if (p->n_type == UCHAR || p->n_type == USHORT) {
                        p->n_left = makety(l, UNSIGNED, 0, 0, 0);
                  }
                  l = p->n_left;
                  p->n_type = l->n_type;
                  p->n_qual = l->n_qual;
                  p->n_df = l->n_df;
                  p->n_ap = l->n_ap;

                  /* FALLTHROUGH */
            case LSEQ:
            case RSEQ: /* ...but not for assigned types */
                  if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT)
                        p->n_right = makety(r, INT, 0, 0, 0);
                  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 */

                  if (strmemb(l->n_ap) != strmemb(r->n_ap))
                        uerror("assignment of different structures");

                  r = buildtree(ADDROF, r, NIL);

                  l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap);
                  l = clocal(l);

                  if( o == RETURN ){
                        nfree(p);
                        p = l;
                        break;
                  }

                  p->n_op = UMUL;
                  p->n_left = l;
                  p->n_right = NIL;
                  break;

            case QUEST: /* fixup types of : */
                  if (r->n_left->n_type != p->n_type)
                        r->n_left = makety(r->n_left, p->n_type,
                            p->n_qual, p->n_df, p->n_ap);
                  if (r->n_right->n_type != p->n_type)
                        r->n_right = makety(r->n_right, p->n_type,
                            p->n_qual, p->n_df, p->n_ap);
                  break;

            case COLON:
                  /* structure colon */

                  if (strmemb(l->n_ap) != strmemb(r->n_ap))
                        uerror( "type clash in conditional" );
                  break;

            case CALL:
                  p->n_right = r = strargs(p->n_right);
                  p = funcode(p);
                  /* FALLTHROUGH */
            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+1; /* add one for prototypes */
                  p->n_ap = l->n_ap;
                  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);

      }

/* Find a member in a struct or union.  May be an unnamed member */
static struct symtab *
findmember(struct symtab *sp, char *s)
{
      struct symtab *sp2, *sp3;

      for (; sp != NULL; sp = sp->snext) {
            if (sp->sname[0] == '*') {
                  /* unnamed member, recurse down */
                  if ((sp2 = findmember(strmemb(sp->sap), s))) {
                        sp3 = tmpalloc(sizeof (struct symtab));
                        *sp3 = *sp2;
                        sp3->soffset += sp->soffset;
                        return sp3;
                  }
            } else if (sp->sname == s)
                  return sp;
      }
      return NULL;
}


/*
 * Check if there will be a lost label destination inside of a ?:
 * It cannot be reached so just print it out.
 */
void
putjops(NODE *p, void *arg)
{
      if (p->n_op == COMOP && p->n_left->n_op == GOTO)
            plabel(p->n_left->n_left->n_lval+1);
}

/*
 * Build a name node based on a symtab entry.
 * broken out from buildtree().
 */
NODE *
nametree(struct symtab *sp)
{
      NODE *p;

      p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap);
      p->n_qual = sp->squal;
      p->n_sp = sp;

#ifndef NO_C_BUILTINS
      if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0)
            return p;  /* do not touch builtins here */
      
#endif

      if (sp->sflags & STNODE) {
            /* Generated for optimizer */
            p->n_op = TEMP;
            p->n_rval = sp->soffset;
      }

#ifdef GCC_COMPAT
      /* Get a label name */
      if (sp->sflags == SLBLNAME) {
            p->n_type = VOID;
      }
#endif
      if (sp->stype == UNDEF) {
            uerror("%s undefined", sp->sname);
            /* make p look reasonable */
            p->n_type = INT;
            p->n_df = NULL;
            defid(p, SNULL);
      }
      if (sp->sclass == MOE) {
            p->n_op = ICON;
            p->n_lval = sp->soffset;
            p->n_df = NULL;
            p->n_sp = NULL;
      }
      return clocal(p);
}

/*
 * Cast a node to another type by inserting a cast.
 * Just a nicer interface to buildtree.
 * Returns the new tree.
 */
NODE *
cast(NODE *p, TWORD t, TWORD u)
{
      NODE *q;

      q = block(NAME, NIL, NIL, t, 0, 0);
      q->n_qual = u;
      q = buildtree(CAST, q, p);
      p = q->n_right;
      nfree(q->n_left);
      nfree(q);
      return p;
}

/*
 * Cast and complain if necessary by not inserining a cast.
 */
NODE *
ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap)
{
      NODE *q;

      /* let buildtree do typechecking (and casting) */ 
      q = block(NAME, NIL, NIL, t, df, ap);
      p = buildtree(ASSIGN, q, p);
      nfree(p->n_left);
      q = optim(p->n_right);
      nfree(p);
      return q;
}

/*
 * 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 */
                  reached = 0;
            }
            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_ap);
            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)
{
      TWORD tl = p->n_type, tr = q->n_type, td;
      int i, u;
      CONSZ val;
      U_CONSZ v1, v2;

      val = q->n_lval;

      /* make both sides same type */
      if (tl < BTMASK && tr < BTMASK) {
            td = tl > tr ? tl : tr;
            if (td < INT)
                  td = INT;
            u = ISUNSIGNED(td);
            if (tl != td)
                  p = makety(p, td, 0, 0, 0);
            if (tr != td)
                  q = makety(q, td, 0, 0, 0);
      } else
            u = ISUNSIGNED(tl) || ISUNSIGNED(tr);
      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_right = q->n_right;
                  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 = (int)val;
            p->n_lval = p->n_lval << i;
            break;
      case RS:
            i = (int)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);
            }
      /* Do the best in making everything type correct after calc */
      if (p->n_sp == NULL && q->n_sp == NULL)
            p->n_lval = valcast(p->n_lval, p->n_type);
      return(1);
      }

/*
 * Ensure that v matches the type t; sign- or zero-extended
 * as suitable to CONSZ.
 * Only to be used for integer types.
 */
CONSZ
valcast(CONSZ v, TWORD t)
{
      CONSZ r;
      int sz;

      if (t < CHAR || t > ULONGLONG)
            return v; /* cannot cast */

      if (t >= LONGLONG)
            return v; /* already largest */

#define M(x)      ((((1ULL << ((x)-1)) - 1) << 1) + 1)
#define     NOTM(x)     (~M(x))
#define     SBIT(x)     (1ULL << ((x)-1))

      sz = tsize(t, NULL, NULL);
      r = v & M(sz);
      if (!ISUNSIGNED(t) && (SBIT(sz) & r))
            r = r | NOTM(sz);
      return r;
}

/*
 * 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.
 * XXX - check for COMOPs in assignment RHS?
 */
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;

      /* boolean have special syntax */
      if (t1 == BOOL) {
            if (!ISARY(t2)) /* Anything scalar */
                  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 {
            if (t1 == t2) {
                  if (ISSOU(BTYPE(t1)) &&
                      !suemeq(p->n_left->n_ap, p->n_right->n_ap))
                        werror("illegal structure pointer combination");
                  return;
            }
            d1 = p->n_left->n_df;
            d2 = p->n_right->n_df;
            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
                        break;
                  t1 = DECREF(t1);
                  t2 = DECREF(t2);
            }
            if (DEUNSIGN(t1) != DEUNSIGN(t2))
                  warner(Wpointer_sign, NULL);
      }
}

static NODE *
offplus(NODE *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) {
      if (off != 0) {
            p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap);
            p->n_qual = q;
            p = optim(p);
      }

      return buildtree(UMUL, p, NIL);
}

NODE *
stref(NODE *p)
{
      NODE *r;
      struct attr *ap;
      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;
      ap = s->sap;

      p = makety(p, t, q, d, ap);

      /* compute the offset to be added */

      off = s->soffset;
      dsc = s->sclass;

#ifndef CAN_UNALIGN
      /*
       * If its a packed struct, and the target cannot do unaligned
       * accesses, then split it up in two bitfield operations.
       * LHS and RHS accesses are different, so must delay
       * it until we know.  Do the bitfield construct here though.
       */
      if ((dsc & FIELD) == 0 && (off % talign(s->stype, s->sap))) {
#if 0
            int sz = tsize(s->stype, s->sdf, s->sap);
            int al = talign(s->stype, s->sap);
            int sz1 = al - (off % al);
#endif
      }
#endif

      if (dsc & FIELD) {
            TWORD ftyp = s->stype;
            int fal = talign(ftyp, ap);
            off = (off/fal)*fal;
            p = offplus(p, off, t, q, d, ap);
            p = block(FLD, p, NIL, ftyp, 0, s->sap);
            p->n_qual = q;
            p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%fal);
      } else
            p = offplus(p, off, t, q, d, ap);

      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)
{
      return xbcon(i, NULL, INT);
}

NODE *
xbcon(CONSZ val, struct symtab *sp, TWORD type)
{
      NODE *p;

      p = block(ICON, NIL, NIL, type, 0, 0);
      p->n_lval = val;
      p->n_sp = sp;
      return clocal(p);
}

NODE *
bpsize(NODE *p)
{
      int isdyn(struct symtab *sp);
      struct symtab s;
      NODE *q, *r;
      TWORD t;
      int sz;

      s.stype = DECREF(p->n_type);
      s.sdf = p->n_df;
      if (isdyn(&s)) {
            q = bcon(1);
            for (t = s.stype; t > BTMASK; t = DECREF(t)) {
                  if (ISPTR(t))
                        return buildtree(MUL, q, bcon(SZPOINT(t)));
                  if (ISARY(t)) {
                        if (s.sdf->ddim < 0)
                              r = tempnode(-s.sdf->ddim, INT, 0, 0);
                        else
                              r = bcon(s.sdf->ddim/SZCHAR);
                        q = buildtree(MUL, q, r);
                        s.sdf++;
                  }
            }
            sz = tsize(p->n_type, p->n_df, p->n_ap);
            p = buildtree(MUL, q, bcon(sz/SZCHAR));
      } else
            p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap));
      return p;
}

/*
 * 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_ap));
}

/*
 * 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_ap), s->n_type, s->n_df, s->n_ap);
      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, 0));
            df++;
            ty = DECREF(ty);
      }
      rv = clocal(block(PMCONV, rv, r, INT, 0, 0));
      rv = optim(rv);

      r = block(PMCONV, q, rv, INT, 0, 0);
      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 != INTPTR)
            r = clocal(block(SCONV, r, NIL, INTPTR, 0, 0));
      if (f == CVTL)
            p->n_left = r;
      else
            p->n_right = r;
      return(p);
}

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) ||
                ISPTR(p->n_left->n_type) ||
                ISPTR(p->n_right->n_type))
                   p->n_op += (ULE-LE);
            /* FALLTHROUGH */
      case EQ:
      case NE:
            return( p );

      case MINUS:
            p->n_type = INTPTR;
            p->n_ap = NULL;
            return(  clocal( block( PVCONV,
                  p, bpsize(p->n_left), INT, 0, 0)));
            }

      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 attr *ap, *ap2;
      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;
      ap = p->n_left->n_ap;
      ap2 = p->n_right->n_ap;

      switch( o ){

      case ASSIGN:
      case RETURN:
      case CAST:
            {  break; }

      case MINUS: {
            int isdyn(struct symtab *sp);
            struct symtab s1, s2;

            s1.stype = DECREF(t);
            s1.sdf = d;
            s2.stype = DECREF(t2);
            s2.sdf = d2;
            if (isdyn(&s1) || isdyn(&s2))
                  ; /* We don't know */
            else 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;
                  ap = ap2;
                  break;
                  }
            if( !ISPTR(t2) ){
                  break;
                  }

            /* both are pointers */
            if( talign(t2,ap2) < talign(t,ap) ){
                  t = t2;
                  q = q2;
                  ap = ap2;
                  }
            break;
            }

      p->n_left = makety( p->n_left, t, q, d, ap );
      p->n_right = makety( p->n_right, t, q, d, ap );
      if( o!=MINUS && !clogop(o) ){

            p->n_type = t;
            p->n_qual = q;
            p->n_df = d;
            p->n_ap = ap;
            }

      return(clocal(p));
      }

int tdebug = 0;


/*
 * 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 the op with the highest rank is unsigned, this is the resulting type.
 *  See:  6.3.1.1 rank order equal of signed and unsigned types
 *      6.3.1.8 Usual arithmetic conversions
 */
NODE *
tymatch(NODE *p)
{
      TWORD tl, tr, t, tu;
      NODE *l, *r;
      int o, lu, ru;

      o = p->n_op;
      r = p->n_right;
      l = p->n_left;

      tl = l->n_type;
      tr = r->n_type;

      lu = ru = 0;
      if (ISUNSIGNED(tl)) {
            lu = 1;
            tl = DEUNSIGN(tl);
      }
      if (ISUNSIGNED(tr)) {
            ru = 1;
            tr = DEUNSIGN(tr);
      }

      if (clogop(o) && tl == tr && lu != ru &&
          l->n_op != ICON && r->n_op != ICON)
            warner(Wsign_compare, NULL);

      if (tl == LDOUBLE || tr == LDOUBLE)
            t = LDOUBLE;
      else if (tl == DOUBLE || tr == DOUBLE)
            t = DOUBLE;
      else if (tl == FLOAT || tr == FLOAT)
            t = FLOAT;
      else if (tl==LONGLONG || tr == LONGLONG)
            t = LONGLONG;
      else if (tl==LONG || tr==LONG)
            t = LONG;
      else /* everything else */
            t = INT;

      if (casgop(o)) {
            tu = l->n_type;
            t = tl;
      } else {
            /* Should result be unsigned? */
            /* This depends on ctype() being called correctly */
            tu = t;
            if (UNSIGNABLE(t) && (lu || ru)) {
                  if (tl >= tr && lu)
                        tu = ENUNSIGN(t);
                  if (tr >= tl && ru)
                        tu = ENUNSIGN(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 != tl || (ru && !lu)) {
            if (o != CAST && r->n_op != ICON &&
                tsize(tl, 0, 0) > tsize(tu, 0, 0))
                  warner(Wtruncate, tnames[tu], tnames[tl]);
            p->n_left = makety( p->n_left, tu, 0, 0, 0);
      }

      if (t != tr || o==CAST || (lu && !ru)) {
            if (o != CAST && r->n_op != ICON &&
                tsize(tr, 0, 0) > tsize(tu, 0, 0))
                  warner(Wtruncate, tnames[tu], tnames[tr]);
            p->n_right = makety(p->n_right, tu, 0, 0, 0);
      }

      if( casgop(o) ){
            p->n_type = p->n_left->n_type;
            p->n_df = p->n_left->n_df;
            p->n_ap = p->n_left->n_ap;
            }
      else if( !clogop(o) ){
            p->n_type = tu;
            p->n_df = NULL;
            p->n_ap = NULL;
            }

#ifdef PCC_DEBUG
      if (tdebug) {
            printf("tymatch(%p): ", p);
            tprint(stdout, tl, 0);
            printf(" %s ", copst(o));
            tprint(stdout, tr, 0);
            printf(" => ");
            tprint(stdout, tu, 0);
            printf("\n");
            fwalk(p, eprint, 0);
      }
#endif

      return(p);
      }

/*
 * Create a float const node of zero.
 */
static NODE *
fzero(TWORD t)
{
      NODE *p = block(FCON, NIL, NIL, t, 0, 0);

      p->n_dcon = FLOAT_CAST(0, INT);
      return p;
}

/*
 * make p into type t by inserting a conversion
 */
NODE *
makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap)
{

      if (t == p->n_type) {
            p->n_df = d;
            p->n_ap = ap;
            p->n_qual = q;
            return(p);
      }

      if (p->n_op == FCON && (t >= FLOAT && t <= LDOUBLE)) {
            if (t == FLOAT)
                  p->n_dcon = (float)p->n_dcon;
            else if (t == DOUBLE)
                  p->n_dcon = (double)p->n_dcon;
            else
                  p->n_dcon = (long double)p->n_dcon;
            p->n_type = t;
            return p;
      }

      if (p->n_op == FCON) {
            int isf = ISFTY(t);
            NODE *r;

            if (isf||ISITY(t)) {
                  if (isf == ISFTY(p->n_type)) {
                        p->n_type = t;
                        p->n_qual = q;
                        p->n_df = d;
                        p->n_ap = ap;
                        return(p);
                  } else if (isf == ISITY(p->n_type)) {
                        /* will be zero */
                        nfree(p);
                        return fzero(t);
                  } else if (ISCTY(p->n_type))
                        cerror("complex constant");
            } else if (ISCTY(t)) {
                  if (ISITY(p->n_type)) {
                        /* convert to correct subtype */
                        r = fzero(t - (COMPLEX-DOUBLE));
                        p->n_type = t + (IMAG-COMPLEX);
                        p->n_qual = q;
                        p->n_df = d;
                        p->n_ap = NULL;
                        return block(CM, r, p, t, 0, 0);
                  } else if (ISFTY(p->n_type)) {
                        /* convert to correct subtype */
                        r = fzero(t + (IMAG-COMPLEX));
                        p->n_type = t - (COMPLEX-DOUBLE);
                        p->n_qual = q;
                        p->n_df = d;
                        p->n_ap = NULL;
                        return block(CM, p, r, t, 0, 0);
                  } else if (ISCTY(p->n_type))
                        cerror("complex constant2");
            }
      }

      if (t & TMASK) {
            /* non-simple type */
            p = block(PCONV, p, NIL, t, d, ap);
            p->n_qual = q;
            return clocal(p);
      }

      if (p->n_op == ICON) {
            if (ISFTY(t)) {
                  p->n_op = FCON;
                  p->n_dcon = FLOAT_CAST(p->n_lval, p->n_type);
                  p->n_type = t;
                  p->n_qual = q;
                  p->n_ap = NULL;
                  return (clocal(p));
            } else if (ISCTY(t) || ISITY(t))
                  cerror("complex constant3");
      }

      p = block(SCONV, p, NIL, t, d, ap);
      p->n_qual = q;
      return clocal(p);

}

NODE *
block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct attr *ap)
{
      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_ap = ap;
#if !defined(MULTIPASS)
      /* p->n_reg = */p->n_su = 0;
      p->n_regw = 0;
#endif
      return(p);
      }

/*
 * Return the constant value from an ICON.
 */
CONSZ
icons(NODE *p)
{
      /* if p is an integer constant, return its value */
      CONSZ val;

      if (p->n_op != ICON || p->n_sp != NULL) {
            uerror( "constant expected");
            val = 1;
      } else
            val = p->n_lval;
      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 */

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+PROML );
            break;

      case COMPL:
            if( mt1 & MINT ) return( TYPL+PROML );
            break;

      case ADDROF:
            return( NCVT+OTHER );
      case NOT:
            return( PROML );

/*    case INIT: */
      case CM:
      case CBRANCH:
      case ANDAND:
      case OROR:
            return( 0 );

      case MUL:
      case DIV:
            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+CVTO );
            else if( mt12 & MPTI ) return( PTMATCH+PUN );
            else break;

      case QUEST:
            return( TYPR+OTHER );
      case COMOP:
            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 );
            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 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:
#ifndef NO_COMPLEX
      case FCOMPLEX:
      case COMPLEX:
      case LCOMPLEX:
      case FIMAG:
      case IMAG:
      case LIMAG:
#endif
            return( MDBI );
      default:
            return( MPTR|MPTI );

      }
}

int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 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 attr *ap)
{
      NODE *r;

      if (tvaloff == -NOOFFSET)
            tvaloff++; /* Skip this for array indexing */
      r = block(TEMP, NIL, NIL, type, df, ap);
      regno(r) = nr ? nr : tvaloff;
      tvaloff += szty(type);
      return r;
}

/*
 * Do sizeof on p.
 */
NODE *
doszof(NODE *p)
{
      extern NODE *arrstk[10];
      extern int arrstkp;
      union dimfun *df;
      TWORD ty;
      NODE *rv, *q;
      int astkp;

      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;
      astkp = 0;
      while (ISARY(ty)) {
            if (df->ddim == NOOFFSET)
                  uerror("sizeof of incomplete type");
            if (df->ddim < 0) {
                  if (arrstkp)
                        q = arrstk[astkp++];
                  else
                        q = tempnode(-df->ddim, INT, 0, 0);
            } else
                  q = bcon(df->ddim);
            rv = buildtree(MUL, rv, q);
            df++;
            ty = DECREF(ty);
      }
      rv = buildtree(MUL, rv, 
          xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR));
      tfree(p);
      arrstkp = 0; /* XXX - may this fail? */
      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 (p->n_op == XARG || p->n_op == XASM)
            printf("id '%s', ", p->n_name);
      if (ty == LTYPE) {
            printf(CONFMT, p->n_lval);
            if (p->n_op == NAME || p->n_op == ICON)
                  printf(", %p, ", p->n_sp);
            else
                  printf(", %d, ", p->n_rval);
      }
      tprint(stdout, p->n_type, p->n_qual);
      printf( ", %p, ", p->n_df);
      dump_attr(p->n_ap);
}
# endif

/*
 * Emit everything that should be emitted on the left side 
 * of a comma operator, and remove the operator.
 * Do not traverse through QUEST, ANDAND and OROR.
 * Enable this for all targets when stable enough.
 */
static void
comops(NODE *p)
{
      int o;
      NODE *q;

      while (p->n_op == COMOP) {
            /* XXX hack for GCC ({ }) ops */
            if (p->n_left->n_op == GOTO) {
                  int v = (int)p->n_left->n_left->n_lval;
                  ecomp(p->n_left);
                  plabel(v+1);
            } else
                  ecomp(p->n_left); /* will recurse if more COMOPs */
            q = p->n_right;
            *p = *q;
            nfree(q);
      }
      o = coptype(p->n_op);
      if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR)
            o = UTYPE;
      if (o != LTYPE)
            comops(p->n_left);
      if (o == BITYPE)
            comops(p->n_right);
}

/*
 * 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];
#if 0
                              p->n_op = NE; /* toggla */
#endif
                  } 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];
#if 0
                              p->n_op = EQ; /* toggla */
#endif
                  } 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 (nncon(p->n_right) && 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 (nncon(p->n_right) && 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);
            comops(p->n_right);
            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);
            comops(p->n_right);
            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);
            }
      }
}

/*
 * Create a node for either TEMP or on-stack storage.
 */
NODE *
cstknode(TWORD t, union dimfun *df, struct attr *ap)
{
      struct symtab *sp;

      /* create a symtab entry suitable for this type */
      sp = getsymtab("0hej", STEMP);
      sp->stype = t;
      sp->sdf = df;
      sp->sap = ap;
      sp->sclass = AUTO;
      sp->soffset = NOOFFSET;
      oalloc(sp, &autooff);
      return nametree(sp);

}

/*
 * 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, *tval;
      int o, ty, lbl, lbl2;

      tval = NIL;
      o = p->n_op;
      ty = coptype(o);
      if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */
            struct symtab *sp = strmemb(p->n_ap);
            MODTYPE(p->n_type, sp->stype);
            /*
             * XXX may fail if these are true:
             * - variable-sized enums
             * - non-byte-addressed targets.
             */
            if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type))
                  MODTYPE(p->n_type, INT); /* INT ok? */
      }
      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;
            comops(q);
            if (type != VOID) {
                  tval = cstknode(q->n_type, q->n_df, q->n_ap);
                  q = buildtree(ASSIGN, ccopy(tval), q);
            }
            rmcops(q);
            ecode(q); /* Done with assign */
            branch(lbl2 = getlab());
            plabel( lbl);

            q = p->n_right->n_right;
            comops(q);
            if (type != VOID) {
                  q = buildtree(ASSIGN, ccopy(tval), q);
            }
            rmcops(q);
            ecode(q); /* Done with assign */

            plabel( lbl2);

            nfree(p->n_right);
            if (p->n_type != VOID) {
                  *p = *tval;
                  nfree(tval);
            } else {
                  p->n_op = ICON;
                  p->n_lval = 0;
                  p->n_sp = NULL;
            }
            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());

            tval = cstknode(p->n_type, p->n_df, p->n_ap);

            ecode(buildtree(ASSIGN, ccopy(tval), bcon(1)));
            branch(lbl2 = getlab());
            plabel( lbl);
            ecode(buildtree(ASSIGN, ccopy(tval), bcon(0)));
            plabel( lbl2);

            *p = *tval;
            nfree(tval);

#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:
            cerror("COMOP error");

      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 unnecessary.
             */
            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_ap);
                  tval = regno(q);
                  r = tempnode(tval, ll->n_type, ll->n_df,ll->n_ap);
                  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_ap);
#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) {
            warner(Wunreachable_code, NULL);
            reached = 1;
      }
      p = optim(p);
      comops(p);
      rmcops(p);
      p = delasgop(p);
      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;

      myp2tree(p);  /* local action can be taken here */

      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)) {
                        printf(LABFMT, q->soffset);
                  } else
                        printf("%s\n",
                            q->soname ? q->soname : 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_ap));
            printf("\t%d\t\n", talign(STRTY, p->n_left->n_ap));
            break;

      case XARG:
      case XASM:
            break;

      default:
            printf(      "\n" );
      }

      if (ty != LTYPE)
            p2tree(p->n_left);
      if (ty == BITYPE)
            p2tree(p->n_right);
}
#else
static char *
sptostr(struct symtab *sp)
{
      char *cp = inlalloc(32);
      int n = sp->soffset;
      if (n < 0)
            n = -n;
      snprintf(cp, 32, LABFMT, n);
      return cp;
}

void
p2tree(NODE *p)
{
      struct symtab *q;
      int ty;

      myp2tree(p);  /* local action can be taken here */

      /* Fix left imaginary types */
      if (ISITY(BTYPE(p->n_type)))
            MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT));

      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
                      ) {
                        p->n_name = sptostr(q);
                  } else {
                        if ((p->n_name = q->soname) == NULL)
                              p->n_name = addname(exname(q->sname));
                  }
            } else
                  p->n_name = "";
            break;

      case STASG:
            /* STASG used for stack array init */
            if (ISARY(p->n_type)) {
                  int size1 = (int)tsize(p->n_type, p->n_left->n_df,
                      p->n_left->n_ap)/SZCHAR;
                  p->n_stsize = (int)tsize(p->n_type, p->n_right->n_df,
                      p->n_right->n_ap)/SZCHAR;
                  if (size1 < p->n_stsize)
                        p->n_stsize = size1;
                  p->n_stalign = talign(p->n_type,
                      p->n_left->n_ap)/SZCHAR;
                  break;
            }
            /* FALLTHROUGH */
      case STARG:
      case STCALL:
      case USTCALL:
            /* set up size parameters */
            p->n_stsize = (int)((tsize(STRTY, p->n_left->n_df,
                p->n_left->n_ap)+SZCHAR-1)/SZCHAR);
            p->n_stalign = talign(STRTY,p->n_left->n_ap)/SZCHAR;
            if (p->n_stalign == 0)
                  p->n_stalign = 1; /* At least char for packed structs */
            break;

      case XARG:
      case XASM:
            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, void *arg)
{
      /* 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 *r;
                  int l, l2;

                  r = tempnode(0, BOOL_TYPE, NULL, 0);
                  cbranch(buildtree(EQ, p->n_left, bcon(0)),
                      bcon(l = getlab()));
                  *p = *r;
                  ecode(buildtree(ASSIGN, tcopy(r), bcon(1)));
                  branch(l2 = getlab());
                  plabel(l);
                  ecode(buildtree(ASSIGN, r, bcon(0)));
                  plabel(l2);
            } 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;

#ifdef GCC_COMPAT
      {
            NODE *q = p;

            if (q->n_op == UMUL)
                  q = p->n_left;
            if (cdope(q->n_op)&CALLFLG &&
                attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT))
                  werror("return value ignored");
      }
#endif
      p = optim(p);
      p = delasgop(p);
      walkf(p, delvoid, 0);
#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 (cftnsp == NULL && type != IP_ASM) {
#ifdef notyet
            cerror("no function");
#endif
            if (type == IP_NODE)
                  tfree(va_arg(ap, NODE *));
            return;
      }
      if (type == IP_PROLOG || type == IP_EPILOG)
            sz = sizeof(struct interpass_prolog);
      else
            sz = sizeof(struct interpass);

      ip = inlalloc(sz);
      ip->type = type;
      ip->lineno = lineno;
      switch (type) {
      case IP_NODE:
            ip->ip_node = va_arg(ap, NODE *);
            break;
      case IP_EPILOG:
            if (!isinlining)
                  defloc(cftnsp);
            /* FALLTHROUGH */
      case IP_PROLOG:
            inftn = type == IP_PROLOG ? 1 : 0;
            ipp = (struct interpass_prolog *)ip;
            memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0,
                sizeof(ipp->ipp_regs));
            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 = va_arg(ap, int);
            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");
                  printf("%s", va_arg(ap, char *));
                  printf("\n");
                  va_end(ap);
                  defloc(NULL);
                  return;
            }
            ip->ip_asm = va_arg(ap, char *);
            break;
      default:
            cerror("bad send_passt type %d", type);
      }
      va_end(ap);
      pass1_lastchance(ip); /* target-specific info */
      if (isinlining)
            inline_addarg(ip);
      else
            pass2_compile(ip);
}

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,--)
      SNAM(STRING,STRING)
      SNAM(SZOF,SIZEOF)
      SNAM(ATTRIB,ATTRIBUTE)
      SNAM(TYMERGE,TYMERGE)
#ifdef GCC_COMPAT
      SNAM(XREAL,__real__)
      SNAM(XIMAG,__imag__)
#endif
      default:
            cerror("bad copst %d", op);
      }
      return 0; /* XXX gcc */
}

int
cdope(int op)
{
      if (op <= MAXOP)
            return dope[op];
      switch (op) {
      case CLOP:
      case STRING:
      case QUALIFIER:
      case CLASS:
      case RB:
      case ELLIPSIS:
      case TYPE:
            return LTYPE;
      case DOT:
      case SZOF:
      case COMOP:
      case QUEST:
      case COLON:
      case LB:
      case TYMERGE:
            return BITYPE;
      case XIMAG:
      case XREAL:
      case ATTRIB:
            return UTYPE;
      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;
      }
      cerror("cdope missing op %d", op);
      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)
{
      reached = 1; /* Will this always be correct? */
      send_passt(IP_DEFLAB, label);
}

/*
 * Perform integer promotion on node n.
 */
NODE *
intprom(NODE *n)
{
      if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) {
            if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) ||
                (n->n_type == USHORT && MAX_USHORT > MAX_INT))
                  return makety(n, UNSIGNED, 0, 0, 0);
            return makety(n, INT, 0, 0, 0);
      }
      return n;
}

/*
 * Return CON/VOL/0, whichever are active for the current type.
 */
int
cqual(TWORD t, TWORD q)
{
      while (ISARY(t))
            t = DECREF(t), q = DECQAL(q);
      if (t <= BTMASK)
            q <<= TSHIFT;
      return q & (CON|VOL);
}

int crslab = 10;
/*
 * Return a number for internal labels.
 */
int
getlab(void)
{
      return crslab++;
}

Generated by  Doxygen 1.6.0   Back to index