home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
379a.lha
/
p2c1_13a
/
src
/
src.zoo
/
expr5.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-11
|
39KB
|
1,338 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_EXPR5_C
#include "trans.h"
#define ISCONST(kind) ((kind)==EK_CONST || (kind)==EK_LONGCONST)
long po2m1(n)
int n;
{
if (n == 32)
return -1;
else if (n == 31)
return 0x7fffffff;
else
return (1<<n) - 1;
}
int isarithkind(kind)
enum exprkind kind;
{
return (kind == EK_EQ || kind == EK_LT || kind == EK_GT ||
kind == EK_NE || kind == EK_LE || kind == EK_GE ||
kind == EK_PLUS || kind == EK_TIMES || kind == EK_DIVIDE ||
kind == EK_DIV || kind == EK_MOD || kind == EK_NEG ||
kind == EK_AND || kind == EK_OR || kind == EK_NOT ||
kind == EK_BAND || kind == EK_BOR || kind == EK_BXOR ||
kind == EK_LSH || kind == EK_RSH || kind == EK_BNOT ||
kind == EK_FUNCTION || kind == EK_BICALL);
}
Expr *makeexpr_assign(a, b)
Expr *a, *b;
{
int i, j;
Expr *ex, *ex2, *ex3, **ep;
Meaning *mp;
Type *tp;
if (debug>2) { fprintf(outf,"makeexpr_assign("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
if (stringtrunclimit > 0 &&
a->val.type->kind == TK_STRING &&
(i = strmax(a)) <= stringtrunclimit &&
strmax(b) > i) {
note("Possible string truncation in assignment [145]");
}
a = un_sign_extend(a);
b = gentle_cast(b, a->val.type);
if (b->kind == EK_BICALL && !strcmp(b->val.s, "sprintf") &&
(mp = istempvar(b->args[0])) != NULL &&
b->nargs >= 2 &&
b->args[1]->kind == EK_CONST && /* all this handles string appending */
b->args[1]->val.i > 2 && /* of the form, "s := s + ..." */
!strncmp(b->args[1]->val.s, "%s", 2) &&
exprsame(a, b->args[2], 1) &&
nosideeffects(a, 0) &&
(ex = singlevar(a)) != NULL) {
ex2 = copyexpr(b);
delfreearg(&ex2, 2);
freeexpr(ex2->args[1]);
ex2->args[1] = makeexpr_lstring(b->args[1]->val.s+2,
b->args[1]->val.i-2);
if (/*(ex = singlevar(a)) != NULL && */
/* noargdependencies(ex2) && */ !exproccurs(ex2, ex)) {
freeexpr(b);
if (ex2->args[1]->val.i == 2 && /* s := s + s2 */
!strncmp(ex2->args[1]->val.s, "%s", 2)) {
canceltempvar(mp);
tp = ex2->val.type;
return makeexpr_bicall_2("strcat", tp,
makeexpr_addrstr(a), grabarg(ex2, 2));
} else if (sprintflength(ex2, 0) >= 0) { /* s := s + 's2' */
tp = ex2->val.type;
return makeexpr_bicall_2("strcat", tp,
makeexpr_addrstr(a),
makeexpr_unsprintfify(ex2));
} else { /* general case */
canceltempvar(mp);
freeexpr(ex2->args[0]);
ex = makeexpr_bicall_1("strlen", tp_int, copyexpr(a));
ex2->args[0] = bumpstring(a, ex, 0);
return ex2;
}
} else
freeexpr(ex2);
}
if (b->kind == EK_BICALL && !strcmp(b->val.s, "sprintf") &&
istempvar(b->args[0]) &&
(ex = singlevar(a)) != NULL) {
j = -1; /* does lhs var appear exactly once on rhs? */
for (i = 2; i < b->nargs; i++) {
if (exprsame(b->args[i], ex, 1) && j < 0)
j = i;
else if (exproccurs(b->args[i], ex))
break;
}
if (i == b->nargs && j > 0) {
b->args[j] = makeexpr_bicall_2("strcpy", tp_str255,
makeexpr_addrstr(b->args[0]),
makeexpr_addrstr(b->args[j]));
b->args[0] = makeexpr_addrstr(a);
return b;
}
}
if (structuredfunc(b) && (ex2 = singlevar(a)) != NULL) {
ep = &b->args[0];
i = strlapfunc(b);
while (structuredfunc((ex = *ep))) {
i = i && strlapfunc(ex);
ep = &ex->args[0];
}
if ((mp = istempvar(ex)) != NULL &&
(i || !exproccurs(b, ex2))) {
canceltempvar(mp);
freeexpr(*ep);
*ep = makeexpr_addrstr(a);
return b;
}
}
if (a->val.type->kind == TK_PROCPTR &&
(mp = istempprocptr(b)) != NULL &&
nosideeffects(a, 0)) {
freeexpr(b->args[0]->args[0]->args[0]);
b->args[0]->args[0]->args[0] = copyexpr(a);
if (b->nargs == 3) {
freeexpr(b->args[1]->args[0]->args[0]);
b->args[1]->args[0]->args[0] = a;
delfreearg(&b, 2);
} else {
freeexpr(b->args[1]);
b->args[1] = makeexpr_assign(makeexpr_dotq(a, "link", tp_anyptr),
makeexpr_nil());
}
canceltempvar(mp);
return b;
}
if (a->val.type->kind == TK_PROCPTR &&
(b->val.type->kind == TK_CPROCPTR ||
checkconst(b, 0))) {
ex = makeexpr_dotq(copyexpr(a), "proc", tp_anyptr);
b = makeexpr_comma(makeexpr_assign(ex, b),
makeexpr_assign(makeexpr_dotq(a, "link", tp_anyptr),
makeexpr_nil()));
return b;
}
if (a->val.type->kind == TK_CPROCPTR &&
(mp = istempprocptr(b)) != NULL &&
nosideeffects(a, 0)) {
freeexpr(b->args[0]->args[0]);
b->args[0]->args[0] = a;
if (b->nargs == 3)
delfreearg(&b, 1);
delfreearg(&b, 1);
canceltempvar(mp);
return b;
}
if (a->val.type->kind == TK_CPROCPTR &&
b->val.type->kind == TK_PROCPTR) {
b = makeexpr_dotq(b, "proc", tp_anyptr);
}
if (a->val.type->kind == TK_STRING) {
if (b->kind == EK_CONST && b->val.i == 0 && !isretvar(a)) {
/* optimizing retvar would mess up "return" optimization */
return makeexpr_assign(makeexpr_hat(a, 0),
makeexpr_char(0));
}
a = makeexpr_addrstr(a);
b = makeexpr_addrstr(b);
return makeexpr_bicall_2("strcpy", a->val.type, a, b);
}
if (a->kind == EK_BICALL && !strcmp(a->val.s, "strlen")) {
if (b->kind == EK_CAST &&
ord_type(b->args[0]->val.type)->kind == TK_INTEGER) {
b = grabarg(b, 0);
}
j = (b->kind == EK_PLUS && /* handle "s[0] := xxx" */
b->args[0]->kind == EK_BICALL &&
!strcmp(b->args[0]->val.s, "strlen") &&
exprsame(a->args[0], b->args[0]->args[0], 0) &&
isliteralconst(b->args[1], NULL) == 2);
if (j && b->args[1]->val.i > 0 &&
b->args[1]->val.i <= 5) { /* lengthening the string */
a = grabarg(a, 0);
i = b->args[1]->val.i;
freeexpr(b);
if (i == 1)
b = makeexpr_string(" ");
else
b = makeexpr_lstring("12345", i);
return makeexpr_bicall_2("strcat", a->val.type, a, b);
} else { /* maybe shortening the string */
if (!j && !isconstexpr(b, NULL))
note("Modification of string length may translate incorrectly [146]");
a = grabarg(a, 0);
b = makeexpr_ord(b);
return makeexpr_assign(makeexpr_index(a, b, NULL),
makeexpr_char(0));
}
}
if (a->val.type->kind == TK_ARRAY ||
(a->val.type->kind == TK_PROCPTR && copystructs < 1) ||
(a->val.type->kind == TK_RECORD &&
(copystructs < 1 || a->val.type != b->val.type))) {
ex = makeexpr_sizeof(copyexpr(a), 0);
ex2 = makeexpr_sizeof(copyexpr(b), 0);
if (!exprsame(ex, ex2, 1) &&
!(a->val.type->kind == TK_ARRAY &&
b->val.type->kind != TK_ARRAY))
warning("Incompatible types or sizes [167]");
freeexpr(ex2);
ex = makeexpr_arglong(ex, (size_t_long != 0));
a = makeexpr_addrstr(a);
b = makeexpr_addrstr(b);
return makeexpr_bicall_3("memcpy", a->val.type, a, b, ex);
}
if (a->val.type->kind == TK_SET) {
a = makeexpr_addrstr(a);
b = makeexpr_addrstr(b);
return makeexpr_bicall_2(setcopyname, a->val.type, a, b);
}
for (ep = &a; (ex3 = *ep); ) {
if (ex3->kind == EK_COMMA)
ep = &ex3->args[ex3->nargs-1];
else if (ex3->kind == EK_CAST || ex3->kind == EK_ACTCAST)
ep = &ex3->args[0];
else
break;
}
if (ex3->kind == EK_BICALL) {
if (!strcmp(ex3->val.s, getbitsname)) {
tp = ex3->args[0]->val.type;
if (tp->kind == TK_ARRAY)
ex3->args[0] = makeexpr_addr(ex3->args[0]);
ex3->val.type = tp_void;
if (checkconst(b, 0) && *clrbitsname) {
strchange(&ex3->val.s, clrbitsname);
} else if (*putbitsname &&
((ISCONST(b->kind) &&
(b->val.i | ~((1 << (1 << tp->escale)) - 1)) == -1) ||
checkconst(b, (1 << (1 << tp->escale)) - 1))) {
strchange(&ex3->val.s, putbitsname);
insertarg(ep, 2, makeexpr_arglong(makeexpr_ord(b), 0));
} else {
b = makeexpr_arglong(makeexpr_ord(b), 0);
if (*storebitsname) {
strchange(&ex3->val.s, storebitsname);
insertarg(ep, 2, b);
} else {
if (exproccurs(b, ex3->args[0])) {
mp = makestmttempvar(b->val.type, name_TEMP);
ex2 = makeexpr_assign(makeexpr_var(mp), b);
b = makeexpr_var(mp);
} else
ex2 = NULL;
ex = copyexpr(ex3);
strchange(&ex3->val.s, putbitsname);
insertarg(&ex3, 2, b);
strchange(&ex->val.s, clrbitsname);
*ep = makeexpr_comma(ex2, makeexpr_comma(ex, ex3));
}
}
return a;
} else if (!strcmp(ex3->val.s, getfbufname)) {
ex3->val.type = tp_void;
strchange(&ex3->val.s, putfbufname);
insertarg(ep, 2, b);
return a;
} else if (!strcmp(ex3->val.s, chargetfbufname)) {
ex3->val.type = tp_void;
if (*charputfbufname) {
strchange(&ex3->val.s, charputfbufname);
insertarg(ep, 1, b);
} else {
strchange(&ex3->val.s, putfbufname);
insertarg(ep, 1, makeexpr_type(ex3->val.type->basetype->basetype));
insertarg(ep, 2, b);
}
return a;
} else if (!strcmp(ex3->val.s, arraygetfbufname)) {
ex3->val.type = tp_void;
if (*arrayputfbufname) {
strchange(&ex3->val.s, arrayputfbufname);
insertarg(ep, 1, b);
} else {
strchange(&ex3->val.s, putfbufname);
insertarg(ep, 1, makeexpr_type(ex3->val.type->basetype->basetype));
insertarg(ep, 2, b);
}
return a;
}
}
while (a->kind == EK_CAST || a->kind == EK_ACTCAST) {
if (ansiC < 2 || /* in GNU C, a cast is an lvalue */
isarithkind(a->args[0]->kind) ||
(a->val.type->kind == TK_POINTER &&
a->args[0]->val.type->kind == TK_POINTER)) {
if (a->kind == EK_CAST)
b = makeexpr_cast(b, a->args[0]->val.type);
else
b = makeexpr_actcast(b, a->args[0]->val.type);
a = grabarg(a, 0);
} else
break;
}
if (a->kind == EK_NEG)
return makeexpr_assign(grabarg(a, 0), makeexpr_neg(b));
if (a->kind == EK_NOT)
return makeexpr_assign(grabarg(a, 0), makeexpr_not(b));
if (a->kind == EK_BNOT)
return makeexpr_assign(grabarg(a, 0),
makeexpr_un(EK_BNOT, b->val.type, b));
if (a->kind == EK_PLUS) {
for (i = 0; i < a->nargs && a->nargs > 1; ) {
if (isconstantexpr(a->args[i])) {
b = makeexpr_minus(b, a->args[i]);
deletearg(&a, i);
} else
i++;
}
if (a->nargs == 1)
return makeexpr_assign(grabarg(a, 0), b);
}
if (a->kind == EK_TIMES) {
for (i = 0; i < a->nargs && a->nargs > 1; ) {
if (isconstantexpr(a->args[i])) {
if (a->val.type->kind == TK_REAL)
b = makeexpr_divide(b, a->args[i]);
else {
if (ISCONST(b->kind) && ISCONST(a->args[i]->kind) &&
(b->val.i % a->args[i]->val.i) != 0) {
break;
}
b = makeexpr_div(b, a->args[i]);
}
deletearg(&a, i);
} else
i++;
}
if (a->nargs == 1)
return makeexpr_assign(grabarg(a, 0), b);
}
if ((a->kind == EK_DIVIDE || a->kind == EK_DIV) &&
isconstantexpr(a->args[1])) {
b = makeexpr_times(b, a->args[1]);
return makeexpr_assign(a->args[0], b);
}
if (a->kind == EK_LSH && isconstantexpr(a->args[1])) {
if (ISCONST(b->kind) && ISCONST(a->args[1]->kind)) {
if ((b->val.i & ((1L << a->args[1]->val.i)-1)) == 0) {
b->val.i >>= a->args[1]->val.i;
return makeexpr_assign(grabarg(a, 0), b);
}
} else {
b = makeexpr_bin(EK_RSH, b->val.type, b, a->args[1]);
return makeexpr_assign(a->args[0], b);
}
}
if (a->kind == EK_RSH && isconstantexpr(a->args[1])) {
if (ISCONST(b->kind) && ISCONST(a->args[1]->kind))
b->val.i <<= a->args[1]->val.i;
else
b = makeexpr_bin(EK_LSH, b->val.type, b, a->args[1]);
return makeexpr_assign(a->args[0], b);
}
if (isarithkind(a->kind))
warning("Invalid assignment [168]");
return makeexpr_bin(EK_ASSIGN, a->val.type, a, makeexpr_unlongcast(b));
}
Expr *makeexpr_comma(a, b)
Expr *a, *b;
{
Type *type;
if (!a || nosideeffects(a, 1))
return b;
if (!b)
return a;
type = b->val.type;
a = commute(a, b, EK_COMMA);
a->val.type = type;
return a;
}
int strmax(ex)
Expr *ex;
{
Meaning *mp;
long smin, smax;
Value val;
Type *type;
type = ex->val.type;
if (type->kind == TK_POINTER)
type = type->basetype;
if (type->kind == TK_CHAR)
return 1;
if (type->kind == TK_ARRAY && type->basetype->kind == TK_CHAR) {
if (ord_range(type->indextype, &smin, &smax))
return smax - smin + 1;
else
return stringceiling;
}
if (type->kind != TK_STRING) {
intwarning("strmax", "strmax encountered a non-string value [169]");
return stringceiling;
}
if (ex->kind == EK_CONST)
return ex->val.i;
if (ex->kind == EK_VAR && foldstrconsts != 0 &&
(mp = (Meaning *)(ex->val.i))->kind == MK_CONST)
return mp->val.i;
if (ex->kind == EK_BICALL) {
if (!strcmp(ex->val.s, strsubname)) {
if (isliteralconst(ex->args[3], &val) && val.type)
return val.i;
}
}
if (ord_range(type->indextype, NULL, &smax))
return smax;
else
return stringceiling;
}
int strhasnull(val)
Value val;
{
int i;
for (i = 0; i < val.i; i++) {
if (!val.s[i])
return (i == val.i-1) ? 1 : 2;
}
return 0;
}
int istempsprintf(ex)
Expr *ex;
{
return (ex->kind == EK_BICALL && !strcmp(ex->val.s, "sprintf") &&
ex->nargs >= 2 &&
istempvar(ex->args[0]) &&
ex->args[1]->kind == EK_CONST &&
ex->args[1]->val.type->kind == TK_STRING);
}
Expr *makeexpr_sprintfify(ex)
Expr *ex;
{
Meaning *tvar;
char stringbuf[500];
char *cp, ch;
int j, nnulls;
Expr *ex2;
if (debug>2) { fprintf(outf,"makeexpr_sprintfify("); dumpexpr(ex); fprintf(outf,")\n"); }
if (istempsprintf(ex))
return ex;
ex = makeexpr_stringcast(ex);
tvar = makestmttempvar(tp_str255, name_STRING);
if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING) {
cp = stringbuf;
nnulls = 0;
for (j = 0; j < ex->val.i; j++) {
ch = ex->val.s[j];
if (!ch) {
if (j < ex->val.i-1)
note("Null character in sprintf control string [147]");
else
note("Null character at end of sprintf control string [148]");
if (keepnulls) {
*cp++ = '%';
*cp++ = 'c';
nnulls++;
}
} else {
*cp++ = ch;
if (ch == '%')
*cp++ = ch;
}
}
*cp = 0;
ex = makeexpr_bicall_2("sprintf", tp_str255,
makeexpr_var(tvar),
makeexpr_string(stringbuf));
while (--nnulls >= 0)
insertarg(&ex, 2, makeexpr_char(0));
return ex;
} else if (ex->val.type->kind == TK_ARRAY &&
ex->val.type->basetype->kind == TK_CHAR) {
ex2 = arraysize(ex->val.type, 0);
return cleansprintf(
makeexpr_bicall_4("sprintf", tp_str255,
makeexpr_var(tvar),
makeexpr_string("%.*s"),
ex2,
makeexpr_addrstr(ex)));
} else {
if (ord_type(ex->val.type)->kind == TK_CHAR)
cp = "%c";
else if (ex->val.type->kind == TK_STRING)
cp = "%s";
else {
warning("Mixing non-strings with strings [170]");
return ex;
}
return makeexpr_bicall_3("sprintf", tp_str255,
makeexpr_var(tvar),
makeexpr_string(cp),
ex);
}
}
Expr *makeexpr_unsprintfify(ex)
Expr *ex;
{
char stringbuf[500];
char *cp, ch;
int i;
if (debug>2) { fprintf(outf,"makeexpr_unsprintfify("); dumpexpr(ex); fprintf(outf,")\n"); }
if (!istempsprintf(ex))
return ex;
canceltempvar(istempvar(ex->args[0]));
for (i = 2; i < ex->nargs; i++) {
if (ex->args[i]->val.type->kind != TK_CHAR ||
!checkconst(ex, 0))
return ex;
}
cp = stringbuf;
for (i = 0; i < ex->args[1]->val.i; i++) {
ch = ex->args[1]->val.s[i];
*cp++ = ch;
if (ch == '%') {
if (++i == ex->args[1]->val.i)
return ex;
ch = ex->args[1]->val.s[i];
if (ch == 'c')
cp[-1] = 0;
else if (ch != '%')
return ex;
}
}
freeexpr(ex);
return makeexpr_lstring(stringbuf, cp - stringbuf);
}
/* Returns >= 0 iff unsprintfify would return a string constant */
int sprintflength(ex, allownulls)
Expr *ex;
int allownulls;
{
int i, len;
if (!istempsprintf(ex))
return -1;
for (i = 2; i < ex->nargs; i++) {
if (!allownulls ||
ex->args[i]->val.type->kind != TK_CHAR ||
!checkconst(ex, 0))
return -1;
}
len = 0;
for (i = 0; i < ex->args[1]->val.i; i++) {
len++;
if (ex->args[1]->val.s[i] == '%') {
if (++i == ex->args[1]->val.i)
return -1;
if (ex->args[1]->val.s[i] != 'c' &&
ex->args[1]->val.s[i] != '%')
return -1;
}
}
return len;
}
Expr *makeexpr_concat(a, b, usesprintf)
Expr *a, *b;
int usesprintf;
{
int i, ii, j, len, nargs;
Type *type;
Meaning *mp, *tvar;
Expr *ex, *args[2];
int akind[2];
Value val, val1, val2;
char formatstr[300];
if (debug>2) { fprintf(outf,"makeexpr_concat("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); }
if (!a)
return b;
if (!b)
return a;
a = makeexpr_stringcast(a);
b = makeexpr_stringcast(b);
if (checkconst(a, 0)) {
freeexpr(a);
return b;
}
if (checkconst(b, 0)) {
freeexpr(b);
return a;
}
len = strmax(a) + strmax(b);
type = makestringtype(len);
if (a->kind == EK_CONST && b->kind == EK_CONST) {
val1 = a->val;
val2 = b->val;
val.i = val1.i + val2.i;
val.s = ALLOC(val.i+1, char, literals);
val.s[val.i] = 0;
val.type = type;
memcpy(val.s, val1.s, val1.i);
memcpy(val.s + val1.i, val2.s, val2.i);
freeexpr(a);
freeexpr(b);
return makeexpr_val(val);
}
tvar = makestmttempvar(type, name_STRING);
if (sprintf_value != 2 || usesprintf) {
nargs = 2; /* Generate a call to sprintf(), unfolding */
args[0] = a; /* nested sprintf()'s. */
args[1] = b;
*formatstr = 0;
for (i = 0; i < 2; i++) {
#if 1
ex = args[i] = makeexpr_sprintfify(args[i]);
if (!ex->args[1] || !ex->args[1]->val.s)
intwarning("makeexpr_concat", "NULL in ex->args[1]");
else
strncat(formatstr, ex->args[1]->val.s, ex->args[1]->val.i);
canceltempvar(istempvar(ex->args[0]));
nargs += (ex->nargs - 2);
akind[i] = 0; /* now obsolete */
#else
ex = args[i];
if (ex->kind == EK_CONST)
ex = makeexpr_sprintfify(ex);
if (istempsprintf(ex)) {
strncat(formatstr, ex->args[1]->val.s, ex->args[1]->val.i);
canceltempvar(istempvar(ex->args[0]));
nargs += (ex->nargs - 2);
akind[i] = 0;
} else {
strcat(formatstr, "%s");
nargs++;
akind[i] = 1;
}
#endif
}
ex = makeexpr(EK_BICALL, nargs);
ex->val.type = type;
ex->val.s = stralloc("sprintf");
ex->args[0] = makeexpr_var(tvar);
ex->args[1] = makeexpr_string(formatstr);
j = 2;
for (i = 0; i < 2; i++) {
switch (akind[i]) {
case 0: /* flattened sub-sprintf */
for (ii = 2; ii < args[i]->nargs; ii++)
ex->args[j++] = copyexpr(args[i]->args[ii]);
freeexpr(args[i]);
break;
case 1: /* included string expr */
ex->args[j++] = args[i];
break;
}
}
} else {
ex = a;
while (ex->kind == EK_BICALL && !strcmp(ex->val.s, "strcat"))
ex = ex->args[0];
if (ex->kind == EK_BICALL && !strcmp(ex->val.s, "strcpy") &&
(mp = istempvar(ex->args[0])) != NULL) {
canceltempvar(mp);
freeexpr(ex->args[0]);
ex->args[0] = makeexpr_var(tvar);
} else {
a = makeexpr_bicall_2("strcpy", type, makeexpr_var(tvar), a);
}
ex = makeexpr_bicall_2("strcat", type, a, b);
}
if (debug>2) { fprintf(outf,"makeexpr_concat returns "); dumpexpr(ex); fprintf(outf,"\n"); }
return ex;
}
Expr *cleansprintf(ex)
Expr *ex;
{
int fidx, i, j, k, len, changed = 0;
char *cp, *bp;
char fmtbuf[300];
if (ex->kind != EK_BICALL)
return ex;
if (!strcmp(ex->val.s, "printf"))
fidx = 0;
else if (!strcmp(ex->val.s, "sprintf") ||
!strcmp(ex->val.s, "fprintf"))
fidx = 1;
else
return ex;
len = ex->args[fidx]->val.i;
cp = ex->args[fidx]->val.s; /* printf("%*d",17,x) => printf("%17d",x) */
bp = fmtbuf;
j = fidx + 1;
for (i = 0; i < len; i++) {
*bp++ = cp[i];
if (cp[i] == '%') {
if (cp[i+1] == 's' && ex->args[j]->kind == EK_CONST) {
bp--;
for (k = 0; k < ex->args[j]->val.i; k++)
*bp++ = ex->args[j]->val.s[k];
delfreearg(&ex, j);
changed = 1;
i++;
continue;
}
for (i++; i < len &&
!(isalpha(cp[i]) && cp[i] != 'l'); i++) {
if (cp[i] == '*') {
if (isliteralconst(ex->args[j], NULL) == 2) {
sprintf(bp, "%ld", ex->args[j]->val.i);
bp += strlen(bp);
delfreearg(&ex, j);
changed = 1;
} else {
*bp++ = cp[i];
j++;
}
} else
*bp++ = cp[i];
}
if (i < len)
*bp++ = cp[i];
j++;
}
}
*bp = 0;
if (changed) {
freeexpr(ex->args[fidx]);
ex->args[fidx] = makeexpr_string(fmtbuf);
}
return ex;
}
Expr *makeexpr_substring(vex, ex, exi, exj)
Expr *vex, *ex, *exi, *exj;
{
exi = makeexpr_unlongcast(exi);
exj = makeexpr_longcast(exj, 0);
ex = bumpstring(ex, exi, 1);
return cleansprintf(makeexpr_bicall_4("sprintf", tp_str255,
vex,
makeexpr_string("%.*s"),
exj,
ex));
}
Expr *makeexpr_dot(ex, mp)
Expr *ex;
Meaning *mp;
{
Type *ot1, *ot2;
Expr *ex2, *ex3, *nex;
Meaning *tvar;
if (ex->kind == EK_FUNCTION && copystructfuncs > 0) {
tvar = makestmttempvar(ex->val.type, name_TEMP);
ex2 = makeexpr_assign(makeexpr_var(tvar), ex);
ex = makeexpr_var(tvar);
} else
ex2 = NULL;
if (mp->constdefn) {
nex = makeexpr(EK_MACARG, 0);
nex->val.type = tp_integer;
ex3 = replaceexprexpr(copyexpr(mp->constdefn), nex, ex);
freeexpr(ex);
freeexpr(nex);
ex = gentle_cast(ex3, mp->val.type);
} else {
ex = makeexpr_un(EK_DOT, mp->type, ex);
ex->val.i = (long)mp;
ot1 = ord_type(mp->type);
ot2 = ord_type(mp->val.type);
if (ot1->kind != ot2->kind && ot2->kind == TK_ENUM && ot2->meaning && useenum)
ex = makeexpr_cast(ex, mp->val.type);
else if (mp->val.i && !hassignedchar &&
(mp->type == tp_sint || mp->type == tp_abyte)) {
if (*signextname) {
ex = makeexpr_bicall_2(signextname, tp_integer,
ex, makeexpr_long(mp->val.i));
} else
note(format_s("Unable to sign-extend field %s [149]", mp->name));
}
}
ex->val.type = mp->val.type;
return makeexpr_comma(ex2, ex);
}
Expr *makeexpr_dotq(ex, name, type)
Expr *ex;
char *name;
Type *type;
{
ex = makeexpr_un(EK_DOT, type, ex);
ex->val.s = stralloc(name);
return ex;
}
Expr *strmax_func(ex)
Expr *ex;
{
Meaning *mp;
Expr *ex2;
Type *type;
type = ex->val.type;
if (type->kind == TK_POINTER) {
intwarning("strmax_func", "got a pointer instead of a string [171]");
type = type->basetype;
}
if (type->kind == TK_CHAR)
return makeexpr_long(1);
if (type->kind != TK_STRING) {
warning("STRMAX of non-string value [172]");
return makeexpr_long(stringceiling);
}
if (ex->kind == EK_CONST)
return makeexpr_long(ex->val.i);
if (ex->kind == EK_VAR &&
(mp = (Meaning *)ex->val.i)->kind == MK_CONST &&
mp->type == tp_str255)
return makeexpr_long(mp->val.i);
if (ex->kind == EK_VAR &&
(mp = (Meaning *)ex->val.i)->kind == MK_VARPARAM &&
mp->type == tp_strptr) {
if (mp->anyvarflag) {
if (mp->ctx != curctx && mp->ctx->kind == MK_FUNCTION)
note(format_s("Reference to STRMAX of parent proc's \"%s\" must be fixed [150]",
mp->name));
return makeexpr_name(format_s(name_STRMAX, mp->name), tp_int);
} else
note(format_s("STRMAX of \"%s\" wants VarStrings=1 [151]", mp->name));
}
ord_range_expr(type->indextype, NULL, &ex2);
return copyexpr(ex2);
}
Expr *makeexpr_nil()
{
Expr *ex;
ex = makeexpr(EK_CONST, 0);
ex->val.type = tp_anyptr;
ex->val.i = 0;
ex->val.s = NULL;
return ex;
}
Expr *makeexpr_ctx(ctx)
Meaning *ctx;
{
Expr *ex;
ex = makeexpr(EK_CTX, 0);
ex->val.type = tp_text; /* handy pointer type */
ex->val.i = (long)ctx;
return ex;
}
Expr *force_signed(ex)
Expr *ex;
{
Type *tp;
if (isliteralconst(ex, NULL) == 2 && ex->nargs == 0)
return ex;
tp = true_type(ex);
if (tp == tp_ushort || tp == tp_ubyte || tp == tp_uchar)
return makeexpr_cast(ex, tp_sshort);
else if (tp == tp_unsigned || tp == tp_uint) {
if (exprlongness(ex) < 0)
return makeexpr_cast(ex, tp_sint);
else
return makeexpr_cast(ex, tp_integer);
}
return ex;
}
Expr *force_unsigned(ex)
Expr *ex;
{
Type *tp;
if (isliteralconst(ex, NULL) == 2 && !expr_is_neg(ex))
return ex;
tp = true_type(ex);
if (tp == tp_unsigned || tp == tp_uint || tp == tp_ushort ||
tp == tp_ubyte || tp == tp_uchar)
return ex;
if (tp->kind == TK_CHAR)
return makeexpr_actcast(ex, tp_uchar);
else if (exprlongness(ex) < 0)
return makeexpr_cast(ex, tp_uint);
else
return makeexpr_cast(ex, tp_unsigned);
}
#define CHECKSIZE(size) (((size) > 0 && (size)%charsize == 0) ? (size)/charsize : 0)
long type_sizeof(type, pasc)
Type *type;
int pasc;
{
long s1, smin, smax;
int charsize = (sizeof_char) ? sizeof_char : CHAR_BIT; /* from <limits.h> */
switch (type->kind) {
case TK_INTEGER:
if (type == tp_integer ||
type == tp_unsigned)
return pasc ? 4 : CHECKSIZE(sizeof_integer);
else
return pasc ? 2 : CHECKSIZE(sizeof_short);
case TK_CHAR:
case TK_BOOLEAN:
return 1;
case TK_SUBR:
type = findbasetype(type, 0);
if (pasc) {
if (type == tp_integer || type == tp_unsigned)
return 4;
else
return 2;
} else {
if (type == tp_abyte || type == tp_ubyte || type == tp_sbyte)
return 1;
else if (type == tp_ushort || type == tp_sshort)
return CHECKSIZE(sizeof_short);
else
return CHECKSIZE(sizeof_integer);
}
case TK_POINTER:
return pasc ? 4 : CHECKSIZE(sizeof_pointer);
case TK_REAL:
if (type == tp_longreal)
return pasc ? (which_lang == LANG_TURBO ? 6 : 8) : CHECKSIZE(sizeof_double);
else
return pasc ? 4 : CHECKSIZE(sizeof_float);
case TK_ENUM:
if (!pasc)
return CHECKSIZE(sizeof_enum);
type = findbasetype(type, 0);
return type->kind != TK_ENUM ? type_sizeof(type, pasc)
: CHECKSIZE(pascalenumsize);
case TK_SMALLSET:
case TK_SMALLARRAY:
return pasc ? 0 : type_sizeof(type->basetype, pasc);
case TK_ARRAY:
s1 = type_sizeof(type->basetype, pasc);
if (s1 && ord_range(type->indextype, &smin, &smax))
return s1 * (smax - smin + 1);
else
return 0;
case TK_RECORD:
if (pasc && type->meaning) {
if (!strcmp(type->meaning->sym->name, "NA_WORD"))
return 2;
else if (!strcmp(type->meaning->sym->name, "NA_LONGWORD"))
return 4;
else if (!strcmp(type->meaning->sym->name, "NA_QUADWORD"))
return 8;
else
return 0;
} else
return 0;
default:
return 0;
}
}
Static Value eval_expr_either(ex, pasc)
Expr *ex;
int pasc;
{
Value val, val2;
Meaning *mp;
int i;
if (debug>2) { fprintf(outf,"eval_expr("); dumpexpr(ex); fprintf(outf,")\n"); }
switch (ex->kind) {
case EK_CONST:
case EK_LONGCONST:
return ex->val;
case EK_VAR:
mp = (Meaning *) ex->val.i;
if (mp->kind == MK_CONST &&
(foldconsts != 0 ||
mp == mp_maxint || mp == mp_minint))
return mp->val;
break;
case EK_SIZEOF:
i = type_sizeof(ex->args[0]->val.type, pasc);
if (i)
return make_ord(tp_integer, i);
break;
case EK_PLUS:
val = eval_expr_either(ex->args[0], pasc);
if (!val.type || ord_type(val.type) != tp_integer)
val.type = NULL;
for (i = 1; val.type && i < ex->nargs; i++) {
val2 = eval_expr_either(ex->args[i], pasc);
if (!val2.type || ord_type(val2.type) != tp_integer)
val.type = NULL;
else
val.i += val2.i;
}
return val;
case EK_TIMES:
val = eval_expr_either(ex->args[0], pasc);
if (!val.type || ord_type(val.type) != tp_integer)
val.type = NULL;
for (i = 1; val.type && i < ex->nargs; i++) {
val2 = eval_expr_either(ex->args[i], pasc);
if (!val2.type || ord_type(val2.type) != tp_integer)
val.type = NULL;
else
val.i *= val2.i;
}
return val;
case EK_DIV:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && ord_type(val.type) == tp_integer &&
val2.type && ord_type(val2.type) == tp_integer && val2.i) {
val.i /= val2.i;
return val;
}
break;
case EK_MOD:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && ord_type(val.type) == tp_integer &&
val2.type && ord_type(val2.type) == tp_integer && val2.i) {
val.i %= val2.i;
return val;
}
break;
case EK_NEG:
val = eval_expr_either(ex->args[0], pasc);
if (val.type) {
val.i = -val.i;
return val;
}
break;
case EK_LSH:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && val2.type) {
val.i <<= val2.i;
return val;
}
break;
case EK_RSH:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && val2.type) {
val.i >>= val2.i;
return val;
}
break;
case EK_BAND:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && val2.type) {
val.i &= val2.i;
return val;
}
break;
case EK_BOR:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && val2.type) {
val.i |= val2.i;
return val;
}
break;
case EK_BXOR:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type && val2.type) {
val.i ^= val2.i;
return val;
}
break;
case EK_BNOT:
val = eval_expr_either(ex->args[0], pasc);
if (val.type) {
val.i = ~val.i;
return val;
}
break;
case EK_EQ:
case EK_NE:
case EK_GT:
case EK_LT:
case EK_GE:
case EK_LE:
val = eval_expr_either(ex->args[0], pasc);
val2 = eval_expr_either(ex->args[1], pasc);
if (val.type) {
if (val.i == val2.i)
val.i = (ex->kind == EK_EQ || ex->kind == EK_GE || ex->kind == EK_LE);
else if (val.i < val2.i)
val.i = (ex->kind == EK_LT || ex->kind == EK_LE || ex->kind == EK_NE);
else
val.i = (ex->kind == EK_GT || ex->kind == EK_GE || ex->kind == EK_NE);
val.type = tp_boolean;
return val;
}
break;
case EK_NOT:
val = eval_expr_either(ex->args[0], pasc);
if (val.type)
val.i = !val.i;
return val;
case EK_AND:
for (i = 0; i < ex->nargs; i++) {
val = eval_expr_either(ex->args[i], pasc);
if (!val.type || !val.i)
return val;
}
return val;
case EK_OR:
for (i = 0; i < ex->nargs; i++) {
val = eval_expr_either(ex->args[i], pasc);
if (!val.type || val.i)
return val;
}
return val;
case EK_COMMA:
return eval_expr_either(ex->args[ex->nargs-1], pasc);
default:
break;
}
val.type = NULL;
return val;
}
Value eval_expr(ex)
Expr *ex;
{
return eval_expr_either(ex, 0);
}
Value eval_expr_consts(ex)
Expr *ex;
{
Value val;
short save_fold = foldconsts;
foldconsts = 1;
val = eval_expr_either(ex, 0);
foldconsts = save_fold;
return val;
}
Value eval_expr_pasc(ex)
Expr *ex;
{
return eval_expr_either(ex, 1);
}
int expr_is_const(ex)
Expr *ex;
{
int i;
switch (ex->kind) {
case EK_CONST:
case EK_LONGCONST:
case EK_SIZEOF:
return 1;
case EK_VAR:
return (((Meaning *)ex->val.i)->kind == MK_CONST);
case EK_HAT:
case EK_ASSIGN:
case EK_POSTINC:
case EK_POSTDEC:
return 0;
case EK_ADDR:
if (ex->args[0]->kind == EK_VAR)
return 1;
return 0; /* conservative */
case EK_FUNCTION:
if (!nosideeffects_func(ex))
return 0;
break;
case EK_BICALL:
if (!nosideeffects_func(ex))
return 0;
break;
default:
break;
}
for (i = 0; i < ex->nargs; i++) {
if (!expr_is_const(ex->args[i]))
return 0;
}
return 1;
}
Expr *eatcasts(ex)
Expr *ex;
{
while (ex->kind == EK_CAST)
ex = grabarg(ex, 0);
return ex;
}
/* End. */