home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
379a.lha
/
p2c1_13a
/
src
/
src.zoo
/
expr3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-11
|
34KB
|
1,175 lines
/* "p2c", a Pascal to C translator.
Copyright (C) 1989 David Gillespie.
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_EXPR3_C
#include "trans.h"
#define ISCONST(kind) ((kind)==EK_CONST || (kind)==EK_LONGCONST)
#define MOVCONST(ex) (ISCONST((ex)->kind) && (ex)->val.type->kind != TK_STRING)
#define COMMUTATIVE (kind != EK_COMMA && type->kind != TK_REAL)
int ischartype(ex)
Expr *ex;
{
if (ord_type(ex->val.type)->kind == TK_CHAR)
return 1;
if (true_type(ex)->kind == TK_CHAR)
return 1;
if (ISCONST(ex->kind) && ex->nargs > 0 &&
ex->args[0]->kind == EK_NAME &&
ex->args[0]->val.s[0] == '\'')
return 1;
return 0;
}
Expr *commute(a, b, kind)
Expr *a, *b;
enum exprkind kind;
{
int i, di;
Type *type;
if (debug>2) { fprintf(outf,"commute("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
#if 1
type = promote_type_bin(a->val.type, b->val.type);
#else
type = a->val.type;
if (b->val.type->kind == TK_REAL)
type = b->val.type;
#endif
if (MOVCONST(a) && !MOVCONST(b) && COMMUTATIVE)
swapexprs(a, b); /* put constant last */
if (a->kind == kind) {
di = (MOVCONST(a->args[a->nargs-1]) && COMMUTATIVE) ? -1 : 0;
if (b->kind == kind) {
for (i = 0; i < b->nargs; i++)
insertarg(&a, a->nargs + di, b->args[i]);
FREE(b);
} else
insertarg(&a, a->nargs + di, b);
a->val.type = type;
} else if (b->kind == kind) {
if (MOVCONST(a) && COMMUTATIVE)
insertarg(&b, b->nargs, a);
else
insertarg(&b, 0, a);
a = b;
a->val.type = type;
} else {
a = makeexpr_bin(kind, type, a, b);
}
if (debug>2) { fprintf(outf,"commute returns "); dumpexpr(a); fprintf(outf,"\n"); }
return a;
}
Expr *makeexpr_plus(a, b)
Expr *a, *b;
{
int i, j, k;
Type *type;
if (debug>2) { fprintf(outf,"makeexpr_plus("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
if (!a)
return b;
if (!b)
return a;
if (a->kind == EK_NEG && a->args[0]->kind == EK_PLUS)
a = neg_inside_sum(grabarg(a, 0));
if (b->kind == EK_NEG && b->args[0]->kind == EK_PLUS)
b = neg_inside_sum(grabarg(b, 0));
a = commute(enum_to_int(a), enum_to_int(b), EK_PLUS);
type = NULL;
for (i = 0; i < a->nargs; i++) {
if (ord_type(a->args[i]->val.type)->kind == TK_CHAR ||
a->args[i]->val.type->kind == TK_POINTER ||
a->args[i]->val.type->kind == TK_STRING) { /* for string literals */
if (type == ord_type(a->args[i]->val.type))
type = tp_integer; /* 'z'-'a' and p1-p2 are integers */
else
type = ord_type(a->args[i]->val.type);
}
}
if (type)
a->val.type = type;
for (i = 0; i < a->nargs && !ISCONST(a->args[i]->kind); i++) ;
if (i < a->nargs-1) {
for (j = i+1; j < a->nargs; j++) {
if (ISCONST(a->args[j]->kind)) {
if ((ord_type(a->args[i]->val.type) == ord_type(a->args[j]->val.type) ||
ord_type(a->args[i]->val.type)->kind == TK_INTEGER ||
ord_type(a->args[j]->val.type)->kind == TK_INTEGER) &&
(!ischartype(a->args[i]) || !ischartype(a->args[j])) &&
(a->args[i]->val.type->kind != TK_REAL &&
a->args[i]->val.type->kind != TK_STRING &&
a->args[j]->val.type->kind != TK_REAL &&
a->args[j]->val.type->kind != TK_STRING)) {
a->args[i]->val.i += a->args[j]->val.i;
delfreearg(&a, j);
j--;
} else if (a->args[i]->val.type->kind == TK_STRING &&
ord_type(a->args[j]->val.type)->kind == TK_INTEGER &&
a->args[j]->val.i < 0 &&
a->args[j]->val.i >= -stringleaders) {
/* strictly speaking, the following is illegal pointer arithmetic */
a->args[i] = makeexpr_lstring(a->args[i]->val.s + a->args[j]->val.i,
a->args[i]->val.i - a->args[j]->val.i);
for (k = 0; k < - a->args[j]->val.i; k++)
a->args[i]->val.s[k] = '>';
delfreearg(&a, j);
j--;
}
}
}
}
if (checkconst(a->args[a->nargs-1], 0))
delfreearg(&a, a->nargs-1);
for (i = 0; i < a->nargs; i++) {
if (a->args[i]->kind == EK_NEG && nosideeffects(a->args[i], 1)) {
for (j = 0; j < a->nargs; j++) {
if (exprsame(a->args[j], a->args[i]->args[0], 1)) {
delfreearg(&a, i);
if (i < j) j--; else i--;
delfreearg(&a, j);
i--;
break;
}
}
}
}
if (a->nargs < 2) {
if (a->nargs < 1) {
type = a->val.type;
FREE(a);
a = gentle_cast(makeexpr_long(0), type);
a->val.type = type;
return a;
} else {
b = a->args[0];
FREE(a);
return b;
}
}
if (a->nargs == 2 && ISCONST(a->args[1]->kind) &&
a->args[1]->val.i <= -127 &&
true_type(a->args[0]) == tp_char && signedchars != 0) {
a->args[0] = force_unsigned(a->args[0]);
}
if (a->nargs > 2 &&
ISCONST(a->args[a->nargs-1]->kind) &&
ISCONST(a->args[a->nargs-2]->kind) &&
ischartype(a->args[a->nargs-1]) &&
ischartype(a->args[a->nargs-2])) {
i = a->args[a->nargs-1]->val.i;
j = a->args[a->nargs-2]->val.i;
if ((i == 'a' || i == 'A' || i == -'a' || i == -'A') &&
(j == 'a' || j == 'A' || j == -'a' || j == -'A')) {
if (abs(i+j) == 32) {
delfreearg(&a, a->nargs-1);
delsimpfreearg(&a, a->nargs-1);
a = makeexpr_bicall_1((i+j > 0) ? "_tolower" : "_toupper",
tp_char, a);
}
}
}
return a;
}
Expr *makeexpr_minus(a, b)
Expr *a, *b;
{
int okneg;
if (debug>2) { fprintf(outf,"makeexpr_minus("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
if (ISCONST(b->kind) && b->val.i == 0 && /* kludge for array indexing */
ord_type(b->val.type)->kind == TK_ENUM) {
b->val.type = tp_integer;
}
okneg = (a->kind != EK_PLUS && b->kind != EK_PLUS);
a = makeexpr_plus(a, makeexpr_neg(b));
if (okneg && a->kind == EK_PLUS)
a->val.i = 1; /* this flag says to write as "a-b" if possible */
return a;
}
Expr *makeexpr_inc(a, b)
Expr *a, *b;
{
Type *type;
type = a->val.type;
a = makeexpr_plus(makeexpr_charcast(a), b);
if (ord_type(type)->kind != TK_INTEGER &&
ord_type(type)->kind != TK_CHAR)
a = makeexpr_cast(a, type);
return a;
}
/* Apply the distributive law for a sum of products */
Expr *distribute_plus(ex)
Expr *ex;
{
int i, j, icom;
Expr *common, *outer, *ex2, **exp;
if (debug>2) { fprintf(outf,"distribute_plus("); dumpexpr(ex); fprintf(outf,")\n"); }
if (ex->kind != EK_PLUS)
return ex;
for (i = 0; i < ex->nargs; i++)
if (ex->args[i]->kind == EK_TIMES)
break;
if (i == ex->nargs)
return ex;
outer = NULL;
icom = 0;
for (;;) {
ex2 = ex->args[0];
if (ex2->kind == EK_NEG)
ex2 = ex2->args[0];
if (ex2->kind == EK_TIMES) {
if (icom >= ex2->nargs)
break;
common = ex2->args[icom];
if (common->kind == EK_NEG)
common = common->args[0];
} else {
if (icom > 0)
break;
common = ex2;
icom++;
}
for (i = 1; i < ex->nargs; i++) {
ex2 = ex->args[i];
if (ex2->kind == EK_NEG)
ex2 = ex2->args[i];
if (ex2->kind == EK_TIMES) {
for (j = ex2->nargs; --j >= 0; ) {
if (exprsame(ex2->args[j], common, 1) ||
(ex2->args[j]->kind == EK_NEG &&
exprsame(ex2->args[j]->args[0], common, 1)))
break;
}
if (j < 0)
break;
} else {
if (!exprsame(ex2, common, 1))
break;
}
}
if (i == ex->nargs) {
if (debug>2) { fprintf(outf,"distribute_plus does "); dumpexpr(common); fprintf(outf,"\n"); }
common = copyexpr(common);
for (i = 0; i < ex->nargs; i++) {
if (ex->args[i]->kind == EK_NEG)
ex2 = *(exp = &ex->args[i]->args[0]);
else
ex2 = *(exp = &ex->args[i]);
if (ex2->kind == EK_TIMES) {
for (j = ex2->nargs; --j >= 0; ) {
if (exprsame(ex2->args[j], common, 1)) {
delsimpfreearg(exp, j);
break;
} else if (ex2->args[j]->kind == EK_NEG &&
exprsame(ex2->args[j]->args[0], common,1)) {
freeexpr(ex2->args[j]);
ex2->args[j] = makeexpr_long(-1);
break;
}
}
} else {
freeexpr(ex2);
*exp = makeexpr_long(1);
}
ex->args[i] = resimplify(ex->args[i]);
}
outer = makeexpr_times(common, outer);
} else
icom++;
}
return makeexpr_times(resimplify(ex), outer);
}
Expr *makeexpr_times(a, b)
Expr *a, *b;
{
int i, n;
Type *type;
if (debug>2) { fprintf(outf,"makeexpr_times("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
if (!a)
return b;
if (!b)
return a;
a = commute(a, b, EK_TIMES);
if (a->val.type->kind == TK_INTEGER) {
i = a->nargs-1;
if (i > 0 && ISCONST(a->args[i-1]->kind)) {
a->args[i-1]->val.i *= a->args[i]->val.i;
delfreearg(&a, i);
}
}
for (i = n = 0; i < a->nargs; i++) {
if (expr_neg_cost(a->args[i]) < 0)
n++;
}
if (n & 1) {
for (i = 0; i < a->nargs; i++) {
if (ISCONST(a->args[i]->kind) &&
expr_neg_cost(a->args[i]) >= 0) {
a->args[i] = makeexpr_neg(a->args[i]);
n++;
break;
}
}
} else
n++;
for (i = 0; i < a->nargs && n >= 2; i++) {
if (expr_neg_cost(a->args[i]) < 0) {
a->args[i] = makeexpr_neg(a->args[i]);
n--;
}
}
if (checkconst(a->args[a->nargs-1], 1))
delfreearg(&a, a->nargs-1);
if (checkconst(a->args[a->nargs-1], -1)) {
delfreearg(&a, a->nargs-1);
a->args[0] = makeexpr_neg(a->args[0]);
}
if (checkconst(a->args[a->nargs-1], 0) && nosideeffects(a, 1)) {
type = a->val.type;
return makeexpr_cast(grabarg(a, a->nargs-1), type);
}
if (a->nargs < 2) {
if (a->nargs < 1) {
FREE(a);
a = makeexpr_long(1);
} else {
b = a->args[0];
FREE(a);
a = b;
}
}
return a;
}
Expr *makeexpr_sqr(ex, cube)
Expr *ex;
int cube;
{
Expr *ex2;
Meaning *tvar;
Type *type;
if (exprspeed(ex) <= 2 && nosideeffects(ex, 0)) {
ex2 = NULL;
} else {
type = (ex->val.type->kind == TK_REAL) ? tp_longreal : tp_integer;
tvar = makestmttempvar(type, name_TEMP);
ex2 = makeexpr_assign(makeexpr_var(tvar), ex);
ex = makeexpr_var(tvar);
}
if (cube)
ex = makeexpr_times(ex, makeexpr_times(copyexpr(ex), copyexpr(ex)));
else
ex = makeexpr_times(ex, copyexpr(ex));
return makeexpr_comma(ex2, ex);
}
Expr *makeexpr_divide(a, b)
Expr *a, *b;
{
Expr *ex;
int p;
if (debug>2) {
fprintf(outf,"makeexpr_divide(");
dumpexpr(a);
fprintf(outf,", ");
dumpexpr(b);
fprintf(outf,")\n");
}
if (a->val.type->kind != TK_REAL &&
b->val.type->kind != TK_REAL) { /* must do a real division */
ex = docast(a, tp_longreal);
if (ex)
a = ex;
else {
ex = docast(b, tp_longreal);
if (ex)
b = ex;
else
a = makeexpr_cast(a, tp_longreal);
}
}
if (a->kind == EK_TIMES) {
for (p = 0; p < a->nargs; p++)
if (exprsame(a->args[p], b, 1))
break;
if (p < a->nargs) {
delfreearg(&a, p);
freeexpr(b);
if (a->nargs == 1)
return grabarg(a, 0);
else
return a;
}
}
if (expr_neg_cost(a) < 0 && expr_neg_cost(b) < 0) {
a = makeexpr_neg(a);
b = makeexpr_neg(b);
}
if (checkconst(b, 0))
warning("Division by zero [163]");
return makeexpr_bin(EK_DIVIDE, tp_longreal, a, b);
}
int gcd(a, b)
int a, b;
{
if (a < 0) a = -a;
if (b < 0) b = -b;
while (a != 0) {
b %= a;
if (b != 0)
a %= b;
else
return a;
}
return b;
}
/* possible signs of ex: 1=may be neg, 2=may be zero, 4=may be pos */
int negsigns(mask)
int mask;
{
return (mask & 2) |
((mask & 1) << 2) |
((mask & 4) >> 2);
}
int possiblesigns(ex)
Expr *ex;
{
Value val;
Type *tp;
char *cp;
int i, mask, mask2;
if (isliteralconst(ex, &val) && val.type) {
if (val.type == tp_real || val.type == tp_longreal) {
if (realzero(val.s))
return 2;
if (*val.s == '-')
return 1;
return 4;
} else
return (val.i < 0) ? 1 : (val.i == 0) ? 2 : 4;
}
if (ex->kind == EK_CAST &&
similartypes(ex->val.type, ex->args[0]->val.type))
return possiblesigns(ex->args[0]);
if (ex->kind == EK_NEG)
return negsigns(possiblesigns(ex->args[0]));
if (ex->kind == EK_TIMES || ex->kind == EK_DIVIDE) {
mask = possiblesigns(ex->args[0]);
for (i = 1; i < ex->nargs; i++) {
mask2 = possiblesigns(ex->args[i]);
if (mask2 & 2)
mask |= 2;
if ((mask2 & (1|4)) == 1)
mask = negsigns(mask);
else if ((mask2 & (1|4)) != 4)
mask = 1|2|4;
}
return mask;
}
if (ex->kind == EK_DIV || ex->kind == EK_MOD) {
mask = possiblesigns(ex->args[0]);
mask2 = possiblesigns(ex->args[1]);
if (!((mask | mask2) & 1))
return 2|4;
}
if (ex->kind == EK_PLUS) {
mask = 0;
for (i = 0; i < ex->nargs; i++) {
mask2 = possiblesigns(ex->args[i]);
if ((mask & negsigns(mask2)) & (1|4))
mask |= (1|2|4);
else
mask |= mask2;
}
return mask;
}
if (ex->kind == EK_COND) {
return possiblesigns(ex->args[1]) | possiblesigns(ex->args[2]);
}
if (ex->kind == EK_EQ || ex->kind == EK_LT || ex->kind == EK_GT ||
ex->kind == EK_NE || ex->kind == EK_LE || ex->kind == EK_GE ||
ex->kind == EK_AND || ex->kind == EK_OR || ex->kind == EK_NOT)
return 2|4;
if (ex->kind == EK_BICALL) {
cp = ex->val.s;
if (!strcmp(cp, "strlen") ||
!strcmp(cp, "abs") ||
!strcmp(cp, "labs") ||
!strcmp(cp, "fabs"))
return 2|4;
}
tp = (ex->kind == EK_VAR) ? ((Meaning *)ex->val.i)->type : ex->val.type;
if (ord_range(ex->val.type, &val.i, NULL)) {
if (val.i > 0)
return 4;
if (val.i >= 0)
return 2|4;
}
if (ord_range(ex->val.type, NULL, &val.i)) {
if (val.i < 0)
return 1;
if (val.i <= 0)
return 1|2;
}
return 1|2|4;
}
Expr *dodivmod(funcname, ekind, a, b)
char *funcname;
enum exprkind ekind;
Expr *a, *b;
{
Meaning *tvar;
Type *type;
Expr *asn;
int sa, sb;
type = promote_type_bin(a->val.type, b->val.type);
tvar = NULL;
sa = possiblesigns(a);
sb = possiblesigns(b);
if ((sa & 1) || (sb & 1)) {
if (*funcname) {
asn = NULL;
if (*funcname == '*') {
if (exprspeed(a) >= 5 || !nosideeffects(a, 0)) {
tvar = makestmttempvar(a->val.type, name_TEMP);
asn = makeexpr_assign(makeexpr_var(tvar), a);
a = makeexpr_var(tvar);
}
if (exprspeed(b) >= 5 || !nosideeffects(b, 0)) {
tvar = makestmttempvar(b->val.type, name_TEMP);
asn = makeexpr_comma(asn,
makeexpr_assign(makeexpr_var(tvar),
b));
b = makeexpr_var(tvar);
}
}
return makeexpr_comma(asn,
makeexpr_bicall_2(funcname, type, a, b));
} else {
if ((sa & 1) && (ekind == EK_MOD))
note("Using % for possibly-negative arguments [317]");
return makeexpr_bin(ekind, type, a, b);
}
} else
return makeexpr_bin(ekind, type, a, b);
}
Expr *makeexpr_div(a, b)
Expr *a, *b;
{
Meaning *mp;
Type *type;
long i;
int p;
if (ISCONST(a->kind) && ISCONST(b->kind)) {
if (a->val.i >= 0 && b->val.i > 0) {
a->val.i /= b->val.i;
freeexpr(b);
return a;
}
i = gcd(a->val.i, b->val.i);
if (i >= 0) {
a->val.i /= i;
b->val.i /= i;
}
}
if (((b->kind == EK_CONST && (i = b->val.i)) ||
(b->kind == EK_VAR && (mp = (Meaning *)b->val.i)->kind == MK_CONST &&
(i = mp->val.i) && foldconsts != 0)) && i > 0) {
if (i == 1)
return a;
if (div_po2 > 0) {
p = 0;
while (!(i&1))
p++, i >>= 1;
if (i == 1) {
type = promote_type_bin(a->val.type, b->val.type);
return makeexpr_bin(EK_RSH, type, a, makeexpr_long(p));
}
}
}
if (a->kind == EK_TIMES) {
for (p = 0; p < a->nargs; p++) {
if (exprsame(a->args[p], b, 1)) {
delfreearg(&a, p);
freeexpr(b);
if (a->nargs == 1)
return grabarg(a, 0);
else
return a;
} else if (ISCONST(a->args[p]->kind) && ISCONST(b->kind)) {
i = gcd(a->args[p]->val.i, b->val.i);
if (i > 1) {
a->args[p]->val.i /= i;
b->val.i /= i;
i = a->args[p]->val.i;
delfreearg(&a, p);
a = makeexpr_times(a, makeexpr_long(i)); /* resimplify */
p = -1; /* start the loop over */
}
}
}
}
if (checkconst(b, 1)) {
freeexpr(b);
return a;
} else if (checkconst(b, -1)) {
freeexpr(b);
return makeexpr_neg(a);
} else {
if (checkconst(b, 0))
warning("Division by zero [163]");
return dodivmod(divname, EK_DIV, a, b);
}
}
Expr *makeexpr_mod(a, b)
Expr *a, *b;
{
Meaning *mp;
Type *type;
long i;
if (a->kind == EK_CONST && b->kind == EK_CONST &&
a->val.i >= 0 && b->val.i > 0) {
a->val.i %= b->val.i;
freeexpr(b);
return a;
}
if (((b->kind == EK_CONST && (i = b->val.i)) ||
(b->kind == EK_VAR && (mp = (Meaning *)b->val.i)->kind == MK_CONST &&
(i = mp->val.i) && foldconsts != 0)) && i > 0) {
if (i == 1)
return makeexpr_long(0);
if (mod_po2 != 0) {
while (!(i&1))
i >>= 1;
if (i == 1) {
type = promote_type_bin(a->val.type, b->val.type);
return makeexpr_bin(EK_BAND, type, a,
makeexpr_minus(b, makeexpr_long(1)));
}
}
}
if (checkconst(b, 0))
warning("Division by zero [163]");
return dodivmod(modname, EK_MOD, a, b);
}
Expr *makeexpr_rem(a, b)
Expr *a, *b;
{
if (!(possiblesigns(a) & 1) && !(possiblesigns(b) & 1))
return makeexpr_mod(a, b);
if (checkconst(b, 0))
warning("Division by zero [163]");
if (!*remname)
note("Translating REM same as MOD [141]");
return dodivmod(*remname ? remname : modname, EK_MOD, a, b);
}
int expr_not_cost(a)
Expr *a;
{
int i, c;
switch (a->kind) {
case EK_CONST:
return 0;
case EK_NOT:
return -1;
case EK_EQ:
case EK_NE:
case EK_LT:
case EK_GT:
case EK_LE:
case EK_GE:
return 0;
case EK_AND:
case EK_OR:
c = 0;
for (i = 0; i < a->nargs; i++)
c += expr_not_cost(a->args[i]);
return (c > 1) ? 1 : c;
case EK_BICALL:
if (!strcmp(a->val.s, oddname) ||
!strcmp(a->val.s, evenname))
return 0;
return 1;
default:
return 1;
}
}
Expr *makeexpr_not(a)
Expr *a;
{
Expr *ex;
int i;
if (debug>2) { fprintf(outf,"makeexpr_not("); dumpexpr(a); fprintf(outf,")\n"); }
switch (a->kind) {
case EK_CONST:
if (a->val.type == tp_boolean) {
a->val.i = !a->val.i;
return a;
}
break;
case EK_EQ:
a->kind = EK_NE;
return a;
case EK_NE:
a->kind = EK_EQ;
return a;
case EK_LT:
a->kind = EK_GE;
return a;
case EK_GT:
a->kind = EK_LE;
return a;
case EK_LE:
a->kind = EK_GT;
return a;
case EK_GE:
a->kind = EK_LT;
return a;
case EK_AND:
case EK_OR:
if (expr_not_cost(a) > 0)
break;
a->kind = (a->kind == EK_OR) ? EK_AND : EK_OR;
for (i = 0; i < a->nargs; i++)
a->args[i] = makeexpr_not(a->args[i]);
return a;
case EK_NOT:
ex = a->args[0];
FREE(a);
ex->val.type = tp_boolean;
return ex;
case EK_BICALL:
if (!strcmp(a->val.s, oddname) && *evenname) {
strchange(&a->val.s, evenname);
return a;
} else if (!strcmp(a->val.s, evenname)) {
strchange(&a->val.s, oddname);
return a;
}
break;
default:
break;
}
return makeexpr_un(EK_NOT, tp_boolean, a);
}
Type *mixsets(ep1, ep2)
Expr **ep1, **ep2;
{
Expr *ex1 = *ep1, *ex2 = *ep2;
Meaning *tvar;
long min1, max1, min2, max2;
Type *type;
if (ex1->val.type->kind == TK_SMALLSET &&
ex2->val.type->kind == TK_SMALLSET)
return ex1->val.type;
if (ex1->val.type->kind == TK_SMALLSET) {
tvar = makestmttempvar(ex2->val.type, name_SET);
ex1 = makeexpr_bicall_2(setexpandname, ex2->val.type,
makeexpr_var(tvar),
makeexpr_arglong(ex1, 1));
}
if (ex2->val.type->kind == TK_SMALLSET) {
tvar = makestmttempvar(ex1->val.type, name_SET);
ex2 = makeexpr_bicall_2(setexpandname, ex1->val.type,
makeexpr_var(tvar),
makeexpr_arglong(ex2, 1));
}
if (ord_range(ex1->val.type->indextype, &min1, &max1) &&
ord_range(ex2->val.type->indextype, &min2, &max2)) {
if (min1 <= min2 && max1 >= max2)
type = ex1->val.type;
else if (min2 <= min1 && max2 >= max1)
type = ex2->val.type;
else {
if (min2 < min1) min1 = min2;
if (max2 > max1) max1 = max2;
type = maketype(TK_SET);
type->basetype = tp_integer;
type->indextype = maketype(TK_SUBR);
type->indextype->basetype = ord_type(ex1->val.type->indextype);
type->indextype->smin = makeexpr_long(min1);
type->indextype->smax = makeexpr_long(max1);
}
} else
type = ex1->val.type;
*ep1 = ex1, *ep2 = ex2;
return type;
}
Meaning *istempprocptr(ex)
Expr *ex;
{
Meaning *mp;
if (debug>2) { fprintf(outf,"istempprocptr("); dumpexpr(ex); fprintf(outf,")\n"); }
if (ex->kind == EK_COMMA && ex->nargs == 3) {
if ((mp = istempvar(ex->args[2])) != NULL &&
mp->type->kind == TK_PROCPTR &&
ex->args[0]->kind == EK_ASSIGN &&
ex->args[0]->args[0]->kind == EK_DOT &&
exprsame(ex->args[0]->args[0]->args[0], ex->args[2], 1) &&
ex->args[1]->kind == EK_ASSIGN &&
ex->args[1]->args[0]->kind == EK_DOT &&
exprsame(ex->args[1]->args[0]->args[0], ex->args[2], 1))
return mp;
}
if (ex->kind == EK_COMMA && ex->nargs == 2) {
if ((mp = istempvar(ex->args[1])) != NULL &&
mp->type->kind == TK_CPROCPTR &&
ex->args[0]->kind == EK_ASSIGN &&
exprsame(ex->args[0]->args[0], ex->args[1], 1))
return mp;
}
return NULL;
}
Expr *makeexpr_stringify(ex)
Expr *ex;
{
ex = makeexpr_stringcast(ex);
if (ex->val.type->kind == TK_STRING)
return ex;
return makeexpr_sprintfify(ex);
}
Expr *makeexpr_rel(rel, a, b)
enum exprkind rel;
Expr *a, *b;
{
int i, sign;
Expr *ex, *ex2;
Meaning *mp;
char *name;
if (debug>2) { fprintf(outf,"makeexpr_rel(%s,", exprkindname(rel)); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
a = makeexpr_unlongcast(a);
b = makeexpr_unlongcast(b);
if ((compenums == 0 || (compenums < 0 && ansiC <= 0)) &&
(rel != EK_EQ && rel != EK_NE)){
a = enum_to_int(a);
b = enum_to_int(b);
}
if (a->val.type != b->val.type) {
if (a->val.type->kind == TK_STRING &&
a->kind != EK_CONST) {
b = makeexpr_stringify(b);
} else if (b->val.type->kind == TK_STRING &&
b->kind != EK_CONST) {
a = makeexpr_stringify(a);
} else if (ord_type(a->val.type)->kind == TK_CHAR ||
a->val.type->kind == TK_ARRAY) {
b = gentle_cast(b, ord_type(a->val.type));
} else if (ord_type(b->val.type)->kind == TK_CHAR ||
b->val.type->kind == TK_ARRAY) {
a = gentle_cast(a, ord_type(b->val.type));
} else if (a->val.type == tp_anyptr && !voidstar) {
a = gentle_cast(a, b->val.type);
} else if (b->val.type == tp_anyptr && !voidstar) {
b = gentle_cast(b, a->val.type);
}
}
if (useisspace && b->val.type->kind == TK_CHAR && checkconst(b, ' ')) {
if (rel == EK_EQ) {
freeexpr(b);
return makeexpr_bicall_1("isspace", tp_boolean, a);
} else if (rel == EK_NE) {
freeexpr(b);
return makeexpr_not(makeexpr_bicall_1("isspace", tp_boolean, a));
}
}
if (rel == EK_LT || rel == EK_GE)
sign = 1;
else if (rel == EK_GT || rel == EK_LE)
sign = -1;
else
sign = 0;
if (ord_type(b->val.type)->kind == TK_INTEGER ||
ord_type(b->val.type)->kind == TK_CHAR) {
for (;;) {
if (a->kind == EK_PLUS && ISCONST(a->args[a->nargs-1]->kind) &&
a->args[a->nargs-1]->val.i &&
(ISCONST(b->kind) ||
(b->kind == EK_PLUS && ISCONST(b->args[b->nargs-1]->kind)))) {
b = makeexpr_minus(b, copyexpr(a->args[a->nargs-1]));
a = makeexpr_minus(a, copyexpr(a->args[a->nargs-1]));
continue;
}
if (b->kind == EK_PLUS && ISCONST(b->args[b->nargs-1]->kind) &&
b->args[b->nargs-1]->val.i &&
ISCONST(a->kind)) {
a = makeexpr_minus(a, copyexpr(b->args[b->nargs-1]));
b = makeexpr_minus(b, copyexpr(b->args[b->nargs-1]));
continue;
}
if (b->kind == EK_PLUS && sign &&
checkconst(b->args[b->nargs-1], sign)) {
b = makeexpr_plus(b, makeexpr_long(-sign));
switch (rel) {
case EK_LT:
rel = EK_LE;
break;
case EK_GT:
rel = EK_GE;
break;
case EK_LE:
rel = EK_LT;
break;
case EK_GE:
rel = EK_GT;
break;
default:
break;
}
sign = -sign;
continue;
}
if (a->kind == EK_TIMES && checkconst(b, 0) && !sign) {
for (i = 0; i < a->nargs; i++) {
if (ISCONST(a->args[i]->kind) && a->args[i]->val.i)
break;
if (a->args[i]->kind == EK_SIZEOF)
break;
}
if (i < a->nargs) {
delfreearg(&a, i);
continue;
}
}
break;
}
if (a->kind == EK_BICALL && !strcmp(a->val.s, "strlen") &&
checkconst(b, 0)) {
if (rel == EK_LT || rel == EK_GE) {
note("Unusual use of STRLEN encountered [142]");
} else {
freeexpr(b);
a = makeexpr_hat(grabarg(a, 0), 0);
b = makeexpr_char(0); /* "strlen(a) = 0" => "*a == 0" */
if (rel == EK_EQ || rel == EK_LE)
return makeexpr_rel(EK_EQ, a, b);
else
return makeexpr_rel(EK_NE, a, b);
}
}
if (ISCONST(a->kind) && ISCONST(b->kind)) {
if ((a->val.i == b->val.i && (rel == EK_EQ || rel == EK_GE || rel == EK_LE)) ||
(a->val.i < b->val.i && (rel == EK_NE || rel == EK_LE || rel == EK_LT)) ||
(a->val.i > b->val.i && (rel == EK_NE || rel == EK_GE || rel == EK_GT)))
return makeexpr_val(make_ord(tp_boolean, 1));
else
return makeexpr_val(make_ord(tp_boolean, 0));
}
if ((a->val.type == tp_char || true_type(a) == tp_char) &&
ISCONST(b->kind) && signedchars != 0) {
i = (b->val.i == 128 && sign == 1) ||
(b->val.i == 127 && sign == -1);
if (highcharbits && (highcharbits > 0 || signedchars < 0) && i) {
if (highcharbits == 2)
b = makeexpr_long(128);
else
b = makeexpr_un(EK_BNOT, tp_integer, makeexpr_long(127));
return makeexpr_rel((rel == EK_GE || rel == EK_GT)
? EK_NE : EK_EQ,
makeexpr_bin(EK_BAND, tp_integer,
eatcasts(a), b),
makeexpr_long(0));
} else if (signedchars == 1 && i) {
return makeexpr_rel((rel == EK_GE || rel == EK_GT)
? EK_LT : EK_GE,
eatcasts(a), makeexpr_long(0));
} else if (signedchars == 1 && b->val.i >= 128 && sign == 0) {
b->val.i -= 256;
} else if (b->val.i >= 128 ||
(b->val.i == 127 && sign != 0)) {
if (highcharbits && (highcharbits > 0 || signedchars < 0))
a = makeexpr_bin(EK_BAND, a->val.type, eatcasts(a),
makeexpr_long(255));
else
a = force_unsigned(a);
}
}
} else if (a->val.type->kind == TK_STRING &&
b->val.type->kind == TK_STRING) {
if (b->kind == EK_CONST && b->val.i == 0 && !sign) {
a = makeexpr_hat(a, 0);
b = makeexpr_char(0); /* "a = ''" => "*a == 0" */
} else {
a = makeexpr_bicall_2("strcmp", tp_int, a, b);
b = makeexpr_long(0);
}
} else if ((a->val.type->kind == TK_ARRAY ||
a->val.type->kind == TK_STRING ||
a->val.type->kind == TK_RECORD) &&
(b->val.type->kind == TK_ARRAY ||
b->val.type->kind == TK_STRING ||
b->val.type->kind == TK_RECORD)) {
if (a->val.type->kind == TK_ARRAY) {
if (b->val.type->kind == TK_ARRAY) {
ex = makeexpr_sizeof(copyexpr(a), 0);
ex2 = makeexpr_sizeof(copyexpr(b), 0);
if (!exprsame(ex, ex2, 1))
warning("Incompatible array sizes [164]");
freeexpr(ex2);
} else {
ex = makeexpr_sizeof(copyexpr(a), 0);
}
} else
ex = makeexpr_sizeof(copyexpr(b), 0);
name = (usestrncmp &&
a->val.type->kind == TK_ARRAY &&
a->val.type->basetype->kind == TK_CHAR) ? "strncmp" : "memcmp";
a = makeexpr_bicall_3(name, tp_int,
makeexpr_addr(a),
makeexpr_addr(b), ex);
b = makeexpr_long(0);
} else if (a->val.type->kind == TK_SET ||
a->val.type->kind == TK_SMALLSET) {
if (rel == EK_GE) {
swapexprs(a, b);
rel = EK_LE;
}
if (mixsets(&a, &b)->kind == TK_SMALLSET) {
if (rel == EK_LE) {
a = makeexpr_bin(EK_BAND, tp_integer,
a, makeexpr_un(EK_BNOT, tp_integer, b));
b = makeexpr_long(0);
rel = EK_EQ;
}
} else if (b->kind == EK_BICALL &&
!strcmp(b->val.s, setexpandname) &&
(mp = istempvar(b->args[0])) != NULL &&
checkconst(b->args[1], 0)) {
canceltempvar(mp);
a = makeexpr_hat(a, 0);
b = grabarg(b, 1);
if (rel == EK_LE)
rel = EK_EQ;
} else {
ex = makeexpr_bicall_2((rel == EK_LE) ? subsetname : setequalname,
tp_boolean, a, b);
return (rel == EK_NE) ? makeexpr_not(ex) : ex;
}
} else if (a->val.type->kind == TK_PROCPTR ||
a->val.type->kind == TK_CPROCPTR) {
/* we compare proc only (not link) -- same as Pascal compiler! */
if (a->val.type->kind == TK_PROCPTR)
a = makeexpr_dotq(a, "proc", tp_anyptr);
if ((mp = istempprocptr(b)) != NULL) {
canceltempvar(mp);
b = grabarg(grabarg(b, 0), 1);
if (!voidstar)
b = makeexpr_cast(b, tp_anyptr);
} else if (b->val.type->kind == TK_PROCPTR)
b = makeexpr_dotq(b, "proc", tp_anyptr);
}
return makeexpr_bin(rel, tp_boolean, a, b);
}