home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
379a.lha
/
p2c1_13a
/
src
/
src.zoo
/
parse3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-11
|
32KB
|
981 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_PARSE3_C
#include "trans.h"
#define BR_NEVER 0x1 /* never use braces */
#define BR_FUNCTION 0x2 /* function body */
#define BR_THENPART 0x4 /* before an "else" */
#define BR_ALWAYS 0x8 /* always use braces */
#define BR_REPEAT 0x10 /* "do-while" loop */
#define BR_TRY 0x20 /* in a recover block */
#define BR_ELSEPART 0x40 /* after an "else" */
#define BR_CASE 0x80 /* case of a switch stmt */
int printnl_func(ex)
Expr *ex;
{
char *cp, ch;
int i, len;
if (debug>2) { fprintf(outf,"printnl_func("); dumpexpr(ex); fprintf(outf, ")\n"); }
if (!strcmp(ex->val.s, "printf") ||
!strcmp(ex->val.s, "puts") ||
!strcmp(ex->val.s, "fputs")) {
if (ex->args[0]->kind != EK_CONST)
return 0;
cp = ex->args[0]->val.s;
len = ex->args[0]->val.i;
} else if (!strcmp(ex->val.s, "fprintf")) {
if (ex->args[1]->kind != EK_CONST)
return 0;
cp = ex->args[1]->val.s;
len = ex->args[1]->val.i;
} else if (!strcmp(ex->val.s, "putchar") ||
!strcmp(ex->val.s, "putc") ||
!strcmp(ex->val.s, "fputc")) {
if (ex->args[0]->kind != EK_CONST)
return 0;
ch = ex->args[0]->val.i;
cp = &ch;
len = 1;
} else
return 0;
for (i = 1; i <= len; i++)
if (*cp++ != '\n')
return 0;
return len + (!strcmp(ex->val.s, "puts"));
}
Expr *chg_printf(ex)
Expr *ex;
{
Expr *fex;
if (debug>2) { fprintf(outf,"chg_printf("); dumpexpr(ex); fprintf(outf, ")\n"); }
if (!strcmp(ex->val.s, "putchar")) {
ex = makeexpr_sprintfify(grabarg(ex, 0));
canceltempvar(istempvar(ex->args[0]));
strchange(&ex->val.s, "printf");
delfreearg(&ex, 0);
ex->val.type = tp_void;
} else if (!strcmp(ex->val.s, "putc") ||
!strcmp(ex->val.s, "fputc") ||
!strcmp(ex->val.s, "fputs")) {
fex = copyexpr(ex->args[1]);
ex = makeexpr_sprintfify(grabarg(ex, 0));
canceltempvar(istempvar(ex->args[0]));
strchange(&ex->val.s, "fprintf");
ex->args[0] = fex;
ex->val.type = tp_void;
} else if (!strcmp(ex->val.s, "puts")) {
ex = makeexpr_concat(makeexpr_sprintfify(grabarg(ex, 0)),
makeexpr_string("\n"), 1);
strchange(&ex->val.s, "printf");
delfreearg(&ex, 0);
ex->val.type = tp_void;
}
if (!strcmp(ex->val.s, "fprintf") && exprsame(ex->args[0], ex_output, 1)) {
delfreearg(&ex, 0);
strchange(&ex->val.s, "printf");
}
return ex;
}
Expr *mix_printf(ex, ex2)
Expr *ex, *ex2;
{
int i;
ex = chg_printf(ex);
if (debug>2) { fprintf(outf,"chg_printf returns "); dumpexpr(ex); fprintf(outf, "\n"); }
ex2 = chg_printf(copyexpr(ex2));
if (debug>2) { fprintf(outf,"chg_printf returns "); dumpexpr(ex2);fprintf(outf, "\n"); }
i = (!strcmp(ex->val.s, "printf")) ? 0 : 1;
ex->args[i] = makeexpr_concat(ex->args[i], ex2->args[i], 0);
for (i++; i < ex2->nargs; i++) {
insertarg(&ex, ex->nargs, ex2->args[i]);
}
return ex;
}
void eatstmt(spp)
Stmt **spp;
{
Stmt *sp = *spp;
if (debug>2) { fprintf(outf, "eatstmt on:\n"); dumpstmt(sp, 5); }
*spp = sp->next;
sp->next = NULL;
free_stmt(sp);
}
int haslabels(sp)
Stmt *sp;
{
if (!sp)
return 0;
if (haslabels(sp->stm1) || haslabels(sp->stm2))
return 1;
return (sp->kind == SK_LABEL);
}
void fixblock(spp, thereturn)
Stmt **spp, *thereturn;
{
Stmt *sp, *sp1, *sp2, *sp3, **spp2, *thisreturn;
Expr *ex;
Meaning *tvar, *mp;
int save_tryblock;
short save_tryflag;
int i, j, de1, de2;
long saveserial = curserial;
while ((sp = *spp)) {
sp2 = sp->next;
sp->next = NULL;
sp = fix_statement(*spp);
if (!sp) {
*spp = sp2;
continue;
}
*spp = sp;
for (sp3 = sp; sp3->next; sp3 = sp3->next) ;
sp3->next = sp2;
if (!sp->next)
thisreturn = thereturn;
else if (sp->next->kind == SK_RETURN ||
(sp->next->kind == SK_ASSIGN &&
isescape(sp->next->exp1)))
thisreturn = sp->next;
else
thisreturn = NULL;
if (sp->serial >= 0)
curserial = sp->serial;
switch (sp->kind) {
case SK_ASSIGN:
if (sp->exp1)
sp->exp1 = fixexpr(sp->exp1, ENV_STMT);
if (!sp->exp1)
intwarning("fixblock", "sp->exp1 == NULL in SK_ASSIGN");
if (!sp->exp1 || nosideeffects(sp->exp1, 1)) {
eatstmt(spp);
continue;
} else {
switch (sp->exp1->kind) {
case EK_COND:
*spp = makestmt_if(sp->exp1->args[0],
makestmt_call(sp->exp1->args[1]),
makestmt_call(sp->exp1->args[2]));
(*spp)->next = sp->next;
continue; /* ... to fix this new if statement */
case EK_ASSIGN:
if (sp->exp1->args[1]->kind == EK_COND && usecommas != 1) {
*spp = makestmt_if(sp->exp1->args[1]->args[0],
makestmt_assign(copyexpr(sp->exp1->args[0]),
sp->exp1->args[1]->args[1]),
makestmt_assign(sp->exp1->args[0],
sp->exp1->args[1]->args[2]));
(*spp)->next = sp->next;
continue;
}
if (isescape(sp->exp1->args[1])) {
sp->exp1 = grabarg(sp->exp1, 1);
continue;
}
if (exprsame(sp->exp1->args[0], sp->exp1->args[1], 1)) {
/* *spp = sp->next; */
sp->exp1 = grabarg(sp->exp1, 0);
continue;
}
if (sp->exp1->args[1]->kind == EK_BICALL) {
if (!strcmp(sp->exp1->args[1]->val.s,
getfbufname) &&
buildreads == 1 &&
sp->next &&
sp->next->kind == SK_ASSIGN &&
sp->next->exp1->kind == EK_BICALL &&
!strcmp(sp->next->exp1->val.s,
getname) &&
expr_has_address(sp->exp1->args[0]) &&
similartypes(sp->exp1->args[0]->val.type,
sp->exp1->args[1]->args[0]->val.type->basetype->basetype) &&
exprsame(sp->exp1->args[1]->args[0],
sp->next->exp1->args[0], 1)) {
eatstmt(&sp->next);
ex = makeexpr_bicall_4("fread", tp_integer,
makeexpr_addr(sp->exp1->args[0]),
makeexpr_sizeof(sp->exp1->args[1]->args[1], 0),
makeexpr_long(1),
sp->exp1->args[1]->args[0]);
FREE(sp->exp1);
sp->exp1 = ex;
continue;
}
if (!strcmp(sp->exp1->args[1]->val.s,
chargetfbufname) &&
buildreads != 0 &&
sp->next &&
sp->next->kind == SK_ASSIGN &&
sp->next->exp1->kind == EK_BICALL &&
!strcmp(sp->next->exp1->val.s,
chargetname) &&
expr_has_address(sp->exp1->args[0]) &&
exprsame(sp->exp1->args[1]->args[0],
sp->next->exp1->args[0], 1)) {
eatstmt(&sp->next);
strchange(&sp->exp1->args[1]->val.s,
"getc");
continue;
}
}
break;
case EK_BICALL:
if (!strcmp(sp->exp1->val.s, name_ESCAPE)) {
if (fixexpr_tryblock) {
*spp = makestmt_assign(makeexpr_var(mp_escapecode),
grabarg(sp->exp1, 0));
(*spp)->next = makestmt(SK_GOTO);
(*spp)->next->exp1 = makeexpr_name(format_s(name_LABEL,
format_d("try%d",
fixexpr_tryblock)),
tp_integer);
(*spp)->next->next = sp->next;
fixexpr_tryflag = 1;
continue;
}
} else if (!strcmp(sp->exp1->val.s, name_ESCIO)) {
if (fixexpr_tryblock) {
*spp = makestmt_assign(makeexpr_var(mp_escapecode),
makeexpr_long(-10));
(*spp)->next = makestmt_assign(makeexpr_var(mp_ioresult),
grabarg(sp->exp1, 0));
(*spp)->next->next = makestmt(SK_GOTO);
(*spp)->next->next->exp1 = makeexpr_name(format_s(name_LABEL,
format_d("try%d",
fixexpr_tryblock)),
tp_integer);
(*spp)->next->next->next = sp->next;
fixexpr_tryflag = 1;
continue;
}
}
if (!strcmp(sp->exp1->val.s, putfbufname) &&
buildwrites == 1 &&
sp->next &&
sp->next->kind == SK_ASSIGN &&
sp->next->exp1->kind == EK_BICALL &&
!strcmp(sp->next->exp1->val.s,
putname) &&
exprsame(sp->exp1->args[0],
sp->next->exp1->args[0], 1)) {
eatstmt(&sp->next);
if (!expr_has_address(sp->exp1->args[2]) ||
sp->exp1->args[2]->val.type !=
sp->exp1->args[1]->val.type) {
tvar = maketempvar(sp->exp1->args[1]->val.type,
name_TEMP);
sp2 = makestmt_assign(makeexpr_var(tvar),
sp->exp1->args[2]);
sp2->next = sp;
*spp = sp2;
sp->exp1->args[2] = makeexpr_var(tvar);
freetempvar(tvar);
}
ex = makeexpr_bicall_4("fwrite", tp_integer,
makeexpr_addr(sp->exp1->args[2]),
makeexpr_sizeof(sp->exp1->args[1], 0),
makeexpr_long(1),
sp->exp1->args[0]);
FREE(sp->exp1);
sp->exp1 = ex;
continue;
}
if (!strcmp(sp->exp1->val.s, charputfbufname) &&
buildwrites != 0 &&
sp->next &&
sp->next->kind == SK_ASSIGN &&
sp->next->exp1->kind == EK_BICALL &&
!strcmp(sp->next->exp1->val.s,
charputname) &&
exprsame(sp->exp1->args[0],
sp->next->exp1->args[0], 1)) {
eatstmt(&sp->next);
swapexprs(sp->exp1->args[0],
sp->exp1->args[1]);
strchange(&sp->exp1->val.s, "putc");
continue;
}
if ((!strcmp(sp->exp1->val.s, resetbufname) ||
!strcmp(sp->exp1->val.s, setupbufname)) &&
(mp = isfilevar(sp->exp1->args[0])) != NULL &&
!mp->bufferedfile) {
eatstmt(spp);
continue;
}
ex = print_func(sp->exp1);
if (ex && sp->next && mixwritelns &&
sp->next->kind == SK_ASSIGN &&
exprsame(ex, print_func(sp->next->exp1), 1) &&
(printnl_func(sp->exp1) ||
printnl_func(sp->next->exp1))) {
sp->exp1 = mix_printf(sp->exp1,
sp->next->exp1);
eatstmt(&sp->next);
continue;
}
break;
case EK_FUNCTION:
case EK_SPCALL:
case EK_POSTINC:
case EK_POSTDEC:
case EK_AND:
case EK_OR:
break;
default:
spp2 = spp;
for (i = 0; i < sp->exp1->nargs; i++) {
*spp2 = makestmt_call(sp->exp1->args[i]);
spp2 = &(*spp2)->next;
}
*spp2 = sp->next;
continue; /* ... to fix these new statements */
}
}
break;
case SK_IF:
fixblock(&sp->stm1, thisreturn);
fixblock(&sp->stm2, thisreturn);
if (!sp->stm1) {
if (!sp->stm2) {
sp->kind = SK_ASSIGN;
continue;
} else {
if (sp->stm2->kind == SK_IF && sp->stm2->exp2) {
freeexpr(sp->stm2->exp2);
sp->stm2->exp2 = NULL;
}
sp->exp1 = makeexpr_not(sp->exp1); /* if (x) else foo => if (!x) foo */
swapstmts(sp->stm1, sp->stm2);
/* Ought to exchange comments for then/else parts */
}
}
/* At this point we know sp1 != NULL */
if (thisreturn) {
if (thisreturn->kind == SK_WHILE) {
if (usebreaks) {
sp1 = sp->stm1;
while (sp1->next)
sp1 = sp1->next;
if (sp->stm2) {
sp2 = sp->stm2;
while (sp2->next)
sp2 = sp2->next;
i = stmtcount(sp->stm1);
j = stmtcount(sp->stm2);
if (j >= breaklimit && i <= 2 && j > i*2 &&
((implies(sp->exp1, thisreturn->exp1, 0, 1) &&
!checkexprchanged(sp->stm1, sp->exp1)) ||
(sp1->kind == SK_ASSIGN &&
implies(sp1->exp1, thisreturn->exp1, 0, 1)))) {
sp1->next = makestmt(SK_BREAK);
} else if (i >= breaklimit && j <= 2 && i > j*2 &&
((implies(sp->exp1, thisreturn->exp1, 1, 1) &&
!checkexprchanged(sp->stm2, sp->exp1)) ||
(sp2->kind == SK_ASSIGN &&
implies(sp2->exp1, thisreturn->exp1, 0, 1)))) {
sp2->next = makestmt(SK_BREAK);
} else if (!checkconst(sp->exp2, 1)) {
/* not part of an else-if */
if (j >= continuelimit) {
sp1->next = makestmt(SK_CONTINUE);
} else if (i >= continuelimit) {
sp2->next = makestmt(SK_CONTINUE);
}
}
} else {
i = stmtcount(sp->stm1);
if (i >= breaklimit &&
implies(sp->exp1, thisreturn->exp1, 1, 1)) {
sp->exp1 = makeexpr_not(sp->exp1);
sp1->next = sp->next;
sp->next = sp->stm1;
sp->stm1 = makestmt(SK_BREAK);
} else if (i >= continuelimit) {
sp->exp1 = makeexpr_not(sp->exp1);
sp1->next = sp->next;
sp->next = sp->stm1;
sp->stm1 = makestmt(SK_CONTINUE);
}
}
}
} else {
if (usereturns) {
sp2 = sp->stm1;
while (sp2->next)
sp2 = sp2->next;
if (sp->stm2) {
/* if (x) foo; else bar; (return;) => if (x) {foo; return;} bar; */
if (stmtcount(sp->stm2) >= returnlimit) {
if (!deadendblock(sp->stm1))
sp2->next = copystmt(thisreturn);
} else if (stmtcount(sp->stm1) >= returnlimit) {
sp2 = sp->stm2;
while (sp2->next)
sp2 = sp2->next;
if (!deadendblock(sp->stm2))
sp2->next = copystmt(thisreturn);
}
} else { /* if (x) foo; (return;) => if (!x) return; foo; */
if (stmtcount(sp->stm1) >= returnlimit) {
sp->exp1 = makeexpr_not(sp->exp1);
sp2->next = sp->next;
sp->next = sp->stm1;
sp->stm1 = copystmt(thisreturn);
}
}
}
}
}
if (!checkconst(sp->exp2, 1)) { /* not part of an else-if */
de1 = deadendblock(sp->stm1);
de2 = deadendblock(sp->stm2);
if (de2 && !de1) {
sp->exp1 = makeexpr_not(sp->exp1);
swapstmts(sp->stm1, sp->stm2);
de1 = 1, de2 = 0;
}
if (de1 && !de2 && sp->stm2) {
if (sp->stm2->kind == SK_IF && sp->stm2->exp2) {
freeexpr(sp->stm2->exp2);
sp->stm2->exp2 = NULL;
}
for (sp2 = sp->stm2; sp2->next; sp2 = sp2->next) ;
sp2->next = sp->next;
sp->next = sp->stm2; /* if (x) ESCAPE else foo => if (x) ESCAPE; foo */
sp->stm2 = NULL;
}
}
sp->exp1 = fixexpr(sp->exp1, ENV_BOOL);
break;
case SK_WHILE:
if (whilefgets && /* handle "while eof(f) do readln(f,...)" */
sp->stm1->kind == SK_ASSIGN &&
sp->stm1->exp1->kind == EK_BICALL &&
!strcmp(sp->stm1->exp1->val.s, "fgets") &&
nosideeffects(sp->stm1->exp1->args[0], 1) &&
nosideeffects(sp->stm1->exp1->args[1], 1) &&
nosideeffects(sp->stm1->exp1->args[2], 1)) {
if ((sp->exp1->kind == EK_NOT &&
sp->exp1->args[0]->kind == EK_BICALL && *eofname &&
!strcmp(sp->exp1->args[0]->val.s, eofname) &&
exprsame(sp->exp1->args[0]->args[0],
sp->stm1->exp1->args[2], 1)) ||
(sp->exp1->kind == EK_EQ &&
sp->exp1->args[0]->kind == EK_BICALL &&
!strcmp(sp->exp1->args[0]->val.s, "feof") &&
checkconst(sp->exp1->args[1], 0) &&
exprsame(sp->exp1->args[0]->args[0],
sp->stm1->exp1->args[2], 1))) {
sp->stm1->exp1->val.type = tp_strptr;
sp->exp1 = makeexpr_rel(EK_NE,
sp->stm1->exp1,
makeexpr_nil());
sp->stm1 = sp->stm1->next;
}
}
fixblock(&sp->stm1, sp);
sp->exp1 = fixexpr(sp->exp1, ENV_BOOL);
if (checkconst(sp->exp1, 1))
infiniteloop(sp);
break;
case SK_REPEAT:
fixblock(&sp->stm1, NULL);
sp->exp1 = fixexpr(sp->exp1, ENV_BOOL);
if (checkconst(sp->exp1, 1))
infiniteloop(sp);
break;
case SK_TRY:
save_tryblock = fixexpr_tryblock;
save_tryflag = fixexpr_tryflag;
fixexpr_tryblock = sp->exp1->val.i;
fixexpr_tryflag = 0;
fixblock(&sp->stm1, NULL);
if (fixexpr_tryflag)
sp->exp2 = makeexpr_long(1);
fixexpr_tryblock = save_tryblock;
fixexpr_tryflag = save_tryflag;
fixblock(&sp->stm2, NULL);
break;
case SK_BODY:
fixblock(&sp->stm1, thisreturn);
break;
case SK_CASE:
fixblock(&sp->stm1, NULL);
sp->exp1 = fixexpr(sp->exp1, ENV_EXPR);
if (!sp->stm1) { /* empty case */
sp->kind = SK_ASSIGN;
continue;
} else if (sp->stm1->kind != SK_CASELABEL) { /* default only */
for (sp2 = sp->stm1; sp2->next; sp2 = sp2->next) ;
sp2->next = sp->next;
sp->next = sp->stm1;
sp->kind = SK_ASSIGN;
sp->stm1 = NULL;
continue;
}
break;
default:
fixblock(&sp->stm1, NULL);
fixblock(&sp->stm2, NULL);
sp->exp1 = fixexpr(sp->exp1, ENV_EXPR);
sp->exp2 = fixexpr(sp->exp2, ENV_EXPR);
sp->exp3 = fixexpr(sp->exp3, ENV_EXPR);
if (sp->next &&
(sp->kind == SK_GOTO ||
sp->kind == SK_BREAK ||
sp->kind == SK_CONTINUE ||
sp->kind == SK_RETURN) &&
!haslabels(sp->next)) {
if (elimdeadcode) {
note("Deleting unreachable code [255]");
while (sp->next && !haslabels(sp->next))
eatstmt(&sp->next);
} else {
note("Code is unreachable [256]");
}
} else if (sp->kind == SK_RETURN &&
thisreturn &&
thisreturn->kind == SK_RETURN &&
exprsame(sp->exp1, thisreturn->exp1, 1)) {
eatstmt(spp);
continue;
}
break;
}
spp = &sp->next;
}
saveserial = curserial;
}
/* Convert comma expressions into multiple statements */
Static int checkcomma_expr(spp, exp)
Stmt **spp;
Expr **exp;
{
Stmt *sp;
Expr *ex = *exp;
int i, res;
switch (ex->kind) {
case EK_COMMA:
if (spp) {
res = checkcomma_expr(spp, &ex->args[ex->nargs-1]);
for (i = ex->nargs-1; --i >= 0; ) {
sp = makestmt(SK_ASSIGN);
sp->exp1 = ex->args[i];
sp->next = *spp;
*spp = sp;
res = checkcomma_expr(spp, &ex->args[i]);
}
*exp = ex->args[ex->nargs-1];
}
return 1;
case EK_COND:
if (isescape(ex->args[1]) && spp &&
!isescape(ex->args[2])) {
swapexprs(ex->args[1], ex->args[2]);
ex->args[0] = makeexpr_not(ex->args[0]);
}
if (isescape(ex->args[2])) {
if (spp) {
res = checkcomma_expr(spp, &ex->args[1]);
if (ex->args[0]->kind == EK_ASSIGN) {
sp = makestmt(SK_ASSIGN);
sp->exp1 = copyexpr(ex->args[0]);
sp->next = makestmt(SK_IF);
sp->next->next = *spp;
*spp = sp;
res = checkcomma_expr(spp, &sp->exp1);
ex->args[0] = grabarg(ex->args[0], 0);
sp = sp->next;
} else {
sp = makestmt(SK_IF);
sp->next = *spp;
*spp = sp;
}
sp->exp1 = makeexpr_not(ex->args[0]);
sp->stm1 = makestmt(SK_ASSIGN);
sp->stm1->exp1 = eatcasts(ex->args[2]);
res = checkcomma_expr(&sp->stm1, &ex->args[2]);
res = checkcomma_expr(spp, &sp->exp1);
*exp = ex->args[1];
}
return 1;
}
return checkcomma_expr(spp, &ex->args[0]);
case EK_AND:
case EK_OR:
return checkcomma_expr(spp, &ex->args[0]);
default:
res = 0;
for (i = ex->nargs; --i >= 0; ) {
res += checkcomma_expr(spp, &ex->args[i]);
}
return res;
}
}
Static void checkcommas(spp)
Stmt **spp;
{
Stmt *sp;
int res;
while ((sp = *spp)) {
checkcommas(&sp->stm1);
checkcommas(&sp->stm2);
switch (sp->kind) {
case SK_ASSIGN:
case SK_IF:
case SK_CASE:
case SK_RETURN:
if (sp->exp1)
res = checkcomma_expr(spp, &sp->exp1);
break;
case SK_WHILE:
/* handle the argument */
break;
case SK_REPEAT:
/* handle the argument */
break;
case SK_FOR:
if (sp->exp1)
res = checkcomma_expr(spp, &sp->exp1);
/* handle the other arguments */
break;
default:
break;
}
spp = &sp->next;
}
}
Static int checkvarchangeable(ex, mp)
Expr *ex;
Meaning *mp;
{
switch (ex->kind) {
case EK_VAR:
return (mp == (Meaning *)ex->val.i);
case EK_DOT:
case EK_INDEX:
return checkvarchangeable(ex->args[0], mp);
default:
return 0;
}
}
int checkvarchangedexpr(ex, mp, addrokay)
Expr *ex;
Meaning *mp;
int addrokay;
{
int i;
Meaning *mp3;
unsigned int safemask = 0;
switch (ex->kind) {
case EK_FUNCTION:
case EK_SPCALL:
if (ex->kind == EK_FUNCTION) {
i = 0;
mp3 = ((Meaning *)ex->val.i)->type->fbase;
} else {
i = 1;
if (ex->args[0]->val.type->kind != TK_PROCPTR)
return 1;
mp3 = ex->args[0]->val.type->basetype->fbase;
}
for ( ; i < ex->nargs && i < 16; i++) {
if (!mp3) {
intwarning("checkvarchangedexpr", "Too many arguments for EK_FUNCTION [266]");
break;
}
if (mp3->kind == MK_PARAM &&
(mp3->type->kind == TK_ARRAY ||
mp3->type->kind == TK_STRING ||
mp3->type->kind == TK_SET))
safemask |= 1<<i;
if (mp3->kind == MK_VARPARAM &&
mp3->type == tp_strptr && mp3->anyvarflag)
i++;
mp3 = mp3->xnext;
}
if (mp3)
intwarning("checkvarchangedexpr", "Too few arguments for EK_FUNCTION [267]");
break;
case EK_VAR:
if (mp == (Meaning *)ex->val.i) {
if ((mp->type->kind == TK_ARRAY ||
mp->type->kind == TK_STRING ||
mp->type->kind == TK_SET) &&
ex->val.type->kind == TK_POINTER && !addrokay)
return 1; /* must be an implicit & */
}
break;
case EK_ADDR:
case EK_ASSIGN:
case EK_POSTINC:
case EK_POSTDEC:
if (checkvarchangeable(ex->args[0], mp))
return 1;
break;
case EK_BICALL:
if (structuredfunc(ex) && checkvarchangeable(ex->args[0], mp))
return 1;
safemask = safemask_bicall(ex->val.s);
break;
/* In case calls to these functions were lazy and passed
the array rather than its (implicit) address. Other
BICALLs had better be careful about their arguments. */
case EK_PLUS:
if (addrokay) /* to keep from being scared by pointer */
safemask = ~0; /* arithmetic on string being passed */
break; /* to functions. */
default:
break;
}
for (i = 0; i < ex->nargs; i++) {
if (checkvarchangedexpr(ex->args[i], mp, safemask&1))
return 1;
safemask >>= 1;
}
return 0;
}
int checkvarchanged(sp, mp)
Stmt *sp;
Meaning *mp;
{
if (mp->constqual)
return 0;
if (mp->varstructflag || !mp->ctx || mp->ctx->kind != MK_FUNCTION ||
mp->volatilequal || alwayscopyvalues)
return 1;
while (sp) {
if (/* sp->kind == SK_GOTO || */
sp->kind == SK_LABEL ||
checkvarchanged(sp->stm1, mp) ||
checkvarchanged(sp->stm2, mp) ||
(sp->exp1 && checkvarchangedexpr(sp->exp1, mp, 1)) ||
(sp->exp2 && checkvarchangedexpr(sp->exp2, mp, 1)) ||
(sp->exp3 && checkvarchangedexpr(sp->exp3, mp, 1)))
return 1;
sp = sp->next;
}
return 0;
}
int checkexprchanged(sp, ex)
Stmt *sp;
Expr *ex;
{
Meaning *mp;
int i;
for (i = 0; i < ex->nargs; i++) {
if (checkexprchanged(sp, ex->args[i]))
return 1;
}
switch (ex->kind) {
case EK_VAR:
mp = (Meaning *)ex->val.i;
if (mp->kind == MK_CONST)
return 0;
else
return checkvarchanged(sp, mp);
case EK_HAT:
case EK_INDEX:
case EK_SPCALL:
return 1;
case EK_FUNCTION:
case EK_BICALL:
return !nosideeffects_func(ex);
default:
return 0;
}
}
/* Check if a variable always occurs with a certain offset added, e.g. "i+1" */
Static int theoffset, numoffsets, numzerooffsets;
#define BadOffset (-999)
void checkvaroffsetexpr(ex, mp, myoffset)
Expr *ex;
Meaning *mp;
int myoffset;
{
int i, nextoffset = 0;
Expr *ex2;
if (!ex)
return;
switch (ex->kind) {
case EK_VAR:
if (ex->val.i == (long)mp) {
if (myoffset == 0)
numzerooffsets++;
else if (numoffsets == 0 || myoffset == theoffset) {
theoffset = myoffset;
numoffsets++;
} else
theoffset = BadOffset;
}
break;
case EK_PLUS:
ex2 = ex->args[ex->nargs-1];
if (ex2->kind == EK_CONST &&
ex2->val.type->kind == TK_INTEGER) {
nextoffset = ex2->val.i;
}
break;
case EK_HAT:
case EK_POSTINC:
case EK_POSTDEC:
nextoffset = BadOffset;
break;
case EK_ASSIGN:
checkvaroffsetexpr(ex->args[0], mp, BadOffset);
checkvaroffsetexpr(ex->args[1], mp, 0);
return;
default:
break;
}
i = ex->nargs;
while (--i >= 0)
checkvaroffsetexpr(ex->args[i], mp, nextoffset);
}
void checkvaroffsetstmt(sp, mp)
Stmt *sp;
Meaning *mp;
{
while (sp) {
checkvaroffsetstmt(sp->stm1, mp);
checkvaroffsetstmt(sp->stm1, mp);
checkvaroffsetexpr(sp->exp1, mp, 0);
checkvaroffsetexpr(sp->exp2, mp, 0);
checkvaroffsetexpr(sp->exp3, mp, 0);
sp = sp->next;
}
}
int checkvaroffset(sp, mp)
Stmt *sp;
Meaning *mp;
{
if (mp->varstructflag || !mp->ctx || mp->ctx->kind != MK_FUNCTION)
return 0;
numoffsets = 0;
numzerooffsets = 0;
checkvaroffsetstmt(sp, mp);
if (numoffsets == 0 || theoffset == BadOffset ||
numoffsets <= numzerooffsets * 3)
return 0;
else
return theoffset;
}