blob: ed8c7c50db3aea2fb4554919fd8a4a034fa3714e [file] [log] [blame]
/* "p2c", a Pascal to C translator.
Copyright (C) 1989, 1990, 1991 Free Software Foundation.
Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.
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;
}
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;
}
mp = curtoksym->fbase;
while (mp && mp->rectype != ex->val.type)
mp = mp->snext;
if (mp)
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);
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 (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;
}
}
Static 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 (mp->kind == MK_FIELD) {
ex = makeexpr_dot(copyexpr(withexprs[curtokint]), mp);
} 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) {
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 |= 1<<j;
} else
val.i |= 1 << 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() == ':' || !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 (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(copyexpr(tp2->indextype->smin),
integer16 == 0);
ex->args[fakenum++] =
makeexpr_arglong(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_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_IDENT:
mp = curtokmeaning;
switch ((mp) ? mp->kind : MK_VAR) {
case MK_TYPE:
gettok();
type = mp->type;
switch (curtok) {
case TOK_LPAR: /* Turbo type cast */
gettok();
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);
}
default:
wexpected("an expression");
return makeexpr_name(mp->name, mp->type);
}
case MK_SPECIAL:
if (mp->handler && mp->isfunction &&
(curtok == TOK_LPAR || !target ||
(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 ex;
} 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++;
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:
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;
}
}
}
Static 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:
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_expr(target)
Type *target;
{
Expr *ex = p_sexpr(target);
Expr *ex2, *ex3, *ex4;
Type *type;
Meaning *tvar;
long mask, smin, smax;
int i, j;
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(1<<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 & (1<<i++)) {
if (i+1 < setbits && (mask & (2<<i))) {
for (j = i; j < setbits && (mask & (1<<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;
}
}
/* 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()
{
switch (curtok) {
case TOK_CONST:
return 1;
case TOK_IDENT:
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_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()) {
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()) {
ex = makeexpr_sizeof(pc_parentype(cp), 1);
} else {
ex = makeexpr_sizeof(pc_expr(), 1);
skipcloseparen();
}
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),
makeexpr_bicall_1(name_ESCIO, tp_int, ex->args[1]));
} 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);
if (checkconst(ex->args[i], (ex->kind == EK_OR) ? 0 : 1) &&
ex->nargs > 1)
delfreearg(&ex, i);
else if (checkconst(ex->args[i], (ex->kind == EK_OR) ? 1 : 0))
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;
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;
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");}
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("\015");
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_FIELD) {
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]) {
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");
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) {
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_INDEX:
setprec(16);
wrexpr(ex->args[0], subprec-1);
if (lookback(1) == ']')
output("\001");
output("[");
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 {
setprec2(14);
output("(");
out_type(ex->val.type, 0);
output(")\002");
EXTRASPACE();
if (extraparens != 0)
wrexpr(ex->args[0], 15);
else
wrexpr(ex->args[0], subprec-1);
}
break;
case EK_LITCAST:
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, 1);
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. */