blob: 1d0be409d1346eb119270dc531bce9a0aaa9a365 [file] [log] [blame]
/* "p2c", a Pascal to C translator.
Copyright (C) 1989, 1990, 1991 Free Software Foundation.
Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (any version).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#define PROTO_PARSE_C
#include "trans.h"
Static short candeclare;
Static int trycount;
Static Strlist *includedfiles;
Static char echo_first;
Static int echo_pos;
void setup_parse()
{
candeclare = 0;
trycount = 0;
includedfiles = NULL;
echo_first = 1;
echo_pos = 0;
fixexpr_tryblock = 0;
}
void echobreak()
{
if (echo_pos > 0) {
printf("\n");
echo_pos = 0;
echo_first = 0;
}
}
void echoword(name, comma)
char *name;
int comma;
{
FILE *f = (outf == stdout) ? stderr : stdout;
if (quietmode || showprogress)
return;
if (!echo_first) {
if (comma) {
fprintf(f, ",");
echo_pos++;
}
if (echo_pos + strlen(name) > 77) {
fprintf(f, "\n");
echo_pos = 0;
} else {
fprintf(f, " ");
echo_pos++;
}
}
echo_first = 0;
fprintf(f, "%s", name);
echo_pos += strlen(name);
fflush(f);
}
void echoprocname(mp)
Meaning *mp;
{
echoword(mp->name, 1);
}
Static void forward_decl(func, isextern)
Meaning *func;
int isextern;
{
if (func->wasdeclared)
return;
if (isextern && func->constdefn && !checkvarmac(func))
return;
if (isextern) {
output("extern ");
} else if (func->ctx->kind == MK_FUNCTION) {
if (useAnyptrMacros)
output("Local ");
else
output("static ");
} else if ((use_static != 0 && !useAnyptrMacros) ||
(findsymbol(func->name)->flags & NEEDSTATIC)) {
output("static ");
} else if (useAnyptrMacros) {
output("Static ");
}
if (func->type->basetype != tp_void || ansiC != 0) {
outbasetype(func->type, ODECL_FORWARD);
output(" ");
}
outdeclarator(func->type, func->name, ODECL_FORWARD);
output(";\n");
func->wasdeclared = 1;
}
/* Check if calling a parent procedure, whose body must */
/* be declared forward */
void need_forward_decl(func)
Meaning *func;
{
Meaning *mp;
if (func->wasdeclared)
return;
for (mp = curctx->ctx; mp; mp = mp->ctx) {
if (mp == func) {
if (func->ctx->kind == MK_FUNCTION)
func->isforward = 1;
else
forward_decl(func, 0);
return;
}
}
}
void free_stmt(sp)
register Stmt *sp;
{
if (sp) {
free_stmt(sp->stm1);
free_stmt(sp->stm2);
free_stmt(sp->next);
freeexpr(sp->exp1);
freeexpr(sp->exp2);
freeexpr(sp->exp3);
FREE(sp);
}
}
Stmt *makestmt(kind)
enum stmtkind kind;
{
Stmt *sp;
sp = ALLOC(1, Stmt, stmts);
sp->kind = kind;
sp->next = NULL;
sp->stm1 = NULL;
sp->stm2 = NULL;
sp->exp1 = NULL;
sp->exp2 = NULL;
sp->exp3 = NULL;
sp->serial = curserial = ++serialcount;
return sp;
}
Stmt *makestmt_call(call)
Expr *call;
{
Stmt *sp = makestmt(SK_ASSIGN);
sp->exp1 = call;
return sp;
}
Stmt *makestmt_assign(lhs, rhs)
Expr *lhs, *rhs;
{
Stmt *sp = makestmt(SK_ASSIGN);
sp->exp1 = makeexpr_assign(lhs, rhs);
return sp;
}
Stmt *makestmt_if(cond, thn, els)
Expr *cond;
Stmt *thn, *els;
{
Stmt *sp = makestmt(SK_IF);
sp->exp1 = cond;
sp->stm1 = thn;
sp->stm2 = els;
return sp;
}
Stmt *makestmt_seq(s1, s2)
Stmt *s1, *s2;
{
Stmt *s1a;
if (!s1)
return s2;
if (!s2)
return s1;
for (s1a = s1; s1a->next; s1a = s1a->next) ;
s1a->next = s2;
return s1;
}
Stmt *copystmt(sp)
Stmt *sp;
{
Stmt *sp2;
if (sp) {
sp2 = makestmt(sp->kind);
sp2->stm1 = copystmt(sp->stm1);
sp2->stm2 = copystmt(sp->stm2);
sp2->exp1 = copyexpr(sp->exp1);
sp2->exp2 = copyexpr(sp->exp2);
sp2->exp3 = copyexpr(sp->exp3);
return sp2;
} else
return NULL;
}
void nukestmt(sp)
Stmt *sp;
{
if (sp) {
sp->kind = SK_ASSIGN;
sp->exp1 = makeexpr_long(0);
}
}
void splicestmt(sp, spnew)
Stmt *sp, *spnew;
{
Stmt *snext;
if (spnew) {
snext = sp->next;
*sp = *spnew;
while (sp->next)
sp = sp->next;
sp->next = snext;
} else
nukestmt(sp);
}
int stmtcount(sp)
Stmt *sp;
{
int i = 0;
while (sp) {
i += 1 + stmtcount(sp->stm1) + stmtcount(sp->stm2);
sp = sp->next;
}
return i;
}
Stmt *close_files_to_ctx(ctx)
Meaning *ctx;
{
Meaning *ctx2, *mp;
Stmt *splist = NULL, *sp;
ctx2 = curctx;
while (ctx2 && ctx2 != ctx && ctx2->kind == MK_FUNCTION) {
for (mp = ctx2->cbase; mp; mp = mp->cnext) {
if (mp->kind == MK_VAR &&
isfiletype(mp->type, -1) && !mp->istemporary) {
var_reference(mp);
sp = makestmt_if(makeexpr_rel(EK_NE,
filebasename(makeexpr_var(mp)),
makeexpr_nil()),
makestmt_call(
makeexpr_bicall_1("fclose", tp_void,
filebasename(makeexpr_var(mp)))),
NULL);
splist = makestmt_seq(splist, sp);
}
}
ctx2 = ctx2->ctx;
}
return splist;
}
int simplewith(ex)
Expr *ex;
{
switch (ex->kind) {
case EK_VAR:
case EK_CONST:
return 1;
case EK_DOT:
return simplewith(ex->args[0]);
default:
return 0;
}
}
int simplefor(sp, ex)
Stmt *sp;
Expr *ex;
{
return (exprspeed(sp->exp2) <= 3 &&
!checkexprchanged(sp->stm1, sp->exp2) &&
!exproccurs(sp->exp2, ex));
}
int tryfuncmacro(exp, mp)
Expr **exp;
Meaning *mp;
{
char *name;
Strlist *lp;
Expr *ex = *exp, *ex2;
ex2 = (mp) ? mp->constdefn : NULL;
if (!ex2) {
if (ex->kind == EK_BICALL || ex->kind == EK_NAME)
name = ex->val.s;
else if (ex->kind == EK_FUNCTION)
name = ((Meaning *)ex->val.i)->name;
else
return 0;
lp = strlist_cifind(funcmacros, name);
ex2 = (lp) ? (Expr *)lp->value : NULL;
}
if (ex2) {
*exp = replacemacargs(copyexpr(ex2), ex);
freeexpr(ex);
return 1;
}
return 0;
}
#define addstmt(kind) \
*spp = sp = makestmt(kind), \
spp = &(sp->next)
#define newstmt(kind) \
addstmt(kind), \
steal_comments(firstserial, sp->serial, sflags & SF_FIRST), \
sflags &= ~SF_FIRST
#define SF_FUNC 0x1
#define SF_SAVESER 0x2
#define SF_FIRST 0x4
#define SF_IF 0x8
Static Stmt *p_stmt(slist, sflags)
Stmt *slist;
int sflags;
{
Stmt *sbase = NULL, **spp = &sbase, **spp2, **spp3, **savespp;
Stmt *defsp, **defsphook;
register Stmt *sp;
Stmt *sp2;
long li1, li2, firstserial = 0, saveserial = 0, saveserial2;
int i, forfixed, offset, line1, line2, toobig, isunsafe;
Token savetok;
char *name;
Expr *ep, *ep2, *ep3, *forstep, *range, *swexpr, *trueswexpr;
Type *tp;
Meaning *mp, *tvar, *tempmark;
Symbol *sym;
enum exprkind ekind;
Stmt *(*prochandler)();
Strlist *cmt;
tempmark = markstmttemps();
again:
while (findlabelsym()) {
newstmt(SK_LABEL);
sp->exp1 = makeexpr_name(format_s(name_LABEL, curtokmeaning->name), tp_integer);
gettok();
wneedtok(TOK_COLON);
}
firstserial = curserial;
checkkeyword(TOK_TRY);
checkkeyword(TOK_INLINE);
checkkeyword(TOK_LOOP);
checkkeyword(TOK_RETURN);
if (modula2) {
if (sflags & SF_SAVESER)
goto stmtSeq;
}
switch (curtok) {
case TOK_BEGIN:
stmtSeq:
if (sflags & (SF_FUNC|SF_SAVESER)) {
saveserial = curserial;
cmt = grabcomment(CMT_ONBEGIN);
if (sflags & SF_FUNC)
cmt = fixbeginendcomment(cmt);
strlist_mix(&curcomments, cmt);
}
i = sflags & SF_FIRST;
do {
if (modula2) {
if (curtok == TOK_BEGIN || curtok == TOK_SEMI)
gettok();
checkkeyword(TOK_ELSIF);
if (curtok == TOK_ELSE || curtok == TOK_ELSIF)
break;
} else
gettok();
*spp = p_stmt(sbase, i);
i = 0;
while (*spp)
spp = &((*spp)->next);
} while (curtok == TOK_SEMI);
if (sflags & (SF_FUNC|SF_SAVESER)) {
cmt = grabcomment(CMT_ONEND);
changecomments(cmt, -1, -1, -1, saveserial);
if (sflags & SF_FUNC)
cmt = fixbeginendcomment(cmt);
strlist_mix(&curcomments, cmt);
if (sflags & SF_FUNC)
changecomments(curcomments, -1, saveserial, -1, 10000);
curserial = saveserial;
}
checkkeyword(TOK_ELSIF);
if (modula2 && (sflags & SF_IF)) {
break;
}
if (curtok == TOK_VBAR)
break;
if (!wneedtok(TOK_END))
skippasttoken(TOK_END);
break;
case TOK_CASE:
gettok();
swexpr = trueswexpr = p_ord_expr();
if (nosideeffects(swexpr, 1)) {
tvar = NULL;
} else {
tvar = makestmttempvar(swexpr->val.type, name_TEMP);
swexpr = makeexpr_var(tvar);
}
savespp = spp;
newstmt(SK_CASE);
saveserial2 = curserial;
sp->exp1 = trueswexpr;
spp2 = &sp->stm1;
tp = swexpr->val.type;
defsp = NULL;
defsphook = &defsp;
if (!wneedtok(TOK_OF)) {
skippasttoken(TOK_END);
break;
}
i = 1;
while (curtok == TOK_VBAR)
gettok();
checkkeyword(TOK_OTHERWISE);
while (curtok != TOK_END && curtok != TOK_OTHERWISE && curtok != TOK_ELSE) {
spp3 = spp2;
saveserial = curserial;
*spp2 = sp = makestmt(SK_CASELABEL);
steal_comments(saveserial, sp->serial, i);
spp2 = &sp->next;
range = NULL;
toobig = 0;
for (;;) {
ep = gentle_cast(p_expr(tp), tp);
if (curtok == TOK_DOTS) {
li1 = ord_value(eval_expr(ep));
gettok();
ep2 = gentle_cast(p_expr(tp), tp);
li2 = ord_value(eval_expr(ep2));
range = makeexpr_or(range,
makeexpr_range(copyexpr(swexpr),
ep, ep2, 1));
if (li2 - li1 >= caselimit)
toobig = 1;
if (!toobig) {
for (;;) {
sp->exp1 = makeexpr_val(make_ord(tp, li1));
if (li1 >= li2) break;
li1++;
serialcount--; /* make it reuse the count */
sp->stm1 = makestmt(SK_CASELABEL);
sp = sp->stm1;
}
}
} else {
sp->exp1 = copyexpr(ep);
range = makeexpr_or(range,
makeexpr_rel(EK_EQ,
copyexpr(swexpr),
ep));
}
if (curtok == TOK_COMMA) {
gettok();
serialcount--; /* make it reuse the count */
sp->stm1 = makestmt(SK_CASELABEL);
sp = sp->stm1;
} else
break;
}
wneedtok(TOK_COLON);
if (toobig) {
free_stmt(*spp3);
spp2 = spp3;
*defsphook = makestmt_if(range, p_stmt(NULL, SF_SAVESER),
NULL);
if (defsphook != &defsp && elseif != 0)
(*defsphook)->exp2 = makeexpr_long(1);
defsphook = &((*defsphook)->stm2);
} else {
freeexpr(range);
sp->stm1 = p_stmt(NULL, SF_SAVESER);
}
i = 0;
checkkeyword(TOK_OTHERWISE);
if (curtok != TOK_END && curtok != TOK_OTHERWISE && curtok != TOK_ELSE) {
if (curtok == TOK_VBAR) {
while (curtok == TOK_VBAR)
gettok();
} else
wneedtok(TOK_SEMI);
checkkeyword(TOK_OTHERWISE);
}
}
if (defsp) {
*spp2 = defsp;
spp2 = defsphook;
if (tvar) {
sp = makestmt_assign(makeexpr_var(tvar), trueswexpr);
sp->next = *savespp;
*savespp = sp;
sp->next->exp1 = swexpr;
}
} else {
if (tvar) {
canceltempvar(tvar);
freeexpr(swexpr);
}
}
if (curtok == TOK_OTHERWISE || curtok == TOK_ELSE) {
gettok();
while (curtok == TOK_SEMI)
gettok();
/* changecomments(curcomments, CMT_TRAIL, curserial,
CMT_POST, -1); */
i = SF_FIRST;
while (curtok != TOK_END) {
*spp2 = p_stmt(NULL, i);
while (*spp2)
spp2 = &((*spp2)->next);
i = 0;
if (curtok != TOK_SEMI)
break;
gettok();
}
if (!wexpecttok(TOK_END))
skiptotoken(TOK_END);
} else if (casecheck == 1 || (casecheck == 2 && range_flag)) {
*spp2 = makestmt(SK_CASECHECK);
}
curserial = saveserial2;
strlist_mix(&curcomments, grabcomment(CMT_ONEND));
gettok();
break;
case TOK_FOR:
forfixed = fixedflag;
gettok();
newstmt(SK_FOR);
ep = p_expr(tp_integer);
if (!wneedtok(TOK_ASSIGN)) {
skippasttoken(TOK_DO);
break;
}
ep2 = makeexpr_charcast(p_expr(ep->val.type));
if (curtok != TOK_DOWNTO) {
if (!wexpecttok(TOK_TO)) {
skippasttoken(TOK_DO);
break;
}
}
savetok = curtok;
gettok();
sp->exp2 = makeexpr_charcast(p_expr(ep->val.type));
checkkeyword(TOK_BY);
if (curtok == TOK_BY) {
gettok();
forstep = p_expr(tp_integer);
i = possiblesigns(forstep);
if ((i & 5) == 5) {
if (expr_is_neg(forstep)) {
ekind = EK_GE;
note("Assuming FOR loop step is negative [252]");
} else {
ekind = EK_LE;
note("Assuming FOR loop step is positive [252]");
}
} else {
if (!(i & 1))
ekind = EK_LE;
else
ekind = EK_GE;
}
} else {
if (savetok == TOK_DOWNTO) {
ekind = EK_GE;
forstep = makeexpr_long(-1);
} else {
ekind = EK_LE;
forstep = makeexpr_long(1);
}
}
tvar = NULL;
swexpr = NULL;
if (ep->kind == EK_VAR) {
tp = findbasetype(ep->val.type, ODECL_NOPRES);
if ((tp == tp_char || tp == tp_schar || tp == tp_uchar ||
tp == tp_abyte || tp == tp_sbyte || tp == tp_ubyte ||
tp == tp_boolean) &&
((checkconst(sp->exp2, 0) &&
tp != tp_sbyte && tp != tp_schar) ||
checkconst(sp->exp2, -128) ||
(checkconst(sp->exp2, 127) &&
tp != tp_ubyte && tp != tp_uchar) ||
checkconst(sp->exp2, 255) ||
(tp == tp_char &&
(useAnyptrMacros == 1 || unsignedchar != 1) &&
isliteralconst(sp->exp2, NULL) == 2 &&
sp->exp2->val.i >= 128))) {
swexpr = ep;
tvar = makestmttempvar(tp_sshort, name_TEMP);
ep = makeexpr_var(tvar);
} else if (((tp == tp_sshort &&
(checkconst(sp->exp2, -32768) ||
checkconst(sp->exp2, 32767))) ||
(tp == tp_ushort &&
(checkconst(sp->exp2, 0) ||
checkconst(sp->exp2, 65535))))) {
swexpr = ep;
tvar = makestmttempvar(tp_integer, name_TEMP);
ep = makeexpr_var(tvar);
} else if (tp == tp_integer &&
(checkconst(sp->exp2, LONG_MAX) ||
(sp->exp2->kind == EK_VAR &&
sp->exp2->val.i == (long)mp_maxint))) {
swexpr = ep;
tvar = makestmttempvar(tp_unsigned, name_TEMP);
ep = makeexpr_var(tvar);
}
}
sp->exp3 = makeexpr_assign(copyexpr(ep),
makeexpr_inc(copyexpr(ep),
copyexpr(forstep)));
wneedtok(TOK_DO);
forfixed = (fixedflag != forfixed);
mp = makestmttempvar(ep->val.type, name_FOR);
sp->stm1 = p_stmt(NULL, SF_SAVESER);
if (tvar) {
if (checkexprchanged(sp->stm1, swexpr))
note(format_s("Rewritten FOR loop won't work if it meddles with %s [253]",
((Meaning *)swexpr->val.i)->name));
sp->stm1 = makestmt_seq(makestmt_assign(swexpr, makeexpr_var(tvar)),
sp->stm1);
} else if (offsetforloops && ep->kind == EK_VAR) {
offset = checkvaroffset(sp->stm1, (Meaning *)ep->val.i);
if (offset != 0) {
ep3 = makeexpr_inc(copyexpr(ep), makeexpr_long(-offset));
replaceexpr(sp->stm1, ep, ep3);
freeexpr(ep3);
ep2 = makeexpr_plus(ep2, makeexpr_long(offset));
sp->exp2 = makeexpr_inc(sp->exp2, makeexpr_long(offset));
}
}
if (!exprsame(ep, ep2, 1))
sp->exp1 = makeexpr_assign(copyexpr(ep), copyexpr(ep2));
isunsafe = ((!nodependencies(ep2, 2) &&
!nosideeffects(sp->exp2, 1)) ||
(!nodependencies(sp->exp2, 2) &&
!nosideeffects(ep2, 1)));
if (forfixed || (simplefor(sp, ep) && !isunsafe)) {
canceltempvar(mp);
sp->exp2 = makeexpr_rel(ekind, ep, sp->exp2);
} else {
ep3 = makeexpr_neg(copyexpr(forstep));
if ((checkconst(forstep, 1) || checkconst(forstep, -1)) &&
sp->exp2->kind == EK_PLUS &&
exprsame(sp->exp2->args[sp->exp2->nargs-1], ep3, 2)) {
sp->exp2 = makeexpr_inc(sp->exp2, forstep);
} else {
freeexpr(forstep);
freeexpr(ep3);
ep3 = makeexpr_long(0);
}
if (forevalorder && isunsafe) {
if (exprdepends(sp->exp2, ep)) {
tvar = makestmttempvar(mp->type, name_TEMP);
sp->exp1 = makeexpr_comma(
makeexpr_comma(
makeexpr_assign(makeexpr_var(tvar),
copyexpr(ep2)),
makeexpr_assign(makeexpr_var(mp),
sp->exp2)),
makeexpr_assign(copyexpr(ep),
makeexpr_var(tvar)));
} else
sp->exp1 = makeexpr_comma(
sp->exp1,
makeexpr_assign(makeexpr_var(mp),
sp->exp2));
} else {
if (isunsafe)
note("Evaluating FOR loop limit before initial value [315]");
sp->exp1 = makeexpr_comma(
makeexpr_assign(makeexpr_var(mp),
sp->exp2),
sp->exp1);
}
sp->exp2 = makeexpr_inc(makeexpr_var(mp), ep3);
sp->exp2 = makeexpr_rel(ekind, ep, sp->exp2);
}
freeexpr(ep2);
break;
case TOK_GOTO:
gettok();
if (findlabelsym()) {
if (curtokmeaning->ctx != curctx) {
curtokmeaning->val.i = 1;
*spp = close_files_to_ctx(curtokmeaning->ctx);
while (*spp)
spp = &((*spp)->next);
newstmt(SK_ASSIGN);
var_reference(curtokmeaning->xnext);
if (curtokmeaning->ctx->kind == MK_MODULE &&
!curtokmeaning->xnext->wasdeclared) {
outsection(minorspace);
declarevar(curtokmeaning->xnext, 0x7);
curtokmeaning->xnext->wasdeclared = 1;
outsection(minorspace);
}
sp->exp1 = makeexpr_bicall_2("longjmp", tp_void,
makeexpr_var(curtokmeaning->xnext),
makeexpr_long(1));
} else {
newstmt(SK_GOTO);
sp->exp1 = makeexpr_name(format_s(name_LABEL,
curtokmeaning->name),
tp_integer);
}
} else {
warning("Expected a label [263]");
}
gettok();
break;
case TOK_IF:
gettok();
newstmt(SK_IF);
saveserial = curserial;
curserial = ++serialcount;
sp->exp1 = p_expr(tp_boolean);
wneedtok(TOK_THEN);
sp->stm1 = p_stmt(NULL, SF_SAVESER|SF_IF);
changecomments(curcomments, -1, saveserial+1, -1, saveserial);
checkkeyword(TOK_ELSIF);
while (curtok == TOK_ELSIF) {
gettok();
sp->stm2 = makestmt(SK_IF);
sp = sp->stm2;
sp->exp1 = p_expr(tp_boolean);
wneedtok(TOK_THEN);
sp->stm1 = p_stmt(NULL, SF_SAVESER|SF_IF);
sp->exp2 = makeexpr_long(1);
}
if (curtok == TOK_ELSE) {
line1 = inf_lnum;
strlist_mix(&curcomments, grabcomment(CMT_ONELSE));
gettok();
line2 = (curtok == TOK_IF) ? inf_lnum : -1;
saveserial2 = curserial;
sp->stm2 = p_stmt(NULL, SF_SAVESER|SF_IF);
changecomments(curcomments, -1, saveserial2, -1, saveserial+1);
if (sp->stm2 && sp->stm2->kind == SK_IF &&
!sp->stm2->next && !modula2) {
sp->stm2->exp2 = makeexpr_long(elseif > 0 ||
(elseif < 0 && line1 == line2));
}
}
if (modula2)
wneedtok(TOK_END);
curserial = saveserial;
break;
case TOK_INLINE:
gettok();
note("Inline assembly language encountered [254]");
if (curtok != TOK_LPAR) { /* Macintosh style */
newstmt(SK_ASSIGN);
sp->exp1 = makeexpr_bicall_1("inline", tp_void,
p_expr(tp_integer));
break;
}
do {
name = getinlinepart();
if (!*name)
break;
newstmt(SK_ASSIGN);
sp->exp1 = makeexpr_bicall_1("asm", tp_void,
makeexpr_string(format_s(" inline %s", name)));
gettok();
} while (curtok == TOK_SLASH);
skipcloseparen();
break;
case TOK_LOOP:
gettok();
newstmt(SK_WHILE);
sp->exp1 = makeexpr_long(1);
sp->stm1 = p_stmt(NULL, SF_SAVESER);
break;
case TOK_REPEAT:
newstmt(SK_REPEAT);
saveserial = curserial;
spp2 = &(sp->stm1);
i = SF_FIRST;
do {
gettok();
*spp2 = p_stmt(sp->stm1, i);
i = 0;
while (*spp2)
spp2 = &((*spp2)->next);
} while (curtok == TOK_SEMI);
if (!wneedtok(TOK_UNTIL))
skippasttoken(TOK_UNTIL);
sp->exp1 = makeexpr_not(p_expr(tp_boolean));
curserial = saveserial;
strlist_mix(&curcomments, grabcomment(CMT_ONEND));
break;
case TOK_RETURN:
gettok();
newstmt(SK_RETURN);
if (curctx->isfunction) {
sp->exp1 = gentle_cast(p_expr(curctx->cbase->type),
curctx->cbase->type);
}
break;
case TOK_TRY:
findsymbol("RECOVER")->flags &= ~KWPOSS;
newstmt(SK_TRY);
sp->exp1 = makeexpr_long(++trycount);
spp2 = &(sp->stm1);
i = SF_FIRST;
do {
gettok();
*spp2 = p_stmt(sp->stm1, i);
i = 0;
while (*spp2)
spp2 = &((*spp2)->next);
} while (curtok == TOK_SEMI);
if (!wneedtok(TOK_RECOVER))
skippasttoken(TOK_RECOVER);
sp->stm2 = p_stmt(NULL, SF_SAVESER);
break;
case TOK_WHILE:
gettok();
newstmt(SK_WHILE);
sp->exp1 = p_expr(tp_boolean);
wneedtok(TOK_DO);
sp->stm1 = p_stmt(NULL, SF_SAVESER);
break;
case TOK_WITH:
gettok();
if (withlevel >= MAXWITHS-1)
error("Too many nested WITHs");
ep = p_expr(NULL);
if (ep->val.type->kind != TK_RECORD)
warning("Argument of WITH is not a RECORD [264]");
withlist[withlevel] = ep->val.type;
if (simplewith(ep)) {
withexprs[withlevel] = ep;
mp = NULL;
} else { /* need to save a temporary pointer */
tp = makepointertype(ep->val.type);
mp = makestmttempvar(tp, name_WITH);
withexprs[withlevel] = makeexpr_hat(makeexpr_var(mp), 0);
}
withlevel++;
if (curtok == TOK_COMMA) {
curtok = TOK_WITH;
sp2 = p_stmt(NULL, sflags & SF_FIRST);
} else {
wneedtok(TOK_DO);
sp2 = p_stmt(NULL, sflags & SF_FIRST);
}
withlevel--;
if (mp) { /* if "with p^" for constant p, don't need temp ptr */
if (ep->kind == EK_HAT && ep->args[0]->kind == EK_VAR &&
!checkvarchanged(sp2, (Meaning *)ep->args[0]->val.i)) {
replaceexpr(sp2, withexprs[withlevel]->args[0],
ep->args[0]);
freeexpr(ep);
canceltempvar(mp);
} else {
newstmt(SK_ASSIGN);
sp->exp1 = makeexpr_assign(makeexpr_var(mp),
makeexpr_addr(ep));
}
}
freeexpr(withexprs[withlevel]);
*spp = sp2;
while (*spp)
spp = &((*spp)->next);
break;
case TOK_INCLUDE:
badinclude();
goto again;
case TOK_ADDR: /* flakey Turbo "@procptr := anyptr" assignment */
newstmt(SK_ASSIGN);
ep = p_expr(tp_void);
if (wneedtok(TOK_ASSIGN))
sp->exp1 = makeexpr_assign(ep, p_expr(ep->val.type));
else
sp->exp1 = ep;
break;
case TOK_IDENT:
mp = curtokmeaning;
if (mp == mp_str_hp)
mp = curtokmeaning = mp_str_turbo;
if (mp == mp_val_modula)
mp = curtokmeaning = mp_val_turbo;
if (mp == mp_blockread_ucsd)
mp = curtokmeaning = mp_blockread_turbo;
if (mp == mp_blockwrite_ucsd)
mp = curtokmeaning = mp_blockwrite_turbo;
if (mp == mp_dec_dec)
mp = curtokmeaning = mp_dec_turbo;
if (!mp) {
sym = curtoksym; /* make a guess at what the undefined name is... */
name = stralloc(curtokcase);
gettok();
newstmt(SK_ASSIGN);
if (curtok == TOK_ASSIGN) {
gettok();
ep = p_expr(NULL);
mp = addmeaning(sym, MK_VAR);
mp->name = name;
mp->type = ep->val.type;
sp->exp1 = makeexpr_assign(makeexpr_var(mp), ep);
} else if (curtok == TOK_HAT || curtok == TOK_ADDR ||
curtok == TOK_LBR || curtok == TOK_DOT) {
ep = makeexpr_name(name, tp_integer);
ep = fake_dots_n_hats(ep);
if (wneedtok(TOK_ASSIGN))
sp->exp1 = makeexpr_assign(ep, p_expr(NULL));
else
sp->exp1 = ep;
} else if (curtok == TOK_LPAR) {
ep = makeexpr_bicall_0(name, tp_void);
do {
gettok();
insertarg(&ep, ep->nargs, p_expr(NULL));
} while (curtok == TOK_COMMA);
skipcloseparen();
sp->exp1 = ep;
} else {
sp->exp1 = makeexpr_bicall_0(name, tp_void);
}
if (!tryfuncmacro(&sp->exp1, NULL))
undefsym(sym);
} else if (mp->kind == MK_FUNCTION && !mp->isfunction) {
mp->refcount++;
gettok();
ep = p_funccall(mp);
if (!mp->constdefn)
need_forward_decl(mp);
if (mp->handler && !(mp->sym->flags & LEAVEALONE) &&
!mp->constdefn) {
prochandler = (Stmt *(*)())mp->handler;
*spp = (*prochandler)(ep, slist);
while (*spp)
spp = &((*spp)->next);
} else {
newstmt(SK_ASSIGN);
sp->exp1 = ep;
}
} else if (mp->kind == MK_SPECIAL) {
gettok();
if (mp->handler && !mp->isfunction) {
if ((mp->sym->flags & LEAVEALONE) || mp->constdefn) {
ep = makeexpr_bicall_0(mp->name, tp_void);
if (curtok == TOK_LPAR) {
do {
gettok();
insertarg(&ep, ep->nargs, p_expr(NULL));
} while (curtok == TOK_COMMA);
skipcloseparen();
}
newstmt(SK_ASSIGN);
tryfuncmacro(&ep, mp);
sp->exp1 = ep;
} else {
prochandler = (Stmt *(*)())mp->handler;
*spp = (*prochandler)(mp, slist);
while (*spp)
spp = &((*spp)->next);
}
} else
symclass(curtoksym);
} else {
newstmt(SK_ASSIGN);
if (curtokmeaning->kind == MK_FUNCTION &&
peeknextchar() != '(') {
mp = curctx;
while (mp && mp != curtokmeaning)
mp = mp->ctx;
if (mp)
curtokmeaning = curtokmeaning->cbase;
}
ep = p_expr(tp_void);
#if 0
if (!(ep->kind == EK_SPCALL ||
(ep->kind == EK_COND &&
ep->args[1]->kind == EK_SPCALL)))
wexpecttok(TOK_ASSIGN);
#endif
if (curtok == TOK_ASSIGN) {
gettok();
if (curtok == TOK_IDENT && !strcicmp(curtokbuf, "ZERO") &&
!curtokmeaning) { /* VAX Pascal foolishness */
gettok();
ep2 = makeexpr_sizeof(copyexpr(ep), 0);
sp->exp1 = makeexpr_bicall_3("memset", tp_void,
makeexpr_addr(ep),
makeexpr_long(0), ep2);
} else
sp->exp1 = makeexpr_assign(ep, p_expr(ep->val.type));
} else
sp->exp1 = ep;
}
break;
default:
break; /* null statement */
}
freestmttemps(tempmark);
if (sflags & SF_SAVESER)
curserial = firstserial;
return sbase;
}
#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 */
Static int usebraces(sp, opts)
Stmt *sp;
int opts;
{
if (opts & (BR_FUNCTION|BR_ALWAYS))
return 1;
if (opts & BR_NEVER)
return 0;
switch (bracesalways) {
case 0:
if (sp) {
if (sp->next ||
sp->kind == SK_TRY ||
(sp->kind == SK_IF && !sp->stm2) ||
(opts & BR_REPEAT))
return 1;
}
break;
case 1:
return 1;
default:
if (sp) {
if (sp->next ||
sp->kind == SK_IF ||
sp->kind == SK_WHILE ||
sp->kind == SK_REPEAT ||
sp->kind == SK_TRY ||
sp->kind == SK_CASE ||
sp->kind == SK_FOR)
return 1;
}
break;
}
if (sp != NULL &&
findcomment(curcomments, CMT_NOT | CMT_TRAIL, sp->serial) != NULL)
return 1;
return 0;
}
#define outspnl(spflag) output((spflag) ? " " : "\n")
#define openbrace() \
wbraces = (!candeclare); \
if (wbraces) { \
output("{"); \
outspnl(braceline <= 0); \
candeclare = 1; \
}
#define closebrace() \
if (wbraces) { \
if (sp->next || braces) \
output("}\n"); \
else \
braces = 1; \
}
Meaning *outcontext;
Static void outnl(serial)
int serial;
{
outtrailcomment(curcomments, serial, commentindent);
}
Static void out_block(spbase, opts, serial)
Stmt *spbase;
int opts, serial;
{
int i, j, braces, always, trynum, istrail, hascmt;
int gotcomments = 0;
int saveindent, saveindent2, delta;
Stmt *sp = spbase;
Stmt *sp2, *sp3;
Meaning *ctx, *mp;
Strlist *curcmt, *cmt, *savecurcmt = curcomments;
Strlist *trailcmt, *begincmt, *endcmt;
if (debug>1) { fprintf(outf, "out_block of:\n"); dumpstmt(spbase,5); }
if (opts & BR_FUNCTION) {
if (outcontext && outcontext->comments) {
gotcomments = 1;
curcomments = outcontext->comments;
}
attach_comments(spbase);
}
braces = usebraces(sp, opts);
trailcmt = findcomment(curcomments, CMT_TRAIL, serial);
begincmt = findcomment(curcomments, CMT_ONBEGIN, serial);
istrail = 1;
if (!trailcmt) {
trailcmt = begincmt;
begincmt = NULL;
istrail = 0;
}
endcmt = findcomment(curcomments, CMT_ONEND, serial);
if ((begincmt || endcmt) && !(opts & BR_NEVER))
braces = 1;
if (opts & BR_ELSEPART) {
cmt = findcomment(curcomments, CMT_ONELSE, serial);
if (cmt) {
if (trailcmt) {
out_spaces(bracecommentindent, commentoverindent,
commentlen(cmt), 0);
output("\001");
outcomment(cmt);
} else
trailcmt = cmt;
}
}
if (braces) {
j = (opts & BR_FUNCTION) ? funcopenindent : openbraceindent;
if (!line_start()) {
if (trailcmt &&
cur_column() + commentlen(trailcmt) + 2 > linewidth &&
outindent + commentlen(trailcmt) + 2 < linewidth) /*close enough*/
i = 0;
else if (opts & BR_ELSEPART)
i = ((braceelseline & 2) == 0);
else if (braceline >= 0)
i = (braceline == 0);
else
i = ((opts & BR_FUNCTION) == 0);
if (trailcmt && begincmt) {
out_spaces(commentindent, commentoverindent,
commentlen(trailcmt), j);
outcomment(trailcmt);
trailcmt = begincmt;
begincmt = NULL;
istrail = 0;
} else
outspnl(i);
}
if (line_start())
singleindent(j);
output("{");
candeclare = 1;
} else if (!sp) {
if (!line_start())
outspnl(!nullstmtline && !(opts & BR_TRY));
if (line_start())
singleindent(tabsize);
output(";");
}
if (opts & BR_CASE)
delta = 0;
else {
delta = tabsize;
if (opts & BR_FUNCTION)
delta = adddeltas(delta, bodyindent);
else if (braces)
delta = adddeltas(delta, blockindent);
}
futureindent(delta);
if (bracecombine && braces)
i = applydelta(outindent, delta) - cur_column();
else
i = -1;
if (commentvisible(trailcmt)) {
if (line_start()) {
singleindent(delta);
out_spaces(commentoverindent, 1000, commentlen(trailcmt), 0);
outcomment(trailcmt);
} else /*if (commentlen(trailcmt) + cur_column() + 1 <= linewidth)*/ {
out_spaces(istrail ? commentindent : bracecommentindent,
commentoverindent, commentlen(trailcmt), delta);
outcomment(trailcmt);
} /*else {
output("\n");
singleindent(delta);
out_spaces(commentoverindent, 1000, commentlen(trailcmt), 0);
outcomment(trailcmt);
}*/
i = -9999;
}
if (i > 0)
out_spaces(i, 0, 0, 0);
else if (i != -9999)
output("\n");
saveindent = outindent;
moreindent(delta);
outcomment(begincmt);
while (sp) {
flushcomments(NULL, CMT_PRE, sp->serial);
if (cmtdebug)
output(format_d("[%d] ", sp->serial));
switch (sp->kind) {
case SK_HEADER:
ctx = (Meaning *)sp->exp1->val.i;
eatblanklines();
if (declarevars(ctx, 0))
outsection(minorspace);
flushcomments(NULL, CMT_NOT | CMT_ONEND, serial);
if (ctx->kind == MK_MODULE) {
if (ctx->anyvarflag) {
output(format_s(name_MAIN, ""));
if (spacefuncs)
output(" ");
output("(argc,");
if (spacecommas)
output(" ");
output("argv);\n");
} else {
output("static int _was_initialized = 0;\n");
output("if (_was_initialized++)\n");
singleindent(tabsize);
output("return;\n");
}
while (initialcalls) {
output(initialcalls->s);
output(";\n");
strlist_remove(&initialcalls, initialcalls->s);
}
} else {
if (ctx->varstructflag && ctx->ctx->kind == MK_FUNCTION &&
ctx->ctx->varstructflag) {
output(format_s(name_VARS, ctx->name));
output(".");
output(format_s(name_LINK, ctx->ctx->name));
output(" = ");
output(format_s(name_LINK, ctx->ctx->name));
output(";\n");
}
for (mp = ctx->cbase; mp; mp = mp->cnext) {
if ((mp->kind == MK_VAR || /* these are variables with */
mp->kind == MK_VARREF) &&
((mp->varstructflag && /* initializers which were moved */
mp->cnext && /* into a varstruct, so they */
mp->cnext->snext == mp && /* must be initialized now */
mp->cnext->constdefn &&
ctx->kind == MK_FUNCTION) ||
(mp->constdefn &&
mp->type->kind == TK_ARRAY &&
mp->constdefn->val.type->kind == TK_STRING &&
!initpacstrings))) {
if (mp->type->kind == TK_ARRAY) {
output("memcpy(");
out_var(mp, 2);
output(",\002");
if (spacecommas)
output(" ");
if (mp->constdefn) {
output(makeCstring(mp->constdefn->val.s,
mp->constdefn->val.i));
mp->constdefn = NULL;
} else
out_var(mp->cnext, 2);
output(",\002");
if (spacecommas)
output(" ");
output("sizeof(");
out_type(mp->type, 1);
output("))");
} else {
out_var(mp, 2);
output(" = ");
out_var(mp->cnext, 2);
}
output(";\n");
}
}
}
break;
case SK_RETURN:
output("return");
if (sp->exp1) {
switch (returnparens) {
case 0:
output(" ");
out_expr(sp->exp1);
break;
case 1:
if (spaceexprs != 0)
output(" ");
out_expr_parens(sp->exp1);
break;
default:
if (sp->exp1->kind == EK_VAR ||
sp->exp1->kind == EK_CONST ||
sp->exp1->kind == EK_LONGCONST ||
sp->exp1->kind == EK_BICALL) {
output(" ");
out_expr(sp->exp1);
} else {
if (spaceexprs != 0)
output(" ");
out_expr_parens(sp->exp1);
}
break;
}
}
output(";");
outnl(sp->serial);
break;
case SK_ASSIGN:
out_expr_stmt(sp->exp1);
output(";");
outnl(sp->serial);
break;
case SK_CASE:
output("switch (");
out_expr(sp->exp1);
output(")");
outspnl(braceline <= 0);
output("{");
outnl(sp->serial);
saveindent2 = outindent;
moreindent(tabsize);
moreindent(switchindent);
sp2 = sp->stm1;
while (sp2 && sp2->kind == SK_CASELABEL) {
outsection(casespacing);
sp3 = sp2;
i = 0;
hascmt = (findcomment(curcomments, -1, sp2->serial) != NULL);
singleindent(caseindent);
flushcomments(NULL, CMT_PRE, sp2->serial);
for (;;) {
if (i)
singleindent(caseindent);
i = 0;
output("case ");
out_expr(sp3->exp1);
output(":\001");
sp3 = sp3->stm1;
if (!sp3 || sp3->kind != SK_CASELABEL)
break;
if (casetabs != 1000)
out_spaces(casetabs, 0, 0, 0);
else {
output("\n");
i = 1;
}
}
if (sp3)
out_block(sp3, BR_NEVER|BR_CASE, sp2->serial);
else {
outnl(sp2->serial);
if (!hascmt)
output("/* blank case */\n");
}
output("break;\n");
flushcomments(NULL, -1, sp2->serial);
sp2 = sp2->next;
}
if (sp2) {
outsection(casespacing);
singleindent(caseindent);
flushcomments(NULL, CMT_PRE, sp2->serial);
output("default:");
out_block(sp2, BR_NEVER|BR_CASE, sp2->serial);
output("break;\n");
flushcomments(NULL, -1, sp2->serial);
}
outindent = saveindent2;
output("}");
curcmt = findcomment(curcomments, CMT_ONEND, sp->serial);
if (curcmt)
outcomment(curcmt);
else
output("\n");
break;
case SK_CASECHECK:
output(name_CASECHECK);
output("(); /* CASE value range error */\n");
break;
case SK_FOR:
output("for (");
if (for_allornone)
output("\007");
if (sp->exp1 || sp->exp2 || sp->exp3 || spaceexprs > 0) {
if (sp->exp1)
out_expr_top(sp->exp1);
else if (spaceexprs > 0)
output(" ");
output(";\002 ");
if (sp->exp2)
out_expr(sp->exp2);
output(";\002 ");
if (sp->exp3)
out_expr_top(sp->exp3);
} else {
output(";;");
}
output(")");
out_block(sp->stm1, 0, sp->serial);
break;
case SK_LABEL:
if (!line_start())
output("\n");
singleindent(labelindent);
out_expr(sp->exp1);
output(":");
if (!sp->next)
output(" ;");
outnl(sp->serial);
break;
case SK_GOTO:
/* what about non-local goto's? */
output("goto ");
out_expr(sp->exp1);
output(";");
outnl(sp->serial);
break;
case SK_IF:
sp2 = sp;
for (;;) {
output("if (");
out_expr_bool(sp2->exp1);
output(")");
if (sp2->stm2) {
cmt = findcomment(curcomments, CMT_ONELSE, sp->serial+1);
i = (!cmt && sp2->stm2->kind == SK_IF &&
!sp2->stm2->next &&
((sp2->stm2->exp2)
? checkconst(sp2->stm2->exp2, 1)
: (elseif > 0)));
if (braceelse &&
(usebraces(sp2->stm1, 0) ||
usebraces(sp2->stm2, 0) || i))
always = BR_ALWAYS;
else
always = 0;
out_block(sp2->stm1, BR_THENPART|always, sp->serial);
output("else");
sp2 = sp2->stm2;
if (i) {
output(" ");
} else {
out_block(sp2, BR_ELSEPART|always, sp->serial+1);
break;
}
} else {
out_block(sp2->stm1, 0, sp->serial);
break;
}
}
break;
case SK_REPEAT:
output("do");
out_block(sp->stm1, BR_ALWAYS|BR_REPEAT, sp->serial);
output("while (");
out_expr_bool(sp->exp1);
output(");");
cmt = findcomment(curcomments, CMT_ONEND, sp->serial);
if (commentvisible(cmt)) {
out_spaces(commentindent, commentoverindent,
commentlen(cmt), 0);
output("\001");
outcomment(cmt);
} else
output("\n");
break;
case SK_TRY:
trynum = sp->exp1->val.i;
output(format_d("TRY(try%d);", trynum));
out_block(sp->stm1, BR_NEVER|BR_TRY, sp->serial);
if (sp->exp2)
output(format_ds("RECOVER2(try%d,%s);", trynum,
format_s(name_LABEL, format_d("try%d", trynum))));
else
output(format_d("RECOVER(try%d);", trynum));
out_block(sp->stm2, BR_NEVER|BR_TRY, sp->serial);
output(format_d("ENDTRY(try%d);\n", trynum));
break;
case SK_WHILE:
output("while (");
out_expr_bool(sp->exp1);
output(")");
out_block(sp->stm1, 0, sp->serial);
break;
case SK_BREAK:
output("break;");
outnl(sp->serial);
break;
case SK_CONTINUE:
output("continue;");
outnl(sp->serial);
break;
default:
intwarning("out_block",
format_s("Misplaced statement kind %s [265]",
stmtkindname(sp->kind)));
break;
}
flushcomments(NULL, -1, sp->serial);
candeclare = 0;
if (debug>1) { fprintf(outf, "in out_block:\n"); dumpstmt(spbase,5); }
sp = sp->next;
}
if (opts & BR_FUNCTION) {
cmt = extractcomment(&curcomments, CMT_ONEND, serial);
if (findcomment(curcomments, -1, -1) != NULL) /* check for non-DONE */
output("\n");
flushcomments(NULL, -1, -1);
curcomments = cmt;
}
outindent = saveindent;
if (braces) {
if (line_start()) {
if (opts & BR_FUNCTION)
singleindent(funccloseindent);
else
singleindent(closebraceindent);
}
output("}");
i = 1;
cmt = findcomment(curcomments, CMT_ONEND, serial);
if (!(opts & BR_REPEAT) && commentvisible(cmt)) {
out_spaces(bracecommentindent, commentoverindent,
commentlen(cmt), 0);
output("\001");
outcomment(cmt);
i = 0;
}
if (i) {
outspnl((opts & BR_REPEAT) ||
((opts & BR_THENPART) && (braceelseline & 1) == 0));
}
candeclare = 0;
}
if (gotcomments) {
outcontext->comments = curcomments;
curcomments = savecurcmt;
}
}
/* Should have a way to convert GOTO's to the end of the function to RETURN's */
/* Convert "_RETV = foo;" at end of function to "return foo" */
Static int checkreturns(spp, nearret)
Stmt **spp;
int nearret;
{
Stmt *sp;
Expr *rvar, *ex;
Meaning *mp;
int spnearret, spnextreturn;
int result = 0;
if (debug>2) { fprintf(outf, "checkreturns on:\n"); dumpstmt(*spp, 5); }
while ((sp = *spp)) {
spnextreturn = (sp->next &&
sp->next->kind == SK_RETURN && sp->next->exp1 &&
isretvar(sp->next->exp1) == curctx->cbase);
spnearret = (nearret && !sp->next) || spnextreturn;
result = 0;
switch (sp->kind) {
case SK_ASSIGN:
ex = sp->exp1;
if (ex->kind == EK_ASSIGN || structuredfunc(ex)) {
rvar = ex->args[0];
mp = isretvar(rvar);
if (mp == curctx->cbase && spnearret) {
if (ex->kind == EK_ASSIGN) {
if (mp->kind == MK_VARPARAM) {
ex = makeexpr_comma(ex, makeexpr_var(mp));
} else {
ex = grabarg(ex, 1);
mp->refcount--;
}
}
sp->exp1 = ex;
sp->kind = SK_RETURN;
if (spnextreturn) {
mp->refcount--;
sp->next = sp->next->next;
}
result = 1;
}
}
break;
case SK_RETURN:
case SK_GOTO:
result = 1;
break;
case SK_IF:
result = checkreturns(&sp->stm1, spnearret) & /* NOT && */
checkreturns(&sp->stm2, spnearret);
break;
case SK_TRY:
(void) checkreturns(&sp->stm1, 0);
(void) checkreturns(&sp->stm2, spnearret);
break;
/* should handle CASE statements as well */
default:
(void) checkreturns(&sp->stm1, 0);
(void) checkreturns(&sp->stm2, 0);
break;
}
spp = &sp->next;
}
return result;
}
/* Replace all occurrences of one expression with another expression */
Expr *replaceexprexpr(ex, oldex, newex, keeptype)
Expr *ex, *oldex, *newex;
int keeptype;
{
int i;
Type *type;
for (i = 0; i < ex->nargs; i++)
ex->args[i] = replaceexprexpr(ex->args[i], oldex, newex, keeptype);
if (exprsame(ex, oldex, 2)) {
if (ex->val.type->kind == TK_POINTER &&
ex->val.type->basetype == oldex->val.type) {
freeexpr(ex);
return makeexpr_addr(copyexpr(newex));
} else if (oldex->val.type->kind == TK_POINTER &&
oldex->val.type->basetype == ex->val.type) {
freeexpr(ex);
return makeexpr_hat(copyexpr(newex), 0);
} else {
type = ex->val.type;
freeexpr(ex);
ex = copyexpr(newex);
if (keeptype)
ex->val.type = type;
return ex;
}
}
return resimplify(ex);
}
void replaceexpr(sp, oldex, newex)
Stmt *sp;
Expr *oldex, *newex;
{
while (sp) {
replaceexpr(sp->stm1, oldex, newex);
replaceexpr(sp->stm2, oldex, newex);
if (sp->exp1)
sp->exp1 = replaceexprexpr(sp->exp1, oldex, newex, 1);
if (sp->exp2)
sp->exp2 = replaceexprexpr(sp->exp2, oldex, newex, 1);
if (sp->exp3)
sp->exp3 = replaceexprexpr(sp->exp3, oldex, newex, 1);
sp = sp->next;
}
}
Stmt *mixassignments(sp, mp)
Stmt *sp;
Meaning *mp;
{
if (!sp)
return NULL;
sp->next = mixassignments(sp->next, mp);
if (sp->next &&
sp->kind == SK_ASSIGN &&
sp->exp1->kind == EK_ASSIGN &&
sp->exp1->args[0]->kind == EK_VAR &&
(!mp || mp == (Meaning *)sp->exp1->args[0]->val.i) &&
ord_type(sp->exp1->args[0]->val.type)->kind == TK_INTEGER &&
nodependencies(sp->exp1->args[1], 0) &&
sp->next->kind == SK_ASSIGN &&
sp->next->exp1->kind == EK_ASSIGN &&
(exprsame(sp->exp1->args[0], sp->next->exp1->args[0], 1) ||
(mp && mp->istemporary)) &&
exproccurs(sp->next->exp1->args[1], sp->exp1->args[0]) == 1) {
sp->next->exp1->args[1] = replaceexprexpr(sp->next->exp1->args[1],
sp->exp1->args[0],
sp->exp1->args[1], 1);
if (mp && mp->istemporary)
canceltempvar(mp);
return sp->next;
}
return sp;
}
/* Do various simple (sometimes necessary) massages on the statements */
Static Stmt bogusreturn = { SK_RETURN, NULL, NULL, NULL, NULL, NULL, NULL };
Static int isescape(ex)
Expr *ex;
{
if (ex->kind == EK_BICALL && (!strcmp(ex->val.s, name_ESCAPE) ||
!strcmp(ex->val.s, name_ESCIO) ||
!strcmp(ex->val.s, name_OUTMEM) ||
!strcmp(ex->val.s, name_CASECHECK) ||
!strcmp(ex->val.s, name_NILCHECK) ||
!strcmp(ex->val.s, "_exit") ||
!strcmp(ex->val.s, "exit")))
return 1;
if (ex->kind == EK_CAST)
return isescape(ex->args[0]);
return 0;
}
/* check if a block can never exit by falling off the end */
Static int deadendblock(sp)
Stmt *sp;
{
if (!sp)
return 0;
while (sp->next)
sp = sp->next;
return (sp->kind == SK_GOTO ||
sp->kind == SK_BREAK ||
sp->kind == SK_CONTINUE ||
sp->kind == SK_RETURN ||
sp->kind == SK_CASECHECK ||
(sp->kind == SK_IF && deadendblock(sp->stm1) &&
deadendblock(sp->stm2)) ||
(sp->kind == SK_ASSIGN && isescape(sp->exp1)));
}
int expr_is_bool(ex, want)
Expr *ex;
int want;
{
long val;
if (ex->val.type == tp_boolean && isconstexpr(ex, &val))
return (val == want);
return 0;
}
/* Returns 1 if c1 implies c2, 0 otherwise */
/* If not1 is true, then checks if (!c1) implies c2; similarly for not2 */
/* Identities used:
c1 -> (c2a && c2b) <=> (c1 -> c2a) && (c1 -> c2b)
c1 -> (c2a || c2b) <=> (c1 -> c2a) || (c1 -> c2b)
(c1a && c1b) -> c2 <=> (c1a -> c2) || (c1b -> c2)
(c1a || c1b) -> c2 <=> (c1a -> c2) && (c1b -> c2)
(!c1) -> (!c2) <=> c2 -> c1
(a == b) -> c2(b) <=> c2(a)
!(c1 && c2) <=> (!c1) || (!c2)
!(c1 || c2) <=> (!c1) && (!c2)
*/
/* This could be smarter about, e.g., (a>5) -> (a>0) */
int implies(c1, c2, not1, not2)
Expr *c1, *c2;
int not1, not2;
{
Expr *ex;
int i;
if (c1->kind == EK_EQ && c1->args[0]->val.type == tp_boolean) {
if (checkconst(c1->args[0], 1)) { /* things like "flag = true" */
return implies(c1->args[1], c2, not1, not2);
} else if (checkconst(c1->args[1], 1)) {
return implies(c1->args[0], c2, not1, not2);
} else if (checkconst(c1->args[0], 0)) {
return implies(c1->args[1], c2, !not1, not2);
} else if (checkconst(c1->args[1], 0)) {
return implies(c1->args[0], c2, !not1, not2);
}
}
if (c2->kind == EK_EQ && c2->args[0]->val.type == tp_boolean) {
if (checkconst(c2->args[0], 1)) {
return implies(c1, c2->args[1], not1, not2);
} else if (checkconst(c2->args[1], 1)) {
return implies(c1, c2->args[0], not1, not2);
} else if (checkconst(c2->args[0], 0)) {
return implies(c1, c2->args[1], not1, !not2);
} else if (checkconst(c2->args[1], 0)) {
return implies(c1, c2->args[0], not1, !not2);
}
}
switch (c2->kind) {
case EK_AND:
if (not2) /* c1 -> (!c2a || !c2b) */
return (implies(c1, c2->args[0], not1, 1) ||
implies(c1, c2->args[1], not1, 1));
else /* c1 -> (c2a && c2b) */
return (implies(c1, c2->args[0], not1, 0) &&
implies(c1, c2->args[1], not1, 0));
case EK_OR:
if (not2) /* c1 -> (!c2a && !c2b) */
return (implies(c1, c2->args[0], not1, 1) &&
implies(c1, c2->args[1], not1, 1));
else /* c1 -> (c2a || c2b) */
return (implies(c1, c2->args[0], not1, 0) ||
implies(c1, c2->args[1], not1, 0));
case EK_NOT: /* c1 -> (!c2) */
return (implies(c1, c2->args[0], not1, !not2));
case EK_CONST:
if ((c2->val.i != 0) != not2) /* c1 -> true */
return 1;
break;
default:
break;
}
switch (c1->kind) {
case EK_AND:
if (not1) /* (!c1a || !c1b) -> c2 */
return (implies(c1->args[0], c2, 1, not2) &&
implies(c1->args[1], c2, 1, not2));
else /* (c1a && c1b) -> c2 */
return (implies(c1->args[0], c2, 0, not2) ||
implies(c1->args[1], c2, 0, not2));
case EK_OR:
if (not1) /* (!c1a && !c1b) -> c2 */
return (implies(c1->args[0], c2, 1, not2) ||
implies(c1->args[1], c2, 1, not2));
else /* (c1a || c1b) -> c2 */
return (implies(c1->args[0], c2, 0, not2) &&
implies(c1->args[1], c2, 0, not2));
case EK_NOT: /* (!c1) -> c2 */
return (implies(c1->args[0], c2, !not1, not2));
case EK_CONST:
if ((c1->val.i != 0) == not1) /* false -> c2 */
return 1;
break;
case EK_EQ: /* (a=b) -> c2 */
case EK_ASSIGN: /* (a:=b) -> c2 */
case EK_NE: /* (a<>b) -> c2 */
if ((c1->kind == EK_NE) == not1) {
if (c1->args[0]->kind == EK_VAR) {
ex = replaceexprexpr(copyexpr(c2), c1->args[0], c1->args[1], 1);
i = expr_is_bool(ex, !not2);
freeexpr(ex);
if (i)
return 1;
}
if (c1->args[1]->kind == EK_VAR) {
ex = replaceexprexpr(copyexpr(c2), c1->args[1], c1->args[0], 1);
i = expr_is_bool(ex, !not2);
freeexpr(ex);
if (i)
return 1;
}
}
break;
default:
break;
}
if (not1 == not2 && exprequiv(c1, c2)) { /* c1 -> c1 */
return 1;
}
return 0;
}
void infiniteloop(sp)
Stmt *sp;
{
switch (infloopstyle) {
case 1: /* write "for (;;) ..." */
sp->kind = SK_FOR;
freeexpr(sp->exp1);
sp->exp1 = NULL;
break;
case 2: /* write "while (1) ..." */
sp->kind = SK_WHILE;
freeexpr(sp->exp1);
sp->exp1 = makeexpr_val(make_ord(tp_boolean, 1));
break;
case 3: /* write "do ... while (1)" */
sp->kind = SK_REPEAT;
freeexpr(sp->exp1);
sp->exp1 = makeexpr_val(make_ord(tp_boolean, 1));
break;
default: /* leave it alone */
break;
}
}
Expr *print_func(ex)
Expr *ex;
{
if (!ex || ex->kind != EK_BICALL)
return NULL;
if ((!strcmp(ex->val.s, "printf") &&
ex->args[0]->kind == EK_CONST) ||
!strcmp(ex->val.s, "putchar") ||
!strcmp(ex->val.s, "puts"))
return ex_output;
if ((!strcmp(ex->val.s, "fprintf") ||
!strcmp(ex->val.s, "sprintf")) &&
ex->args[1]->kind == EK_CONST)
return ex->args[0];
if (!strcmp(ex->val.s, "putc") ||
!strcmp(ex->val.s, "fputc") ||
!strcmp(ex->val.s, "fputs"))
return ex->args[1];
return NULL;
}
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;
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,
filebasetype(sp->exp1->args[1]->args[0]->val.type)) &&
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)) &&
!fileisbuffered(sp->exp1->args[0], 0)) {
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);
if (elimdeadcode > 1 && checkconst(sp->exp1, 0)) {
note("Eliminated \"if false\" statement [326]");
splicestmt(sp, sp->stm2);
continue;
} else if (elimdeadcode > 1 && checkconst(sp->exp1, 1)) {
note("Eliminated \"if true\" statement [327]");
splicestmt(sp, sp->stm1);
continue;
}
break;
case SK_WHILE:
if (whilefgets && /* handle "while eof(f) do readln(f,...)" */
sp->stm1 &&
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;
}
Expr *initfilevar(ex)
Expr *ex;
{
Expr *ex2;
Meaning *mp;
char *name;
if (ex->val.type->kind == TK_BIGFILE) {
ex2 = copyexpr(ex);
if (ex->kind == EK_VAR &&
(mp = (Meaning *)ex->val.i)->kind == MK_VAR &&
mp->ctx->kind != MK_FUNCTION &&
!is_std_file(ex) &&
literalfilesflag > 0 &&
(literalfilesflag == 1 ||
strlist_cifind(literalfiles, mp->name)))
name = mp->name;
else
name = "";
return makeexpr_comma(makeexpr_assign(filebasename(ex),
makeexpr_nil()),
makeexpr_assign(makeexpr_dotq(ex2, "name",
tp_str255),
makeexpr_string(name)));
} else {
return makeexpr_assign(ex, makeexpr_nil());
}
}
void initfilevars(mp, sppp, exbase)
Meaning *mp;
Stmt ***sppp;
Expr *exbase;
{
Stmt *sp;
Type *tp;
Expr *ex;
while (mp) {
if ((mp->kind == MK_VAR && mp->refcount > 0 && !mp->istemporary) ||
mp->kind == MK_FIELD) {
tp = mp->type;
if (isfiletype(tp, -1)) {
mp->refcount++;
sp = makestmt(SK_ASSIGN);
sp->next = **sppp;
**sppp = sp;
if (exbase)
ex = makeexpr_dot(copyexpr(exbase), mp);
else
ex = makeexpr_var(mp);
sp->exp1 = initfilevar(copyexpr(ex));
} else if (tp->kind == TK_RECORD) {
if (exbase)
ex = makeexpr_dot(copyexpr(exbase), mp);
else
ex = makeexpr_var(mp);
initfilevars(tp->fbase, sppp, ex);
freeexpr(ex);
} else if (tp->kind == TK_ARRAY) {
while (tp->kind == TK_ARRAY)
tp = tp->basetype;
if (isfiletype(tp, -1))
note(format_s("Array of files %s should be initialized [257]",
mp->name));
}
}
mp = mp->cnext;
}
}
Static Stmt *p_body()
{
Stmt *sp, **spp, *spbody, **sppbody, *spbase, *thereturn;
Meaning *mp;
Expr *ex;
int haspostamble;
long saveserial;
if (verbose)
fprintf(logf, "%s, %d/%d: Translating %s (in %s)\n",
infname, inf_lnum, outf_lnum,
curctx->name, curctx->ctx->name);
notephase = 1;
spp = &spbase;
addstmt(SK_HEADER);
sp->exp1 = makeexpr_var(curctx);
checkkeyword(TOK_INLINE);
if (curtok != TOK_END && curtok != TOK_BEGIN && curtok != TOK_INLINE) {
if (curctx->kind == MK_FUNCTION || curctx->anyvarflag)
wexpecttok(TOK_BEGIN);
else
wexpecttok(TOK_END);
skiptotoken2(TOK_BEGIN, TOK_END);
}
if (curtok == TOK_END) {
gettok();
spbody = NULL;
} else {
spbody = p_stmt(NULL, SF_FUNC); /* parse the procedure/program body */
}
if (curtok == TOK_IDENT && curtokmeaning == curctx) {
gettok(); /* Modula-2 */
}
notephase = 2;
saveserial = curserial;
curserial = 10000;
if (curctx->kind == MK_FUNCTION) { /* handle copy parameters */
for (mp = curctx->type->fbase; mp; mp = mp->xnext) {
if (!mp->othername && mp->varstructflag) {
mp->othername = stralloc(format_s(name_COPYPAR, mp->name));
mp->rectype = mp->type;
addstmt(SK_ASSIGN);
sp->exp1 = makeexpr_assign(makeexpr_var(mp),
makeexpr_name(mp->othername, mp->rectype));
mp->refcount++;
} else if (mp->othername) {
if (checkvarchanged(spbody, mp)) {
addstmt(SK_ASSIGN);
sp->exp1 = makeexpr_assign(makeexpr_var(mp),
makeexpr_hat(makeexpr_name(mp->othername,
mp->rectype), 0));
mp->refcount++;
} else { /* don't need to copy it after all */
strchange(&mp->othername, mp->name);
ex = makeexpr_var(mp);
ex->val.type = mp->rectype;
replaceexpr(spbody, makeexpr_var(mp), makeexpr_hat(ex, 0));
}
}
}
}
for (mp = curctx->cbase; mp; mp = mp->cnext) {
if (mp->kind == MK_LABEL && mp->val.i) {
addstmt(SK_IF);
sp->exp1 = makeexpr_bicall_1("setjmp", tp_int,
makeexpr_var(mp->xnext));
sp->stm1 = makestmt(SK_GOTO);
sp->stm1->exp1 = makeexpr_name(format_s(name_LABEL, mp->name),
tp_integer);
}
}
*spp = spbody;
sppbody = spp;
while (*spp)
spp = &((*spp)->next);
haspostamble = 0;
initfilevars(curctx->cbase, &sppbody, NULL);
for (mp = curctx->cbase; mp; mp = mp->cnext) {
if (mp->kind == MK_VAR && mp->refcount > 0 &&
isfiletype(mp->type, -1) &&
!mp->istemporary) {
if (curctx->kind != MK_MODULE || curctx->anyvarflag) {
addstmt(SK_IF); /* close file variables */
sp->exp1 = makeexpr_rel(EK_NE, filebasename(makeexpr_var(mp)),
makeexpr_nil());
sp->stm1 = makestmt(SK_ASSIGN);
sp->stm1->exp1 = makeexpr_bicall_1("fclose", tp_void,
filebasename(makeexpr_var(mp)));
}
haspostamble = 1;
}
}
thereturn = &bogusreturn;
if (curctx->kind == MK_FUNCTION && curctx->type->basetype != tp_void) {
if ((haspostamble || !checkreturns(&spbase, 1)) &&
curctx->cbase->refcount > 0) { /* add function return code */
addstmt(SK_RETURN);
sp->exp1 = makeexpr_var(curctx->cbase);
}
thereturn = NULL;
} else if (curctx->kind == MK_MODULE && curctx->anyvarflag) {
addstmt(SK_ASSIGN);
sp->exp1 = makeexpr_bicall_1("exit", tp_void,
makeexpr_name("EXIT_SUCCESS",
tp_integer));
thereturn = NULL;
}
if (debug>2) { fprintf(outf, "calling fixblock/usecommas on:\n"); dumpstmt(spbase, 5); }
curserial = saveserial;
sp = makestmt(SK_BODY);
sp->stm1 = spbase;
fixblock(&sp, thereturn); /* finishing touches to statements and expressions */
spbase = sp->stm1;
FREE(sp);
if (usecommas != 1)
checkcommas(&spbase); /* unroll ugly EK_COMMA and EK_COND expressions */
if (debug>1) { fprintf(outf, "p_body returns:\n"); dumpstmt(spbase, 5); }
notephase = 0;
return spbase;
}
#define checkWord() if (anywords) output(" "); anywords = 1
Static void out_function(func)
Meaning *func;
{
Meaning *mp;
Symbol *sym;
int opts, anywords, spacing, saveindent;
if (func->varstructflag) {
makevarstruct(func);
}
if (collectnest) {
for (mp = func->cbase; mp; mp = mp->cnext) {
if (mp->kind == MK_FUNCTION && mp->isforward) {
forward_decl(mp, 0);
}
}
for (mp = func->cbase; mp; mp = mp->cnext) {
if (mp->kind == MK_FUNCTION && mp->type && !mp->exported) {
pushctx(mp);
out_function(mp); /* generate the sub-procedures first */
popctx();
}
}
}
spacing = functionspace;
for (mp = func; mp->ctx->kind == MK_FUNCTION; mp = mp->ctx) {
if (spacing > minfuncspace)
spacing--;
}
outsection(spacing);
flushcomments(&func->comments, -1, 0);
if (usePPMacros == 1) {
forward_decl(func, 0);
outsection(minorspace);
}
opts = ODECL_HEADER;
anywords = 0;
if (func->namedfile) {
checkWord();
if (useAnyptrMacros || ansiC < 2)
output("Inline");
else
output("inline");
}
if (!func->exported) {
if (func->ctx->kind == MK_FUNCTION) {
if (useAnyptrMacros) {
checkWord();
output("Local");
} else if (use_static) {
checkWord();
output("static");
}
} else if ((findsymbol(func->name)->flags & NEEDSTATIC) ||
(use_static != 0 && !useAnyptrMacros)) {
checkWord();
output("static");
} else if (useAnyptrMacros) {
checkWord();
output("Static");
}
}
if (func->type->basetype != tp_void || ansiC != 0) {
checkWord();
outbasetype(func->type, 0);
}
if (anywords) {
if (newlinefunctions)
opts |= ODECL_FUNCTION;
else
output(" ");
}
outdeclarator(func->type, func->name, opts);
if (fullprototyping == 0) {
saveindent = outindent;
moreindent(argindent);
out_argdecls(func->type);
outindent = saveindent;
}
for (mp = func->type->fbase; mp; mp = mp->xnext) {
if (mp->othername && strcmp(mp->name, mp->othername))
mp->wasdeclared = 0; /* make sure we also declare the copy */
}
func->wasdeclared = 1;
outcontext = func;
out_block((Stmt *)func->val.i, BR_FUNCTION, 10000);
if (useundef) {
anywords = 0;
for (mp = func->cbase; mp; mp = mp->cnext) {
if (mp->kind == MK_CONST &&
mp->isreturn) { /* the was-#defined flag */
if (!anywords)
outsection(minorspace);
anywords++;
output(format_s("#undef %s\n", mp->name));
sym = findsymbol(mp->name);
sym->flags &= ~AVOIDNAME;
}
}
}
if (conserve_mem) {
free_stmt((Stmt *)func->val.i); /* is this safe? */
func->val.i = 0;
forget_ctx(func, 0);
}
outsection(spacing);
}
void movetoend(mp)
Meaning *mp;
{
Meaning **mpp;
if (mp->ctx != curctx) {
intwarning("movetoend", "curctx is wrong [268]");
} else {
mpp = &mp->ctx->cbase; /* move a meaning to end of its parent context */
while (*mpp != mp) {
if (!*mpp) {
intwarning("movetoend", "meaning not on its context list [269]");
return;
}
mpp = &(*mpp)->cnext;
}
*mpp = mp->cnext; /* Remove from present position in list */
while (*mpp)
mpp = &(*mpp)->cnext;
*mpp = mp; /* Insert at end of list */
mp->cnext = NULL;
curctxlast = mp;
}
}
Static void scanfwdparams(mp)
Meaning *mp;
{
Symbol *sym;
mp = mp->type->fbase;
while (mp) {
sym = findsymbol(mp->name);
sym->flags |= FWDPARAM;
mp = mp->xnext;
}
}
Static void p_function(isfunc)
int isfunc;
{
Meaning *func;
Type *type;
Stmt *sp;
Strlist *sl, *comments, *savecmt;
int initializeattr = 0, isinline = 0;
if ((sl = strlist_find(attrlist, "INITIALIZE")) != NULL) {
initializeattr = 1;
strlist_delete(&attrlist, sl);
}
if ((sl = strlist_find(attrlist, "OPTIMIZE")) != NULL &&
sl->value != -1 &&
!strcmp((char *)(sl->value), "INLINE")) {
isinline = 1;
strlist_delete(&attrlist, sl);
}
ignore_attributes();
comments = extractcomment(&curcomments, -1, curserial);
changecomments(comments, -1, -1, -1, 0);
if (curctx->kind == MK_FUNCTION) { /* sub-procedure */
savecmt = curcomments;
} else {
savecmt = NULL;
flushcomments(&curcomments, -1, -1);
}
curcomments = comments;
curserial = serialcount = 1;
gettok();
if (!wexpecttok(TOK_IDENT))
skiptotoken(TOK_IDENT);
if (curtokmeaning && curtokmeaning->ctx == curctx &&
curtokmeaning->kind == MK_FUNCTION) {
func = curtokmeaning;
if (!func->isforward || func->val.i)
warning(format_s("Redeclaration of function %s [270]", func->name));
skiptotoken(TOK_SEMI);
movetoend(func);
pushctx(func);
type = func->type;
} else {
func = addmeaning(curtoksym, MK_FUNCTION);
gettok();
func->val.i = 0;
pushctx(func);
func->type = type = p_funcdecl(&isfunc, 0);
func->isfunction = isfunc;
func->namedfile = isinline;
type->meaning = func;
}
if (blockkind == TOK_EXPORT)
flushcomments(NULL, -1, -1);
wneedtok(TOK_SEMI);
if (initializeattr) {
sl = strlist_append(&initialcalls, format_s("%s()", func->name));
sl->value = 1;
}
if (curtok == TOK_IDENT && !strcmp(curtokbuf, "C")) {
gettok();
wneedtok(TOK_SEMI);
}
if (blockkind == TOK_IMPORT) {
strlist_empty(&curcomments);
if (curtok == TOK_IDENT &&
(!strcicmp(curtokbuf, "FORWARD") ||
strlist_cifind(externwords, curtokbuf) ||
strlist_cifind(cexternwords, curtokbuf))) {
gettok();
while (curtok == TOK_IDENT)
gettok();
wneedtok(TOK_SEMI);
}
/* do nothing more */
} else if (blockkind == TOK_EXPORT) {
func->isforward = 1;
scanfwdparams(func);
forward_decl(func, 1);
} else {
checkkeyword(TOK_INTERRUPT);
checkkeyword(TOK_INLINE);
if (curtok == TOK_INTERRUPT) {
note("Ignoring INTERRUPT keyword [258]");
gettok();
wneedtok(TOK_SEMI);
}
if (curtok == TOK_IDENT && !strcicmp(curtokbuf, "FORWARD")) {
func->isforward = 1;
scanfwdparams(func);
gettok();
if (func->ctx->kind != MK_FUNCTION) {
outsection(minorspace);
flushcomments(NULL, -1, -1);
forward_decl(func, 0);
outsection(minorspace);
}
} else if (curtok == TOK_IDENT &&
(strlist_cifind(externwords, curtokbuf) ||
strlist_cifind(cexternwords, curtokbuf))) {
if (*externalias && my_strchr(externalias, '%')) {
strchange(&func->name, format_s(externalias, func->name));
} else if (strlist_cifind(cexternwords, curtokbuf)) {
if (func->name[0] == '_')
strchange(&func->name, func->name + 1);
if (func->name[strlen(func->name)-1] == '_')
func->name[strlen(func->name)-1] = 0;
}
func->isforward = 1; /* for Oregon Software Pascal-2 */
func->exported = 1;
gettok();
while (curtok == TOK_IDENT)
gettok();
outsection(minorspace);
flushcomments(NULL, -1, -1);
scanfwdparams(func);
forward_decl(func, 1);
outsection(minorspace);
} else if (curtok == TOK_IDENT) {
wexpecttok(TOK_BEGIN); /* print warning */
gettok();
outsection(minorspace);
flushcomments(NULL, -1, -1);
scanfwdparams(func);
forward_decl(func, 1);
outsection(minorspace);
} else {
if (func->ctx->kind == MK_FUNCTION)
func->ctx->needvarstruct = 1;
func->comments = curcomments;
curcomments = NULL;
p_block(TOK_FUNCTION);
echoprocname(func);
changecomments(curcomments, -1, curserial, -1, 10000);
sp = p_body();
func->ctx->needvarstruct = 0;
func->val.i = (long)sp;
strlist_mix(&func->comments, curcomments);
curcomments = NULL;
if (func->ctx->kind != MK_FUNCTION || !collectnest) {
out_function(func); /* output top-level procedures immediately */
} /* (sub-procedures are output later) */
}
if (!wneedtok(TOK_SEMI))
skippasttoken(TOK_SEMI);
}
strlist_mix(&curcomments, savecmt);
popctx();
}
Static void out_include(name, quoted)
char *name;
int quoted;
{
if (*name == '"' || *name == '<')
output(format_s("#include %s\n", name));
else if (quoted)
output(format_s("#include \"%s\"\n", name));
else
output(format_s("#include <%s>\n", name));
}
Static void cleanheadername(dest, name)
char *dest, *name;
{
char *cp;
int len;
if (*name == '<' || *name == '"')
name++;
cp = my_strrchr(name, '/');
if (cp)
cp++;
else
cp = name;
strcpy(dest, cp);
len = strlen(dest);
if (dest[len-1] == '>' || dest[len-1] == '"')
dest[len-1] = 0;
}
Static int tryimport(sym, fname, ext, need)
Symbol *sym;
char *fname, *ext;
int need;
{
int found = 0;
Meaning *savectx, *savectxlast;
savectx = curctx;
savectxlast = curctxlast;
curctx = nullctx;
curctxlast = curctx->cbase;
while (curctxlast && curctxlast->cnext)
curctxlast = curctxlast->cnext;
if (p_search(fname, ext, need)) {
curtokmeaning = sym->mbase;
while (curtokmeaning && !curtokmeaning->isactive)
curtokmeaning = curtokmeaning->snext;
if (curtokmeaning)
found = 1;
}
curctx = savectx;
curctxlast = savectxlast;
return found;
}
Static void p_import(inheader)
int inheader;
{
Strlist *sl;
Symbol *sym;
char *name;
int found, isfrom = (curtok == TOK_FROM);
outsection(minorspace);
do {
gettok();
if (!wexpecttok(TOK_IDENT)) {
skiptotoken(TOK_SEMI);
break;
}
sym = curtoksym;
if (curtokmeaning && curtokmeaning->kind == MK_MODULE) {
found = 1;
} else if (strlist_cifind(permimports, sym->name)) {
found = 2; /* built-in module, there already! */
} else {
found = 0;
sl = strlist_cifind(importfrom, sym->name);
name = (sl) ? format_none((char *)sl->value) : NULL;
if (name) {
if (tryimport(sym, name, "pas", 1))
found = 1;
} else {
for (sl = importdirs; sl && !found; sl = sl->next) {
if (tryimport(sym, format_s(sl->s, curtokcase), NULL, 0))
found = 1;
}
}
}
if (found == 1) {
if (!inheader) {
sl = strlist_cifind(includefrom, curtokmeaning->name);
name = (sl) ? (char *)sl->value :
format_ss(*headerfnfmt2 ? headerfnfmt2 : headerfnfmt,
infname, curtokmeaning->name);
if (name && !strlist_find(includedfiles, name)) {
strlist_insert(&includedfiles, name);
if (*name_HSYMBOL)
output(format_s("#ifndef %s\n", format_s(name_HSYMBOL, sym->name)));
out_include(name, quoteincludes);
if (*name_HSYMBOL)
output("#endif\n");
outsection(minorspace);
}
}
import_ctx(curtokmeaning);
} else if (curtokmeaning) {
/* Modula-2, importing a single ident */
/* Ignored for now, since we always import whole modules */
} else if (found == 0) {
warning(format_s("Could not find module %s [271]", sym->name));
if (!inheader) {
out_include(format_ss(*headerfnfmt2?headerfnfmt2:headerfnfmt,
sym->name, sym->name),
quoteincludes);
}
}
gettok();
} while (curtok == TOK_COMMA);
if (isfrom) {
checkkeyword(TOK_IMPORT);
if (wneedtok(TOK_IMPORT)) {
do {
gettok();
if (curtok == TOK_IDENT)
gettok();
} while (curtok == TOK_COMMA);
}
}
if (!wneedtok(TOK_SEMI))
skippasttoken(TOK_SEMI);
outsection(minorspace);
}
void do_include(blkind)
Token blkind;
{
FILE *oldfile = outf;
int savelnum = outf_lnum;
char fname[256];
outsection(majorspace);
strcpy(fname, curtokbuf);
removesuffix(fname);
strcat(fname, ".c");
if (!strcmp(fname, codefname)) {
warning("Include file name conflict! [272]");
badinclude();
return;
}
saveoldfile(fname);
outf = fopen(fname, "w");
if (!outf) {
outf = oldfile;
perror(fname);
badinclude();
return;
}
outf_lnum = 1;
if (nobanner)
output("\n");
else
output(format_ss("\n/* Include file %s from %s */\n\n",
fname, codefname));
if (blkind == TOK_END)
gettok();
else
curtok = blkind;
p_block(blockkind);
if (nobanner)
output("\n");
else
output("\n\n/* End. */\n\n");
fclose(outf);
outf = oldfile;
outf_lnum = savelnum;
if (curtok != TOK_EOF) {
warning("Junk at end of include file ignored [273]");
}
outsection(majorspace);
if (*includefnfmt)
out_include(format_s(includefnfmt, fname), 1);
else
out_include(fname, 1);
outsection(majorspace);
pop_input();
p2c_getline();
gettok();
}
/* blockkind is one of:
TOK_PROGRAM: Global declarations of a program
TOK_FUNCTION: Declarations local to a procedure or function
TOK_IMPORT: Import text read from a module
TOK_EXPORT: Export section of a module
TOK_IMPLEMENT: Implementation section of a module
TOK_END: None of the above
*/
void p_block(blkind)
Token blkind;
{
Token saveblockkind = blockkind;
Token lastblockkind = TOK_END;
blockkind = blkind;
for (;;) {
while (curtok == TOK_INTFONLY) {
include_as_import();
gettok();
}
if (curtok == TOK_CONST || curtok == TOK_TYPE ||
curtok == TOK_VAR || curtok == TOK_VALUE) {
while (curtok == TOK_CONST || curtok == TOK_TYPE ||
curtok == TOK_VAR || curtok == TOK_VALUE) {
lastblockkind = curtok;
switch (curtok) {
case TOK_CONST:
p_constdecl();
break;
case TOK_TYPE:
p_typedecl();
break;
case TOK_VAR:
p_vardecl();
break;
case TOK_VALUE:
p_valuedecl();
break;
default:
break;
}
}
if ((blkind == TOK_PROGRAM ||
blkind == TOK_EXPORT ||
blkind == TOK_IMPLEMENT) &&
(curtok != TOK_BEGIN || !mainlocals)) {
outsection(majorspace);
if (declarevars(curctx, 0))
outsection(majorspace);
}
} else {
checkmodulewords();
checkkeyword(TOK_SEGMENT);
if (curtok == TOK_SEGMENT) {
note("SEGMENT or OVERLAY keyword ignored [259]");
gettok();
}
p_attributes();
switch (curtok) {
case TOK_LABEL:
p_labeldecl();
break;
case TOK_IMPORT:
case TOK_FROM:
p_import(0);
break;
case TOK_EXPORT:
do {
gettok();
checkkeyword(TOK_QUALIFIED);
if (curtok == TOK_QUALIFIED)
gettok();
wneedtok(TOK_IDENT);
} while (curtok == TOK_COMMA);
if (!wneedtok(TOK_SEMI))
skippasttoken(TOK_SEMI);
break;
case TOK_MODULE:
p_nested_module();
break;
case TOK_PROCEDURE:
p_function(0);
break;
case TOK_FUNCTION:
p_function(1);
break;
case TOK_INCLUDE:
if (blockkind == TOK_PROGRAM ||
blockkind == TOK_IMPLEMENT ||
(blockkind == TOK_FUNCTION && !collectnest)) {
do_include(lastblockkind);
} else {
badinclude();
}
break;
default:
if (curtok == TOK_BEGIN && blockkind == TOK_IMPORT) {
warning("BEGIN encountered in interface text [274]");
skipparens();
if (curtok == TOK_SEMI)
gettok();
break;
}
blockkind = saveblockkind;
return;
}
lastblockkind = TOK_END;
}
}
}
Static void skipunitheader()
{
if (curtok == TOK_LPAR || curtok == TOK_LBR) {
skipparens();
}
}
Static void skiptomodule()
{
skipping_module++;
while (curtok != TOK_MODULE) {
if (curtok == TOK_END) {
gettok();
if (curtok == TOK_DOT)
break;
} else
gettok();
}
skipping_module--;
}
Static void p_moduleinit(mod)
Meaning *mod;
{
Stmt *sp;
Strlist *sl;
if (curtok != TOK_BEGIN && curtok != TOK_END) {
wexpecttok(TOK_END);
skiptotoken2(TOK_BEGIN, TOK_END);
}
if (curtok == TOK_BEGIN || initialcalls) {
echoprocname(mod);
sp = p_body();
strlist_mix(&mod->comments, curcomments);
curcomments = NULL;
if (ansiC != 0)
output("void ");
output(format_s(name_UNITINIT, mod->name));
if (void_args)
output("(void)\n");
else
output("()\n");
outcontext = mod;
out_block(sp, BR_FUNCTION, 10000);
free_stmt(sp);
/* The following must come after out_block! */
sl = strlist_append(&initialcalls,
format_s("%s()",
format_s(name_UNITINIT, mod->name)));
sl->value = 1;
} else
wneedtok(TOK_END);
}
Static void p_nested_module()
{
Meaning *mp;
if (!modula2) {
note("Ignoring nested module [260]");
p_module(1, 0);
return;
}
note("Nested modules not fully supported [261]");
checkmodulewords();
wneedtok(TOK_MODULE);
wexpecttok(TOK_IDENT);
mp = addmeaning(curtoksym, MK_MODULE);
mp->anyvarflag = 0;
gettok();
skipunitheader();
wneedtok(TOK_SEMI);
p_block(TOK_IMPLEMENT);
p_moduleinit(mp);
if (curtok == TOK_IDENT)
gettok();
wneedtok(TOK_SEMI);
}
Static int p_module(ignoreit, isdefn)
int ignoreit;
int isdefn; /* Modula-2: 0=local module, 1=DEFINITION, 2=IMPLEMENTATION */
{
Meaning *mod, *mp;
Strlist *sl;
int kind;
char *cp;
checkmodulewords();
wneedtok(TOK_MODULE);
wexpecttok(TOK_IDENT);
if (curtokmeaning && curtokmeaning->kind == MK_MODULE && isdefn == 2) {
mod = curtokmeaning;
import_ctx(mod);
for (mp = mod->cbase; mp; mp = mp->cnext)
if (mp->kind == MK_FUNCTION)
mp->isforward = 1;
} else {
mod = addmeaning(curtoksym, MK_MODULE);
}
mod->anyvarflag = 0;
pushctx(mod);
gettok();
skipunitheader();
wneedtok(TOK_SEMI);
if (ignoreit ||
(requested_module && strcicmp(requested_module, mod->name))) {
if (!quietmode)
if (outf == stdout)
fprintf(stderr, "Skipping over module \"%s\"\n", mod->name);
else
printf("Skipping over module \"%s\"\n", mod->name);
checkmodulewords();
while (curtok == TOK_IMPORT || curtok == TOK_FROM)
p_import(1);
checkmodulewords();
if (curtok == TOK_EXPORT)
gettok();
strlist_empty(&curcomments);
p_block(TOK_IMPORT);
setup_module(mod->sym->name, 0);
checkmodulewords();
if (curtok == TOK_IMPLEMENT) {
skiptomodule();
} else {
if (!wneedtok(TOK_END))
skippasttoken(TOK_END);
if (curtok == TOK_SEMI)
gettok();
}
popctx();
strlist_empty(&curcomments);
return 0;
}
found_module = 1;
if (isdefn != 2) {
if (!*hdrfname) {
sl = strlist_cifind(includefrom, mod->name);
if (sl)
cleanheadername(hdrfname, (char *)sl->value);
else
strcpy(hdrfname, format_ss(headerfnfmt, infname, mod->name));
}
saveoldfile(hdrfname);
hdrf = fopen(hdrfname, "w");
if (!hdrf) {
perror(hdrfname);
error("Could not open output file for header");
}
outsection(majorspace);
if (usevextern && my_strchr(name_GSYMBOL, '%'))
output(format_s("#define %s\n", format_s(name_GSYMBOL, mod->sym->name)));
if (*selfincludefmt)
cp = format_s(selfincludefmt, hdrfname);
else
cp = hdrfname;
out_include(cp, quoteincludes);
outsection(majorspace);
select_outfile(hdrf);
if (nobanner)
output("\n");
else
output(format_s("/* Header for module %s, generated by p2c */\n",
mod->name));
if (*name_HSYMBOL) {
cp = format_s(name_HSYMBOL, mod->sym->name);
output(format_ss("#ifndef %s\n#define %s\n", cp, cp));
}
outsection(majorspace);
checkmodulewords();
while (curtok == TOK_IMPORT || curtok == TOK_FROM)
p_import(0);
checkmodulewords();
if (curtok == TOK_EXPORT)
gettok();
checkmodulewords();
while (curtok == TOK_IMPORT || curtok == TOK_FROM)
p_import(0);
outsection(majorspace);
if (usevextern) {
output(format_s("#ifdef %s\n# define vextern\n#else\n",
format_s(name_GSYMBOL, mod->sym->name)));
output("# define vextern extern\n#endif\n");
}
checkmodulewords();
p_block(TOK_EXPORT);
flushcomments(NULL, -1, -1);
setup_module(mod->sym->name, 1);
outsection(majorspace);
if (usevextern)
output("#undef vextern\n");
outsection(minorspace);
if (*name_HSYMBOL)
output(format_s("#endif /*%s*/\n", format_s(name_HSYMBOL, mod->sym->name)));
if (nobanner)
output("\n");
else
output("\n/* End. */\n\n");
select_outfile(codef);
fclose(hdrf);
*hdrfname = 0;
redeclarevars(mod);
declarevars(mod, 0);
}
checkmodulewords();
if (curtok != TOK_END) {
if (!modula2 && !implementationmodules)
wneedtok(TOK_IMPLEMENT);
import_ctx(mod);
p_block(TOK_IMPLEMENT);
flushcomments(NULL, -1, -1);
p_moduleinit(mod);
kind = 1;
} else {
kind = 0;
if (!wneedtok(TOK_END))
skippasttoken(TOK_END);
}
if (curtok == TOK_IDENT)
gettok();
if (curtok == TOK_SEMI)
gettok();
popctx();
return kind;
}
int p_search(fname, ext, need)
char *fname, *ext;
int need;
{
char infnbuf[300];
FILE *fp;
Meaning *mod;
int savesysprog, savecopysource;
int outerimportmark, importmark, mypermflag;
strcpy(infnbuf, fname);
fixfname(infnbuf, ext);
fp = fopen(infnbuf, "r");
if (!fp) {
if (need)
perror(infnbuf);
if (logf)
fprintf(logf, "(Unable to open search file \"%s\")\n", infnbuf);
return 0;
}
flushcomments(NULL, -1, -1);
ignore_directives++;
savesysprog = sysprog_flag;
sysprog_flag |= 3;
savecopysource = copysource;
copysource = 0;
outerimportmark = numimports; /*obsolete*/
importmark = push_imports();
clearprogress();
push_input_file(fp, infnbuf, 0);
do {
strlist_empty(&curcomments);
checkmodulewords();
permflag = 0;
if (curtok == TOK_DEFINITION) {
gettok();
checkmodulewords();
} else if (curtok == TOK_IMPLEMENT && modula2) {
gettok();
checkmodulewords();
warning("IMPLEMENTATION module in search text! [275]");
}
if (!wneedtok(TOK_MODULE))
break;
if (!wexpecttok(TOK_IDENT))
break;
mod = addmeaning(curtoksym, MK_MODULE);
mod->anyvarflag = 0;
if (!quietmode && !showprogress)
if (outf == stdout)
fprintf(stderr, "Reading import text for \"%s\"\n", mod->name);
else
printf("Reading import text for \"%s\"\n", mod->name);
if (verbose)
fprintf(logf, "%s, %d/%d: Reading import text for \"%s\"\n",
infname, inf_lnum, outf_lnum, mod->name);
pushctx(mod);
gettok();
skipunitheader();
wneedtok(TOK_SEMI);
mypermflag = permflag;
if (debug>0) printf("Found module %s\n", mod->name);
checkmodulewords();
while (curtok == TOK_IMPORT || curtok == TOK_FROM)
p_import(1);
checkmodulewords();
if (curtok == TOK_EXPORT)
gettok();
strlist_empty(&curcomments);
p_block(TOK_IMPORT);
setup_module(mod->sym->name, 0);
if (mypermflag) {
strlist_add(&permimports, mod->sym->name)->value = (long)mod;
perm_import(mod);
}
checkmodulewords();
if (curtok == TOK_END) {
gettok();
if (curtok == TOK_SEMI)
gettok();
} else {
wexpecttok(TOK_IMPLEMENT);
if (importall) {
skiptomodule();
}
}
popctx();
} while (curtok == TOK_MODULE);
pop_imports(importmark);
unimport(outerimportmark);
sysprog_flag = savesysprog;
copysource = savecopysource;
ignore_directives--;
pop_input();
strlist_empty(&curcomments);
clearprogress();
return 1;
}
void p_program()
{
Meaning *prog;
Stmt *sp;
int nummods, isdefn = 0;
flushcomments(NULL, -1, -1);
output(format_s("\n#include %s\n", p2c_h_name));
outsection(majorspace);
p_attributes();
ignore_attributes();
checkmodulewords();
if (modula2) {
if (curtok == TOK_MODULE) {
curtok = TOK_PROGRAM;
} else {
if (curtok == TOK_DEFINITION) {
isdefn = 1;
gettok();
checkmodulewords();
} else if (curtok == TOK_IMPLEMENT) {
isdefn = 2;
gettok();
checkmodulewords();
}
}
}
switch (curtok) {
case TOK_MODULE:
if (implementationmodules)
isdefn = 2;
nummods = 0;
while (curtok == TOK_MODULE) {
if (p_module(0, isdefn)) {
nummods++;
if (nummods == 2 && !requested_module)
warning("Multiple modules in one source file may not work correctly [276]");
}
}
wneedtok(TOK_DOT);
break;
default:
if (curtok == TOK_PROGRAM) {
gettok();
if (!wexpecttok(TOK_IDENT))
skiptotoken(TOK_IDENT);
prog = addmeaning(curtoksym, MK_MODULE);
gettok();
if (curtok == TOK_LPAR) {
while (curtok != TOK_RPAR) {
if (curtok == TOK_IDENT &&
strcicmp(curtokbuf, "INPUT") &&
strcicmp(curtokbuf, "OUTPUT") &&
strcicmp(curtokbuf, "KEYBOARD") &&
strcicmp(curtokbuf, "LISTING")) {
if (literalfilesflag == 2) {
strlist_add(&literalfiles, curtokbuf);
} else
note(format_s("Unexpected name \"%s\" in program header [262]",
curtokcase));
}
gettok();
}
gettok();
}
if (curtok == TOK_LBR)
skipparens();
wneedtok(TOK_SEMI);
} else {
prog = addmeaning(findsymbol("program"), MK_MODULE);
}
prog->anyvarflag = 1;
if (requested_module && strcicmp(requested_module, prog->name) &&
strcicmp(requested_module, "program")) {
for (;;) {
skiptomodule();
if (curtok == TOK_DOT)
break;
(void)p_module(0, 2);
}
gettok();
break;
}
pushctx(prog);
p_block(TOK_PROGRAM);
echoprocname(prog);
flushcomments(NULL, -1, -1);
if (curtok != TOK_EOF) {
sp = p_body();
strlist_mix(&prog->comments, curcomments);
curcomments = NULL;
if (fullprototyping > 0) {
output(format_sss("main%s(int argc,%s%s *argv[])",
spacefuncs ? " " : "",
spacecommas ? " " : "",
charname));
} else {
output("main");
if (spacefuncs)
output(" ");
output("(argc,");
if (spacecommas)
output(" ");
output("argv)\n");
singleindent(argindent);
output("int argc;\n");
singleindent(argindent);
output(format_s("%s *argv[];\n", charname));
}
outcontext = prog;
out_block(sp, BR_FUNCTION, 10000);
free_stmt(sp);
popctx();
if (curtok == TOK_SEMI)
gettok();
else
wneedtok(TOK_DOT);
}
break;
}
if (curtok != TOK_EOF) {
warning("Junk at end of input file ignored [277]");
}
}
/* End. */