Subject: v21i075: Pascal to C translator, Part30/32 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: d140c78b e19ae830 375027e7 9a3c700a Submitted-by: Dave Gillespie Posting-number: Volume 21, Issue 75 Archive-name: p2c/part30 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'src/parse.c.2' <<'END_OF_FILE' X if (spnextreturn) { X mp->refcount--; X sp->next = sp->next->next; X } X result = 1; X } X } X break; X X case SK_RETURN: X case SK_GOTO: X result = 1; X break; X X case SK_IF: X result = checkreturns(&sp->stm1, spnearret) & /* NOT && */ X checkreturns(&sp->stm2, spnearret); X break; X X case SK_TRY: X (void) checkreturns(&sp->stm1, 0); X (void) checkreturns(&sp->stm2, spnearret); X break; X X /* should handle CASE statements as well */ X X default: X (void) checkreturns(&sp->stm1, 0); X (void) checkreturns(&sp->stm2, 0); X break; X } X spp = &sp->next; X } X return result; X} X X X X X X X X/* Replace all occurrences of one expression with another expression */ X XExpr *replaceexprexpr(ex, oldex, newex) XExpr *ex, *oldex, *newex; X{ X int i; X Type *type; X X for (i = 0; i < ex->nargs; i++) X ex->args[i] = replaceexprexpr(ex->args[i], oldex, newex); X if (exprsame(ex, oldex, 2)) { X if (ex->val.type->kind == TK_POINTER && X ex->val.type->basetype == oldex->val.type) { X freeexpr(ex); X return makeexpr_addr(copyexpr(newex)); X } else if (oldex->val.type->kind == TK_POINTER && X oldex->val.type->basetype == ex->val.type) { X freeexpr(ex); X return makeexpr_hat(copyexpr(newex), 0); X } else { X type = ex->val.type; X freeexpr(ex); X ex = copyexpr(newex); X ex->val.type = type; X return ex; X } X } X return resimplify(ex); X} X X Xvoid replaceexpr(sp, oldex, newex) XStmt *sp; XExpr *oldex, *newex; X{ X while (sp) { X replaceexpr(sp->stm1, oldex, newex); X replaceexpr(sp->stm2, oldex, newex); X if (sp->exp1) X sp->exp1 = replaceexprexpr(sp->exp1, oldex, newex); X if (sp->exp2) X sp->exp2 = replaceexprexpr(sp->exp2, oldex, newex); X if (sp->exp3) X sp->exp3 = replaceexprexpr(sp->exp3, oldex, newex); X sp = sp->next; X } X} X X X X X X XStmt *mixassignments(sp, mp) XStmt *sp; XMeaning *mp; X{ X if (!sp) X return NULL; X sp->next = mixassignments(sp->next, mp); X if (sp->next && X sp->kind == SK_ASSIGN && X sp->exp1->kind == EK_ASSIGN && X sp->exp1->args[0]->kind == EK_VAR && X (!mp || mp == (Meaning *)sp->exp1->args[0]->val.i) && X ord_type(sp->exp1->args[0]->val.type)->kind == TK_INTEGER && X nodependencies(sp->exp1->args[1], 0) && X sp->next->kind == SK_ASSIGN && X sp->next->exp1->kind == EK_ASSIGN && X (exprsame(sp->exp1->args[0], sp->next->exp1->args[0], 1) || X (mp && mp->istemporary)) && X exproccurs(sp->next->exp1->args[1], sp->exp1->args[0]) == 1) { X sp->next->exp1->args[1] = replaceexprexpr(sp->next->exp1->args[1], X sp->exp1->args[0], X sp->exp1->args[1]); X if (mp && mp->istemporary) X canceltempvar(mp); X return sp->next; X } X return sp; X} X X X X X X X X X/* Do various simple (sometimes necessary) massages on the statements */ X X XStatic Stmt bogusreturn = { SK_RETURN, NULL, NULL, NULL, NULL, NULL, NULL }; X X X XStatic int isescape(ex) XExpr *ex; X{ X if (ex->kind == EK_BICALL && (!strcmp(ex->val.s, name_ESCAPE) || X !strcmp(ex->val.s, name_ESCIO) || X !strcmp(ex->val.s, name_OUTMEM) || X !strcmp(ex->val.s, name_CASECHECK) || X !strcmp(ex->val.s, name_NILCHECK) || X !strcmp(ex->val.s, "_exit") || X !strcmp(ex->val.s, "exit"))) X return 1; X if (ex->kind == EK_CAST) X return isescape(ex->args[0]); X return 0; X} X X X/* check if a block can never exit by falling off the end */ XStatic int deadendblock(sp) XStmt *sp; X{ X if (!sp) X return 0; X while (sp->next) X sp = sp->next; X return (sp->kind == SK_GOTO || X sp->kind == SK_BREAK || X sp->kind == SK_CONTINUE || X sp->kind == SK_RETURN || X sp->kind == SK_CASECHECK || X (sp->kind == SK_IF && deadendblock(sp->stm1) && X deadendblock(sp->stm2)) || X (sp->kind == SK_ASSIGN && isescape(sp->exp1))); X} X X X X Xint expr_is_bool(ex, want) XExpr *ex; Xint want; X{ X long val; X X if (ex->val.type == tp_boolean && isconstexpr(ex, &val)) X return (val == want); X return 0; X} X X X X X/* Returns 1 if c1 implies c2, 0 otherwise */ X/* If not1 is true, then checks if (!c1) implies c2; similarly for not2 */ X X/* Identities used: X c1 -> (c2a && c2b) <=> (c1 -> c2a) && (c1 -> c2b) X c1 -> (c2a || c2b) <=> (c1 -> c2a) || (c1 -> c2b) X (c1a && c1b) -> c2 <=> (c1a -> c2) || (c1b -> c2) X (c1a || c1b) -> c2 <=> (c1a -> c2) && (c1b -> c2) X (!c1) -> (!c2) <=> c2 -> c1 X (a == b) -> c2(b) <=> c2(a) X !(c1 && c2) <=> (!c1) || (!c2) X !(c1 || c2) <=> (!c1) && (!c2) X*/ X/* This could be smarter about, e.g., (a>5) -> (a>0) */ X Xint implies(c1, c2, not1, not2) XExpr *c1, *c2; Xint not1, not2; X{ X Expr *ex; X int i; X X if (c1->kind == EK_EQ && c1->args[0]->val.type == tp_boolean) { X if (checkconst(c1->args[0], 1)) { /* things like "flag = true" */ X return implies(c1->args[1], c2, not1, not2); X } else if (checkconst(c1->args[1], 1)) { X return implies(c1->args[0], c2, not1, not2); X } else if (checkconst(c1->args[0], 0)) { X return implies(c1->args[1], c2, !not1, not2); X } else if (checkconst(c1->args[1], 0)) { X return implies(c1->args[0], c2, !not1, not2); X } X } X if (c2->kind == EK_EQ && c2->args[0]->val.type == tp_boolean) { X if (checkconst(c2->args[0], 1)) { X return implies(c1, c2->args[1], not1, not2); X } else if (checkconst(c2->args[1], 1)) { X return implies(c1, c2->args[0], not1, not2); X } else if (checkconst(c2->args[0], 0)) { X return implies(c1, c2->args[1], not1, !not2); X } else if (checkconst(c2->args[1], 0)) { X return implies(c1, c2->args[0], not1, !not2); X } X } X switch (c2->kind) { X X case EK_AND: X if (not2) /* c1 -> (!c2a || !c2b) */ X return (implies(c1, c2->args[0], not1, 1) || X implies(c1, c2->args[1], not1, 1)); X else /* c1 -> (c2a && c2b) */ X return (implies(c1, c2->args[0], not1, 0) && X implies(c1, c2->args[1], not1, 0)); X X case EK_OR: X if (not2) /* c1 -> (!c2a && !c2b) */ X return (implies(c1, c2->args[0], not1, 1) && X implies(c1, c2->args[1], not1, 1)); X else /* c1 -> (c2a || c2b) */ X return (implies(c1, c2->args[0], not1, 0) || X implies(c1, c2->args[1], not1, 0)); X X case EK_NOT: /* c1 -> (!c2) */ X return (implies(c1, c2->args[0], not1, !not2)); X X case EK_CONST: X if ((c2->val.i != 0) != not2) /* c1 -> true */ X return 1; X break; X X default: X break; X } X switch (c1->kind) { X X case EK_AND: X if (not1) /* (!c1a || !c1b) -> c2 */ X return (implies(c1->args[0], c2, 1, not2) && X implies(c1->args[1], c2, 1, not2)); X else /* (c1a && c1b) -> c2 */ X return (implies(c1->args[0], c2, 0, not2) || X implies(c1->args[1], c2, 0, not2)); X X case EK_OR: X if (not1) /* (!c1a && !c1b) -> c2 */ X return (implies(c1->args[0], c2, 1, not2) || X implies(c1->args[1], c2, 1, not2)); X else /* (c1a || c1b) -> c2 */ X return (implies(c1->args[0], c2, 0, not2) && X implies(c1->args[1], c2, 0, not2)); X X case EK_NOT: /* (!c1) -> c2 */ X return (implies(c1->args[0], c2, !not1, not2)); X X case EK_CONST: X if ((c1->val.i != 0) == not1) /* false -> c2 */ X return 1; X break; X X case EK_EQ: /* (a=b) -> c2 */ X case EK_ASSIGN: /* (a:=b) -> c2 */ X case EK_NE: /* (a<>b) -> c2 */ X if ((c1->kind == EK_NE) == not1) { X if (c1->args[0]->kind == EK_VAR) { X ex = replaceexprexpr(copyexpr(c2), c1->args[0], c1->args[1]); X i = expr_is_bool(ex, !not2); X freeexpr(ex); X if (i) X return 1; X } X if (c1->args[1]->kind == EK_VAR) { X ex = replaceexprexpr(copyexpr(c2), c1->args[1], c1->args[0]); X i = expr_is_bool(ex, !not2); X freeexpr(ex); X if (i) X return 1; X } X } X break; X X default: X break; X } X if (not1 == not2 && exprequiv(c1, c2)) { /* c1 -> c1 */ X return 1; X } X return 0; X} X X X X X Xvoid infiniteloop(sp) XStmt *sp; X{ X switch (infloopstyle) { X X case 1: /* write "for (;;) ..." */ X sp->kind = SK_FOR; X freeexpr(sp->exp1); X sp->exp1 = NULL; X break; X X case 2: /* write "while (1) ..." */ X sp->kind = SK_WHILE; X freeexpr(sp->exp1); X sp->exp1 = makeexpr_val(make_ord(tp_boolean, 1)); X break; X X case 3: /* write "do ... while (1)" */ X sp->kind = SK_REPEAT; X freeexpr(sp->exp1); X sp->exp1 = makeexpr_val(make_ord(tp_boolean, 1)); X break; X X default: /* leave it alone */ X break; X X } X} X X X X X XExpr *print_func(ex) XExpr *ex; X{ X if (!ex || ex->kind != EK_BICALL) X return NULL; X if ((!strcmp(ex->val.s, "printf") && X ex->args[0]->kind == EK_CONST) || X !strcmp(ex->val.s, "putchar") || X !strcmp(ex->val.s, "puts")) X return ex_output; X if ((!strcmp(ex->val.s, "fprintf") || X !strcmp(ex->val.s, "sprintf")) && X ex->args[1]->kind == EK_CONST) X return ex->args[0]; X if (!strcmp(ex->val.s, "putc") || X !strcmp(ex->val.s, "fputc") || X !strcmp(ex->val.s, "fputs")) X return ex->args[1]; X return NULL; X} X X X Xint printnl_func(ex) XExpr *ex; X{ X char *cp, ch; X int i, len; X X if (debug>2) { fprintf(outf,"printnl_func("); dumpexpr(ex); fprintf(outf, ")\n"); } X if (!strcmp(ex->val.s, "printf") || X !strcmp(ex->val.s, "puts") || X !strcmp(ex->val.s, "fputs")) { X if (ex->args[0]->kind != EK_CONST) X return 0; X cp = ex->args[0]->val.s; X len = ex->args[0]->val.i; X } else if (!strcmp(ex->val.s, "fprintf")) { X if (ex->args[1]->kind != EK_CONST) X return 0; X cp = ex->args[1]->val.s; X len = ex->args[1]->val.i; X } else if (!strcmp(ex->val.s, "putchar") || X !strcmp(ex->val.s, "putc") || X !strcmp(ex->val.s, "fputc")) { X if (ex->args[0]->kind != EK_CONST) X return 0; X ch = ex->args[0]->val.i; X cp = &ch; X len = 1; X } else X return 0; X for (i = 1; i <= len; i++) X if (*cp++ != '\n') X return 0; X return len + (!strcmp(ex->val.s, "puts")); X} X X X XExpr *chg_printf(ex) XExpr *ex; X{ X Expr *fex; X X if (debug>2) { fprintf(outf,"chg_printf("); dumpexpr(ex); fprintf(outf, ")\n"); } X if (!strcmp(ex->val.s, "putchar")) { X ex = makeexpr_sprintfify(grabarg(ex, 0)); X canceltempvar(istempvar(ex->args[0])); X strchange(&ex->val.s, "printf"); X delfreearg(&ex, 0); X ex->val.type = tp_void; X } else if (!strcmp(ex->val.s, "putc") || X !strcmp(ex->val.s, "fputc") || X !strcmp(ex->val.s, "fputs")) { X fex = copyexpr(ex->args[1]); X ex = makeexpr_sprintfify(grabarg(ex, 0)); X canceltempvar(istempvar(ex->args[0])); X strchange(&ex->val.s, "fprintf"); X ex->args[0] = fex; X ex->val.type = tp_void; X } else if (!strcmp(ex->val.s, "puts")) { X ex = makeexpr_concat(makeexpr_sprintfify(grabarg(ex, 0)), X makeexpr_string("\n"), 1); X strchange(&ex->val.s, "printf"); X delfreearg(&ex, 0); X ex->val.type = tp_void; X } X if (!strcmp(ex->val.s, "fprintf") && exprsame(ex->args[0], ex_output, 1)) { X delfreearg(&ex, 0); X strchange(&ex->val.s, "printf"); X } X return ex; X} X X XExpr *mix_printf(ex, ex2) XExpr *ex, *ex2; X{ X int i; X X ex = chg_printf(ex); X if (debug>2) { fprintf(outf,"chg_printf returns "); dumpexpr(ex); fprintf(outf, "\n"); } X ex2 = chg_printf(copyexpr(ex2)); X if (debug>2) { fprintf(outf,"chg_printf returns "); dumpexpr(ex2);fprintf(outf, "\n"); } X i = (!strcmp(ex->val.s, "printf")) ? 0 : 1; X ex->args[i] = makeexpr_concat(ex->args[i], ex2->args[i], 0); X for (i++; i < ex2->nargs; i++) { X insertarg(&ex, ex->nargs, ex2->args[i]); X } X return ex; X} X X X X X X Xvoid eatstmt(spp) XStmt **spp; X{ X Stmt *sp = *spp; X X if (debug>2) { fprintf(outf, "eatstmt on:\n"); dumpstmt(sp, 5); } X *spp = sp->next; X sp->next = NULL; X free_stmt(sp); X} X X X Xint haslabels(sp) XStmt *sp; X{ X if (!sp) X return 0; X if (haslabels(sp->stm1) || haslabels(sp->stm2)) X return 1; X return (sp->kind == SK_LABEL); X} X X X Xvoid fixblock(spp, thereturn) XStmt **spp, *thereturn; X{ X Stmt *sp, *sp1, *sp2, *sp3, **spp2, *thisreturn; X Expr *ex; X Meaning *tvar, *mp; X int save_tryblock; X short save_tryflag; X int i, j, de1, de2; X long saveserial = curserial; X X while ((sp = *spp)) { X sp2 = sp->next; X sp->next = NULL; X sp = fix_statement(*spp); X if (!sp) { X *spp = sp2; X continue; X } X *spp = sp; X for (sp3 = sp; sp3->next; sp3 = sp3->next) ; X sp3->next = sp2; X if (!sp->next) X thisreturn = thereturn; X else if (sp->next->kind == SK_RETURN || X (sp->next->kind == SK_ASSIGN && X isescape(sp->next->exp1))) X thisreturn = sp->next; X else X thisreturn = NULL; X if (sp->serial >= 0) X curserial = sp->serial; X switch (sp->kind) { X X case SK_ASSIGN: X if (sp->exp1) X sp->exp1 = fixexpr(sp->exp1, ENV_STMT); X if (!sp->exp1) X intwarning("fixblock", "sp->exp1 == NULL in SK_ASSIGN"); X if (!sp->exp1 || nosideeffects(sp->exp1, 1)) { X eatstmt(spp); X continue; X } else { X switch (sp->exp1->kind) { X X case EK_COND: X *spp = makestmt_if(sp->exp1->args[0], X makestmt_call(sp->exp1->args[1]), X makestmt_call(sp->exp1->args[2])); X (*spp)->next = sp->next; X continue; /* ... to fix this new if statement */ X X case EK_ASSIGN: X if (sp->exp1->args[1]->kind == EK_COND && usecommas != 1) { X *spp = makestmt_if(sp->exp1->args[1]->args[0], X makestmt_assign(copyexpr(sp->exp1->args[0]), X sp->exp1->args[1]->args[1]), X makestmt_assign(sp->exp1->args[0], X sp->exp1->args[1]->args[2])); X (*spp)->next = sp->next; X continue; X } X if (isescape(sp->exp1->args[1])) { X sp->exp1 = grabarg(sp->exp1, 1); X continue; X } X if (exprsame(sp->exp1->args[0], sp->exp1->args[1], 1)) { X /* *spp = sp->next; */ X sp->exp1 = grabarg(sp->exp1, 0); X continue; X } X if (sp->exp1->args[1]->kind == EK_BICALL) { X if (!strcmp(sp->exp1->args[1]->val.s, X getfbufname) && X buildreads == 1 && X sp->next && X sp->next->kind == SK_ASSIGN && X sp->next->exp1->kind == EK_BICALL && X !strcmp(sp->next->exp1->val.s, X getname) && X expr_has_address(sp->exp1->args[0]) && X similartypes(sp->exp1->args[0]->val.type, X sp->exp1->args[1]->args[0]->val.type->basetype->basetype) && X exprsame(sp->exp1->args[1]->args[0], X sp->next->exp1->args[0], 1)) { X eatstmt(&sp->next); X ex = makeexpr_bicall_4("fread", tp_integer, X makeexpr_addr(sp->exp1->args[0]), X makeexpr_sizeof(sp->exp1->args[1]->args[1], 0), X makeexpr_long(1), X sp->exp1->args[1]->args[0]); X FREE(sp->exp1); X sp->exp1 = ex; X continue; X } X if (!strcmp(sp->exp1->args[1]->val.s, X chargetfbufname) && X buildreads != 0 && X sp->next && X sp->next->kind == SK_ASSIGN && X sp->next->exp1->kind == EK_BICALL && X !strcmp(sp->next->exp1->val.s, X chargetname) && X expr_has_address(sp->exp1->args[0]) && X exprsame(sp->exp1->args[1]->args[0], X sp->next->exp1->args[0], 1)) { X eatstmt(&sp->next); X strchange(&sp->exp1->args[1]->val.s, X "getc"); X continue; X } X } X break; X X case EK_BICALL: X if (!strcmp(sp->exp1->val.s, name_ESCAPE)) { X if (fixexpr_tryblock) { X *spp = makestmt_assign(makeexpr_var(mp_escapecode), X grabarg(sp->exp1, 0)); X (*spp)->next = makestmt(SK_GOTO); X (*spp)->next->exp1 = makeexpr_name(format_s(name_LABEL, X format_d("try%d", X fixexpr_tryblock)), X tp_integer); X (*spp)->next->next = sp->next; X fixexpr_tryflag = 1; X continue; X } X } else if (!strcmp(sp->exp1->val.s, name_ESCIO)) { X if (fixexpr_tryblock) { X *spp = makestmt_assign(makeexpr_var(mp_escapecode), X makeexpr_long(-10)); X (*spp)->next = makestmt_assign(makeexpr_var(mp_ioresult), X grabarg(sp->exp1, 0)); X (*spp)->next->next = makestmt(SK_GOTO); X (*spp)->next->next->exp1 = makeexpr_name(format_s(name_LABEL, X format_d("try%d", X fixexpr_tryblock)), X tp_integer); X (*spp)->next->next->next = sp->next; X fixexpr_tryflag = 1; X continue; X } X } X if (!strcmp(sp->exp1->val.s, putfbufname) && X buildwrites == 1 && X sp->next && X sp->next->kind == SK_ASSIGN && X sp->next->exp1->kind == EK_BICALL && X !strcmp(sp->next->exp1->val.s, X putname) && X exprsame(sp->exp1->args[0], X sp->next->exp1->args[0], 1)) { X eatstmt(&sp->next); X if (!expr_has_address(sp->exp1->args[2]) || X sp->exp1->args[2]->val.type != X sp->exp1->args[1]->val.type) { X tvar = maketempvar(sp->exp1->args[1]->val.type, X name_TEMP); X sp2 = makestmt_assign(makeexpr_var(tvar), X sp->exp1->args[2]); X sp2->next = sp; X *spp = sp2; X sp->exp1->args[2] = makeexpr_var(tvar); X freetempvar(tvar); X } X ex = makeexpr_bicall_4("fwrite", tp_integer, X makeexpr_addr(sp->exp1->args[2]), X makeexpr_sizeof(sp->exp1->args[1], 0), X makeexpr_long(1), X sp->exp1->args[0]); X FREE(sp->exp1); X sp->exp1 = ex; X continue; X } X if (!strcmp(sp->exp1->val.s, charputfbufname) && X buildwrites != 0 && X sp->next && X sp->next->kind == SK_ASSIGN && X sp->next->exp1->kind == EK_BICALL && X !strcmp(sp->next->exp1->val.s, X charputname) && X exprsame(sp->exp1->args[0], X sp->next->exp1->args[0], 1)) { X eatstmt(&sp->next); X swapexprs(sp->exp1->args[0], X sp->exp1->args[1]); X strchange(&sp->exp1->val.s, "putc"); X continue; X } X if ((!strcmp(sp->exp1->val.s, resetbufname) || X !strcmp(sp->exp1->val.s, setupbufname)) && X (mp = isfilevar(sp->exp1->args[0])) != NULL && X !mp->bufferedfile) { X eatstmt(spp); X continue; X } X ex = print_func(sp->exp1); X if (ex && sp->next && mixwritelns && X sp->next->kind == SK_ASSIGN && X exprsame(ex, print_func(sp->next->exp1), 1) && X (printnl_func(sp->exp1) || X printnl_func(sp->next->exp1))) { X sp->exp1 = mix_printf(sp->exp1, X sp->next->exp1); X eatstmt(&sp->next); X continue; X } X break; X X case EK_FUNCTION: X case EK_SPCALL: X case EK_POSTINC: X case EK_POSTDEC: X case EK_AND: X case EK_OR: X break; X X default: X spp2 = spp; X for (i = 0; i < sp->exp1->nargs; i++) { X *spp2 = makestmt_call(sp->exp1->args[i]); X spp2 = &(*spp2)->next; X } X *spp2 = sp->next; X continue; /* ... to fix these new statements */ X X } X } X break; X X case SK_IF: X fixblock(&sp->stm1, thisreturn); X fixblock(&sp->stm2, thisreturn); X if (!sp->stm1) { X if (!sp->stm2) { X sp->kind = SK_ASSIGN; X continue; X } else { X if (sp->stm2->kind == SK_IF && sp->stm2->exp2) { X freeexpr(sp->stm2->exp2); X sp->stm2->exp2 = NULL; X } X sp->exp1 = makeexpr_not(sp->exp1); /* if (x) else foo => if (!x) foo */ X swapstmts(sp->stm1, sp->stm2); X /* Ought to exchange comments for then/else parts */ X } X } X /* At this point we know sp1 != NULL */ X if (thisreturn) { X if (thisreturn->kind == SK_WHILE) { X if (usebreaks) { X sp1 = sp->stm1; X while (sp1->next) X sp1 = sp1->next; X if (sp->stm2) { X sp2 = sp->stm2; X while (sp2->next) X sp2 = sp2->next; X i = stmtcount(sp->stm1); X j = stmtcount(sp->stm2); X if (j >= breaklimit && i <= 2 && j > i*2 && X ((implies(sp->exp1, thisreturn->exp1, 0, 1) && X !checkexprchanged(sp->stm1, sp->exp1)) || X (sp1->kind == SK_ASSIGN && X implies(sp1->exp1, thisreturn->exp1, 0, 1)))) { X sp1->next = makestmt(SK_BREAK); X } else if (i >= breaklimit && j <= 2 && i > j*2 && X ((implies(sp->exp1, thisreturn->exp1, 1, 1) && X !checkexprchanged(sp->stm2, sp->exp1)) || X (sp2->kind == SK_ASSIGN && X implies(sp2->exp1, thisreturn->exp1, 0, 1)))) { X sp2->next = makestmt(SK_BREAK); X } else if (!checkconst(sp->exp2, 1)) { X /* not part of an else-if */ X if (j >= continuelimit) { X sp1->next = makestmt(SK_CONTINUE); X } else if (i >= continuelimit) { X sp2->next = makestmt(SK_CONTINUE); X } X } X } else { X i = stmtcount(sp->stm1); X if (i >= breaklimit && X implies(sp->exp1, thisreturn->exp1, 1, 1)) { X sp->exp1 = makeexpr_not(sp->exp1); X sp1->next = sp->next; X sp->next = sp->stm1; X sp->stm1 = makestmt(SK_BREAK); X } else if (i >= continuelimit) { X sp->exp1 = makeexpr_not(sp->exp1); X sp1->next = sp->next; X sp->next = sp->stm1; X sp->stm1 = makestmt(SK_CONTINUE); X } X } X } X } else { X if (usereturns) { X sp2 = sp->stm1; X while (sp2->next) X sp2 = sp2->next; X if (sp->stm2) { X /* if (x) foo; else bar; (return;) => if (x) {foo; return;} bar; */ X if (stmtcount(sp->stm2) >= returnlimit) { X if (!deadendblock(sp->stm1)) X sp2->next = copystmt(thisreturn); X } else if (stmtcount(sp->stm1) >= returnlimit) { X sp2 = sp->stm2; X while (sp2->next) X sp2 = sp2->next; X if (!deadendblock(sp->stm2)) X sp2->next = copystmt(thisreturn); X } X } else { /* if (x) foo; (return;) => if (!x) return; foo; */ X if (stmtcount(sp->stm1) >= returnlimit) { X sp->exp1 = makeexpr_not(sp->exp1); X sp2->next = sp->next; X sp->next = sp->stm1; X sp->stm1 = copystmt(thisreturn); X } X } X } X } X } X if (!checkconst(sp->exp2, 1)) { /* not part of an else-if */ X de1 = deadendblock(sp->stm1); X de2 = deadendblock(sp->stm2); X if (de2 && !de1) { X sp->exp1 = makeexpr_not(sp->exp1); X swapstmts(sp->stm1, sp->stm2); X de1 = 1, de2 = 0; X } X if (de1 && !de2 && sp->stm2) { X if (sp->stm2->kind == SK_IF && sp->stm2->exp2) { X freeexpr(sp->stm2->exp2); X sp->stm2->exp2 = NULL; X } X for (sp2 = sp->stm2; sp2->next; sp2 = sp2->next) ; X sp2->next = sp->next; X sp->next = sp->stm2; /* if (x) ESCAPE else foo => if (x) ESCAPE; foo */ X sp->stm2 = NULL; X } X } X sp->exp1 = fixexpr(sp->exp1, ENV_BOOL); X break; X X case SK_WHILE: X if (whilefgets && /* handle "while eof(f) do readln(f,...)" */ X sp->stm1->kind == SK_ASSIGN && X sp->stm1->exp1->kind == EK_BICALL && X !strcmp(sp->stm1->exp1->val.s, "fgets") && X nosideeffects(sp->stm1->exp1->args[0], 1) && X nosideeffects(sp->stm1->exp1->args[1], 1) && X nosideeffects(sp->stm1->exp1->args[2], 1)) { X if ((sp->exp1->kind == EK_NOT && X sp->exp1->args[0]->kind == EK_BICALL && *eofname && X !strcmp(sp->exp1->args[0]->val.s, eofname) && X exprsame(sp->exp1->args[0]->args[0], X sp->stm1->exp1->args[2], 1)) || X (sp->exp1->kind == EK_EQ && X sp->exp1->args[0]->kind == EK_BICALL && X !strcmp(sp->exp1->args[0]->val.s, "feof") && X checkconst(sp->exp1->args[1], 0) && X exprsame(sp->exp1->args[0]->args[0], X sp->stm1->exp1->args[2], 1))) { X sp->stm1->exp1->val.type = tp_strptr; X sp->exp1 = makeexpr_rel(EK_NE, X sp->stm1->exp1, X makeexpr_nil()); X sp->stm1 = sp->stm1->next; X } X } X fixblock(&sp->stm1, sp); X sp->exp1 = fixexpr(sp->exp1, ENV_BOOL); X if (checkconst(sp->exp1, 1)) X infiniteloop(sp); X break; X X case SK_REPEAT: X fixblock(&sp->stm1, NULL); X sp->exp1 = fixexpr(sp->exp1, ENV_BOOL); X if (checkconst(sp->exp1, 1)) X infiniteloop(sp); X break; X X case SK_TRY: X save_tryblock = fixexpr_tryblock; X save_tryflag = fixexpr_tryflag; X fixexpr_tryblock = sp->exp1->val.i; X fixexpr_tryflag = 0; X fixblock(&sp->stm1, NULL); X if (fixexpr_tryflag) X sp->exp2 = makeexpr_long(1); X fixexpr_tryblock = save_tryblock; X fixexpr_tryflag = save_tryflag; X fixblock(&sp->stm2, NULL); X break; X X case SK_BODY: X fixblock(&sp->stm1, thisreturn); X break; X X case SK_CASE: X fixblock(&sp->stm1, NULL); X sp->exp1 = fixexpr(sp->exp1, ENV_EXPR); X if (!sp->stm1) { /* empty case */ X sp->kind = SK_ASSIGN; X continue; X } else if (sp->stm1->kind != SK_CASELABEL) { /* default only */ X for (sp2 = sp->stm1; sp2->next; sp2 = sp2->next) ; X sp2->next = sp->next; X sp->next = sp->stm1; X sp->kind = SK_ASSIGN; X sp->stm1 = NULL; X continue; X } X break; X X default: X fixblock(&sp->stm1, NULL); X fixblock(&sp->stm2, NULL); X sp->exp1 = fixexpr(sp->exp1, ENV_EXPR); X sp->exp2 = fixexpr(sp->exp2, ENV_EXPR); X sp->exp3 = fixexpr(sp->exp3, ENV_EXPR); X if (sp->next && X (sp->kind == SK_GOTO || X sp->kind == SK_BREAK || X sp->kind == SK_CONTINUE || X sp->kind == SK_RETURN) && X !haslabels(sp->next)) { X if (elimdeadcode) { X note("Deleting unreachable code [255]"); X while (sp->next && !haslabels(sp->next)) X eatstmt(&sp->next); X } else { X note("Code is unreachable [256]"); X } X } else if (sp->kind == SK_RETURN && X thisreturn && X thisreturn->kind == SK_RETURN && X exprsame(sp->exp1, thisreturn->exp1, 1)) { X eatstmt(spp); X continue; X } X break; X } X spp = &sp->next; X } X saveserial = curserial; X} X X X X X/* Convert comma expressions into multiple statements */ X XStatic int checkcomma_expr(spp, exp) XStmt **spp; XExpr **exp; X{ X Stmt *sp; X Expr *ex = *exp; X int i, res; X X switch (ex->kind) { X X case EK_COMMA: X if (spp) { X res = checkcomma_expr(spp, &ex->args[ex->nargs-1]); X for (i = ex->nargs-1; --i >= 0; ) { X sp = makestmt(SK_ASSIGN); X sp->exp1 = ex->args[i]; X sp->next = *spp; X *spp = sp; X res = checkcomma_expr(spp, &ex->args[i]); X } X *exp = ex->args[ex->nargs-1]; X } X return 1; X X case EK_COND: X if (isescape(ex->args[1]) && spp && X !isescape(ex->args[2])) { X swapexprs(ex->args[1], ex->args[2]); X ex->args[0] = makeexpr_not(ex->args[0]); X } X if (isescape(ex->args[2])) { X if (spp) { X res = checkcomma_expr(spp, &ex->args[1]); X if (ex->args[0]->kind == EK_ASSIGN) { X sp = makestmt(SK_ASSIGN); X sp->exp1 = copyexpr(ex->args[0]); X sp->next = makestmt(SK_IF); X sp->next->next = *spp; X *spp = sp; X res = checkcomma_expr(spp, &sp->exp1); X ex->args[0] = grabarg(ex->args[0], 0); X sp = sp->next; X } else { X sp = makestmt(SK_IF); X sp->next = *spp; X *spp = sp; X } X sp->exp1 = makeexpr_not(ex->args[0]); X sp->stm1 = makestmt(SK_ASSIGN); X sp->stm1->exp1 = eatcasts(ex->args[2]); X res = checkcomma_expr(&sp->stm1, &ex->args[2]); X res = checkcomma_expr(spp, &sp->exp1); X *exp = ex->args[1]; X } X return 1; X } X return checkcomma_expr(spp, &ex->args[0]); X X case EK_AND: X case EK_OR: X return checkcomma_expr(spp, &ex->args[0]); X X default: X res = 0; X for (i = ex->nargs; --i >= 0; ) { X res += checkcomma_expr(spp, &ex->args[i]); X } X return res; X X } X} X X X XStatic void checkcommas(spp) XStmt **spp; X{ X Stmt *sp; X int res; X X while ((sp = *spp)) { X checkcommas(&sp->stm1); X checkcommas(&sp->stm2); X switch (sp->kind) { X X case SK_ASSIGN: X case SK_IF: X case SK_CASE: X case SK_RETURN: X if (sp->exp1) X res = checkcomma_expr(spp, &sp->exp1); X break; X X case SK_WHILE: X /* handle the argument */ X break; X X case SK_REPEAT: X /* handle the argument */ X break; X X case SK_FOR: X if (sp->exp1) X res = checkcomma_expr(spp, &sp->exp1); X /* handle the other arguments */ X break; X X default: X break; X } X spp = &sp->next; X } X} X X X X XStatic int checkvarchangeable(ex, mp) XExpr *ex; XMeaning *mp; X{ X switch (ex->kind) { X X case EK_VAR: X return (mp == (Meaning *)ex->val.i); X X case EK_DOT: X case EK_INDEX: X return checkvarchangeable(ex->args[0], mp); X X default: X return 0; X } X} X X X Xint checkvarchangedexpr(ex, mp, addrokay) XExpr *ex; XMeaning *mp; Xint addrokay; X{ X int i; X Meaning *mp3; X unsigned int safemask = 0; X X switch (ex->kind) { X X case EK_FUNCTION: X case EK_SPCALL: X if (ex->kind == EK_FUNCTION) { X i = 0; X mp3 = ((Meaning *)ex->val.i)->type->fbase; X } else { X i = 1; X if (ex->args[0]->val.type->kind != TK_PROCPTR) X return 1; X mp3 = ex->args[0]->val.type->basetype->fbase; X } X for ( ; i < ex->nargs && i < 16; i++) { X if (!mp3) { X intwarning("checkvarchangedexpr", "Too many arguments for EK_FUNCTION [266]"); X break; X } X if (mp3->kind == MK_PARAM && X (mp3->type->kind == TK_ARRAY || X mp3->type->kind == TK_STRING || X mp3->type->kind == TK_SET)) X safemask |= 1<kind == MK_VARPARAM && X mp3->type == tp_strptr && mp3->anyvarflag) X i++; X mp3 = mp3->xnext; X } X if (mp3) X intwarning("checkvarchangedexpr", "Too few arguments for EK_FUNCTION [267]"); X break; X X case EK_VAR: X if (mp == (Meaning *)ex->val.i) { X if ((mp->type->kind == TK_ARRAY || X mp->type->kind == TK_STRING || X mp->type->kind == TK_SET) && X ex->val.type->kind == TK_POINTER && !addrokay) X return 1; /* must be an implicit & */ X } X break; X X case EK_ADDR: X case EK_ASSIGN: X case EK_POSTINC: X case EK_POSTDEC: X if (checkvarchangeable(ex->args[0], mp)) X return 1; X break; X X case EK_BICALL: X if (structuredfunc(ex) && checkvarchangeable(ex->args[0], mp)) X return 1; X safemask = safemask_bicall(ex->val.s); X break; X /* In case calls to these functions were lazy and passed X the array rather than its (implicit) address. Other X BICALLs had better be careful about their arguments. */ X X case EK_PLUS: X if (addrokay) /* to keep from being scared by pointer */ X safemask = ~0; /* arithmetic on string being passed */ X break; /* to functions. */ X X default: X break; X } X for (i = 0; i < ex->nargs; i++) { X if (checkvarchangedexpr(ex->args[i], mp, safemask&1)) X return 1; X safemask >>= 1; X } X return 0; X} X X X Xint checkvarchanged(sp, mp) XStmt *sp; XMeaning *mp; X{ X if (mp->constqual) X return 0; X if (mp->varstructflag || !mp->ctx || mp->ctx->kind != MK_FUNCTION || X mp->volatilequal || alwayscopyvalues) X return 1; X while (sp) { X if (/* sp->kind == SK_GOTO || */ X sp->kind == SK_LABEL || X checkvarchanged(sp->stm1, mp) || X checkvarchanged(sp->stm2, mp) || X (sp->exp1 && checkvarchangedexpr(sp->exp1, mp, 1)) || X (sp->exp2 && checkvarchangedexpr(sp->exp2, mp, 1)) || X (sp->exp3 && checkvarchangedexpr(sp->exp3, mp, 1))) X return 1; X sp = sp->next; X } X return 0; X} X X X Xint checkexprchanged(sp, ex) XStmt *sp; XExpr *ex; X{ X Meaning *mp; X int i; X X for (i = 0; i < ex->nargs; i++) { X if (checkexprchanged(sp, ex->args[i])) X return 1; X } X switch (ex->kind) { X X case EK_VAR: X mp = (Meaning *)ex->val.i; X if (mp->kind == MK_CONST) X return 0; X else X return checkvarchanged(sp, mp); X X case EK_HAT: X case EK_INDEX: X case EK_SPCALL: X return 1; X X case EK_FUNCTION: X case EK_BICALL: X return !nosideeffects_func(ex); X X default: X return 0; X } X} X X X X X X/* Check if a variable always occurs with a certain offset added, e.g. "i+1" */ X XStatic int theoffset, numoffsets, numzerooffsets; X#define BadOffset (-999) X Xvoid checkvaroffsetexpr(ex, mp, myoffset) XExpr *ex; XMeaning *mp; Xint myoffset; X{ X int i, nextoffset = 0; X Expr *ex2; X X if (!ex) X return; X switch (ex->kind) { X X case EK_VAR: X if (ex->val.i == (long)mp) { X if (myoffset == 0) X numzerooffsets++; X else if (numoffsets == 0 || myoffset == theoffset) { X theoffset = myoffset; X numoffsets++; X } else X theoffset = BadOffset; X } X break; X X case EK_PLUS: X ex2 = ex->args[ex->nargs-1]; X if (ex2->kind == EK_CONST && X ex2->val.type->kind == TK_INTEGER) { X nextoffset = ex2->val.i; X } X break; X X case EK_HAT: X case EK_POSTINC: X case EK_POSTDEC: X nextoffset = BadOffset; X break; X X case EK_ASSIGN: X checkvaroffsetexpr(ex->args[0], mp, BadOffset); X checkvaroffsetexpr(ex->args[1], mp, 0); X return; X X default: X break; X } X i = ex->nargs; X while (--i >= 0) X checkvaroffsetexpr(ex->args[i], mp, nextoffset); X} X X Xvoid checkvaroffsetstmt(sp, mp) XStmt *sp; XMeaning *mp; X{ X while (sp) { X checkvaroffsetstmt(sp->stm1, mp); X checkvaroffsetstmt(sp->stm1, mp); X checkvaroffsetexpr(sp->exp1, mp, 0); X checkvaroffsetexpr(sp->exp2, mp, 0); X checkvaroffsetexpr(sp->exp3, mp, 0); X sp = sp->next; X } X} X X Xint checkvaroffset(sp, mp) XStmt *sp; XMeaning *mp; X{ X if (mp->varstructflag || !mp->ctx || mp->ctx->kind != MK_FUNCTION) X return 0; X numoffsets = 0; X numzerooffsets = 0; X checkvaroffsetstmt(sp, mp); X if (numoffsets == 0 || theoffset == BadOffset || X numoffsets <= numzerooffsets * 3) X return 0; X else X return theoffset; X} X X X X Xvoid initfilevars(mp, sppp, exbase) XMeaning *mp; XStmt ***sppp; XExpr *exbase; X{ X Stmt *sp; X Type *tp; X Expr *ex; X X while (mp) { X if ((mp->kind == MK_VAR && mp->refcount > 0 && !mp->istemporary) || X mp->kind == MK_FIELD) { X tp = mp->type; X if (isfiletype(tp)) { X mp->refcount++; X sp = makestmt(SK_ASSIGN); X sp->next = **sppp; X **sppp = sp; X if (exbase) X ex = makeexpr_dot(copyexpr(exbase), mp); X else X ex = makeexpr_var(mp); X sp->exp1 = makeexpr_assign(copyexpr(ex), makeexpr_nil()); X } else if (tp->kind == TK_RECORD) { X if (exbase) X ex = makeexpr_dot(copyexpr(exbase), mp); X else X ex = makeexpr_var(mp); X initfilevars(tp->fbase, sppp, ex); X freeexpr(ex); X } else if (tp->kind == TK_ARRAY) { X while (tp->kind == TK_ARRAY) X tp = tp->basetype; X if (isfiletype(tp)) X note(format_s("Array of files %s should be initialized [257]", X mp->name)); X } X } X mp = mp->cnext; X } X} X X X X X XStatic Stmt *p_body() X{ X Stmt *sp, **spp, *spbody, **sppbody, *spbase, *thereturn; X Meaning *mp; X Expr *ex; X int haspostamble; X long saveserial; X X if (verbose) X fprintf(logf, "%s, %d/%d: Translating %s (in %s)\n", X infname, inf_lnum, outf_lnum, X curctx->name, curctx->ctx->name); X notephase = 1; X spp = &spbase; X addstmt(SK_HEADER); X sp->exp1 = makeexpr_var(curctx); X checkkeyword(TOK_INLINE); X if (curtok != TOK_END && curtok != TOK_BEGIN && curtok != TOK_INLINE) { X if (curctx->kind == MK_FUNCTION || curctx->anyvarflag) X wexpecttok(TOK_BEGIN); X else X wexpecttok(TOK_END); X skiptotoken2(TOK_BEGIN, TOK_END); X } X if (curtok == TOK_END) { X gettok(); X spbody = NULL; X } else { X spbody = p_stmt(NULL, SF_FUNC); /* parse the procedure/program body */ X } X if (curtok == TOK_IDENT && curtokmeaning == curctx) { X gettok(); /* Modula-2 */ X } X notephase = 2; X saveserial = curserial; X curserial = 10000; X if (curctx->kind == MK_FUNCTION) { /* handle copy parameters */ X for (mp = curctx->type->fbase; mp; mp = mp->xnext) { X if (!mp->othername && mp->varstructflag) { X mp->othername = stralloc(format_s(name_COPYPAR, mp->name)); X mp->rectype = mp->type; X addstmt(SK_ASSIGN); X sp->exp1 = makeexpr_assign(makeexpr_var(mp), X makeexpr_name(mp->othername, mp->rectype)); X mp->refcount++; X } else if (mp->othername) { X if (checkvarchanged(spbody, mp)) { X addstmt(SK_ASSIGN); X sp->exp1 = makeexpr_assign(makeexpr_var(mp), X makeexpr_hat(makeexpr_name(mp->othername, X mp->rectype), 0)); X mp->refcount++; X } else { /* don't need to copy it after all */ X strchange(&mp->othername, mp->name); X ex = makeexpr_var(mp); X ex->val.type = mp->rectype; X replaceexpr(spbody, makeexpr_var(mp), makeexpr_hat(ex, 0)); X } X } X } X } X for (mp = curctx->cbase; mp; mp = mp->cnext) { X if (mp->kind == MK_LABEL && mp->val.i) { X addstmt(SK_IF); X sp->exp1 = makeexpr_bicall_1("setjmp", tp_int, X makeexpr_var(mp->xnext)); X sp->stm1 = makestmt(SK_GOTO); X sp->stm1->exp1 = makeexpr_name(format_s(name_LABEL, mp->name), X tp_integer); X } X } X *spp = spbody; X sppbody = spp; X while (*spp) X spp = &((*spp)->next); X haspostamble = 0; X initfilevars(curctx->cbase, &sppbody, NULL); X for (mp = curctx->cbase; mp; mp = mp->cnext) { X if (mp->kind == MK_VAR && mp->refcount > 0 && isfiletype(mp->type) && X !mp->istemporary) { X if (curctx->kind != MK_MODULE || curctx->anyvarflag) { X addstmt(SK_IF); /* close file variables */ X sp->exp1 = makeexpr_rel(EK_NE, makeexpr_var(mp), makeexpr_nil()); X sp->stm1 = makestmt(SK_ASSIGN); X sp->stm1->exp1 = makeexpr_bicall_1("fclose", tp_void, makeexpr_var(mp)); X } X haspostamble = 1; X } X } X thereturn = &bogusreturn; X if (curctx->kind == MK_FUNCTION && curctx->type->basetype != tp_void) { X if ((haspostamble || !checkreturns(&spbase, 1)) && X curctx->cbase->refcount > 0) { /* add function return code */ X addstmt(SK_RETURN); X sp->exp1 = makeexpr_var(curctx->cbase); X } X thereturn = NULL; X } else if (curctx->kind == MK_MODULE && curctx->anyvarflag) { X addstmt(SK_ASSIGN); X sp->exp1 = makeexpr_bicall_1("exit", tp_void, makeexpr_long(0)); X thereturn = NULL; X } X if (debug>2) { fprintf(outf, "calling fixblock/usecommas on:\n"); dumpstmt(spbase, 5); } X curserial = saveserial; X sp = makestmt(SK_BODY); X sp->stm1 = spbase; X fixblock(&sp, thereturn); /* finishing touches to statements and expressions */ X spbase = sp->stm1; X FREE(sp); X if (usecommas != 1) X checkcommas(&spbase); /* unroll ugly EK_COMMA and EK_COND expressions */ X if (debug>1) { fprintf(outf, "p_body returns:\n"); dumpstmt(spbase, 5); } X notephase = 0; X return spbase; X} X X X X X#define checkWord() if (anywords) output(" "); anywords = 1 X XStatic void out_function(func) XMeaning *func; X{ X Meaning *mp; X Symbol *sym; X int opts, anywords, spacing, saveindent; X X if (func->varstructflag) { X makevarstruct(func); X } X if (collectnest) { X for (mp = func->cbase; mp; mp = mp->cnext) { X if (mp->kind == MK_FUNCTION && mp->isforward) { X forward_decl(mp, 0); X } X } X for (mp = func->cbase; mp; mp = mp->cnext) { X if (mp->kind == MK_FUNCTION && mp->type) { X pushctx(mp); X out_function(mp); /* generate the sub-procedures first */ X popctx(); X } X } X } X spacing = functionspace; X for (mp = func; mp->ctx->kind == MK_FUNCTION; mp = mp->ctx) { X if (spacing > minfuncspace) X spacing--; X } X outsection(spacing); X flushcomments(&func->comments, -1, 0); X if (usePPMacros == 1) { X forward_decl(func, 0); X outsection(minorspace); X } X opts = ODECL_HEADER; X anywords = 0; X if (func->namedfile) { X checkWord(); X if (useAnyptrMacros || ansiC < 2) X output("Inline"); X else X output("inline"); X } X if (!func->exported) { X if (func->ctx->kind == MK_FUNCTION) { X if (useAnyptrMacros) { X checkWord(); X output("Local"); X } else if (use_static) { X checkWord(); X output("static"); X } X } else if ((findsymbol(func->name)->flags & NEEDSTATIC) || X (use_static != 0 && !useAnyptrMacros)) { X checkWord(); X output("static"); X } else if (useAnyptrMacros) { X checkWord(); X output("Static"); X } X } X if (func->type->basetype != tp_void || ansiC != 0) { X checkWord(); X outbasetype(func->type, 0); X } X if (anywords) { X if (newlinefunctions) X opts |= ODECL_FUNCTION; X else X output(" "); X } X outdeclarator(func->type, func->name, opts); X if (fullprototyping == 0) { X saveindent = outindent; X moreindent(argindent); X out_argdecls(func->type); X outindent = saveindent; X } X for (mp = func->type->fbase; mp; mp = mp->xnext) { X if (mp->othername && strcmp(mp->name, mp->othername)) X mp->wasdeclared = 0; /* make sure we also declare the copy */ X } X func->wasdeclared = 1; X outcontext = func; X out_block((Stmt *)func->val.i, BR_FUNCTION, 10000); X if (useundef) { X anywords = 0; X for (mp = func->cbase; mp; mp = mp->cnext) { X if (mp->kind == MK_CONST && END_OF_FILE if test 49392 -ne `wc -c <'src/parse.c.2'`; then echo shar: \"'src/parse.c.2'\" unpacked with wrong size! fi # end of 'src/parse.c.2' fi echo shar: End of archive 30 \(of 32\). cp /dev/null ark30isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 32 archives. echo "Now see PACKNOTES and the README" rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0