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

pexpr.c

/* "p2c", a Pascal to C translator.
   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation.
   Author's address: daveg@synaptics.com.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */



#define PROTO_PEXPR_C
#include "trans.h"




Expr *dots_n_hats(ex, target)
Expr *ex;
Type *target;
{
    Expr *ex2, *ex3;
    Type *tp, *tp2;
    Meaning *mp, *tvar;
    int hassl;

    for (;;) {
      if ((ex->val.type->kind == TK_PROCPTR ||
           ex->val.type->kind == TK_CPROCPTR) &&
          curtok != TOK_ASSIGN &&
          ((mp = (tp2 = ex->val.type)->basetype->fbase) == NULL ||
           (mp->isreturn && mp->xnext == NULL) ||
           curtok == TOK_LPAR) &&
          (tp2->basetype->basetype != tp_void || target == tp_void) &&
          (!target || (target->kind != TK_PROCPTR &&
                   target->kind != TK_CPROCPTR))) {
          hassl = tp2->escale;
          ex2 = ex;
          ex3 = copyexpr(ex2);
          if (hassl != 0)
            ex3 = makeexpr_cast(makeexpr_dotq(ex3, "proc", tp_anyptr),
                            makepointertype(tp2->basetype));
          ex = makeexpr_un(EK_SPCALL, tp2->basetype->basetype, ex3);
          if (mp && mp->isreturn) {  /* pointer to buffer for return value */
            tvar = makestmttempvar(ex->val.type->basetype,
                               (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP);
            insertarg(&ex, 1, makeexpr_addr(makeexpr_var(tvar)));
            mp = mp->xnext;
          }
          if (mp) {
            if (wneedtok(TOK_LPAR)) {
                ex = p_funcarglist(ex, mp, 0, 0);
                skipcloseparen();
            }
          } else if (curtok == TOK_LPAR) {
            gettok();
            if (!wneedtok(TOK_RPAR))
                skippasttoken(TOK_RPAR);
          }
          if (hassl != 1 || hasstaticlinks == 2) {
            freeexpr(ex2);
          } else {
            ex2 = makeexpr_dotq(ex2, "link", tp_anyptr),
            ex3 = copyexpr(ex);
            insertarg(&ex3, ex3->nargs, copyexpr(ex2));
            tp = maketype(TK_FUNCTION);
            tp->basetype = tp2->basetype->basetype;
            tp->fbase = tp2->basetype->fbase;
            tp->issigned = 1;
            ex3->args[0]->val.type = makepointertype(tp);
            ex = makeexpr_cond(makeexpr_rel(EK_NE, ex2, makeexpr_nil()),
                           ex3, ex);
          }
          if (tp2->basetype->fbase &&
            tp2->basetype->fbase->isreturn &&
            tp2->basetype->fbase->kind == MK_VARPARAM)
            ex = makeexpr_hat(ex, 0);    /* returns pointer to structured result */
          continue;
      } else if (ex->val.type->kind == TK_FUNCTION &&
               ex->val.type->meaning &&
               ex->val.type->meaning->kind == MK_FUNCTION &&
               ex->val.type->meaning->rectype) {
          if (curtok == TOK_LPAR || !target ||
            (target->kind != TK_PROCPTR &&
             target->kind != TK_CPROCPTR)) {
            ex = p_memcall(ex, ex->val.type->meaning);
            continue;
          } else {
            ex = makeexpr_addrf(ex);
            ex->val.type = tp_cproc;
            note("Pointer to member function may need to be fixed [343]");
            continue;
          }
      }
        switch (curtok) {

            case TOK_HAT:
          case TOK_ADDR:
                gettok();
                ex = makeexpr_hat(ex, 1);
                break;

            case TOK_LBR:
                do {
                    gettok();
                ex2 = p_ord_expr();
                ex = p_index(ex, ex2);
                } while (curtok == TOK_COMMA);
                if (!wneedtok(TOK_RBR))
                skippasttotoken(TOK_RBR, TOK_SEMI);
                break;

            case TOK_DOT:
                gettok();
                if (!wexpecttok(TOK_IDENT))
                break;
            if (ex->val.type->kind == TK_STRING) {
                if (!strcicmp(curtokbuf, "LENGTH")) {
                  ex = makeexpr_bicall_1("strlen", tp_int, ex);
                } else if (!strcicmp(curtokbuf, "BODY")) {
                  /* nothing to do */
                }
                gettok();
                break;
            }
            tp = ex->val.type;
            if (tp->kind == TK_POINTER &&
                tp->basetype->kind == TK_RECORD &&
                tp->basetype->issigned) {
                ex = makeexpr_hat(ex, 0);
                tp = tp->basetype;
            }
            while (tp) {
                mp = curtoksym->fbase;
                while (mp && mp->rectype != tp)
                  mp = mp->snext;
                if (mp)
                  break;
                tp = tp->basetype;
            }
                if (tp)
                    ex = makeexpr_dot(ex, mp);
                else {
                    warning(format_s("No field called %s in that record [288]", curtokbuf));
                ex = makeexpr_dotq(ex, curtokcase, tp_integer);
            }
                gettok();
                break;

          case TOK_COLONCOLON:
            gettok();
            if (wexpecttok(TOK_IDENT)) {
                ex = pascaltypecast(curtokmeaning->type, ex);
                gettok();
            }
            break;

            default:
                return ex;
        }
    }
}


Expr *p_index(ex, ex2)
Expr *ex, *ex2;
{
    Expr *ex3;
    Type *tp, *ot;
    Meaning *mp;
    int bits;

    tp = ex->val.type;
    if (tp->kind == TK_STRING) {
      if (checkconst(ex2, 0))   /* is it "s[0]"? */
          return makeexpr_bicall_1("strlen", tp_char, ex);
      else
          return makeexpr_index(ex, ex2, makeexpr_long(1));
    } else if (tp->kind == TK_ARRAY ||
             tp->kind == TK_SMALLARRAY) {
      if (tp->smax) {
          ord_range_expr(tp->indextype, &ex3, NULL);
          if (ex3->kind == EK_VAR)
            var_reference((Meaning *)ex3->val.i);
          ex2 = makeexpr_minus(ex2, copyexpr(ex3));
          if (!nodependencies(ex2, 0) &&
            *getbitsname == '*') {
            mp = makestmttempvar(tp_integer, name_TEMP);
            ex3 = makeexpr_assign(makeexpr_var(mp), ex2);
            ex2 = makeexpr_var(mp);
          } else
            ex3 = NULL;
          ex = makeexpr_bicall_3(getbitsname, tp_int,
                           ex, ex2,
                           makeexpr_long(tp->escale));
          if (tp->kind == TK_ARRAY) {
            if (tp->basetype == tp_sshort)
                bits = 4;
            else
                bits = 3;
            insertarg(&ex, 3, makeexpr_long(bits));
          }
          ex = makeexpr_comma(ex3, ex);
          ot = ord_type(tp->smax->val.type);
          if (ot->kind == TK_ENUM && ot->meaning && useenum)
            ex = makeexpr_cast(ex, tp->smax->val.type);
          ex->val.type = tp->smax->val.type;
          return ex;
      } else {
          ord_range_expr(ex->val.type->indextype, &ex3, NULL);
          if (ex3->kind == EK_VAR)
            var_reference((Meaning *)ex3->val.i);
          if (debug>2) { fprintf(outf, "ord_range_expr returns "); dumpexpr(ex3); fprintf(outf, "\n"); }
          return makeexpr_index(ex, ex2, copyexpr(ex3));
      }
    } else {
      warning("Index on a non-array variable [287]");
      return makeexpr_bin(EK_INDEX, tp_integer, ex, ex2);
    }
}


Expr *fake_dots_n_hats(ex)
Expr *ex;
{
    for (;;) {
        switch (curtok) {

            case TOK_HAT:
          case TOK_ADDR:
              if (ex->val.type->kind == TK_POINTER)
                ex = makeexpr_hat(ex, 0);
            else {
                ex->val.type = makepointertype(ex->val.type);
                ex = makeexpr_un(EK_HAT, ex->val.type->basetype, ex);
            }
                gettok();
                break;

            case TOK_LBR:
                do {
                    gettok();
                    ex = makeexpr_bin(EK_INDEX, tp_integer, ex, p_expr(tp_integer));
                } while (curtok == TOK_COMMA);
                if (!wneedtok(TOK_RBR))
                skippasttotoken(TOK_RBR, TOK_SEMI);
                break;

            case TOK_DOT:
                gettok();
                if (!wexpecttok(TOK_IDENT))
                break;
                ex = makeexpr_dotq(ex, curtokcase, tp_integer);
                gettok();
                break;

          case TOK_COLONCOLON:
            gettok();
            if (wexpecttok(TOK_IDENT)) {
                ex = pascaltypecast(curtokmeaning->type, ex);
                gettok();
            }
            break;

            default:
                return ex;
        }
    }
}



Static void bindnames(ex)
Expr *ex;
{
    int i;
    Symbol *sp;
    Meaning *mp;

    if (ex->kind == EK_NAME) {
      sp = findsymbol_opt(fixpascalname(ex->val.s));
      if (sp) {
          mp = sp->mbase;
          while (mp && !mp->isactive)
            mp = mp->snext;
          if (mp && !strcmp(mp->name, ex->val.s)) {
            ex->kind = EK_VAR;
            ex->val.i = (long)mp;
            ex->val.type = mp->type;
          }
      }
    }
    i = ex->nargs;
    while (--i >= 0)
      bindnames(ex->args[i]);
}



void var_reference(mp)
Meaning *mp;
{
    Meaning *mp2;

    mp->refcount++;
    if (mp->ctx && mp->ctx->kind == MK_FUNCTION &&
      mp->ctx->needvarstruct &&
      (mp->kind == MK_VAR ||
       mp->kind == MK_VARREF ||
       mp->kind == MK_VARMAC ||
       mp->kind == MK_PARAM ||
       mp->kind == MK_VARPARAM ||
       (mp->kind == MK_CONST &&
        (mp->type->kind == TK_ARRAY ||
         mp->type->kind == TK_RECORD)))) {
        if (debug>1) { fprintf(outf, "varstruct'ing %s\n", mp->name); }
        if (!mp->varstructflag) {
            mp->varstructflag = 1;
            if (mp->constdefn &&      /* move init code into function body */
            mp->kind != MK_VARMAC) {
                mp2 = addmeaningafter(mp, curtoksym, MK_VAR);
                curtoksym->mbase = mp2->snext;  /* hide this fake variable */
                mp2->snext = mp;      /* remember true variable */
                mp2->type = mp->type;
                mp2->constdefn = mp->constdefn;
                mp2->isforward = 1;   /* declare it "static" */
                mp2->refcount++;      /* so it won't be purged! */
                mp->constdefn = NULL;
                mp->isforward = 0;
            }
        }
        for (mp2 = curctx->ctx; mp2 != mp->ctx; mp2 = mp2->ctx)
            mp2->varstructflag = 1;
        mp2->varstructflag = 1;
    }
}


Expr *expr_reference(ex)
Expr *ex;
{
    int i;

    for (i = 0; i < ex->nargs; i++)
        expr_reference(ex->args[i]);
    if (ex->kind == EK_VAR)
      var_reference((Meaning *)ex->val.i);
    return ex;
}



Expr *p_variable(target)
Type *target;
{
    Expr *ex, *ex2;
    Meaning *mp;
    Symbol *sym;

    if (curtok != TOK_IDENT) {
        warning("Expected a variable [289]");
      return makeexpr_long(0);
    }
    if (!curtokmeaning) {
      sym = curtoksym;
        ex = makeexpr_name(curtokcase, tp_integer);
        gettok();
        if (curtok == TOK_LPAR) {
            ex = makeexpr_bicall_0(ex->val.s, tp_integer);
            do {
                gettok();
                insertarg(&ex, ex->nargs, p_expr(NULL));
            } while (curtok == TOK_COMMA || curtok == TOK_ASSIGN);
            if (!wneedtok(TOK_RPAR))
            skippasttotoken(TOK_RPAR, TOK_SEMI);
        }
      if (!tryfuncmacro(&ex, NULL))
          undefsym(sym);
        return fake_dots_n_hats(ex);
    }
    var_reference(curtokmeaning);
    mp = curtokmeaning;
    if (curtokint >= 0  /*mp->kind == MK_FIELD*/) {
      if (withexprs[curtokint])
          ex = makeexpr_dot(copyexpr(withexprs[curtokint]), mp);
      else
          ex = makeexpr_name(mp->name, mp->type);
    } else if (mp->kind == MK_CONST &&
             mp->type->kind == TK_SET &&
             mp->constdefn) {
      ex = copyexpr(mp->constdefn);
      mp = makestmttempvar(ex->val.type, name_SET);
        ex2 = makeexpr(EK_MACARG, 0);
        ex2->val.type = ex->val.type;
      ex = replaceexprexpr(ex, ex2, makeexpr_var(mp), 0);
        freeexpr(ex2);
    } else if (mp->kind == MK_CONST &&
               (mp == mp_false ||
                mp == mp_true ||
                mp->anyvarflag ||
                (foldconsts > 0 &&
                 (mp->type->kind == TK_INTEGER ||
                  mp->type->kind == TK_BOOLEAN ||
                  mp->type->kind == TK_CHAR ||
                  mp->type->kind == TK_ENUM ||
                  mp->type->kind == TK_SUBR ||
                  mp->type->kind == TK_REAL)) ||
                (foldstrconsts > 0 &&
                 (mp->type->kind == TK_STRING)))) {
        if (mp->constdefn) {
            ex = copyexpr(mp->constdefn);
            if (ex->val.type == tp_int)   /* kludge! */
                ex->val.type = tp_integer;
        } else
            ex = makeexpr_val(copyvalue(mp->val));
    } else if (mp->kind == MK_VARPARAM ||
               mp->kind == MK_VARREF) {
        ex = makeexpr_hat(makeexpr_var(mp), 0);
    } else if (mp->kind == MK_VARMAC) {
        ex = copyexpr(mp->constdefn);
      bindnames(ex);
        ex = gentle_cast(ex, mp->type);
        ex->val.type = mp->type;
    } else if (mp->kind == MK_SPVAR && mp->handler) {
        gettok();
        ex = (*mp->handler)(mp);
        return dots_n_hats(ex, target);
    } else if (mp->kind == MK_VAR ||
               mp->kind == MK_CONST ||
               mp->kind == MK_PARAM) {
      if (mp->varstructflag && mp->isref) {
          ex = makeexpr_var(mp);
          ex->val.type = makepointertype(ex->val.type);
          ex = makeexpr_hat(ex, 0);
      } else
          ex = makeexpr_var(mp);
    } else {
        symclass(mp->sym);
        ex = makeexpr_name(mp->name, tp_integer);
    }
    gettok();
    return dots_n_hats(ex, target);
}




Expr *p_ord_expr()
{
    return makeexpr_charcast(p_expr(tp_integer));
}



Static Expr *makesmallsetconst(bits, type)
long bits;
Type *type;
{
    Expr *ex;

    ex = makeexpr_long(bits);
    ex->val.type = type;
    if (smallsetconst != 2)
        insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
    return ex;
}



Expr *packset(ex, type)
Expr *ex;
Type *type;
{
    Meaning *mp;
    Expr *ex2;
    long max2;

    if (ex->kind == EK_BICALL) {
        if (!strcmp(ex->val.s, setexpandname) &&
            (mp = istempvar(ex->args[0])) != NULL) {
            canceltempvar(mp);
            return grabarg(ex, 1);
        }
        if (!strcmp(ex->val.s, setunionname) &&
            (mp = istempvar(ex->args[0])) != NULL &&
            !exproccurs(ex->args[1], ex->args[0]) &&
            !exproccurs(ex->args[2], ex->args[0])) {
            canceltempvar(mp);
            return makeexpr_bin(EK_BOR, type, packset(ex->args[1], type),
                                              packset(ex->args[2], type));
        }
        if (!strcmp(ex->val.s, setaddname)) {
            ex2 = makeexpr_bin(EK_LSH, type,
                               makeexpr_longcast(makeexpr_long(1), 1),
                               ex->args[1]);
            ex = packset(ex->args[0], type);
            if (checkconst(ex, 0))
                return ex2;
            else
                return makeexpr_bin(EK_BOR, type, ex, ex2);
        }
        if (!strcmp(ex->val.s, setaddrangename)) {
            if (ord_range(type->indextype, NULL, &max2) && max2 == setbits-1)
                note("Range construction was implemented by a subtraction which may overflow [278]");
            ex2 = makeexpr_minus(makeexpr_bin(EK_LSH, type,
                                              makeexpr_longcast(makeexpr_long(1), 1),
                                              makeexpr_plus(ex->args[2],
                                                            makeexpr_long(1))),
                                 makeexpr_bin(EK_LSH, type,
                                              makeexpr_longcast(makeexpr_long(1), 1),
                                              ex->args[1]));
            ex = packset(ex->args[0], type);
            if (checkconst(ex, 0))
                return ex2;
            else
                return makeexpr_bin(EK_BOR, type, ex, ex2);
        }
    }
    return makeexpr_bicall_1(setpackname, type, ex);
}



#define MAXSETLIT 400

Expr *p_setfactor(target, sure)
Type *target;
int sure;
{
    Expr *ex, *exmax = NULL, *ex2;
    Expr *first[MAXSETLIT], *last[MAXSETLIT];
    char doneflag[MAXSETLIT];
    int i, j, num, donecount;
    int isconst, guesstype;
    long maxv, max2;
    Value val;
    Type *tp, *type;
    Meaning *tvar;

    if (curtok == TOK_LBRACE)
      gettok();
    else if (!wneedtok(TOK_LBR))
      return makeexpr_long(0);
    if (curtok == TOK_RBR || curtok == TOK_RBRACE) {        /* empty set */
        gettok();
        val.type = tp_smallset;
        val.i = 0;
        val.s = NULL;
        return makeexpr_val(val);
    }
    type = target;
    guesstype = !sure;
    maxv = -1;
    isconst = 1;
    num = 0;
    for (;;) {
        if (num >= MAXSETLIT) {
            warning(format_d("Too many elements in set literal; max=%d [290]", MAXSETLIT));
            ex = p_expr(type);
            while (curtok != TOK_RBR && curtok != TOK_RBRACE) {
                gettok();
                ex = p_expr(type);
            }
            break;
        }
        if (guesstype && num == 0) {
            ex = p_ord_expr();
          type = ex->val.type;
        } else {
            ex = p_expr(type);
        }
        first[num] = ex = gentle_cast(ex, type);
        doneflag[num] = 0;
        if (curtok == TOK_DOTS || curtok == TOK_COLON) {   /* UCSD? */
            val = eval_expr(ex);
            if (val.type) {
            if (val.i > maxv) {     /* In case of [127..0] */
                maxv = val.i;
                exmax = ex;
            }
          } else
                isconst = 0;
            gettok();
            last[num] = ex = gentle_cast(p_expr(type), type);
        } else {
            last[num] = NULL;
        }
        val = eval_expr(ex);
        if (val.type) {
            if (val.i > maxv) {
                maxv = val.i;
                exmax = ex;
            }
        } else {
            isconst = 0;
            maxv = LONG_MAX;
        }
        num++;
        if (curtok == TOK_COMMA)
            gettok();
        else
            break;
    }
    if (curtok == TOK_RBRACE)
      gettok();
    else if (!wneedtok(TOK_RBR))
      skippasttotoken(TOK_RBR, TOK_SEMI);
    tp = first[0]->val.type;
    if (guesstype) {      /* must determine type */
        if (maxv == LONG_MAX) {
          if (target && ord_range(target, NULL, &max2))
            maxv = max2;
            else if (ord_range(tp, NULL, &max2) && max2 < 1000000 &&
                 (max2 >= defaultsetsize || num == 1))
                maxv = max2;
          else
            maxv = defaultsetsize-1;
            exmax = makeexpr_long(maxv);
        } else
            exmax = copyexpr(exmax);
        if (!ord_range(tp, NULL, &max2) || maxv != max2)
            tp = makesubrangetype(tp, makeexpr_long(0), exmax);
        type = makesettype(tp);
    } else
      type = makesettype(type);
    donecount = 0;
    if (smallsetconst > 0) {
        val.i = 0;
        for (i = 0; i < num; i++) {
            if (first[i]->kind == EK_CONST && first[i]->val.i < setbits &&
                (!last[i] || (last[i]->kind == EK_CONST &&
                              last[i]->val.i >= 0 &&
                              last[i]->val.i < setbits))) {
                if (last[i]) {
                    for (j = first[i]->val.i; j <= last[i]->val.i; j++)
                        val.i |= 1L << j;
                } else
                val.i |= 1L << first[i]->val.i;
                doneflag[i] = 1;
                donecount++;
            }
        }
    }
    if (donecount) {
        ex = makesmallsetconst(val.i, tp_smallset);
    } else
        ex = NULL;
    if (type->kind == TK_SMALLSET) {
        for (i = 0; i < num; i++) {
            if (!doneflag[i]) {
                ex2 = makeexpr_bin(EK_LSH, type,
                           makeexpr_longcast(makeexpr_long(1), 1),
                           enum_to_int(first[i]));
                if (last[i]) {
                    if (ord_range(type->indextype, NULL, &max2) && max2 == setbits-1)
                        note("Range construction was implemented by a subtraction which may overflow [278]");
                    ex2 = makeexpr_minus(makeexpr_bin(EK_LSH, type,
                                                      makeexpr_longcast(makeexpr_long(1), 1),
                                                      makeexpr_plus(enum_to_int(last[i]),
                                                                    makeexpr_long(1))),
                                         ex2);
                }
                if (ex)
                    ex = makeexpr_bin(EK_BOR, type, makeexpr_longcast(ex, 1), ex2);
                else
                    ex = ex2;
            }
        }
    } else {
        tvar = makestmttempvar(type, name_SET);
        if (!ex) {
            val.type = tp_smallset;
          val.i = 0;
          val.s = NULL;
          ex = makeexpr_val(val);
      }
        ex = makeexpr_bicall_2(setexpandname, type,
                               makeexpr_var(tvar), makeexpr_arglong(ex, 1));
        for (i = 0; i < num; i++) {
            if (!doneflag[i]) {
                if (last[i])
                    ex = makeexpr_bicall_3(setaddrangename, type,
                                           ex, makeexpr_arglong(enum_to_int(first[i]), 0),
                                               makeexpr_arglong(enum_to_int(last[i]), 0));
                else
                    ex = makeexpr_bicall_2(setaddname, type,
                                           ex, makeexpr_arglong(enum_to_int(first[i]), 0));
            }
        }
    }
    return ex;
}




Expr *p_funcarglist(ex, args, firstarg, ismacro)
Expr *ex;
Meaning *args;
int firstarg, ismacro;
{
    Meaning *mp, *mp2, *arglist = args, *prevarg = NULL;
    Expr *ex2;
    int i, fi, fakenum = -1, castit, isconf, isnonpos = 0;
    Type *tp, *tp2;
    char *name;

    castit = castargs;
    if (castit < 0)
      castit = (prototypes == 0);
    while (args) {
      if (isnonpos) {
          while (curtok == TOK_COMMA)
            gettok();
          if (curtok == TOK_RPAR) {
            args = arglist;
            i = firstarg;
            while (args) {
                if (ex->nargs <= i)
                  insertarg(&ex, ex->nargs, NULL);
                if (!ex->args[i]) {
                  if (args->constdefn)
                      ex->args[i] = copyexpr(args->constdefn);
                  else {
                      warning(format_s("Missing value for parameter %s [291]",
                                   args->name));
                      ex->args[i] = makeexpr_long(0);
                  }
                }
                args = args->xnext;
                i++;
            }
            break;
          }
      }
      if (args->isreturn || args->fakeparam) {
          if (args->fakeparam) {
            if (fakenum < 0)
                fakenum = ex->nargs;
            if (args->constdefn)
                insertarg(&ex, ex->nargs, copyexpr(args->constdefn));
            else
                insertarg(&ex, ex->nargs, makeexpr_long(0));
          }
          args = args->xnext;     /* return value parameter */
          continue;
      }
      if (curtok == TOK_RPAR) {
          if (args->constdefn) {
            insertarg(&ex, ex->nargs, copyexpr(args->constdefn));
            args = args->xnext;
            continue;
          } else {
            if (ex->kind == EK_FUNCTION) {
                name = ((Meaning *)ex->val.i)->name;
                ex->kind = EK_BICALL;
                ex->val.s = stralloc(name);
            } else
                name = "function";
            warning(format_s("Too few arguments for %s [292]", name));
            return ex;
          }
      }
      if (curtok == TOK_COMMA) {
          if (args->constdefn)
            insertarg(&ex, ex->nargs, copyexpr(args->constdefn));
          else {
            warning(format_s("Missing parameter %s [293]", args->name));
            insertarg(&ex, ex->nargs, makeexpr_long(0));
          }
          gettok();
          args = args->xnext;
          continue;
      }
      p_mech_spec(0);
      if (curtok == TOK_IDENT) {
          mp = arglist;
          mp2 = NULL;
          i = firstarg;
          fi = -1;
          while (mp && strcmp(curtokbuf, mp->sym->name)) {
            if (mp->fakeparam) {
                if (fi < 0)
                  fi = i;
            } else
                fi = -1;
            i++;
            mp2 = mp;
            mp = mp->xnext;
          }
          if (mp &&
            (peeknextchar() == 1 || !curtokmeaning || isnonpos)) {
            gettok();
            wneedtok(TOK_ASSIGN);
            prevarg = mp2;
            args = mp;
            fakenum = fi;
            isnonpos = 1;
          } else
            i = ex->nargs;
      } else
          i = ex->nargs;
      while (ex->nargs <= i)
          insertarg(&ex, ex->nargs, NULL);
      if (ex->args[i])
          warning(format_s("Multiple values for parameter %s [294]",
                       args->name));
      tp = args->type;
      ex2 = p_expr(tp);
      if (args->kind == MK_VARPARAM)
          tp = tp->basetype;
      if (isfiletype(tp, 1) && is_std_file(ex2)) {
          mp2 = makestmttempvar(tp_bigtext, name_TEMP);
          ex2 = makeexpr_comma(
               makeexpr_comma(makeexpr_assign(filebasename(makeexpr_var(mp2)),
                                      ex2),
                          makeexpr_assign(filenamepart(makeexpr_var(mp2)),
                                      makeexpr_string(""))),
                         makeexpr_var(mp2));
      }
      tp2 = ex2->val.type;
      isconf = ((tp->kind == TK_ARRAY ||
               tp->kind == TK_STRING) && tp->structdefd);
        switch (args->kind) {

            case MK_PARAM:
              if (args->isref) {
                if (tp2 != tp && !isconf &&
                  (tp2->kind != TK_STRING ||
                   tp->kind != TK_STRING))
                  warning(format_s("Type mismatch in VAR parameter %s [295]",
                               args->name));
            } else if (castit && tp->kind == TK_REAL &&
                ex2->val.type->kind != TK_REAL)
                    ex2 = makeexpr_cast(ex2, tp);
                else if (ord_type(tp)->kind == TK_INTEGER && !ismacro)
                    ex2 = makeexpr_arglong(ex2, long_type(tp));
                else if (args->othername && args->rectype != tp &&
                         tp->kind != TK_STRING && args->type == tp2)
                    ex2 = makeexpr_addr(ex2);
                else
                    ex2 = gentle_cast(ex2, tp);
            ex->args[i] = ex2;
                break;

            case MK_VARPARAM:
                if (args->type == tp_strptr && args->anyvarflag) {
                ex->args[i] = strmax_func(ex2);
                    insertarg(&ex, ex->nargs-1, makeexpr_addr(ex2));
                if (isnonpos)
                  note("Non-positional conformant parameters may not work [279]");
                } else {                        /* regular VAR parameter */
                if (!expr_is_lvalue(ex2) ||
                  (tp->kind == TK_REAL &&
                   ord_type(tp2)->kind == TK_INTEGER)) {
                  mp2 = makestmttempvar(tp, name_TEMP);
                  ex2 = makeexpr_comma(makeexpr_assign(makeexpr_var(mp2),
                                               ex2),
                                   makeexpr_addrf(makeexpr_var(mp2)));
                } else
                  ex2 = makeexpr_addrf(ex2);
                    if (args->anyvarflag ||
                        (tp->kind == TK_POINTER && tp2->kind == TK_POINTER &&
                         (tp == tp_anyptr || tp2 == tp_anyptr))) {
                  if (!ismacro)
                      ex2 = makeexpr_cast(ex2, args->type);
                    } else {
                        if (tp2 != tp && !isconf &&
                      (tp2->kind != TK_STRING ||
                       tp->kind != TK_STRING))
                            warning(format_s("Type mismatch in VAR parameter %s [295]",
                                             args->name));
                    }
                ex->args[i] = ex2;
                }
                break;

          default:
            intwarning("p_funcarglist",
                     format_s("Parameter type is %s [296]",
                            meaningkindname(args->kind)));
            break;
        }
      if (isconf &&   /* conformant array or string */
          (!prevarg || prevarg->type != args->type)) {
          while (tp->kind == TK_ARRAY && tp->structdefd) {
            if (tp2->kind == TK_SMALLARRAY) {
                warning("Trying to pass a small-array for a conformant array [297]");
                /* this has a chance of working... */
                ex->args[ex->nargs-1] =
                  makeexpr_addr(ex->args[ex->nargs-1]);
            } else if (tp2->kind == TK_STRING) {
                ex->args[fakenum++] =
                  makeexpr_arglong(makeexpr_long(1), integer16 == 0);
                ex->args[fakenum++] =
                  makeexpr_arglong(strmax_func(ex->args[ex->nargs-1]),
                               integer16 == 0);
                break;
              } else if (tp2->kind != TK_ARRAY) {
                warning("Type mismatch for conformant array [298]");
                break;
            }
            ex->args[fakenum++] =
                makeexpr_arglong(expr_reference(copyexpr(tp2->indextype->smin)),
                             integer16 == 0);
            ex->args[fakenum++] =
                makeexpr_arglong(expr_reference(copyexpr(tp2->indextype->smax)),
                             integer16 == 0);
            tp = tp->basetype;
            tp2 = tp2->basetype;
          }
          if (tp->kind == TK_STRING && tp->structdefd) {
            ex->args[fakenum] =
                makeexpr_arglong(strmax_func(ex->args[ex->nargs-1]),
                             integer16 == 0);
          }
      }
      fakenum = -1;
      if (!isnonpos) {
          prevarg = args;
          args = args->xnext;
          if (args) {
            if (curtok != TOK_RPAR && !wneedtok(TOK_COMMA))
                skiptotoken2(TOK_RPAR, TOK_SEMI);
          }
      }
    }
    if (curtok == TOK_COMMA) {
      if (ex->kind == EK_FUNCTION) {
          name = ((Meaning *)ex->val.i)->name;
          ex->kind = EK_BICALL;
          ex->val.s = stralloc(name);
      } else
          name = "function";
      warning(format_s("Too many arguments for %s [299]", name));
      while (curtok == TOK_COMMA) {
          gettok();
          insertarg(&ex, ex->nargs, p_expr(tp_integer));
      }
    }
    return ex;
}



Expr *replacemacargs(ex, fex)
Expr *ex, *fex;
{
    int i;
    Expr *ex2;

    for (i = 0; i < ex->nargs; i++)
        ex->args[i] = replacemacargs(ex->args[i], fex);
    if (ex->kind == EK_MACARG) {
      if (ex->val.i <= fex->nargs) {
          ex2 = copyexpr(fex->args[ex->val.i - 1]);
      } else {
          ex2 = makeexpr_name("<meef>", tp_integer);
          note("FuncMacro specified more arguments than call [280]");
      }
      freeexpr(ex);
      return ex2;
    }
    return resimplify(ex);
}


Expr *p_noarglist(ex, mp, args)
Expr *ex;
Meaning *mp, *args;
{
    while (args && args->constdefn) {
      insertarg(&ex, ex->nargs, copyexpr(args->constdefn));
      args = args->xnext;
    }
    if (args) {
      warning(format_s("Expected an argument list for %s [300]", mp->name));
      ex->kind = EK_BICALL;
      ex->val.s = stralloc(mp->name);
    }
    return ex;
}


void func_reference(func)
Meaning *func;
{
    Meaning *mp;

    if (func->ctx && func->ctx != curctx &&func->ctx->kind == MK_FUNCTION &&
      func->ctx->varstructflag && !curctx->ctx->varstructflag) {
      for (mp = curctx->ctx; mp != func->ctx; mp = mp->ctx)
          mp->varstructflag = 1;
    }
}


Expr *p_memcall(expr, mp)
Expr *expr;
Meaning *mp;
{
    Meaning *tvar, *mp2;
    Expr *ex;
    int firstarg = 0;

    mp2 = mp->type->fbase;
    ex = makeexpr_un(EK_SPCALL, mp->type->basetype, expr);
    if (mp2 && mp2->isreturn) {  /* pointer to buffer for return value */
      tvar = makestmttempvar(ex->val.type->basetype,
                         (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP);
      insertarg(&ex, 1, makeexpr_addr(makeexpr_var(tvar)));
      mp2 = mp2->xnext;
      firstarg++;
    }
    if (mp2 && curtok != TOK_LPAR) {
      ex = p_noarglist(ex, mp, mp2);
    } else if (curtok == TOK_LPAR) {
      gettok();
      ex = p_funcarglist(ex, mp2, firstarg, 0);
      skipcloseparen();
    }
    ex->val.i = 1;
    return ex;
}


Expr *p_funccall(mp)
Meaning *mp;
{
    Meaning *mp2, *tvar;
    Expr *ex, *ex2;
    int firstarg = 0;

    func_reference(mp);
    ex = makeexpr(EK_FUNCTION, 0);
    ex->val.i = (long)mp;
    ex->val.type = mp->type->basetype;
    mp2 = mp->type->fbase;
    if (mp2 && mp2->isreturn) {    /* pointer to buffer for return value */
        tvar = makestmttempvar(ex->val.type->basetype,
            (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP);
        insertarg(&ex, 0, makeexpr_addr(makeexpr_var(tvar)));
        mp2 = mp2->xnext;
      firstarg++;
    }
    if (mp2 && curtok != TOK_LPAR) {
      ex = p_noarglist(ex, mp, mp2);
    } else if (curtok == TOK_LPAR) {
      gettok();
        ex = p_funcarglist(ex, mp2, firstarg, (mp->constdefn != NULL));
        skipcloseparen();
    }
    if (mp->constdefn) {
        ex2 = replacemacargs(copyexpr(mp->constdefn), ex);
      ex2 = gentle_cast(ex2, ex->val.type);
      ex2->val.type = ex->val.type;
        freeexpr(ex);
        return ex2;
    }
    return ex;
}






Expr *accumulate_strlit()
{
    char buf[256], ch, *cp, *cp2;
    int len, i, danger = 0;

    len = 0;
    cp = buf;
    for (;;) {
        if (curtok == TOK_STRLIT) {
            cp2 = curtokbuf;
            i = curtokint;
            while (--i >= 0) {
                if (++len <= 255) {
                    ch = *cp++ = *cp2++;
                    if (ch & 128)
                        danger++;
                }
            }
        } else if (curtok == TOK_HAT) {    /* Turbo */
            i = getchartok() & 0x1f;
            if (++len <= 255)
                *cp++ = i;
      } else if (curtok == TOK_LPAR) {   /* VAX */
          Value val;
          do {
            gettok();
            val = p_constant(tp_integer);
            if (++len <= 255)
                *cp++ = val.i;
          } while (curtok == TOK_COMMA);
          skipcloseparen();
          continue;
        } else
            break;
        gettok();
    }
    if (len > 255) {
        warning("String literal too long [301]");
        len = 255;
    }
    if (danger &&
        !(unsignedchar == 1 ||
          (unsignedchar != 0 && signedchars == 0)))
        note(format_s("Character%s >= 128 encountered [281]", (danger > 1) ? "s" : ""));
    return makeexpr_lstring(buf, len);
}



Expr *pascaltypecast(type, ex2)
Type *type;
Expr *ex2;
{
    if (type->kind == TK_POINTER || type->kind == TK_STRING ||
      type->kind == TK_ARRAY)
      ex2 = makeexpr_stringcast(ex2);
    else
      ex2 = makeexpr_charcast(ex2);
    if ((ex2->val.type->kind == TK_INTEGER ||
       ex2->val.type->kind == TK_CHAR ||
       ex2->val.type->kind == TK_BOOLEAN ||
       ex2->val.type->kind == TK_ENUM ||
       ex2->val.type->kind == TK_SUBR ||
       ex2->val.type->kind == TK_REAL ||
       ex2->val.type->kind == TK_POINTER ||
       ex2->val.type->kind == TK_STRING) &&
      (type->kind == TK_INTEGER ||
       type->kind == TK_CHAR ||
       type->kind == TK_BOOLEAN ||
       type->kind == TK_ENUM ||
       type->kind == TK_SUBR ||
       type->kind == TK_REAL ||
       type->kind == TK_POINTER)) {
      if (type->kind == TK_POINTER || ex2->val.type->kind == TK_POINTER)
          return makeexpr_un(EK_CAST, type, ex2);
      else
          return makeexpr_un(EK_ACTCAST, type, ex2);
    } else {
      return makeexpr_hat(makeexpr_cast(makeexpr_addr(ex2),
                                makepointertype(type)), 0);
    }
}




Static Expr *p_factor(target)
Type *target;
{
    Expr *ex, *ex2;
    Type *type;
    Meaning *mp, *mp2;

    switch (curtok) {

        case TOK_INTLIT:
            ex = makeexpr_long(curtokint);
            gettok();
            return ex;

        case TOK_HEXLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
            gettok();
            return ex;

        case TOK_OCTLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lo", tp_integer));
            gettok();
            return ex;

        case TOK_MININT:
          strcat(curtokbuf, ".0");

      /* fall through */
        case TOK_REALLIT:
            ex = makeexpr_real(curtokbuf);
            gettok();
            return ex;

        case TOK_HAT:
        case TOK_STRLIT:
            ex = accumulate_strlit();
            return ex;

        case TOK_LPAR:
            gettok();
            ex = p_expr(target);
            skipcloseparen();
            return dots_n_hats(ex, target);

        case TOK_NOT:
      case TOK_TWIDDLE:
            gettok();
            ex = p_factor(tp_integer);
            if (ord_type(ex->val.type)->kind == TK_INTEGER)
                return makeexpr_un(EK_BNOT, tp_integer, ex);
            else
                return makeexpr_not(ex);

      case TOK_MINUS:
          gettok();
            if (curtok == TOK_MININT) {
                gettok();
                return makeexpr_long(MININT);
            } else
            return makeexpr_neg(p_factor(target));
          
        case TOK_PLUS:
          gettok();
          return p_factor(target);

        case TOK_ADDR:
            gettok();
          if (curtok == TOK_ADDR) {
            gettok();
            ex = p_factor(tp_proc);
            if (ex->val.type->kind == TK_PROCPTR && ex->kind == EK_COMMA)
                return grabarg(grabarg(grabarg(ex, 0), 1), 0);
            if (ex->val.type->kind != TK_CPROCPTR)
                warning("@@ allowed only for procedure pointers [302]");
            return makeexpr_addrf(ex);
          }
            if (curtok == TOK_IDENT && 0 &&  /***/
                curtokmeaning && (curtokmeaning->kind == MK_FUNCTION ||
                                  curtokmeaning->kind == MK_SPECIAL)) {
                if (curtokmeaning->ctx == nullctx)
                    warning(format_s("Can't take address of predefined object %s [303]",
                                     curtokmeaning->name));
                ex = makeexpr_name(curtokmeaning->name, tp_anyptr);
                gettok();
            } else {
            ex = p_factor(tp_proc);
            if (ex->val.type->kind == TK_PROCPTR) {
              /*  ex = makeexpr_dotq(ex, "proc", tp_anyptr);  */
            } else if (ex->val.type->kind == TK_CPROCPTR) {
                ex = makeexpr_cast(ex, tp_anyptr);
            } else
                ex = makeexpr_addrf(ex);
            }
            return ex;

        case TOK_LBR:
      case TOK_LBRACE:
            return p_setfactor(target && target->kind == TK_SET
                         ? target->indextype : NULL, 0);

        case TOK_NIL:
            gettok();
            return makeexpr_nil();

      case TOK_IF:    /* nifty Pascal extension */
          gettok();
          ex = p_expr(tp_boolean);
          wneedtok(TOK_THEN);
          ex2 = p_expr(tp_integer);
          if (wneedtok(TOK_ELSE))
            return makeexpr_cond(ex, ex2, p_factor(ex2->val.type));
          else
            return makeexpr_cond(ex, ex2, makeexpr_long(0));

      case TOK_INHERITED:
          gettok();
          if (!wexpecttok(TOK_IDENT))
            skiptotoken(TOK_IDENT);
          type = curtokmeaning->rectype;
          if (type) type = type->basetype;
          while (type) {
            mp2 = curtoksym->fbase;
            while (mp2 && mp2->rectype != type)
                mp2 = mp2->snext;
            if (mp2)
                break;
            type = type->basetype;
          }
          if (type) {
            if (mp2->kind == MK_FUNCTION)
                ex = makeexpr_var(mp2->xnext);
            else
                ex = makeexpr_name(format_ss("%s::%s",
                                     type->meaning->name,
                                     mp2->name),
                               mp2->type);
          } else {
            warning(format_s("No field called %s in that object [332]",
                         curtokbuf));
            return p_variable(target);
          }
          gettok();
          return dots_n_hats(ex, target);

        case TOK_IDENT:
            mp = curtokmeaning;
          if (mp == mp_new_normal)
            mp = curtokmeaning = mp_new_turbo;
            switch ((mp) ? mp->kind : MK_VAR) {

                case MK_TYPE:
                gettok();
                    type = mp->type;
                    switch (curtok) {

                        case TOK_LPAR:    /* Turbo type cast */
                            gettok();
                      if (type->kind == TK_RECORD && type->issigned &&
                        !turboobjects)
                        type = makepointertype(type);
                            ex2 = p_expr(type);
                      ex = pascaltypecast(type, ex2);
                            skipcloseparen();
                            return dots_n_hats(ex, target);

                        case TOK_LBR:
                  case TOK_LBRACE:
                            switch (type->kind) {

                                case TK_SET:
                                case TK_SMALLSET:
                                    return p_setfactor(type->indextype, 1);

                                case TK_RECORD:
                                    return p_constrecord(type, 0);

                                case TK_ARRAY:
                                case TK_SMALLARRAY:
                                    return p_constarray(type, 0);

                                case TK_STRING:
                                    return p_conststring(type, 0);

                                default:
                                    warning("Bad type for constructor [304]");
                            skipparens();
                            return makeexpr_name(mp->name, mp->type);
                            }

                  case TOK_DOT:
                      gettok();
                      if (!wexpecttok(TOK_IDENT))
                        skiptotoken(TOK_IDENT);
                      if (type->kind == TK_RECORD) {
                        while (type) {
                            mp2 = curtoksym->fbase;
                            while (mp2 && mp2->rectype != type)
                              mp2 = mp2->snext;
                            if (mp2)
                              break;
                            type = type->basetype;
                        }
                        if (type) {
                            if (mp2->kind == MK_FUNCTION)
                              ex = makeexpr_var(mp2->xnext);
                            else
                              ex = makeexpr_name(format_ss("%s::%s",
                                                     type->meaning->name,
                                                     mp2->name),
                                             mp2->type);
                        } else {
                            warning(format_s("No field called %s in that object [332]",
                                         curtokbuf));
                            return p_variable(target);
                        }
                        gettok();
                        return dots_n_hats(ex, target);
                      } else {
                        warning(format_s("%s is not an object type",
                                     type->meaning->name));
                        return p_variable(target);
                      }

                  default:
                      wexpected("an expression");
                      return makeexpr_name(mp->name, mp->type);
                    }

                case MK_SPECIAL:
                    if (mp->handler && mp->isfunction &&
                  (peeknextchar() == '(' ||
                   !target || mp == mp_self_func ||
                   (target->kind != TK_PROCPTR &&
                    target->kind != TK_CPROCPTR))) {
                        gettok();
                        if ((mp->sym->flags & LEAVEALONE) || mp->constdefn) {
                            ex = makeexpr_bicall_0(mp->name, tp_integer);
                            if (curtok == TOK_LPAR) {
                                do {
                                    gettok();
                                    insertarg(&ex, ex->nargs, p_expr(NULL));
                                } while (curtok == TOK_COMMA);
                                skipcloseparen();
                            }
                            tryfuncmacro(&ex, mp);
                      return ex;
                        }
                        ex = (*mp->handler)(mp);
                  if (!ex)
                      ex = makeexpr_long(0);
                  return dots_n_hats(ex, target);
                    } else {
                  if (target &&
                      (target->kind == TK_PROCPTR ||
                       target->kind == TK_CPROCPTR))
                      note("Using a built-in procedure as a procedure pointer [316]");
                        else
                      symclass(curtoksym);
                        gettok();
                        return makeexpr_name(mp->name, tp_integer);
                    }

                case MK_FUNCTION:
                    mp->refcount++;
                if (mp->rectype)
                  return p_variable(target);
                    need_forward_decl(mp);
                gettok();
                    if (mp->isfunction &&
                  (curtok == TOK_LPAR || !target ||
                   (target->kind != TK_PROCPTR &&
                    target->kind != TK_CPROCPTR))) {
                        ex = p_funccall(mp);
                        if (!mp->constdefn) {
                            if (mp->handler && !(mp->sym->flags & LEAVEALONE))
                                ex = (*mp->handler)(ex);
                  }
                  if (mp->cbase->kind == MK_VARPARAM) {
                      ex = makeexpr_hat(ex, 0);    /* returns pointer to structured result */
                        }
                        return dots_n_hats(ex, target);
                    } else {
                  if (mp->handler && !(mp->sym->flags & LEAVEALONE))
                      note("Using a built-in procedure as a procedure pointer [316]");
                  if (target && target->kind == TK_CPROCPTR) {
                      type = maketype(TK_CPROCPTR);
                      type->basetype = mp->type;
                      type->escale = 0;
                      mp2 = makestmttempvar(type, name_TEMP);
                      ex = makeexpr_comma(
                                    makeexpr_assign(
                                       makeexpr_var(mp2),
                               makeexpr_name(mp->name, tp_text)),
                            makeexpr_var(mp2));
                      if (mp->ctx->kind == MK_FUNCTION)
                        warning("Procedure pointer to nested procedure [305]");
                  } else {
                      type = maketype(TK_PROCPTR);
                      type->basetype = mp->type;
                      type->escale = 1;
                      mp2 = makestmttempvar(type, name_TEMP);
                      ex = makeexpr_comma(
                                    makeexpr_comma(
                                       makeexpr_assign(
                                          makeexpr_dotq(makeexpr_var(mp2),
                                          "proc",
                                          tp_anyptr),
                                makeexpr_name(mp->name, tp_text)),
                                          /* handy pointer type */
                               makeexpr_assign(
                                          makeexpr_dotq(makeexpr_var(mp2),
                                          "link",
                                          tp_anyptr),
                                  makeexpr_ctx(mp->ctx))),
                            makeexpr_var(mp2));
                  }
                        return ex;
                    }

                default:
                    return p_variable(target);
            }

      default:
          wexpected("an expression");
          return makeexpr_long(0);
          
    }
}




Static Expr *p_powterm(target)
Type *target;
{
    Expr *ex = p_factor(target);
    Expr *ex2;
    int i, castit;
    long v;

    if (curtok == TOK_STARSTAR) {
      gettok();
      ex2 = p_powterm(target);
      if (ex->val.type->kind == TK_REAL ||
          ex2->val.type->kind == TK_REAL) {
          if (checkconst(ex2, 2)) {
            ex = makeexpr_sqr(ex, 0);
          } else if (checkconst(ex2, 3)) {
            ex = makeexpr_sqr(ex, 1);
          } else {
            castit = castargs >= 0 ? castargs : (prototypes == 0);
            if (ex->val.type->kind != TK_REAL && castit)
                ex = makeexpr_cast(ex, tp_longreal);
            if (ex2->val.type->kind != TK_REAL && castit)
                ex2 = makeexpr_cast(ex2, tp_longreal);
            ex = makeexpr_bicall_2("pow", tp_longreal, ex, ex2);
          }
      } else if (checkconst(ex, 2)) {
          freeexpr(ex);
          ex = makeexpr_bin(EK_LSH, tp_integer,
                        makeexpr_longcast(makeexpr_long(1), 1), ex2);
      } else if (checkconst(ex, 0) ||
               checkconst(ex, 1) ||
               checkconst(ex2, 1)) {
          freeexpr(ex2);
      } else if (checkconst(ex2, 0)) {
          freeexpr(ex);
          freeexpr(ex2);
          ex = makeexpr_long(1);
      } else if (isliteralconst(ex, NULL) == 2 &&
               isliteralconst(ex2, NULL) == 2 &&
               ex2->val.i > 0) {
          v = ex->val.i;
          i = ex2->val.i;
          while (--i > 0)
            v *= ex->val.i;
          freeexpr(ex);
          freeexpr(ex2);
          ex = makeexpr_long(v);
      } else if (checkconst(ex2, 2)) {
          ex = makeexpr_sqr(ex, 0);
      } else if (checkconst(ex2, 3)) {
          ex = makeexpr_sqr(ex, 1);
      } else {
          ex = makeexpr_bicall_2("ipow", tp_integer,
                           makeexpr_arglong(ex, 1),
                           makeexpr_arglong(ex2, 1));
      }
    }
    return ex;
}


Static Expr *p_term(target)
Type *target;
{
    Expr *ex = p_powterm(target);
    Expr *ex2;
    Type *type;
    Meaning *tvar;
    int useshort;

    for (;;) {
      checkkeyword(TOK_SHL);
      checkkeyword(TOK_SHR);
      checkkeyword(TOK_REM);
        switch (curtok) {

            case TOK_STAR:
                gettok();
                if (ex->val.type->kind == TK_SET ||
                    ex->val.type->kind == TK_SMALLSET) {
                    ex2 = p_powterm(ex->val.type);
                    type = mixsets(&ex, &ex2);
                    if (type->kind == TK_SMALLSET) {
                        ex = makeexpr_bin(EK_BAND, type, ex, ex2);
                    } else {
                        tvar = makestmttempvar(type, name_SET);
                        ex = makeexpr_bicall_3(setintname, type,
                                               makeexpr_var(tvar),
                                               ex, ex2);
                    }
                } else
                    ex = makeexpr_times(ex, p_powterm(tp_integer));
                break;

            case TOK_SLASH:
                gettok();
                if (ex->val.type->kind == TK_SET ||
                    ex->val.type->kind == TK_SMALLSET) {
                    ex2 = p_powterm(ex->val.type);
                    type = mixsets(&ex, &ex2);
                    if (type->kind == TK_SMALLSET) {
                        ex = makeexpr_bin(EK_BXOR, type, ex, ex2);
                    } else {
                        tvar = makestmttempvar(type, name_SET);
                        ex = makeexpr_bicall_3(setxorname, type,
                                               makeexpr_var(tvar),
                                               ex, ex2);
                    }
            } else
                ex = makeexpr_divide(ex, p_powterm(tp_integer));
                break;

            case TOK_DIV:
                gettok();
                ex = makeexpr_div(ex, p_powterm(tp_integer));
                break;

            case TOK_REM:
                gettok();
                ex = makeexpr_rem(ex, p_powterm(tp_integer));
                break;

            case TOK_MOD:
                gettok();
                ex = makeexpr_mod(ex, p_powterm(tp_integer));
                break;

            case TOK_AND:
          case TOK_AMP:
            if (lowpreclogicals || peeknextword("THEN"))
                return ex;
            useshort = (curtok == TOK_AMP);
                gettok();
                ex2 = p_powterm(tp_integer);
                if (ord_type(ex->val.type)->kind == TK_INTEGER)
                    ex = makeexpr_bin(EK_BAND, ex->val.type, ex, ex2);
                else if (partial_eval_flag || useshort ||
                         (shortopt && nosideeffects(ex2, 1)))
                    ex = makeexpr_and(ex, ex2);
                else
                    ex = makeexpr_bin(EK_BAND, tp_boolean, ex, ex2);
                break;

            case TOK_SHL:
                gettok();
                ex = makeexpr_bin(EK_LSH, ex->val.type, ex, p_powterm(tp_integer));
                break;

            case TOK_SHR:
                gettok();
                ex = force_unsigned(ex);
                ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_powterm(tp_integer));
                break;

            default:
                return ex;
        }
    }
}



Expr *p_sexpr(target)
Type *target;
{
    Expr *ex, *ex2;
    Type *type;
    Meaning *tvar;
    int useshort;

    switch (curtok) {
        case TOK_MINUS:
            gettok();
            if (curtok == TOK_MININT) {
                gettok();
                ex = makeexpr_long(MININT);
            break;
            }
            ex = makeexpr_neg(p_term(target));
            break;
        case TOK_PLUS:
            gettok();
        /* fall through */
        default:
            ex = p_term(target);
            break;
    }
    if (curtok == TOK_PLUS &&
        (ex->val.type->kind == TK_STRING ||
         ord_type(ex->val.type)->kind == TK_CHAR ||
         ex->val.type->kind == TK_ARRAY)) {
        while (curtok == TOK_PLUS) {
            gettok();
            ex = makeexpr_concat(ex, p_term(NULL), 0);
        }
        return ex;
    } else {
        for (;;) {
          checkkeyword(TOK_XOR);
            switch (curtok) {

                case TOK_PLUS:
                    gettok();
                    if (ex->val.type->kind == TK_SET ||
                        ex->val.type->kind == TK_SMALLSET) {
                        ex2 = p_term(ex->val.type);
                        type = mixsets(&ex, &ex2);
                        if (type->kind == TK_SMALLSET) {
                            ex = makeexpr_bin(EK_BOR, type, ex, ex2);
                        } else {
                            tvar = makestmttempvar(type, name_SET);
                            ex = makeexpr_bicall_3(setunionname, type,
                                                   makeexpr_var(tvar),
                                                   ex, ex2);
                        }
                    } else
                        ex = makeexpr_plus(ex, p_term(tp_integer));
                    break;

                case TOK_MINUS:
                    gettok();
                    if (ex->val.type->kind == TK_SET ||
                        ex->val.type->kind == TK_SMALLSET) {
                        ex2 = p_term(tp_integer);
                        type = mixsets(&ex, &ex2);
                        if (type->kind == TK_SMALLSET) {
                            ex = makeexpr_bin(EK_BAND, type, ex,
                                              makeexpr_un(EK_BNOT, type, ex2));
                        } else {
                            tvar = makestmttempvar(type, name_SET);
                            ex = makeexpr_bicall_3(setdiffname, type,
                                                   makeexpr_var(tvar), ex, ex2);
                        }
                    } else
                        ex = makeexpr_minus(ex, p_term(tp_integer));
                    break;

            case TOK_VBAR:
                if (modula2)
                  return ex;
                /* fall through */

                case TOK_OR:
                if (lowpreclogicals || peeknextword("ELSE"))
                  return ex;
                useshort = (curtok == TOK_VBAR);
                    gettok();
                    ex2 = p_term(tp_integer);
                    if (ord_type(ex->val.type)->kind == TK_INTEGER)
                        ex = makeexpr_bin(EK_BOR, ex->val.type, ex, ex2);
                    else if (partial_eval_flag || useshort ||
                             (shortopt && nosideeffects(ex2, 1)))
                        ex = makeexpr_or(ex, ex2);
                    else
                        ex = makeexpr_bin(EK_BOR, tp_boolean, ex, ex2);
                    break;

                case TOK_XOR:
                    gettok();
                    ex2 = p_term(tp_integer);
                    ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, ex2);
                    break;

                default:
                    return ex;
            }
        }
    }
}



Expr *p_rexpr(target)
Type *target;
{
    Expr *ex, *ex2, *ex3, *ex4;
    Type *type;
    Meaning *tvar;
    long mask, smin, smax;
    int i, j;

    if (curtok == TOK_NOT && lowpreclogicals) {
      gettok();
      ex = p_rexpr(target);
      if (ord_type(ex->val.type)->kind == TK_INTEGER)
          return makeexpr_un(EK_BNOT, tp_integer, ex);
      else
          return makeexpr_not(ex);
    }
    ex = p_sexpr(target);
    switch (curtok) {

        case TOK_EQ:
            gettok();
            return makeexpr_rel(EK_EQ, ex, p_sexpr(ex->val.type));

        case TOK_NE:
            gettok();
            return makeexpr_rel(EK_NE, ex, p_sexpr(ex->val.type));

        case TOK_LT:
            gettok();
            return makeexpr_rel(EK_LT, ex, p_sexpr(ex->val.type));

        case TOK_GT:
            gettok();
            return makeexpr_rel(EK_GT, ex, p_sexpr(ex->val.type));

        case TOK_LE:
            gettok();
            return makeexpr_rel(EK_LE, ex, p_sexpr(ex->val.type));

        case TOK_GE:
            gettok();
            return makeexpr_rel(EK_GE, ex, p_sexpr(ex->val.type));

        case TOK_IN:
            gettok();
            ex2 = p_sexpr(tp_smallset);
            ex = gentle_cast(ex, ex2->val.type->indextype);
            if (ex2->val.type->kind == TK_SMALLSET) {
                if (!ord_range(ex->val.type, &smin, &smax)) {
                    smin = -1;
                    smax = setbits;
                }
                if (!nosideeffects(ex, 0)) {
                    tvar = makestmttempvar(ex->val.type, name_TEMP);
                    ex3 = makeexpr_assign(makeexpr_var(tvar), ex);
                    ex = makeexpr_var(tvar);
                } else
                    ex3 = NULL;
                ex4 = copyexpr(ex);
                if (ex->kind == EK_CONST && smallsetconst)
                    ex = makesmallsetconst(1L<<ex->val.i, ex2->val.type);
                else
                    ex = makeexpr_bin(EK_LSH, ex2->val.type,
                                      makeexpr_longcast(makeexpr_long(1), 1),
                                      enum_to_int(ex));
                ex = makeexpr_rel(EK_NE, makeexpr_bin(EK_BAND, tp_integer, ex, ex2),
                                         makeexpr_long(0));
                if (*name_SETBITS ||
                    ((ex4->kind == EK_CONST) ? ((unsigned long)ex4->val.i >= setbits)
                                             : !(0 <= smin && smax < setbits))) {
                    ex = makeexpr_and(makeexpr_range(enum_to_int(ex4),
                                                     makeexpr_long(0),
                                                     makeexpr_setbits(), 0),
                                      ex);
                } else
                    freeexpr(ex4);
                ex = makeexpr_comma(ex3, ex);
                return ex;
            } else {
                ex3 = ex2;
                while (ex3->kind == EK_BICALL &&
                       (!strcmp(ex3->val.s, setaddname) ||
                        !strcmp(ex3->val.s, setaddrangename)))
                    ex3 = ex3->args[0];
                if (ex3->kind == EK_BICALL && !strcmp(ex3->val.s, setexpandname) &&
                    (tvar = istempvar(ex3->args[0])) != NULL && 
                    isconstexpr(ex3->args[1], &mask)) {
                    canceltempvar(tvar);
                    if (!nosideeffects(ex, 0)) {
                        tvar = makestmttempvar(ex->val.type, name_TEMP);
                        ex3 = makeexpr_assign(makeexpr_var(tvar), ex);
                        ex = makeexpr_var(tvar);
                    } else
                        ex3 = NULL;
                    type = ord_type(ex2->val.type->indextype);
                    ex4 = NULL;
                    i = 0;
                    while (i < setbits) {
                        if (mask & (1L<<i++)) {
                            if (i+1 < setbits && (mask & (2L<<i))) {
                                for (j = i; j < setbits && (mask & (1L<<j)); j++) ;
                                ex4 = makeexpr_or(ex4,
                                        makeexpr_range(copyexpr(ex),
                                                       makeexpr_val(make_ord(type, i-1)),
                                                       makeexpr_val(make_ord(type, j-1)), 1));
                                i = j;
                            } else {
                                ex4 = makeexpr_or(ex4,
                                        makeexpr_rel(EK_EQ, copyexpr(ex),
                                                            makeexpr_val(make_ord(type, i-1))));
                            }
                        }
                    }
                    mask = 0;
                    for (;;) {
                        if (!strcmp(ex2->val.s, setaddrangename)) {
                            if (checkconst(ex2->args[1], 'a') &&
                                checkconst(ex2->args[2], 'z')) {
                                mask |= 0x1;
                            } else if (checkconst(ex2->args[1], 'A') &&
                                       checkconst(ex2->args[2], 'Z')) {
                                mask |= 0x2;
                            } else if (checkconst(ex2->args[1], '0') &&
                                       checkconst(ex2->args[2], '9')) {
                                mask |= 0x4;
                            } else {
                                ex4 = makeexpr_or(ex4,
                                        makeexpr_range(copyexpr(ex), ex2->args[1], ex2->args[2], 1));
                            }
                        } else if (!strcmp(ex2->val.s, setaddname)) {
                            ex4 = makeexpr_or(ex4,
                                    makeexpr_rel(EK_EQ, copyexpr(ex), ex2->args[1]));
                        } else
                            break;
                        ex2 = ex2->args[0];
                    }
                    /* do these now so that EK_OR optimizations will work: */
                    if (mask & 0x1)
                        ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex),
                                                              makeexpr_char('a'),
                                                              makeexpr_char('z'), 1));
                    if (mask & 0x2)
                        ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex),
                                                              makeexpr_char('A'),
                                                              makeexpr_char('Z'), 1));
                    if (mask & 0x4)
                        ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex),
                                                              makeexpr_char('0'),
                                                              makeexpr_char('9'), 1));
                    freeexpr(ex);
                    return makeexpr_comma(ex3, ex4);
                }
                return makeexpr_bicall_2(setinname, tp_boolean,
                                         makeexpr_arglong(ex, 0), ex2);
            }

      default:
          return ex;
    }
}



Expr *p_andexpr(target)
Type *target;
{
    Expr *ex = p_rexpr(target);
    Expr *ex2;
    int useshort = 0;

    while (curtok == TOK_AND && (lowpreclogicals || peeknextword("THEN"))) {
      gettok();
      if (curtok == TOK_THEN) {
          useshort = 1;
          gettok();
      }
      ex2 = p_rexpr(tp_integer);
      if (ord_type(ex->val.type)->kind == TK_INTEGER)
          ex = makeexpr_bin(EK_BAND, ex->val.type, ex, ex2);
      else if (partial_eval_flag || useshort ||
             (shortopt && nosideeffects(ex2, 1)))
          ex = makeexpr_and(ex, ex2);
      else
          ex = makeexpr_bin(EK_BAND, tp_boolean, ex, ex2);
    }
    return ex;
}



Expr *p_expr(target)
Type *target;
{
    Expr *ex = p_andexpr(target);
    Expr *ex2;
    int useshort = 0;

    while (curtok == TOK_OR && (lowpreclogicals || peeknextword("ELSE"))) {
      gettok();
      if (curtok == TOK_ELSE) {
          useshort = 1;
          gettok();
      }
      ex2 = p_andexpr(tp_integer);
      if (ord_type(ex->val.type)->kind == TK_INTEGER)
          ex = makeexpr_bin(EK_BOR, ex->val.type, ex, ex2);
      else if (partial_eval_flag || useshort ||
             (shortopt && nosideeffects(ex2, 1)))
          ex = makeexpr_or(ex, ex2);
      else
          ex = makeexpr_bin(EK_BOR, tp_boolean, ex, ex2);
    }
    return ex;
}






/* Parse a C expression; used by VarMacro, etc. */

Type *nametotype(name)
char *name;
{
    if (!strcicmp(name, "malloc") ||
      !strcicmp(name, mallocname)) {
      return tp_anyptr;
    }
    return tp_integer;
}


int istypespec(iscast)
int iscast;
{
    char *cp;

    switch (curtok) {

        case TOK_CONST:
            return 1;

        case TOK_IDENT:
          cp = peeknextptr();
          if (*cp == ')' && iscast) {
            while (isspace(*++cp)) ;
            if (*cp == '(' || isalnum(*cp)) {
                return 1;   /* assume (x)(y) is a cast */
            }
          }
            return !strcmp(curtokcase, "volatile") ||
                   !strcmp(curtokcase, "void") ||
                   !strcmp(curtokcase, "char") ||
                   !strcmp(curtokcase, "short") ||
                   !strcmp(curtokcase, "int") ||
                   !strcmp(curtokcase, "long") ||
                   !strcmp(curtokcase, "float") ||
                   !strcmp(curtokcase, "double") ||
                   !strcmp(curtokcase, "signed") ||
                   !strcmp(curtokcase, "unsigned") ||
                   !strcmp(curtokcase, "struct") ||
                   !strcmp(curtokcase, "union") ||
                   !strcmp(curtokcase, "class") ||
                   !strcmp(curtokcase, "enum") ||
                   !strcmp(curtokcase, "typedef") ||
                   (curtokmeaning &&
                    curtokmeaning->kind == MK_TYPE);

        default:
            return 0;
    }
}



Expr *pc_parentype(cp)
char *cp;
{
    Expr *ex;

    if (curtok == TOK_IDENT &&
         curtokmeaning &&
         curtokmeaning->kind == MK_TYPE) {
        ex = makeexpr_type(curtokmeaning->type);
        gettok();
        skipcloseparen();
    } else if (curtok == TOK_IDENT && !strcmp(curtokcase, "typedef")) {
        ex = makeexpr_name(getparenstr(inbufptr), tp_integer);
        gettok();
    } else {
        ex = makeexpr_name(getparenstr(cp), tp_integer);
        gettok();
    }
    return ex;
}


Expr *pc_typename()
{
    Type *tp;
    int sign = 0;

    if (!strcmp(curtokcase, "signed")) {
      sign = 1;
      gettok();
    } else if (!strcmp(curtokcase, "unsigned")) {
      sign = -1;
      gettok();
    } else if (!strcmp(curtokcase, "struct") || !strcmp(curtokcase, "union") ||
             !strcmp(curtokcase, "class") || !strcmp(curtokcase, "enum"))
      gettok();
    if (!strcmp(curtokcase, "void"))
      tp = tp_void;
    else if (!strcmp(curtokcase, "char"))
      tp = (sign > 0) ? tp_schar : (sign < 0) ? tp_uchar : tp_char; 
    else if (!strcmp(curtokcase, "short"))
      tp = (sign >= 0) ? tp_sshort : tp_ushort;
    else if (!strcmp(curtokcase, "int"))
      tp = (sign >= 0) ? tp_int : tp_uint;
    else if (!strcmp(curtokcase, "long"))
      tp = (sign >= 0) ? tp_integer : tp_unsigned;
    else if (!strcmp(curtokcase, "float"))
      tp = tp_real;
    else if (!strcmp(curtokcase, "double"))
      tp = tp_longreal;
    else if (curtokmeaning && curtokmeaning->kind == MK_TYPE)
      tp = curtokmeaning->type;
    else {
      warning("Unrecognized C type name [339]");
      return makeexpr_name(curtokcase, tp_integer);
    }
    gettok();
    if (curtok == TOK_IDENT && !strcmp(curtokcase, "int"))
      gettok();
    while (curtok == TOK_STAR) {
      tp = makepointertype(tp);
      gettok();
    }
    return makeexpr_type(tp);
}



Expr *pc_expr2();

Expr *pc_factor()
{
    Expr *ex;
    char *cp;
    Strlist *sl;
    int i;

    switch (curtok) {

        case TOK_BANG:
            gettok();
            return makeexpr_not(pc_expr2(14));

        case TOK_TWIDDLE:
            gettok();
            return makeexpr_un(EK_BNOT, tp_integer, pc_expr2(14));

        case TOK_PLPL:
            gettok();
            ex = pc_expr2(14);
            return makeexpr_assign(ex, makeexpr_plus(copyexpr(ex), makeexpr_long(1)));

        case TOK_MIMI:
            gettok();
            ex = pc_expr2(14);
            return makeexpr_assign(ex, makeexpr_minus(copyexpr(ex), makeexpr_long(1)));

        case TOK_STAR:
            gettok();
            ex = pc_expr2(14);
            if (ex->val.type->kind != TK_POINTER)
                ex->val.type = makepointertype(ex->val.type);
            return makeexpr_hat(ex, 0);

        case TOK_AMP:
            gettok();
            return makeexpr_addr(pc_expr2(14));

        case TOK_PLUS:
            gettok();
            return pc_expr2(14);

        case TOK_MINUS:
            gettok();
            return makeexpr_neg(pc_expr2(14));

        case TOK_LPAR:
            cp = inbufptr;
            gettok();
            if (istypespec(1)) {
                ex = pc_parentype(cp);
                return makeexpr_bin(EK_LITCAST, tp_integer, ex, pc_expr2(14));
            }
            ex = pc_expr();
            skipcloseparen();
            return ex;

        case TOK_IDENT:
            if (!strcmp(curtokcase, "sizeof")) {
                gettok();
                if (curtok != TOK_LPAR)
                    return makeexpr_sizeof(pc_expr2(14), 1);
                cp = inbufptr;
                gettok();
                if (istypespec(0)) {
                    ex = makeexpr_sizeof(pc_parentype(cp), 1);
                } else {
                    ex = makeexpr_sizeof(pc_expr(), 1);
                    skipcloseparen();
                }
                return ex;
            }
          if (!strcmp(curtokcase, "new") &&
            (cplus > 0 || isalpha(peeknextchar()))) {
            gettok();
            ex = pc_typename();
            if (curtok == TOK_LBR) {
                gettok();
                ex = makeexpr_bin(EK_NEW, makepointertype(ex->val.type),
                              ex, pc_expr());
                wneedtok(TOK_RBR);
            } else
                ex = makeexpr_un(EK_NEW, makepointertype(ex->val.type),
                             ex);
            return ex;
          }
          if (!strcmp(curtokcase, "delete") &&
            (cplus > 0 || isalpha(peeknextchar()) ||
             peeknextchar() == '[')) {
            gettok();
            if (curtok == TOK_LBR) {
                gettok();
                if (curtok != TOK_RBR)
                  ex = pc_expr();
                else
                  ex = makeexpr_name("", tp_integer);
                wneedtok(TOK_RBR);
                ex = makeexpr_bin(EK_DELETE, makepointertype(ex->val.type),
                              pc_expr(), ex);
            } else
                ex = makeexpr_un(EK_DELETE, makepointertype(ex->val.type),
                             pc_expr());
            return ex;
          }
            if (curtoksym->flags & FMACREC) {
                ex = makeexpr(EK_MACARG, 0);
                ex->val.type = tp_integer;
                ex->val.i = 0;
                for (sl = funcmacroargs, i = 1; sl; sl = sl->next, i++) {
                    if (sl->value == (long)curtoksym) {
                        ex->val.i = i;
                        break;
                    }
                }
            } else
                ex = makeexpr_name(curtokcase, nametotype(curtokcase));
            gettok();
            return ex;

        case TOK_INTLIT:
            ex = makeexpr_long(curtokint);
            if (curtokbuf[strlen(curtokbuf)-1] == 'L')
                ex = makeexpr_longcast(ex, 1);
            gettok();
            return ex;

        case TOK_HEXLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer));
            if (curtokbuf[strlen(curtokbuf)-1] == 'L')
                ex = makeexpr_longcast(ex, 1);
            gettok();
            return ex;

        case TOK_OCTLIT:
            ex = makeexpr_long(curtokint);
            insertarg(&ex, 0, makeexpr_name("%#lo", tp_integer));
            if (curtokbuf[strlen(curtokbuf)-1] == 'L')
                ex = makeexpr_longcast(ex, 1);
            gettok();
            return ex;

        case TOK_REALLIT:
            ex = makeexpr_real(curtokbuf);
            gettok();
            return ex;

        case TOK_STRLIT:
            ex = makeexpr_lstring(curtokbuf, curtokint);
            gettok();
            return ex;

        case TOK_CHARLIT:
            ex = makeexpr_char(curtokint);
            gettok();
            return ex;

        default:
          wexpected("a C expression");
          return makeexpr_long(0);
    }
}




#define pc_prec(pr)  if (prec > (pr)) return ex; gettok();

Expr *pc_expr2(prec)
int prec;
{
    Expr *ex, *ex2;
    int i;

    ex = pc_factor();
    for (;;) {
        switch (curtok) {

            case TOK_COMMA:
                pc_prec(1);
                ex = makeexpr_comma(ex, pc_expr2(2));
                break;

            case TOK_EQ:
                pc_prec(2);
                ex = makeexpr_assign(ex, pc_expr2(2));
                break;

            case TOK_QM:
                pc_prec(3);
                ex2 = pc_expr();
                if (wneedtok(TOK_COLON))
                ex = makeexpr_cond(ex, ex2, pc_expr2(3));
            else
                ex = makeexpr_cond(ex, ex2, makeexpr_long(0));
                break;

            case TOK_OROR:
                pc_prec(4);
                ex = makeexpr_or(ex, pc_expr2(5));
                break;

            case TOK_ANDAND:
                pc_prec(5);
                ex = makeexpr_and(ex, pc_expr2(6));
                break;

            case TOK_VBAR:
                pc_prec(6);
                ex = makeexpr_bin(EK_BOR, tp_integer, ex, pc_expr2(7));
                break;

            case TOK_HAT:
                pc_prec(7);
                ex = makeexpr_bin(EK_BXOR, tp_integer, ex, pc_expr2(8));
                break;

            case TOK_AMP:
                pc_prec(8);
                ex = makeexpr_bin(EK_BAND, tp_integer, ex, pc_expr2(9));
                break;

            case TOK_EQEQ:
                pc_prec(9);
                ex = makeexpr_rel(EK_EQ, ex, pc_expr2(10));
                break;

            case TOK_BANGEQ:
                pc_prec(9);
                ex = makeexpr_rel(EK_NE, ex, pc_expr2(10));
                break;

            case TOK_LT:
                pc_prec(10);
                ex = makeexpr_rel(EK_LT, ex, pc_expr2(11));
                break;

            case TOK_LE:
                pc_prec(10);
                ex = makeexpr_rel(EK_LE, ex, pc_expr2(11));
                break;

            case TOK_GT:
                pc_prec(10);
                ex = makeexpr_rel(EK_GT, ex, pc_expr2(11));
                break;

            case TOK_GE:
                pc_prec(10);
                ex = makeexpr_rel(EK_GE, ex, pc_expr2(11));
                break;

            case TOK_LTLT:
                pc_prec(11);
                ex = makeexpr_bin(EK_LSH, tp_integer, ex, pc_expr2(12));
                break;

            case TOK_GTGT:
                pc_prec(11);
                ex = makeexpr_bin(EK_RSH, tp_integer, ex, pc_expr2(12));
                break;

            case TOK_PLUS:
                pc_prec(12);
                ex = makeexpr_plus(ex, pc_expr2(13));
                break;

            case TOK_MINUS:
                pc_prec(12);
                ex = makeexpr_minus(ex, pc_expr2(13));
                break;

            case TOK_STAR:
                pc_prec(13);
                ex = makeexpr_times(ex, pc_expr2(14));
                break;

            case TOK_SLASH:
                pc_prec(13);
                ex = makeexpr_div(ex, pc_expr2(14));
                break;

            case TOK_PERC:
                pc_prec(13);
                ex = makeexpr_mod(ex, pc_expr2(14));
                break;

            case TOK_PLPL:
                pc_prec(15);
                ex = makeexpr_un(EK_POSTINC, tp_integer, ex);
                break;

            case TOK_MIMI:
                pc_prec(15);
                ex = makeexpr_un(EK_POSTDEC, tp_integer, ex);
                break;

            case TOK_LPAR:
                pc_prec(16);
                if (ex->kind == EK_NAME) {
                    ex->kind = EK_BICALL;
                } else {
                    ex = makeexpr_un(EK_SPCALL, tp_integer, ex);
                }
                while (curtok != TOK_RPAR) {
                    insertarg(&ex, ex->nargs, pc_expr2(2));
                    if (curtok != TOK_RPAR)
                        if (!wneedtok(TOK_COMMA))
                      skiptotoken2(TOK_RPAR, TOK_SEMI);
                }
                gettok();
                break;

            case TOK_LBR:
                pc_prec(16);
                ex = makeexpr_index(ex, pc_expr(), NULL);
                if (!wneedtok(TOK_RBR))
                skippasttoken(TOK_RBR);
                break;

            case TOK_ARROW:
                pc_prec(16);
                if (!wexpecttok(TOK_IDENT))
                break;
                if (ex->val.type->kind != TK_POINTER)
                    ex->val.type = makepointertype(ex->val.type);
                ex = makeexpr_dotq(makeexpr_hat(ex, 0),
                                   curtokcase, tp_integer);
                gettok();
                break;

            case TOK_DOT:
                pc_prec(16);
                if (!wexpecttok(TOK_IDENT))
                break;
                ex = makeexpr_dotq(ex, curtokcase, tp_integer);
                gettok();
                break;

          case TOK_COLONCOLON:
            if (prec > 16)
                return ex;
            i = C_lex;
            C_lex = 0;
            gettok();
            if (curtok == TOK_IDENT &&
                curtokmeaning && curtokmeaning->kind == MK_TYPE) {
                ex->val.type = curtokmeaning->type;
            } else if (curtok == TOK_LPAR) {
                gettok();
                ex->val.type = p_type(NULL);
                if (!wexpecttok(TOK_RPAR))
                  skiptotoken(TOK_RPAR);
            } else
                wexpected("a type name");
            C_lex = i;
            gettok();
            break;

            default:
                return ex;
        }
    }
}




Expr *pc_expr()
{
    return pc_expr2(0);
}



Expr *pc_expr_str(buf)
char *buf;
{
    Strlist *defsl, *sl;
    Expr *ex;

    defsl = NULL;
    sl = strlist_append(&defsl, buf);
    C_lex++;
    push_input_strlist(defsl, buf);
    ex = pc_expr();
    if (curtok != TOK_EOF)
        warning(format_s("Junk (%s) at end of C expression [306]",
                   tok_name(curtok)));
    pop_input();
    C_lex--;
    strlist_empty(&defsl);
    return ex;
}






/* Simplify an expression */

Expr *fixexpr(ex, env)
Expr *ex;
int env;
{
    Expr *ex2, *ex3;
    Type *type, *type2;
    char *cp;
    char sbuf[5];
    int i, j;
    Value val;

    if (!ex)
        return NULL;
    if (debug>4) {fprintf(outf, "fixexpr("); dumpexpr(ex); fprintf(outf, ")\n");}
    switch (ex->kind) {

        case EK_BICALL:
            ex2 = fix_bicall(ex, env);
            if (ex2) {
                ex = ex2;
                break;
            }
            cp = ex->val.s;
            if (!strcmp(cp, "strlen")) {
                if (ex->args[0]->kind == EK_BICALL &&
                    !strcmp(ex->args[0]->val.s, "sprintf") &&
                    sprintf_value == 0) {     /* does sprintf return char count? */
                    ex = grabarg(ex, 0);
                    strchange(&ex->val.s, "*sprintf");
                    ex = fixexpr(ex, env);
                } else {
                    ex->args[0] = fixexpr(ex->args[0], ENV_EXPR);
                }
            } else if (!strcmp(cp, name_SETIO)) {
                ex->args[0] = fixexpr(ex->args[0], ENV_BOOL);
            } else if (!strcmp(cp, "~~SETIO")) {
                ex->args[0] = fixexpr(ex->args[0], ENV_BOOL);
                ex = makeexpr_cond(ex->args[0],
                                   makeexpr_long(0),
                                   (ex->nargs == 2)
                           ? makeexpr_bicall_1(name_ESCIO, tp_int,
                                           ex->args[1])
                           : makeexpr_bicall_2(name_ESCIO2, tp_int,
                                           ex->args[1],
                                           ex->args[2]));
            } else if (!strcmp(cp, name_CHKIO)) {
                ex->args[0] = fixexpr(ex->args[0], ENV_BOOL);
                ex->args[2] = fixexpr(ex->args[2], env);
                ex->args[3] = fixexpr(ex->args[3], env);
            } else if (!strcmp(cp, "~~CHKIO")) {
                ex->args[0] = fixexpr(ex->args[0], ENV_BOOL);
                ex->args[2] = fixexpr(ex->args[2], env);
                ex->args[3] = fixexpr(ex->args[3], env);
                ex2 = makeexpr_bicall_1(name_ESCIO, tp_int, ex->args[1]);
                if (ord_type(ex->args[3]->val.type)->kind != TK_INTEGER)
                    ex2 = makeexpr_cast(ex2, ex->args[3]->val.type);
                ex = makeexpr_cond(ex->args[0], ex->args[2], ex2);
            } else if (!strcmp(cp, "assert")) {
                ex->args[0] = fixexpr(ex->args[0], ENV_BOOL);
          } else if ((!strcmp(cp, setaddname) ||
                  !strcmp(cp, setaddrangename)) &&
                   (ex2 = ex->args[0])->kind == EK_BICALL &&
                   (!strcmp(ex2->val.s, setaddname) ||
                  !strcmp(ex2->val.s, setaddrangename))) {
            while (ex2->kind == EK_BICALL &&
                   (!strcmp(ex2->val.s, setaddname) ||
                  !strcmp(ex2->val.s, setaddrangename) ||
                  !strcmp(ex2->val.s, setexpandname)))
                ex2 = ex2->args[0];
            if (nosideeffects(ex2, 1)) {
                ex = makeexpr_comma(ex->args[0], ex);
                ex->args[1]->args[0] = ex2;
                ex = fixexpr(ex, env);
            } else
                for (i = 0; i < ex->nargs; i++)
                  ex->args[i] = fixexpr(ex->args[i], ENV_EXPR);
          } else if (!strcmp(cp, setunionname) &&
                   (ex3 = singlevar(ex->args[0])) != NULL &&
                   ((i=1, exprsame(ex->args[0], ex->args[i], 0)) ||
                  (i=2, exprsame(ex->args[0], ex->args[i], 0))) &&
                   !exproccurs(ex3, ex->args[3-i]) &&
                   ex->args[3-i]->kind == EK_BICALL &&
                   (!strcmp(ex->args[3-i]->val.s, setaddname) ||
                  !strcmp(ex->args[3-i]->val.s, setaddrangename) ||
                  (!strcmp(ex->args[3-i]->val.s, setexpandname) &&
                   checkconst(ex->args[3-i]->args[1], 0))) &&
                   totempvar(ex->args[3-i])) {
            if (!strcmp(ex->args[3-i]->val.s, setexpandname)) {
                ex = grabarg(ex, 0);
            } else {
                ex = makeexpr_comma(ex, ex->args[3-i]);
                ex->args[0]->args[3-i] = ex->args[1]->args[0];
                ex->args[1]->args[0] = copyexpr(ex->args[0]->args[0]);
            }
            ex = fixexpr(ex, env);
          } else if (!strcmp(cp, setdiffname) && *setremname &&
                   (ex3 = singlevar(ex->args[0])) != NULL &&
                   exprsame(ex->args[0], ex->args[1], 0) &&
                   !exproccurs(ex3, ex->args[2]) &&
                   ex->args[2]->kind == EK_BICALL &&
                   (!strcmp(ex->args[2]->val.s, setaddname) ||
                  (!strcmp(ex->args[2]->val.s, setexpandname) &&
                   checkconst(ex->args[2]->args[1], 0))) &&
                   totempvar(ex->args[2])) {
            if (!strcmp(ex->args[2]->val.s, setexpandname)) {
                ex = grabarg(ex, 0);
            } else {
                ex = makeexpr_comma(ex, ex->args[2]);
                ex->args[0]->args[2] = ex->args[1]->args[0];
                ex->args[1]->args[0] = copyexpr(ex->args[0]->args[0]);
                strchange(&ex->args[1]->val.s, setremname);
            }
            ex = fixexpr(ex, env);
            } else {
                for (i = 0; i < ex->nargs; i++)
                    ex->args[i] = fixexpr(ex->args[i], ENV_EXPR);
            ex = cleansprintf(ex);
                if (!strcmp(cp, "sprintf")) {
                    if (checkstring(ex->args[1], "%s")) {
                        delfreearg(&ex, 1);
                        strchange(&ex->val.s, "strcpy");
                        ex = fixexpr(ex, env);
                    } else if (sprintf_value != 1 && env != ENV_STMT) {
                        if (*sprintfname) {
                            strchange(&ex->val.s, format_s("*%s", sprintfname));
                        } else {
                            strchange(&ex->val.s, "*sprintf");
                            ex = makeexpr_comma(ex, copyexpr(ex->args[0]));
                        }
                    }
                } else if (!strcmp(cp, "strcpy")) {
                    if (env == ENV_STMT &&
                         ex->args[1]->kind == EK_BICALL &&
                         !strcmp(ex->args[1]->val.s, "strcpy") &&
                         nosideeffects(ex->args[1]->args[0], 1)) {
                        ex2 = ex->args[1];
                        ex->args[1] = copyexpr(ex2->args[0]);
                        ex = makeexpr_comma(ex2, ex);
                    }
                } else if (!strcmp(cp, "memcpy")) {
                    strchange(&ex->val.s, format_s("*%s", memcpyname));
                    if (!strcmp(memcpyname, "*bcopy")) {
                        swapexprs(ex->args[0], ex->args[1]);
                        if (env != ENV_STMT)
                            ex = makeexpr_comma(ex, copyexpr(ex->args[1]));
                    }
#if 0
            } else if (!strcmp(cp, setunionname) &&
                     (ex3 = singlevar(ex->args[0])) != NULL &&
                     ((i=1, exprsame(ex->args[0], ex->args[i], 0)) ||
                      (i=2, exprsame(ex->args[0], ex->args[i], 0))) &&
                     !exproccurs(ex3, ex->args[3-i])) {
                ep = &ex->args[3-i];
                while ((ex2 = *ep)->kind == EK_BICALL &&
                     (!strcmp(ex2->val.s, setaddname) ||
                      !strcmp(ex2->val.s, setaddrangename)))
                  ep = &ex2->args[0];
                if (ex2->kind == EK_BICALL &&
                  !strcmp(ex2->val.s, setexpandname) &&
                  checkconst(ex2->args[1], 0) &&
                  (mp = istempvar(ex2->args[0])) != NULL) {
                  if (ex2 == ex->args[3-i]) {
                      ex = grabarg(ex, i);
                  } else {
                      freeexpr(ex2);
                      *ep = ex->args[i];
                      ex = ex->args[3-i];
                  }
                }
            } else if (!strcmp(cp, setdiffname) && *setremname &&
                     (ex3 = singlevar(ex->args[0])) != NULL &&
                     exprsame(ex->args[0], ex->args[1], 0) &&
                     !exproccurs(ex3, ex->args[2])) {
                ep = &ex->args[2];
                while ((ex2 = *ep)->kind == EK_BICALL &&
                     !strcmp(ex2->val.s, setaddname))
                  ep = &ex2->args[0];
                if (ex2->kind == EK_BICALL &&
                  !strcmp(ex2->val.s, setexpandname) &&
                  checkconst(ex2->args[1], 0) &&
                  (mp = istempvar(ex2->args[0])) != NULL) {
                  if (ex2 == ex->args[2]) {
                      ex = grabarg(ex, 1);
                  } else {
                      ex2 = ex->args[2];
                      while (ex2->kind == EK_BICALL &&
                           !strcmp(ex2->val.s, setaddname)) {
                        strchange(&ex2->val.s, setremname);
                        ex2 = ex2->args[0];
                      }
                      freeexpr(ex2);
                      *ep = ex->args[1];
                      ex = ex->args[2];
                  }
                }
#endif
                } else if (!strcmp(cp, setexpandname) && env == ENV_STMT &&
                           checkconst(ex->args[1], 0)) {
                    ex = makeexpr_assign(makeexpr_hat(ex->args[0], 0),
                                         ex->args[1]);
                } else if (!strcmp(cp, getbitsname)) {
                type = ex->args[0]->val.type;
                if (type->kind == TK_POINTER)
                  type = type->basetype;
                    sbuf[0] = (type->issigned) ? 'S' : 'U';
                    sbuf[1] = (type->kind == TK_ARRAY) ? 'B' : 'S';
                    sbuf[2] = 0;
                    if (sbuf[1] == 'S' &&
                        type->smax->val.type == tp_boolean) {
                        ex = makeexpr_rel(EK_NE,
                                          makeexpr_bin(EK_BAND, tp_integer,
                                                       ex->args[0],
                                                       makeexpr_bin(EK_LSH, tp_integer,
                                                                    makeexpr_longcast(makeexpr_long(1),
                                                                                      type->basetype
                                                                                            == tp_unsigned),
                                                                    ex->args[1])),
                                          makeexpr_long(0));
                        ex = fixexpr(ex, env);
                    } else
                        strchange(&ex->val.s, format_s(cp, sbuf));
                } else if (!strcmp(cp, putbitsname)) {
                type = ex->args[0]->val.type;
                if (type->kind == TK_POINTER)
                  type = type->basetype;
                    sbuf[0] = (type->issigned) ? 'S' : 'U';
                    sbuf[1] = (type->kind == TK_ARRAY) ? 'B' : 'S';
                    sbuf[2] = 0;
                    if (sbuf[1] == 'S' &&
                        type->smax->val.type == tp_boolean) {
                        ex = makeexpr_assign(ex->args[0],
                                             makeexpr_bin(EK_BOR, tp_integer,
                                                          copyexpr(ex->args[0]),
                                                          makeexpr_bin(EK_LSH, tp_integer,
                                                                       makeexpr_longcast(ex->args[2],
                                                                                         type->basetype
                                                                                               == tp_unsigned),
                                                                       ex->args[1])));
                    } else
                        strchange(&ex->val.s, format_s(cp, sbuf));
                } else if (!strcmp(cp, storebitsname)) {
                type = ex->args[0]->val.type;
                if (type->kind == TK_POINTER)
                  type = type->basetype;
                    sbuf[0] = (type->issigned) ? 'S' : 'U';
                    sbuf[1] = (type->kind == TK_ARRAY) ? 'B' : 'S';
                    sbuf[2] = 0;
                    strchange(&ex->val.s, format_s(cp, sbuf));
                } else if (!strcmp(cp, clrbitsname)) {
                type = ex->args[0]->val.type;
                if (type->kind == TK_POINTER)
                  type = type->basetype;
                    sbuf[0] = (type->kind == TK_ARRAY) ? 'B' : 'S';
                    sbuf[1] = 0;
                    if (sbuf[0] == 'S' &&
                        type->smax->val.type == tp_boolean) {
                        ex = makeexpr_assign(ex->args[0],
                                             makeexpr_bin(EK_BAND, tp_integer,
                                                   copyexpr(ex->args[0]),
                                                   makeexpr_un(EK_BNOT, tp_integer,
                                                          makeexpr_bin(EK_LSH, tp_integer,
                                                                       makeexpr_longcast(makeexpr_long(1),
                                                                                         type->basetype
                                                                                               == tp_unsigned),
                                                                       ex->args[1]))));
                    } else
                        strchange(&ex->val.s, format_s(cp, sbuf));
                } else if (!strcmp(cp, "fopen")) {
                if (which_lang == LANG_HP &&
                  ex->args[0]->kind == EK_CONST &&
                  ex->args[0]->val.type->kind == TK_STRING &&
                  ex->args[0]->val.i >= 1 &&
                  ex->args[0]->val.i <= 2 &&
                  isdigit(ex->args[0]->val.s[0]) &&
                  (ex->args[0]->val.i == 1 ||
                   isdigit(ex->args[0]->val.s[1]))) {
                  strchange(&ex->val.s, "fdopen");
                  ex->args[0] = makeexpr_long(atoi(ex->args[0]->val.s));
                }
            }
            }
            break;

        case EK_NOT:
            ex = makeexpr_not(fixexpr(grabarg(ex, 0), ENV_BOOL));
            break;

        case EK_AND:
        case EK_OR:
            for (i = 0; i < ex->nargs; ) {
                ex->args[i] = fixexpr(ex->args[i], ENV_BOOL);
            j = proveexprprop(ex->args[i], fixexpr_stmt, PROP_ZERO);
            if (j == (ex->kind == EK_OR) && ex->nargs > 1)
                delfreearg(&ex, i);
            else if (j == (ex->kind == EK_AND))
                return grabarg(ex, i);
            else
                i++;
          }
          if (ex->nargs == 1)
            ex = grabarg(ex, 0);
            break;

        case EK_EQ:
        case EK_NE:
            ex->args[0] = fixexpr(ex->args[0], ENV_EXPR);
            ex->args[1] = fixexpr(ex->args[1], ENV_EXPR);
            if (checkconst(ex->args[1], 0) && env == ENV_BOOL &&
                ord_type(ex->args[1]->val.type)->kind != TK_ENUM &&
                (implicitzero > 0 ||
                 (implicitzero < 0 && ex->args[0]->kind == EK_BICALL &&
                                      boolean_bicall(ex->args[0]->val.s)))) {
                if (ex->kind == EK_EQ)
                    ex = makeexpr_not(grabarg(ex, 0));
                else {
                    ex = grabarg(ex, 0);
                    ex->val.type = tp_boolean;
                }
            break;
            }
          if (checkconst(ex->args[1], 0)) {
            i = proveexprprop(ex->args[0], fixexpr_stmt, PROP_ZERO);
            if (i >= 0) {
                ex = makeexpr_val(make_ord(tp_boolean,
                                     (ex->kind == EK_EQ) ? i : !i));
                break;
            }
          }
          ex = makeexpr_rel(ex->kind, ex->args[0], ex->args[1]);
            break;

        case EK_COND:
            ex->args[0] = fixexpr(ex->args[0], ENV_BOOL);
#if 0
            val = eval_expr(ex->args[0]);
#else
          val = ex->args[0]->val;
          if (ex->args[0]->kind != EK_CONST)
            val.type = NULL;
#endif
            if (val.type == tp_boolean) {
                ex = grabarg(ex, (val.i) ? 1 : 2);
                ex = fixexpr(ex, env);
            } else {
                ex->args[1] = fixexpr(ex->args[1], env);
                ex->args[2] = fixexpr(ex->args[2], env);
            }
            break;

        case EK_COMMA:
            for (i = 0; i < ex->nargs; ) {
            j = (i < ex->nargs-1);
                ex->args[i] = fixexpr(ex->args[i], j ? ENV_STMT : env);
                if (nosideeffects(ex->args[i], 1) && j) {
                    delfreearg(&ex, i);
                } else if (ex->args[i]->kind == EK_COMMA) {
                ex2 = ex->args[i];
                ex->args[i++] = ex2->args[0];
                for (j = 1; j < ex2->nargs; j++)
                  insertarg(&ex, i++, ex2->args[j]);
                FREE(ex2);
            } else
                    i++;
            }
            if (ex->nargs == 1)
                ex = grabarg(ex, 0);
            break;

        case EK_CHECKNIL:
            ex->args[0] = fixexpr(ex->args[0], ENV_EXPR);
            if (ex->nargs == 2) {
                ex->args[1] = fixexpr(ex->args[1], ENV_EXPR);
                ex2 = makeexpr_assign(copyexpr(ex->args[1]), ex->args[0]);
                ex3 = ex->args[1];
            } else {
                ex2 = copyexpr(ex->args[0]);
                ex3 = ex->args[0];
            }
            type = ex->args[0]->val.type;
            type2 = ex->val.type;
            ex = makeexpr_cond(makeexpr_rel(EK_NE, ex2, makeexpr_nil()),
                               ex3,
                               makeexpr_cast(makeexpr_bicall_0(name_NILCHECK,
                                                               tp_int),
                                             type));
            ex->val.type = type2;
            ex = fixexpr(ex, env);
            break;

        case EK_CAST:
        case EK_ACTCAST:
            if (env == ENV_STMT) {
                ex = fixexpr(grabarg(ex, 0), ENV_STMT);
            } else {
                ex->args[0] = fixexpr(ex->args[0], ENV_EXPR);
            }
            break;

      case EK_ASSIGN:
          ex->args[0] = fixexpr(ex->args[0], ENV_LVALUE);
          ex->args[1] = fixexpr(ex->args[1], ENV_EXPR);
          break;

      case EK_POSTINC:
      case EK_POSTDEC:
          ex->args[0] = fixexpr(ex->args[0], ENV_LVALUE);
          break;

        default:
            for (i = 0; i < ex->nargs; i++)
                ex->args[i] = fixexpr(ex->args[i], ENV_EXPR);
            break;
    }
    if (debug>4) {fprintf(outf, "fixexpr returns "); dumpexpr(ex); fprintf(outf, "\n");}
    ex = flow_fixexpr(ex, fixexpr_stmt, env);
    return fix_expression(ex, env);
}








/* Output an expression */


#define bitOp(k)  ((k)==EK_BAND || (k)==EK_BOR || (k)==EK_BXOR)

#define shfOp(k)  ((k)==EK_LSH || (k)==EK_RSH)

#define logOp(k)  ((k)==EK_AND || (k)==EK_OR)

#define relOp(k)  ((k)==EK_EQ || (k)==EK_LT || (k)==EK_GT ||    \
               (k)==EK_NE || (k)==EK_GE || (k)==EK_LE)

#define mathOp(k) ((k)==EK_PLUS || (k)==EK_TIMES || (k)==EK_NEG ||   \
               (k)==EK_DIV || (k)==EK_DIVIDE || (k)==EK_MOD)

#define divOp(k)  ((k)==EK_DIV || (k)==EK_DIVIDE)


Static int incompat(ex, num, prec)
Expr *ex;
int num, prec;
{
    Expr *subex = ex->args[num];

    if (extraparens == 0)
      return prec;
    if (ex->kind == subex->kind) {
      if (logOp(ex->kind) || bitOp(ex->kind) ||
          (divOp(ex->kind) && num == 0))
          return -99;   /* not even invisible parens */
      else if (extraparens != 2)
          return prec;
    }
    if (extraparens == 2)
      return 15;
    if (divOp(ex->kind) && num == 0 &&
      (subex->kind == EK_TIMES || divOp(subex->kind)))
      return -99;
    if (bitOp(ex->kind) || shfOp(ex->kind))
      return 15;
    if (relOp(ex->kind) && relOp(subex->kind))
      return 15;
    if ((relOp(ex->kind) || logOp(ex->kind)) && bitOp(subex->kind))
      return 15;
    if (ex->kind == EK_COMMA)
      return 15;
    if (ex->kind == EK_ASSIGN && relOp(subex->kind))
      return 15;
    if (extraparens != 1)
      return prec;
    if (ex->kind == EK_ASSIGN)
      return prec;
    if (relOp(ex->kind) && mathOp(subex->kind))
      return prec;
    return 15;
}




#define EXTRASPACE() if (spaceexprs == 1) output(" ")
#define NICESPACE()  if (spaceexprs != 0) output(" ")

#define setprec(p) \
    if ((subprec=(p)) <= prec) { \
        parens = 1; output("("); \
    }

#define setprec2(p) \
    if ((subprec=(p)) <= prec) { \
        parens = 1; output("("); \
    } else if (prec != -99) { \
        parens = 2; output((breakparens == 1) ? "\010" : "\003"); \
    }

#define setprec3(p) \
    if ((subprec=(p)) <= prec) { \
         parens = 1; output("("); \
    } else if (prec != -99) { \
         parens = 2; output((prec > 2 && breakparens != 0) ? "\010" \
                                                     : "\003"); \
    }


Static void outop3(breakbefore, name)
int breakbefore;
char *name;
{
    if (breakbefore & BRK_LEFT) {
      output("\002");
      if (breakbefore & BRK_RPREF)
          output("\013");
    }
    output(name);
    if (breakbefore & BRK_HANG)
      output("\016");
    if (breakbefore & BRK_RIGHT) {
      output("\002");
      if (breakbefore & BRK_LPREF)
          output("\013");
    }
}

#define outop(name) do { \
    NICESPACE(); outop3(breakflag, name); NICESPACE(); \
} while (0)

#define outop2(name) do { \
    EXTRASPACE(); outop3(breakflag, name); EXTRASPACE(); \
} while (0)

#define checkbreak(code) do { \
    breakflag=(code); \
    if ((prec != -99) && (breakflag & BRK_ALLNONE)) output("\007"); \
} while (0)


Static void out_ctx(ctx, address)
Meaning *ctx;
int address;
{
    Meaning *ctx2;
    int breakflag = breakbeforedot;

    if (ctx->kind == MK_FUNCTION && ctx->varstructflag) {
        if (curctx != ctx) {
          if (address && curctx->ctx && curctx->ctx != ctx) {
            output("\003");
            if (breakflag & BRK_ALLNONE)
                output("\007");
          }
            output(format_s(name_LINK, curctx->ctx->name));
            ctx2 = curctx->ctx;
            while (ctx2 && ctx2 != ctx) {
                outop2("->");
                output(format_s(name_LINK, ctx2->ctx->name));
                ctx2 = ctx2->ctx;
            }
            if (ctx2 != ctx)
                intwarning("out_ctx",
                           format_s("variable from %s not present in context path [307]",
                                     ctx->name));
          if (address && curctx->ctx && curctx->ctx != ctx)
            output("\004");
            if (!address)
                outop2("->");
        } else {
            if (address) {
                output("&");
            EXTRASPACE();
          }
            output(format_s(name_VARS, curctx->name));
            if (!address) {
                outop2(".");
          }
        }
    } else {
        if (address)
            output("NULL");
    }
}



void out_var(mp, prec)
Meaning *mp;
int prec;
{
    switch (mp->kind) {

        case MK_CONST:
            output(mp->name);
            return;

        case MK_VAR:
        case MK_VARREF:
        case MK_VARMAC:
        case MK_PARAM:
        case MK_VARPARAM:
            if (mp->varstructflag) {
            output("\003");
                out_ctx(mp->ctx, 0);
            output(mp->name);
            output("\004");
          } else
            output(mp->name);
            return;

      default:
          if (mp->name)
            output(mp->name);
          else
            intwarning("out_var", "mp->sym == NULL [308]");
          return;
    }
}



Static int scanfield(variants, unions, lev, mp, field)
Meaning **variants, *mp, *field;
short *unions;
int lev;
{
    int i, num, breakflag;
    Value v;

    unions[lev] = (mp && mp->kind == MK_VARIANT);
    while (mp && mp->kind != MK_VARIANT) {
        if (mp == field) {
            for (i = 0; i < lev; i++) {
            v = variants[i]->val;    /* sidestep a Sun 386i compiler bug */
                num = ord_value(v);
            breakflag = breakbeforedot;
                if (!unions[i] && !anonymousunions) {
                    output(format_s(name_UNION, ""));
                outop2(".");
                }
                if (variants[i]->ctx->cnext ||
                    variants[i]->ctx->kind != MK_FIELD) {
                    output(format_s(name_VARIANT, variantfieldname(num)));
                outop2(".");
                }
            }
            output(mp->name);
            return 1;
        }
        mp = mp->cnext;
    }
    while (mp && mp->kind == MK_VARIANT) {
        variants[lev] = mp;
        if (scanfield(variants, unions, lev+1, mp->ctx, field))
            return 1;
        mp = mp->cnext;
    }
    return 0;
}


void out_field(mp)
Meaning *mp;
{
    Meaning *variants[50];
    short unions[51];

    if (!scanfield(variants, unions, 0, mp->rectype->fbase, mp))
        intwarning("out_field", "field name not in tree [309]");
    else if (mp->warnifused) {
        if (mp->rectype->meaning)
            note(format_ss("Reference to field %s of record %s [282]", 
                           mp->name, mp->rectype->meaning->name));
        else
            note(format_s("Reference to field %s [282]", mp->name));
    }
}




Static void wrexpr(ex, prec)
Expr *ex;
int prec;
{
    short parens = 0;
    int subprec, i, j, minusflag, breakflag = 0;
    int saveindent;
    Expr *ex2, *ex3;
    char *cp;
    Meaning *mp;
    Symbol *sp;

    if (debug>2) { fprintf(outf,"wrexpr{"); dumpexpr(ex); fprintf(outf,", %d}\n", prec); }
    switch (ex->kind) {

        case EK_VAR:
            mp = (Meaning *)ex->val.i;
            if (mp->warnifused)
                note(format_s("Reference to %s [283]", mp->name));
            out_var(mp, prec);
            break;

        case EK_NAME:
            output(ex->val.s);
            break;

        case EK_MACARG:
            output("<meef>");
            intwarning("wrexpr", "Stray EK_MACARG encountered [310]");
            break;

        case EK_CTX:
            out_ctx((Meaning *)ex->val.i, 1);
            break;

        case EK_CONST:
            if (ex->nargs > 0)
                cp = value_name(ex->val, ex->args[0]->val.s, 0);
            else
                cp = value_name(ex->val, NULL, 0);
            if (*cp == '-')
                setprec(14);
            output(cp);
            break;

        case EK_LONGCONST:
            if (ex->nargs > 0)
                cp = value_name(ex->val, ex->args[0]->val.s, 1);
            else
                cp = value_name(ex->val, NULL, 1);
            if (*cp == '-')
                setprec(14);
            output(cp);
            break;

        case EK_STRUCTCONST:
            ex3 = NULL;
            for (i = 0; i < ex->nargs; i++) {
                ex2 = ex->args[i];
                if (ex2->kind == EK_STRUCTOF) {
                    j = ex2->val.i;
                    ex2 = ex2->args[0];
                } else
                    j = 1;
                if (ex2->kind == EK_VAR) {
                    mp = (Meaning *)ex2->val.i;
                    if (mp->kind == MK_CONST &&
                  mp->val.type &&
                        (mp->val.type->kind == TK_RECORD ||
                         mp->val.type->kind == TK_ARRAY)) {
                        if (foldconsts != 1)
                            note(format_s("Expanding constant %s into another constant [284]",
                                          mp->name));
                        ex2 = (Expr *)mp->val.i;
                    }
                }
                while (--j >= 0) {
                    if (ex3) {
                        if (ex3->kind == EK_STRUCTCONST ||
                            ex2->kind == EK_STRUCTCONST)
                            output(",\n");
                        else if (spacecommas)
                            output(",\001 ");
                  else
                      output(",\001");
                    }
                    if (ex2->kind == EK_STRUCTCONST) {
                        output("{ \005");
                  saveindent = outindent;
                  moreindent(extrainitindent);
                        out_expr(ex2);
                        outindent = saveindent;
                        output(" }");
                    } else
                        out_expr(ex2);
                    ex3 = ex2;
                }
            }
            break;

        case EK_FUNCTION:
            mp = (Meaning *)ex->val.i;
          sp = findsymbol_opt(mp->name);
          if ((sp && (sp->flags & WARNLIBR)) || mp->warnifused)
                note(format_s("Called procedure %s [285]", mp->name));
            output(mp->name);
          if (spacefuncs)
            output(" ");
            output("(\002");
          j = sp ? (sp->flags & FUNCBREAK) : 0;
          if (j == FALLBREAK)
            output("\007");
            for (i = 0; i < ex->nargs; i++) {
            if ((j == FSPCARG1 && i == 1) ||
                (j == FSPCARG2 && i == 2) ||
                (j == FSPCARG3 && i == 3))
                if (spacecommas)
                  output(",\011 ");
                else
                  output(",\011");
                else if (i > 0)
                if (spacecommas)
                  output(",\002 ");
                else
                  output(",\002");
                out_expr(ex->args[i]);
            }
            if (mp->ctx->kind == MK_FUNCTION && mp->ctx->varstructflag) {
                if (i > 0)
                if (spacecommas)
                  output(",\002 ");
                else
                  output(",\002");
            if (curctx->ctx->kind == MK_FUNCTION &&
                !curctx->ctx->varstructflag && mp->ctx != curctx)
                note(format_ss("Discovered too late that %s needs a %s [340]",
                           curctx->name,
                           format_s(name_LINK, curctx->ctx->name)));
                out_ctx(mp->ctx, 1);
            }
            output(")");
            break;

        case EK_BICALL:
            cp = ex->val.s;
            while (*cp == '*')
                cp++;
          sp = findsymbol_opt(cp);
          if (sp && (sp->flags & WARNLIBR))
                note(format_s("Called library procedure %s [286]", cp));
            output(cp);
          if (spacefuncs)
            output(" ");
            output("(\002");
          j = sp ? (sp->flags & FUNCBREAK) : 0;
          if (j == FALLBREAK)
            output("\007");
            for (i = 0; i < ex->nargs; i++) {
            if ((j == FSPCARG1 && i == 1) ||
                (j == FSPCARG2 && i == 2) ||
                (j == FSPCARG3 && i == 3))
                if (spacecommas)
                  output(",\011 ");
                else
                  output(",\011");
                else if (i > 0)
                if (spacecommas)
                  output(",\002 ");
                else
                  output(",\002");
                out_expr(ex->args[i]);
            }
            output(")");
            break;

        case EK_SPCALL:
            setprec(16);
            if (starfunctions && !ex->val.i) {
                output("(\002*");
                wrexpr(ex->args[0], 13);
                output(")");
            } else
                wrexpr(ex->args[0], subprec-1);
          if (spacefuncs)
            output(" ");
            output("(\002");
            for (i = 1; i < ex->nargs; i++) {
                if (i > 1)
                if (spacecommas)
                  output(",\002 ");
                else
                  output(",\002");
                out_expr(ex->args[i]);
            }
            output(")");
            break;

      case EK_NEW:
          setprec(16);
          output("new ");
          if (ex->nargs >= 2 &&
            (ex->args[1]->kind != EK_NAME || *ex->args[1]->val.s))
            new_array_size = ex->args[1];
          out_expr(ex->args[0]);
          new_array_size = NULL;
#if 0
          if (ex->nargs >= 2 &&
            (ex->args[1]->kind != EK_NAME || *ex->args[1]->val.s)) {
            output("[");
            out_expr(ex->args[1]);
            output("]");
          }
#endif
          break;

      case EK_DELETE:
          setprec(16);
          output("delete ");
          if (ex->nargs >= 2) {
            output("[");
            out_expr(ex->args[1]);
            output("] ");
          }
          out_expr(ex->args[0]);
          break;

        case EK_INDEX:
            setprec(16);
            wrexpr(ex->args[0], subprec-1);
          if (lookback(1) == ']')
            output("\001");
            output("[");
          if (ex->args[1]->kind == EK_PLUS && ex->args[1]->nargs == 2 &&
            ex->args[1]->args[0]->kind == EK_VAR &&
            (ex->args[1]->args[1]->kind == EK_CONST ||
             ex->args[1]->args[1]->kind == EK_LONGCONST) &&
            ex->args[1]->args[1]->val.type->kind == TK_INTEGER) {
            out_expr(ex->args[1]->args[0]);
            if (ex->args[1]->args[1]->val.i >= 0)
                output("+");
            output(format_d("%d", ex->args[1]->args[1]->val.i));
          } else
            out_expr(ex->args[1]);
            output("]");
            break;

        case EK_DOT:
            setprec2(16);
          checkbreak(breakbeforedot);
            if (ex->args[0]->kind == EK_HAT) {
                wrexpr(ex->args[0]->args[0], subprec-1);
                outop2("->");
            } else if (ex->args[0]->kind == EK_CTX) {
                out_ctx((Meaning *)ex->args[0]->val.i, 0);
            } else {
                wrexpr(ex->args[0], subprec-1);
                outop2(".");
            }
            if (ex->val.i)
                out_field((Meaning *)ex->val.i);
            else
                output(ex->val.s);
            break;

        case EK_POSTINC:
          if (prec == 0 && !postincrement) {
            setprec(14);
            output("++");
            EXTRASPACE();
            wrexpr(ex->args[0], subprec);
          } else {
            setprec(15);
            wrexpr(ex->args[0], subprec);
            EXTRASPACE();
            output("++");
          }
            break;

        case EK_POSTDEC:
          if (prec == 0 && !postincrement) {
            setprec(14);
            output("--");
            EXTRASPACE();
            wrexpr(ex->args[0], subprec);
          } else {
            setprec(15);
            wrexpr(ex->args[0], subprec);
            EXTRASPACE();
            output("--");
          }
            break;

        case EK_HAT:
            setprec(14);
          if (lookback_prn(1) == '/')
            output(" ");
            output("*");
            EXTRASPACE();
            wrexpr(ex->args[0], subprec-1);
            break;

        case EK_ADDR:
            setprec(14);
          if (lookback_prn(1) == '&')
            output(" ");
            output("&");
            EXTRASPACE();
            wrexpr(ex->args[0], subprec-1);
            break;

        case EK_NEG:
            setprec(14);
            output("-");
            EXTRASPACE();
            if (ex->args[0]->kind == EK_TIMES)
                wrexpr(ex->args[0], 12);
            else
                wrexpr(ex->args[0], subprec-1);
            break;

        case EK_NOT:
            setprec(14);
            output("!");
            EXTRASPACE();
            wrexpr(ex->args[0], subprec-1);
            break;

        case EK_BNOT:
            setprec(14);
            output("~");
            EXTRASPACE();
            wrexpr(ex->args[0], subprec-1);
            break;

        case EK_CAST:
        case EK_ACTCAST:
            if (similartypes(ex->val.type, ex->args[0]->val.type)) {
                wrexpr(ex->args[0], prec);
            } else if (ord_type(ex->args[0]->val.type)->kind == TK_ENUM &&
                       ex->val.type == tp_int && !useenum) {
                wrexpr(ex->args[0], prec);
            } else if (callcasts &&
                   onewordtype(ex->val.type, ODECL_ARRAYPTRS)) {
            out_type(ex->val.type, 0);
            if (spacefuncs)
                output(" ");
            output("(\002");
            out_expr(ex->args[0]);
            output(")");
          } else {
                setprec2(14);
                output("(");
                out_type(ex->val.type, ODECL_ARRAYPTRS);
                output(")\002");
                EXTRASPACE();
                if (extraparens != 0)
                    wrexpr(ex->args[0], 15);
                else
                    wrexpr(ex->args[0], subprec-1);
            }
            break;

        case EK_LITCAST:
          if (callcasts &&
            ((ex->args[0]->kind == EK_TYPENAME &&
              onewordtype(ex->args[0]->val.type, 0)) ||
             (ex->args[0]->kind == EK_NAME &&
              onewordstring(ex->args[0]->val.s)))) {
            out_expr(ex->args[0]);
            output("(\002");
            out_expr(ex->args[1]);
            output(")");
          } else {
            setprec2(14);
            output("(");
            out_expr(ex->args[0]);
            output(")\002");
            EXTRASPACE();
            if (extraparens != 0)
                wrexpr(ex->args[1], 15);
            else
                wrexpr(ex->args[1], subprec-1);
          }
            break;

        case EK_SIZEOF:
            setprec(14);
            output("sizeof");
          if (spacefuncs)
            output(" ");
          output("(");
          out_expr(ex->args[0]);
            output(")");
            break;

      case EK_TYPENAME:
          out_type(ex->val.type, 0);
          break;

        case EK_TIMES:
          setprec2(13);
          checkbreak(breakbeforearith);
            ex2 = copyexpr(ex);
            if (expr_looks_neg(ex2->args[ex2->nargs-1])) {
                ex2->args[0] = makeexpr_neg(ex2->args[0]);
                ex2->args[ex2->nargs-1] = makeexpr_neg(ex2->args[ex2->nargs-1]);
            }
            wrexpr(ex2->args[0], incompat(ex2, 0, subprec-1));
            for (i = 1; i < ex2->nargs; i++) {
                outop("*");
                wrexpr(ex2->args[i], incompat(ex2, i, subprec));
            }
            freeexpr(ex2);
            break;

        case EK_DIV:
        case EK_DIVIDE:
            setprec2(13);
          checkbreak(breakbeforearith);
          wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
            outop("/");
            wrexpr(ex->args[1], incompat(ex, 1, subprec));
            break;

        case EK_MOD:
            setprec2(13);
          checkbreak(breakbeforearith);
            wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
            outop("%");
            wrexpr(ex->args[1], incompat(ex, 1, subprec));
            break;

        case EK_PLUS:
            setprec2(12);
          checkbreak(breakbeforearith);
            ex2 = copyexpr(ex);
            minusflag = 0;
            if (expr_looks_neg(ex2->args[0])) {
                j = 1;
                while (j < ex2->nargs && expr_looks_neg(ex2->args[j])) j++;
                if (j < ex2->nargs)
                    swapexprs(ex2->args[0], ex2->args[j]);
            } else if (ex2->val.i && ex2->nargs == 2) {   /* this was originally "a-b" */
                if (isliteralconst(ex2->args[1], NULL) != 2) {
                    if (expr_neg_cost(ex2->args[1]) <= 0) {
                        minusflag = 1;
                    } else if (expr_neg_cost(ex2->args[0]) <= 0) {
                        swapexprs(ex2->args[0], ex2->args[1]);
                        if (isliteralconst(ex2->args[0], NULL) != 2)
                            minusflag = 1;
                    }
                }
            }
            wrexpr(ex2->args[0], incompat(ex, 0, subprec));
            for (i = 1; i < ex2->nargs; i++) {
                if (expr_looks_neg(ex2->args[i]) || minusflag) {
                    outop("-");
                    ex2->args[i] = makeexpr_neg(ex2->args[i]);
                } else
                    outop("+");
                wrexpr(ex2->args[i], incompat(ex, i, subprec));
            }
            freeexpr(ex2);
            break;

        case EK_LSH:
            setprec3(11);
          checkbreak(breakbeforearith);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop("<<");
            wrexpr(ex->args[1], incompat(ex, 1, subprec));
            break;

        case EK_RSH:
            setprec3(11);
          checkbreak(breakbeforearith);
          wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop(">>");
            wrexpr(ex->args[1], incompat(ex, 1, subprec));
            break;

        case EK_LT:
            setprec2(10);
          checkbreak(breakbeforerel);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop("<");
            wrexpr(ex->args[1], incompat(ex, 0, subprec));
            break;

        case EK_GT:
            setprec2(10);
          checkbreak(breakbeforerel);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop(">");
            wrexpr(ex->args[1], incompat(ex, 0, subprec));
            break;

        case EK_LE:
            setprec2(10);
          checkbreak(breakbeforerel);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop("<=");
            wrexpr(ex->args[1], incompat(ex, 0, subprec));
            break;

        case EK_GE:
            setprec2(10);
          checkbreak(breakbeforerel);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop(">=");
            wrexpr(ex->args[1], incompat(ex, 0, subprec));
            break;

        case EK_EQ:
            setprec2(9);
          checkbreak(breakbeforerel);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop("==");
            wrexpr(ex->args[1], incompat(ex, 0, subprec));
            break;

        case EK_NE:
            setprec2(9);
          checkbreak(breakbeforerel);
            wrexpr(ex->args[0], incompat(ex, 0, subprec));
            outop("!=");
            wrexpr(ex->args[1], incompat(ex, 0, subprec));
            break;

        case EK_BAND:
            setprec3(8);
          if (ex->val.type == tp_boolean)
            checkbreak(breakbeforelog);
          else
            checkbreak(breakbeforearith);
            wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
          outop("&");
            wrexpr(ex->args[1], incompat(ex, 1, subprec-1));
            break;

        case EK_BXOR:
            setprec3(7);
          checkbreak(breakbeforearith);
            wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
            outop("^");
            wrexpr(ex->args[1], incompat(ex, 1, subprec-1));
            break;

        case EK_BOR:
            setprec3(6);
          if (ex->val.type == tp_boolean)
            checkbreak(breakbeforelog);
          else
            checkbreak(breakbeforearith);
            wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
          outop("|");
            wrexpr(ex->args[1], incompat(ex, 1, subprec-1));
            break;

        case EK_AND:
            setprec3(5);
          checkbreak(breakbeforelog);
          wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
            outop("&&");
          wrexpr(ex->args[1], incompat(ex, 1, subprec-1));
            break;

        case EK_OR:
            setprec3(4);
          checkbreak(breakbeforelog);
          wrexpr(ex->args[0], incompat(ex, 0, subprec-1));
            outop("||");
          wrexpr(ex->args[1], incompat(ex, 1, subprec-1));
            break;

        case EK_COND:
            setprec3(3);
          i = 0;
          for (;;) {
            i++;
            if (extraparens != 0)
                wrexpr(ex->args[0], 15);
            else
                wrexpr(ex->args[0], subprec);
            NICESPACE();
            output("\002?");
            NICESPACE();
            out_expr(ex->args[1]);
            if (ex->args[2]->kind == EK_COND) {
                NICESPACE();
                output("\002:");
                NICESPACE();
                ex = ex->args[2];
            } else {
                NICESPACE();
                output((i == 1) ? "\017:" : "\002:");
                NICESPACE();
                wrexpr(ex->args[2], subprec-1);
                break;
            }
          }
            break;

        case EK_ASSIGN:
            if (ex->args[1]->kind == EK_PLUS &&
                exprsame(ex->args[1]->args[0], ex->args[0], 2) &&
                ex->args[1]->args[1]->kind == EK_CONST &&
                ex->args[1]->args[1]->val.type->kind == TK_INTEGER &&
                abs(ex->args[1]->args[1]->val.i) == 1) {
            if (prec == 0 && postincrement) {
                setprec(15);
                wrexpr(ex->args[0], subprec);
                EXTRASPACE();
                if (ex->args[1]->args[1]->val.i == 1)
                  output("++");
                else
                  output("--");
            } else {
                setprec(14);
                if (ex->args[1]->args[1]->val.i == 1)
                  output("++");
                else
                  output("--");
                EXTRASPACE();
                wrexpr(ex->args[0], subprec-1);
            }
            } else {
                setprec2(2);
            checkbreak(breakbeforeassign);
                wrexpr(ex->args[0], subprec);
                ex2 = copyexpr(ex->args[1]);
                j = -1;
                switch (ex2->kind) {

                    case EK_PLUS:
                    case EK_TIMES:
                    case EK_BAND:
                    case EK_BOR:
                    case EK_BXOR:
                        for (i = 0; i < ex2->nargs; i++) {
                            if (exprsame(ex->args[0], ex2->args[i], 2)) {
                                j = i;
                                break;
                            }
                            if (ex2->val.type->kind == TK_REAL)
                                break;   /* non-commutative */
                        }
                        break;

                    case EK_DIVIDE:
                    case EK_DIV:
                    case EK_MOD:
                    case EK_LSH:
                    case EK_RSH:
                        if (exprsame(ex->args[0], ex2->args[0], 2))
                            j = 0;
                        break;

                default:
                  break;
                }
                if (j >= 0) {
                    if (ex2->nargs == 2)
                        ex2 = grabarg(ex2, 1-j);
                    else
                        delfreearg(&ex2, j);
                    switch (ex->args[1]->kind) {

                        case EK_PLUS:
                            if (expr_looks_neg(ex2)) {
                                outop("-=");
                                ex2 = makeexpr_neg(ex2);
                            } else
                                outop("+=");
                            break;

                        case EK_TIMES:
                            outop("*=");
                            break;

                        case EK_DIVIDE:
                        case EK_DIV:
                            outop("/=");
                            break;

                        case EK_MOD:
                            outop("%=");
                            break;

                        case EK_LSH:
                            outop("<<=");
                            break;

                        case EK_RSH:
                            outop(">>=");
                            break;

                        case EK_BAND:
                            outop("&=");
                            break;

                        case EK_BOR:
                            outop("|=");
                            break;

                        case EK_BXOR:
                            outop("^=");
                            break;

                  default:
                      break;
                    }
                } else {
                output(" ");
                outop3(breakbeforeassign, "=");
                output(" ");
                }
                if (extraparens != 0 &&
                    (ex2->kind == EK_EQ || ex2->kind == EK_NE ||
                     ex2->kind == EK_GT || ex2->kind == EK_LT ||
                     ex2->kind == EK_GE || ex2->kind == EK_LE ||
                     ex2->kind == EK_AND || ex2->kind == EK_OR))
                    wrexpr(ex2, 16);
                else
                    wrexpr(ex2, subprec-1);
                freeexpr(ex2);
            }
            break;

        case EK_COMMA:
            setprec3(1);
            for (i = 0; i < ex->nargs-1; i++) {
                wrexpr(ex->args[i], subprec);
                output(",\002");
            if (spacecommas)
                NICESPACE();
            }
            wrexpr(ex->args[ex->nargs-1], subprec);
            break;

        default:
            intwarning("wrexpr", "bad ex->kind [311]");
    }
    switch (parens) {
      case 1:
        output(")");
      break;
      case 2:
      output("\004");
      break;
    }
}



/* will parenthesize assignments and "," operators */

void out_expr(ex)
Expr *ex;
{
    wrexpr(ex, 2);
}



/* will not parenthesize anything at top level */

void out_expr_top(ex)
Expr *ex;
{
    wrexpr(ex, 0);
}



/* will parenthesize unless only writing a factor */

void out_expr_factor(ex)
Expr *ex;
{
    wrexpr(ex, 15);
}



/* will parenthesize always */

void out_expr_parens(ex)
Expr *ex;
{
    output("(");
    wrexpr(ex, 1);
    output(")");
}



/* evaluate expression for side effects only */
/* no top-level parentheses */

void out_expr_stmt(ex)
Expr *ex;
{
    wrexpr(ex, 0);
}



/* evaluate expression for boolean (zero/non-zero) result only */
/* parenthesizes like out_expr() */

void out_expr_bool(ex)
Expr *ex;
{
    wrexpr(ex, 2);
}




/* End. */




Generated by  Doxygen 1.6.0   Back to index