| /* "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. */ |
| |
| |
| |