diff options
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 1471 |
1 files changed, 201 insertions, 1270 deletions
@@ -29,34 +29,17 @@ extern void after_beginfile(IOBUF **curfile); extern double pow(double x, double y); extern double modf(double x, double *yp); extern double fmod(double x, double y); -NODE **fcall_list; +NODE **fcall_list = NULL; long fcall_count = 0; int currule = 0; IOBUF *curfile = NULL; /* current data file */ int exiting = FALSE; -#ifdef DEBUGGING +int (*interpret)(INSTRUCTION *); + extern int pre_execute(INSTRUCTION **); extern void post_execute(INSTRUCTION *); -#else -#define r_interpret interpret -#endif - -/* - * Flag which executable this is; done here because eval.c is compiled - * differently for each of them. - */ -enum exe_mode which_gawk = -#ifdef PROFILING - exe_profiling /* pgawk */ -#else -# ifdef DEBUGGING - exe_debugging /* dgawk */ -# else - exe_normal /* normal gawk */ -# endif -#endif - ; /* which_gawk */ +extern void frame_popped(); #if __GNUC__ < 2 NODE *_t; /* used as a temporary in macros */ @@ -66,12 +49,7 @@ int ORSlen; int OFMTidx; int CONVFMTidx; -/* Profiling stuff */ -#ifdef PROFILING -#define INCREMENT(n) n++ -#else -#define INCREMENT(n) /* nothing */ -#endif +static NODE *node_Boolean[2]; /* This rather ugly macro is for VMS C */ #ifdef C @@ -262,9 +240,12 @@ static const char *const nodetypes[] = { "Node_var_new", "Node_param_list", "Node_func", + "Node_ext_func", "Node_hashnode", - "Node_ahash", "Node_array_ref", + "Node_array_tree", + "Node_array_leaf", + "Node_dump_array", "Node_arrayfor", "Node_frame", "Node_instruction", @@ -349,6 +330,7 @@ static struct optypetab { { "Op_K_nextfile", "nextfile" }, { "Op_builtin", NULL }, { "Op_sub_builtin", NULL }, + { "Op_ext_builtin", NULL }, { "Op_in_array", " in " }, { "Op_func_call", NULL }, { "Op_indirect_func_call", NULL }, @@ -376,7 +358,6 @@ static struct optypetab { { "Op_field_assign", NULL }, { "Op_after_beginfile", NULL }, { "Op_after_endfile", NULL }, - { "Op_ext_func", NULL }, { "Op_func", NULL }, { "Op_exec_count", NULL }, { "Op_breakpoint", NULL }, @@ -446,20 +427,19 @@ flags2str(int flagval) { static const struct flagtab values[] = { { MALLOC, "MALLOC" }, - { PERM, "PERM" }, { STRING, "STRING" }, { STRCUR, "STRCUR" }, { NUMCUR, "NUMCUR" }, { NUMBER, "NUMBER" }, { MAYBE_NUM, "MAYBE_NUM" }, - { ARRAYMAXED, "ARRAYMAXED" }, - { FUNC, "FUNC" }, { FIELD, "FIELD" }, { INTLSTR, "INTLSTR" }, - { NUMIND, "NUMIND" }, -#ifdef WSTRCUR + { NUMINT, "NUMINT" }, + { INTIND, "INTIND" }, { WSTRCUR, "WSTRCUR" }, -#endif + { ARRAYMAXED, "ARRAYMAXED" }, + { HALFHAT, "HALFHAT" }, + { XARRAY, "XARRAY" }, { 0, NULL }, }; @@ -484,7 +464,7 @@ genflags2str(int flagval, const struct flagtab *tab) * the '|' character. */ space_needed = (strlen(tab[i].name) + (sp != buffer)); - if (space_left < space_needed) + if (space_left <= space_needed) fatal(_("buffer overflow in genflags2str")); if (sp != buffer) { @@ -498,6 +478,7 @@ genflags2str(int flagval, const struct flagtab *tab) } } + *sp = '\0'; return buffer; } @@ -582,7 +563,6 @@ posix_compare(NODE *s1, NODE *s2) return ret; } - /* cmp_nodes --- compare two nodes, returning negative, 0, positive */ int @@ -599,6 +579,11 @@ cmp_nodes(NODE *t1, NODE *t2) (void) force_number(t1); if (t2->flags & MAYBE_NUM) (void) force_number(t2); + if (t1->flags & INTIND) + t1 = force_string(t1); + if (t2->flags & INTIND) + t2 = force_string(t2); + if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) { if (t1->numbr == t2->numbr) ret = 0; @@ -610,8 +595,8 @@ cmp_nodes(NODE *t1, NODE *t2) return ret; } - (void) force_string(t1); - (void) force_string(t2); + t1 = force_string(t1); + t2 = force_string(t2); len1 = t1->stlen; len2 = t2->stlen; ldiff = len1 - len2; @@ -637,11 +622,13 @@ cmp_nodes(NODE *t1, NODE *t2) ret = casetable[*cp1] - casetable[*cp2]; } else ret = memcmp(t1->stptr, t2->stptr, l); - return (ret == 0 ? ldiff : ret); + + ret = ret == 0 ? ldiff : ret; + return ret; } +/* push_frame --- push a frame NODE onto stack */ -#if defined(PROFILING) || defined(DEBUGGING) static void push_frame(NODE *f) { @@ -663,27 +650,20 @@ push_frame(NODE *f) fcall_list[1] = f; } + +/* pop_frame --- pop off a frame NODE*/ + static void pop_frame() { -#ifdef DEBUGGING - extern void frame_popped(); -#endif if (fcall_count > 1) memmove(fcall_list + 1, fcall_list + 2, (fcall_count - 1) * sizeof(NODE *)); fcall_count--; assert(fcall_count >= 0); -#ifdef DEBUGGING - frame_popped(); -#endif + if (do_debug) + frame_popped(); } -#else /* not PROFILING or DEBUGGING */ -#define push_frame(p) /* nothing */ -#define pop_frame() /* nothing */ -#endif - -#ifdef PROFILING /* dump_fcall_stack --- print a backtrace of the awk function calls */ @@ -691,7 +671,7 @@ void dump_fcall_stack(FILE *fp) { NODE *f, *func; - long i = 0; + long i = 0, j, k = 0; if (fcall_count == 0) return; @@ -699,19 +679,20 @@ dump_fcall_stack(FILE *fp) /* current frame */ func = frame_ptr->func_node; - fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param); + for (j = 0; j <= frame_ptr->num_tail_calls; j++) + fprintf(fp, "\t# %3ld. %s\n", k++, func->vname); /* outer frames except main */ for (i = 1; i < fcall_count; i++) { f = fcall_list[i]; func = f->func_node; - fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param); + for (j = 0; j <= f->num_tail_calls; j++) + fprintf(fp, "\t# %3ld. %s\n", k++, func->vname); } - fprintf(fp, "\t# %3ld. -- main --\n", fcall_count); + fprintf(fp, "\t# %3ld. -- main --\n", k); } -#endif /* PROFILING */ /* set_IGNORECASE --- update IGNORECASE as appropriate */ @@ -728,9 +709,10 @@ set_IGNORECASE() if (do_traditional) IGNORECASE = FALSE; else if ((IGNORECASE_node->var_value->flags & (STRING|STRCUR)) != 0) { - if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0) - IGNORECASE = (force_string(IGNORECASE_node->var_value)->stlen > 0); - else + if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0) { + IGNORECASE_node->var_value = force_string(IGNORECASE_node->var_value); + IGNORECASE = (IGNORECASE_node->var_value->stlen > 0); + } else IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); } else if ((IGNORECASE_node->var_value->flags & (NUMCUR|NUMBER)) != 0) IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); @@ -823,7 +805,8 @@ set_BINMODE() void set_OFS() { - OFS = force_string(OFS_node->var_value)->stptr; + OFS_node->var_value = force_string(OFS_node->var_value); + OFS = OFS_node->var_value->stptr; OFSlen = OFS_node->var_value->stlen; OFS[OFSlen] = '\0'; } @@ -833,7 +816,8 @@ set_OFS() void set_ORS() { - ORS = force_string(ORS_node->var_value)->stptr; + ORS_node->var_value = force_string(ORS_node->var_value); + ORS = ORS_node->var_value->stptr; ORSlen = ORS_node->var_value->stlen; ORS[ORSlen] = '\0'; } @@ -849,6 +833,7 @@ fmt_ok(NODE *n) { NODE *tmp = force_string(n); const char *p = tmp->stptr; + #if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1 static const char float_formats[] = "efgEG"; #else @@ -890,7 +875,7 @@ fmt_index(NODE *n) if (fmt_list == NULL) emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index"); - (void) force_string(n); + n = force_string(n); while (ix < fmt_hiwater) { if (cmp_nodes(fmt_list[ix], n) == 0) return ix; @@ -942,41 +927,45 @@ set_LINT() if ((LINT_node->var_value->flags & MAYBE_NUM) == 0) { const char *lintval; size_t lintlen; + NODE *tmp; - do_lint = (force_string(LINT_node->var_value)->stlen > 0); - lintval = LINT_node->var_value->stptr; - lintlen = LINT_node->var_value->stlen; - if (do_lint) { - do_lint = LINT_ALL; + tmp = LINT_node->var_value = force_string(LINT_node->var_value); + lintval = tmp->stptr; + lintlen = tmp->stlen; + if (lintlen > 0) { + do_flags |= DO_LINT_ALL; if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0) lintfunc = r_fatal; - else if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0) - do_lint = LINT_INVALID; - else + else if (lintlen == 7 && strncmp(lintval, "invalid", 7) == 0) { + do_flags &= ~ DO_LINT_ALL; + do_flags |= DO_LINT_INVALID; + } else lintfunc = warning; - } else + } else { + do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); lintfunc = warning; + } } else { if (force_number(LINT_node->var_value) != 0.0) - do_lint = LINT_ALL; + do_flags |= DO_LINT_ALL; else - do_lint = FALSE; + do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); lintfunc = warning; } } else if ((LINT_node->var_value->flags & (NUMCUR|NUMBER)) != 0) { if (force_number(LINT_node->var_value) != 0.0) - do_lint = LINT_ALL; + do_flags |= DO_LINT_ALL; else - do_lint = FALSE; + do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); lintfunc = warning; } else - do_lint = FALSE; /* shouldn't happen */ + do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); /* shouldn't happen */ if (! do_lint) lintfunc = warning; /* explicitly use warning() here, in case lintfunc == r_fatal */ - if (old_lint != do_lint && old_lint && do_lint == FALSE) + if (old_lint != do_lint && old_lint && ! do_lint) warning(_("turning off `--lint' due to assignment to `LINT'")); #endif /* ! NO_LINT */ } @@ -987,9 +976,11 @@ void set_TEXTDOMAIN() { int len; + NODE *tmp; - TEXTDOMAIN = force_string(TEXTDOMAIN_node->var_value)->stptr; - len = TEXTDOMAIN_node->var_value->stlen; + tmp = TEXTDOMAIN_node->var_value = force_string(TEXTDOMAIN_node->var_value); + TEXTDOMAIN = tmp->stptr; + len = tmp->stlen; TEXTDOMAIN[len] = '\0'; /* * Note: don't call textdomain(); this value is for @@ -1057,7 +1048,6 @@ update_FNR() } - NODE *frame_ptr; /* current frame */ STACK_ITEM *stack_ptr = NULL; STACK_ITEM *stack_bottom; @@ -1078,32 +1068,6 @@ NODE **args_array = NULL; STACK_ITEM * grow_stack() { - if (stack_ptr == NULL) { - char *val; - - if ((val = getenv("GAWK_STACKSIZE")) != NULL) { - if (isdigit((unsigned char) *val)) { - unsigned long n = 0; - for (; *val && isdigit((unsigned char) *val); val++) - n = (n * 10) + *val - '0'; - if (n >= 1) - STACK_SIZE = n; - } - } - - emalloc(stack_bottom, STACK_ITEM *, STACK_SIZE * sizeof(STACK_ITEM), "grow_stack"); - stack_ptr = stack_bottom - 1; - stack_top = stack_bottom + STACK_SIZE - 1; - - /* initialize frame pointer */ - getnode(frame_ptr); - frame_ptr->type = Node_frame; - frame_ptr->stack = NULL; - frame_ptr->func_node = NULL; /* in main */ - frame_ptr->vname = NULL; - return stack_ptr; - } - STACK_SIZE *= 2; erealloc(stack_bottom, STACK_ITEM *, STACK_SIZE * sizeof(STACK_ITEM), "grow_stack"); stack_top = stack_bottom + STACK_SIZE - 1; @@ -1123,9 +1087,6 @@ r_get_lhs(NODE *n, int reference) int isparam = FALSE; if (n->type == Node_param_list) { - if ((n->flags & FUNC) != 0) - fatal(_("can't use function name `%s' as variable or array"), - n->vname); isparam = TRUE; n = GET_PARAM(n->param_cnt); } @@ -1139,11 +1100,11 @@ r_get_lhs(NODE *n, int reference) fatal(_("attempt to use array `%s' in a scalar context"), array_vname(n)); n->orig_array->type = Node_var; - n->orig_array->var_value = Nnull_string; + n->orig_array->var_value = dupnode(Nnull_string); /* fall through */ case Node_var_new: n->type = Node_var; - n->var_value = Nnull_string; + n->var_value = dupnode(Nnull_string); break; case Node_var: @@ -1158,7 +1119,7 @@ r_get_lhs(NODE *n, int reference) _("reference to uninitialized argument `%s'") : _("reference to uninitialized variable `%s'")), n->vname); - return &n->var_value; + return & n->var_value; } @@ -1239,17 +1200,42 @@ static INSTRUCTION * setup_frame(INSTRUCTION *pc) { NODE *r = NULL; - NODE *m; - NODE *f; + NODE *m, *f, *fp; NODE **sp = NULL; - char **varnames; - int pcount, arg_count, i; + int pcount, arg_count, i, j; + int tail_optimize = FALSE; f = pc->func_body; - pcount = f->lnode->param_cnt; - varnames = f->parmlist; + pcount = f->param_cnt; + fp = f->fparms; arg_count = (pc + 1)->expr_count; + /* tail recursion optimization */ + tail_optimize = ((pc + 1)->tail_call && do_optimize > 1 + && ! do_debug && ! do_profile); + + if (tail_optimize) { + /* free local vars of calling frame */ + + NODE *func; + int n; + + func = frame_ptr->func_node; + for (n = func->param_cnt, sp = frame_ptr->stack; n > 0; n--) { + r = *sp++; + if (r->type == Node_var) /* local variable */ + DEREF(r->var_value); + else if (r->type == Node_var_array) /* local array */ + assoc_clear(r); + } + sp = frame_ptr->stack; + + } else if (pcount > 0) { + emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame"); + memset(sp, 0, pcount * sizeof(NODE *)); + } + + /* check for extra args */ if (arg_count > pcount) { warning( @@ -1262,23 +1248,23 @@ setup_frame(INSTRUCTION *pc) } while (--arg_count > pcount); } - if (pcount > 0) { - emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame"); - memset(sp, 0, pcount * sizeof(NODE *)); - } + for (i = 0, j = arg_count - 1; i < pcount; i++, j--) { + if (tail_optimize) + r = sp[i]; + else { + getnode(r); + memset(r, 0, sizeof(NODE)); + sp[i] = r; + } - for (i = 0; i < pcount; i++) { - getnode(r); - memset(r, 0, sizeof(NODE)); - sp[i] = r; if (i >= arg_count) { /* local variable */ r->type = Node_var_new; - r->vname = varnames[i]; + r->vname = fp[i].param; continue; } - m = PEEK(arg_count - i - 1); /* arguments in reverse order on runtime stack */ + m = PEEK(j); /* arguments in reverse order on runtime stack */ if (m->type == Node_param_list) m = GET_PARAM(m->param_cnt); @@ -1302,7 +1288,7 @@ setup_frame(INSTRUCTION *pc) * subsequent param. */ r->type = Node_var; - r->var_value = Nnull_string; + r->var_value = dupnode(Nnull_string); break; case Node_val: @@ -1313,10 +1299,16 @@ setup_frame(INSTRUCTION *pc) default: cant_happen(); } - r->vname = varnames[i]; + r->vname = fp[i].param; } + stack_adj(-arg_count); /* adjust stack pointer */ + if (tail_optimize) { + frame_ptr->num_tail_calls++; + return f->code_ptr; + } + if (pc->opcode == Op_indirect_func_call) { r = POP(); /* indirect var */ DEREF(r); @@ -1324,7 +1316,8 @@ setup_frame(INSTRUCTION *pc) frame_ptr->vname = source; /* save current source */ - push_frame(frame_ptr); + if (do_profile || do_debug) + push_frame(frame_ptr); /* save current frame in stack */ PUSH(frame_ptr); @@ -1335,6 +1328,7 @@ setup_frame(INSTRUCTION *pc) frame_ptr->stack = sp; frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the previous stack frame */ frame_ptr->func_node = f; + frame_ptr->num_tail_calls = 0; frame_ptr->vname = NULL; frame_ptr->reti = pc; /* on return execute pc->nexti */ @@ -1354,7 +1348,7 @@ restore_frame(NODE *fp) INSTRUCTION *ri; func = frame_ptr->func_node; - n = func->lnode->param_cnt; + n = func->param_cnt; sp = frame_ptr->stack; for (; n > 0; n--) { @@ -1365,13 +1359,15 @@ restore_frame(NODE *fp) assoc_clear(r); freenode(r); } + if (frame_ptr->stack != NULL) efree(frame_ptr->stack); ri = frame_ptr->reti; /* execution in calling frame * resumes from ri->nexti. */ freenode(frame_ptr); - pop_frame(); + if (do_profile || do_debug) + pop_frame(); /* restore frame */ frame_ptr = fp; @@ -1388,11 +1384,14 @@ restore_frame(NODE *fp) static inline void free_arrayfor(NODE *r) { - if (r->var_array != NULL) { - size_t num_elems = r->table_size; - NODE **list = r->var_array; - while (num_elems > 0) - unref(list[--num_elems]); + if (r->for_list != NULL) { + NODE *n; + size_t num_elems = r->for_list_size; + NODE **list = r->for_list; + while (num_elems > 0) { + n = list[--num_elems]; + unref(n); + } efree(list); } freenode(r); @@ -1471,6 +1470,12 @@ unwind_stack(long n) static inline int eval_condition(NODE *t) { + if (t == node_Boolean[FALSE]) + return FALSE; + + if (t == node_Boolean[TRUE]) + return TRUE; + if ((t->flags & MAYBE_NUM) != 0) force_number(t); @@ -1500,38 +1505,37 @@ cmp_scalar() return di; } + /* op_assign --- assignment operators excluding = */ static void op_assign(OPCODE op) { NODE **lhs; - NODE *r = NULL; - AWKNUM x1, x2; -#ifndef HAVE_FMOD - AWKNUM x; -#endif + NODE *t1; + AWKNUM x = 0.0, x1, x2; lhs = POP_ADDRESS(); - x1 = force_number(*lhs); + t1 = *lhs; + x1 = force_number(t1); TOP_NUMBER(x2); - unref(*lhs); + switch (op) { case Op_assign_plus: - r = *lhs = make_number(x1 + x2); + x = x1 + x2; break; case Op_assign_minus: - r = *lhs = make_number(x1 - x2); + x = x1 - x2; break; case Op_assign_times: - r = *lhs = make_number(x1 * x2); + x = x1 * x2; break; case Op_assign_quotient: if (x2 == (AWKNUM) 0) { decr_sp(); fatal(_("division by zero attempted in `/='")); } - r = *lhs = make_number(x1 / x2); + x = x1 / x2; break; case Op_assign_mod: if (x2 == (AWKNUM) 0) { @@ -1539,22 +1543,29 @@ op_assign(OPCODE op) fatal(_("division by zero attempted in `%%='")); } #ifdef HAVE_FMOD - r = *lhs = make_number(fmod(x1, x2)); + x = fmod(x1, x2); #else /* ! HAVE_FMOD */ (void) modf(x1 / x2, &x); x = x1 - x2 * x; - r = *lhs = make_number(x); #endif /* ! HAVE_FMOD */ break; case Op_assign_exp: - r = *lhs = make_number((AWKNUM) calc_exp((double) x1, (double) x2)); + x = calc_exp((double) x1, (double) x2); break; default: break; } - UPREF(r); - REPLACE(r); + if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) { + /* optimization */ + t1->numbr = x; + } else { + unref(t1); + t1 = *lhs = make_number(x); + } + + UPREF(t1); + REPLACE(t1); } @@ -1652,1127 +1663,47 @@ pop_exec_state(int *rule, char **src, long *sz) return cp; } - -/* - * r_interpret: - * code is a list of instructions to run. returns the exit value - * from the awk code. - */ - - /* N.B.: - * 1) reference counting done for both number and string values. - * 2) TEMP flag no longer needed (consequence of the above; valref = 0 - * is the replacement). - * 3) Stack operations: - * Use REPLACE[_XX] if last stack operation was TOP[_XX], - * PUSH[_XX] if last operation was POP[_XX] instead. - * 4) UPREF and DREF -- see awk.h - */ - - -int -r_interpret(INSTRUCTION *code) +void +init_interpret() { - INSTRUCTION *pc; /* current instruction */ - NODE *r = NULL; - NODE *m; - INSTRUCTION *ni; - NODE *t1, *t2; - NODE *f; /* function definition */ - NODE **lhs; - AWKNUM x, x1, x2; - int di, pre = FALSE; - Regexp *rp; -#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) - int last_was_stopme = FALSE; /* builtin stopme() called ? */ -#endif - int stdio_problem = FALSE; - - - if (args_array == NULL) - emalloc(args_array, NODE **, (max_args + 2)*sizeof(NODE *), "r_interpret"); - else - erealloc(args_array, NODE **, (max_args + 2)*sizeof(NODE *), "r_interpret"); - -/* array subscript */ -#define mk_sub(n) (n == 1 ? POP_STRING() : concat_exp(n, TRUE)) - -#ifdef DEBUGGING -#define JUMPTO(x) do { post_execute(pc); pc = (x); goto top; } while(FALSE) -#else -#define JUMPTO(x) do { pc = (x); goto top; } while(FALSE) -#endif - - pc = code; - - /* N.B.: always use JUMPTO for next instruction, otherwise bad things - * may happen. DO NOT add a real loop (for/while) below to - * replace ' forever {'; this catches failure to use JUMPTO to execute - * next instruction (e.g. continue statement). - */ - - /* loop until hit Op_stop instruction */ - - /* forever { */ -top: - if (pc->source_line > 0) - sourceline = pc->source_line; - -#ifdef DEBUGGING - if (! pre_execute(&pc)) - goto top; -#endif - - switch (pc->opcode) { - case Op_rule: - currule = pc->in_rule; /* for sole use in Op_K_next, Op_K_nextfile, Op_K_getline* */ - /* fall through */ - case Op_func: - case Op_ext_func: - source = pc->source_file; - break; - - case Op_atexit: - /* avoid false source indications */ - source = NULL; - sourceline = 0; - (void) nextfile(&curfile, TRUE); /* close input data file */ - /* - * This used to be: - * - * if (close_io() != 0 && ! exiting && exit_val == 0) - * exit_val = 1; - * - * Other awks don't care about problems closing open files - * and pipes, in that it doesn't affect their exit status. - * So we no longer do either. - */ - (void) close_io(& stdio_problem); - /* - * However, we do want to exit non-zero if there was a problem - * with stdout/stderr, so we reinstate a slightly different - * version of the above: - */ - if (stdio_problem && ! exiting && exit_val == 0) - exit_val = 1; - break; - - case Op_stop: - return 0; - - case Op_push_i: - m = pc->memory; - PUSH((m->flags & INTLSTR) != 0 ? format_val(CONVFMT, CONVFMTidx, m): m); - break; - - case Op_push: - case Op_push_arg: - { - NODE *save_symbol; - int isparam = FALSE; - - save_symbol = m = pc->memory; - if (m->type == Node_param_list) { - if ((m->flags & FUNC) != 0) - fatal(_("can't use function name `%s' as variable or array"), - m->vname); - isparam = TRUE; - save_symbol = m = GET_PARAM(m->param_cnt); - if (m->type == Node_array_ref) - m = m->orig_array; - } - - switch (m->type) { - case Node_var: - if (do_lint && var_uninitialized(m)) - lintwarn(isparam ? - _("reference to uninitialized argument `%s'") : - _("reference to uninitialized variable `%s'"), - save_symbol->vname); - m = m->var_value; - UPREF(m); - PUSH(m); - break; - - case Node_var_new: - m->type = Node_var; - m->var_value = Nnull_string; - if (do_lint) - lintwarn(isparam ? - _("reference to uninitialized argument `%s'") : - _("reference to uninitialized variable `%s'"), - save_symbol->vname); - PUSH(Nnull_string); - break; - - case Node_var_array: - if (pc->opcode == Op_push_arg) - PUSH(m); - else - fatal(_("attempt to use array `%s' in a scalar context"), - array_vname(save_symbol)); - break; - - default: - cant_happen(); - } - } - break; - - case Op_push_param: /* function argument */ - m = pc->memory; - if (m->type == Node_param_list) - m = GET_PARAM(m->param_cnt); - if (m->type == Node_var) { - m = m->var_value; - UPREF(m); - PUSH(m); - break; - } - /* else - fall through */ - case Op_push_array: - PUSH(pc->memory); - break; + long newval; - case Op_push_lhs: - lhs = get_lhs(pc->memory, pc->do_reference); - PUSH_ADDRESS(lhs); - break; - - case Op_subscript: - t2 = mk_sub(pc->sub_count); - t1 = POP_ARRAY(); - r = *assoc_lookup(t1, t2, TRUE); - DEREF(t2); - if (r->type == Node_val) - UPREF(r); - PUSH(r); - break; - - case Op_sub_array: - t2 = mk_sub(pc->sub_count); - t1 = POP_ARRAY(); - r = in_array(t1, t2); - if (r == NULL) { - getnode(r); - r->type = Node_var_array; - r->var_array = NULL; - r->vname = estrdup(t2->stptr, t2->stlen); /* the subscript in parent array */ - r->parent_array = t1; - *assoc_lookup(t1, t2, FALSE) = r; - } else if (r->type != Node_var_array) - fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"), - array_vname(t1), (int) t2->stlen, t2->stptr); - DEREF(t2); - PUSH(r); - break; - - case Op_subscript_lhs: - t2 = mk_sub(pc->sub_count); - t1 = POP_ARRAY(); - lhs = assoc_lookup(t1, t2, pc->do_reference); - if ((*lhs)->type == Node_var_array) - fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"), - array_vname(t1), (int) t2->stlen, t2->stptr); - DEREF(t2); - PUSH_ADDRESS(lhs); - break; - - case Op_field_spec: - t1 = TOP_SCALAR(); - lhs = r_get_field(t1, (Func_ptr *) 0, TRUE); - decr_sp(); - DEREF(t1); - /* This used to look like this: - PUSH(dupnode(*lhs)); - but was changed to bypass an apparent bug in the z/OS C compiler. - Please do not remerge. */ - r = dupnode(*lhs); /* can't use UPREF here */ - PUSH(r); - break; - - case Op_field_spec_lhs: - t1 = TOP_SCALAR(); - lhs = r_get_field(t1, &pc->target_assign->field_assign, pc->do_reference); - decr_sp(); - DEREF(t1); - PUSH_ADDRESS(lhs); - break; - - case Op_lint: - if (do_lint) { - switch (pc->lint_type) { - case LINT_assign_in_cond: - lintwarn(_("assignment used in conditional context")); - break; - - case LINT_no_effect: - lintwarn(_("statement has no effect")); - break; - - default: - cant_happen(); - } - } - break; - - case Op_K_break: - case Op_K_continue: - case Op_jmp: - JUMPTO(pc->target_jmp); - - case Op_jmp_false: - r = POP_SCALAR(); - di = eval_condition(r); - DEREF(r); - if (! di) - JUMPTO(pc->target_jmp); - break; + if ((newval = getenv_long("GAWK_STACKSIZE")) > 0) + STACK_SIZE = newval; - case Op_jmp_true: - r = POP_SCALAR(); - di = eval_condition(r); - DEREF(r); - if (di) - JUMPTO(pc->target_jmp); - break; - - case Op_and: - case Op_or: - t1 = POP_SCALAR(); - di = eval_condition(t1); - DEREF(t1); - if ((pc->opcode == Op_and && di) - || (pc->opcode == Op_or && ! di)) - break; - r = make_number((AWKNUM) di); - PUSH(r); - ni = pc->target_jmp; - JUMPTO(ni->nexti); - - case Op_and_final: - case Op_or_final: - t1 = TOP_SCALAR(); - r = make_number((AWKNUM) eval_condition(t1)); - DEREF(t1); - REPLACE(r); - break; - - case Op_not: - t1 = TOP_SCALAR(); - r = make_number((AWKNUM) ! eval_condition(t1)); - DEREF(t1); - REPLACE(r); - break; - - case Op_equal: - r = make_number((AWKNUM) (cmp_scalar() == 0)); - REPLACE(r); - break; - - case Op_notequal: - r = make_number((AWKNUM) (cmp_scalar() != 0)); - REPLACE(r); - break; - - case Op_less: - r = make_number((AWKNUM) (cmp_scalar() < 0)); - REPLACE(r); - break; - - case Op_greater: - r = make_number((AWKNUM) (cmp_scalar() > 0)); - REPLACE(r); - break; - - case Op_leq: - r = make_number((AWKNUM) (cmp_scalar() <= 0)); - REPLACE(r); - break; - - case Op_geq: - r = make_number((AWKNUM) (cmp_scalar() >= 0)); - REPLACE(r); - break; - - case Op_plus_i: - x2 = force_number(pc->memory); - goto plus; - - case Op_plus: - POP_NUMBER(x2); -plus: - TOP_NUMBER(x1); - r = make_number(x1 + x2); - REPLACE(r); - break; - - case Op_minus_i: - x2 = force_number(pc->memory); - goto minus; - - case Op_minus: - POP_NUMBER(x2); -minus: - TOP_NUMBER(x1); - r = make_number(x1 - x2); - REPLACE(r); - break; - - case Op_times_i: - x2 = force_number(pc->memory); - goto times; - - case Op_times: - POP_NUMBER(x2); -times: - TOP_NUMBER(x1); - r = make_number(x1 * x2); - REPLACE(r); - break; - - case Op_exp_i: - x2 = force_number(pc->memory); - goto exponent; - - case Op_exp: - POP_NUMBER(x2); -exponent: - TOP_NUMBER(x1); - x = calc_exp(x1, x2); - r = make_number(x); - REPLACE(r); - break; - - case Op_quotient_i: - x2 = force_number(pc->memory); - goto quotient; - - case Op_quotient: - POP_NUMBER(x2); -quotient: - if (x2 == 0) - fatal(_("division by zero attempted")); - - TOP_NUMBER(x1); - x = x1 / x2; - r = make_number(x); - REPLACE(r); - break; - - case Op_mod_i: - x2 = force_number(pc->memory); - goto mod; - - case Op_mod: - POP_NUMBER(x2); -mod: - if (x2 == 0) - fatal(_("division by zero attempted in `%%'")); - - TOP_NUMBER(x1); -#ifdef HAVE_FMOD - x = fmod(x1, x2); -#else /* ! HAVE_FMOD */ - (void) modf(x1 / x2, &x); - x = x1 - x * x2; -#endif /* ! HAVE_FMOD */ - r = make_number(x); - REPLACE(r); - break; - - case Op_preincrement: - pre = TRUE; - case Op_postincrement: - x2 = 1.0; -post: - lhs = TOP_ADDRESS(); - x1 = force_number(*lhs); - unref(*lhs); - r = *lhs = make_number(x1 + x2); - if (pre) - UPREF(r); - else - r = make_number(x1); - REPLACE(r); - pre = FALSE; - break; - - case Op_predecrement: - pre = TRUE; - case Op_postdecrement: - x2 = -1.0; - goto post; - - case Op_unary_minus: - TOP_NUMBER(x1); - r = make_number(-x1); - REPLACE(r); - break; - - case Op_store_sub: - /* array[sub] assignment optimization, - * see awkgram.y (optimize_assignment) - */ - t1 = get_array(pc->memory, TRUE); /* array */ - t2 = mk_sub(pc->expr_count); /* subscript */ - lhs = assoc_lookup(t1, t2, FALSE); - if ((*lhs)->type == Node_var_array) - fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"), - array_vname(t1), (int) t2->stlen, t2->stptr); - DEREF(t2); - unref(*lhs); - *lhs = POP_SCALAR(); - break; - - case Op_store_var: - /* simple variable assignment optimization, - * see awkgram.y (optimize_assignment) - */ - - lhs = get_lhs(pc->memory, FALSE); - unref(*lhs); - *lhs = POP_SCALAR(); - break; - - case Op_store_field: - { - /* field assignment optimization, - * see awkgram.y (optimize_assignment) - */ - - Func_ptr assign; - t1 = TOP_SCALAR(); - lhs = r_get_field(t1, &assign, FALSE); - decr_sp(); - DEREF(t1); - unref(*lhs); - *lhs = POP_SCALAR(); - assert(assign != NULL); - assign(); - } - break; - - case Op_assign_concat: - /* x = x ... string concatenation optimization */ - lhs = get_lhs(pc->memory, FALSE); - t1 = force_string(*lhs); - t2 = POP_STRING(); - - free_wstr(*lhs); - - if (t1 != t2 && t1->valref == 1 && (t1->flags & PERM) == 0) { - size_t nlen = t1->stlen + t2->stlen; - erealloc(t1->stptr, char *, nlen + 2, "r_interpret"); - memcpy(t1->stptr + t1->stlen, t2->stptr, t2->stlen); - t1->stlen = nlen; - t1->stptr[nlen] = '\0'; - } else { - size_t nlen = t1->stlen + t2->stlen; - char *p; - - emalloc(p, char *, nlen + 2, "r_interpret"); - memcpy(p, t1->stptr, t1->stlen); - memcpy(p + t1->stlen, t2->stptr, t2->stlen); - unref(*lhs); - t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED); - } - t1->flags &= ~(NUMCUR|NUMBER); - DEREF(t2); - break; - - case Op_assign: - lhs = POP_ADDRESS(); - r = TOP_SCALAR(); - unref(*lhs); - *lhs = r; - UPREF(r); - REPLACE(r); - break; - - /* numeric assignments */ - case Op_assign_plus: - case Op_assign_minus: - case Op_assign_times: - case Op_assign_quotient: - case Op_assign_mod: - case Op_assign_exp: - op_assign(pc->opcode); - break; - - case Op_var_update: /* update value of NR, FNR or NF */ - pc->update_var(); - break; - - case Op_var_assign: - case Op_field_assign: - if (pc->assign_ctxt == Op_sub_builtin - && TOP()->numbr == 0.0 /* top of stack has a number == 0 */ - ) { - /* There wasn't any substitutions. If the target is a FIELD, - * this means no field re-splitting or $0 reconstruction. - * Skip the set_FOO routine if the target is a special variable. - */ - - break; - } else if ((pc->assign_ctxt == Op_K_getline - || pc->assign_ctxt == Op_K_getline_redir) - && TOP()->numbr <= 0.0 /* top of stack has a number <= 0 */ - ) { - /* getline returned EOF or error */ - - break; - } - - if (pc->opcode == Op_var_assign) - pc->assign_var(); - else - pc->field_assign(); - break; - - case Op_concat: - r = concat_exp(pc->expr_count, pc->concat_flag & CSUBSEP); - PUSH(r); - break; - - case Op_K_case: - if ((pc + 1)->match_exp) { - /* match a constant regex against switch expression instead of $0. */ - m = POP(); /* regex */ - t2 = TOP_SCALAR(); /* switch expression */ - (void) force_string(t2); - rp = re_update(m); - di = (research(rp, t2->stptr, 0, t2->stlen, - avoid_dfa(m, t2->stptr, t2->stlen)) >= 0); - } else { - t1 = POP_SCALAR(); /* case value */ - t2 = TOP_SCALAR(); /* switch expression */ - di = (cmp_nodes(t2, t1) == 0); - DEREF(t1); - } - - if (di) { /* match found */ - decr_sp(); - DEREF(t2); - JUMPTO(pc->target_jmp); - } - break; - - case Op_K_delete: - t1 = POP_ARRAY(); - do_delete(t1, pc->expr_count); - stack_adj(-pc->expr_count); - break; - - case Op_K_delete_loop: - t1 = POP_ARRAY(); - lhs = POP_ADDRESS(); /* item */ - do_delete_loop(t1, lhs); - break; - - case Op_in_array: - t1 = POP_ARRAY(); - t2 = mk_sub(pc->expr_count); - di = (in_array(t1, t2) != NULL); - DEREF(t2); - PUSH(make_number((AWKNUM) di)); - break; - - case Op_arrayfor_init: - { - NODE **list = NULL; - NODE *array, *sort_str; - size_t num_elems = 0; - static NODE *sorted_in = NULL; - const char *how_to_sort = "@unsorted"; - - /* get the array */ - array = POP_ARRAY(); - - /* sanity: check if empty */ - if (array->var_array == NULL || array->table_size == 0) - goto arrayfor; - - num_elems = array->table_size; - - if (sorted_in == NULL) /* do this once */ - sorted_in = make_string("sorted_in", 9); - - sort_str = NULL; - /* - * If posix, or if there's no PROCINFO[], - * there's no ["sorted_in"], so no sorting - */ - if (! do_posix && PROCINFO_node != NULL) - sort_str = in_array(PROCINFO_node, sorted_in); - - if (sort_str != NULL) { - sort_str = force_string(sort_str); - if (sort_str->stlen > 0) - how_to_sort = sort_str->stptr; - } - - list = assoc_list(array, how_to_sort, SORTED_IN); - - /* - * Actual array for use in lint warning - * in Op_arrayfor_incr - */ - list[num_elems] = array; - -arrayfor: - getnode(r); - r->type = Node_arrayfor; - r->var_array = list; - r->table_size = num_elems; /* # of elements in list */ - r->array_size = -1; /* current index */ - PUSH(r); - - if (num_elems == 0) - JUMPTO(pc->target_jmp); /* Op_arrayfor_final */ - } - break; - - case Op_arrayfor_incr: - r = TOP(); /* Node_arrayfor */ - if (++r->array_size == r->table_size) { - NODE *array; - array = r->var_array[r->table_size]; /* actual array */ - if (do_lint && array->table_size != r->table_size) - lintwarn(_("for loop: array `%s' changed size from %ld to %ld during loop execution"), - array_vname(array), (long) r->table_size, (long) array->table_size); - JUMPTO(pc->target_jmp); /* Op_arrayfor_final */ - } - - t1 = r->var_array[r->array_size]; - lhs = get_lhs(pc->array_var, FALSE); - unref(*lhs); - *lhs = make_string(t1->ahname_str, t1->ahname_len); - break; - - case Op_arrayfor_final: - r = POP(); - assert(r->type == Node_arrayfor); - free_arrayfor(r); - break; - - case Op_builtin: - r = pc->builtin(pc->expr_count); -#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) - if (! r) - last_was_stopme = TRUE; - else -#endif - PUSH(r); - break; - - case Op_sub_builtin: /* sub, gsub and gensub */ - r = do_sub(pc->expr_count, pc->sub_flags); - PUSH(r); - break; - - case Op_K_print: - do_print(pc->expr_count, pc->redir_type); - break; - - case Op_K_printf: - do_printf(pc->expr_count, pc->redir_type); - break; - - case Op_K_print_rec: - do_print_rec(pc->expr_count, pc->redir_type); - break; - - case Op_push_re: - m = pc->memory; - if (m->type == Node_dynregex) { - r = POP_STRING(); - unref(m->re_exp); - m->re_exp = r; - } - PUSH(m); - break; - - case Op_match_rec: - m = pc->memory; - t1 = *get_field(0, (Func_ptr *) 0); -match_re: - rp = re_update(m); - /* - * Any place where research() is called with a last parameter of - * zero, we need to use the avoid_dfa test. This appears here and - * in the code for Op_K_case. - * - * A new or improved dfa that distinguishes beginning/end of - * string from beginning/end of line will allow us to get rid of - * this hack. - * - * The avoid_dfa() function is in re.c; it is not very smart. - */ - - di = research(rp, t1->stptr, 0, t1->stlen, - avoid_dfa(m, t1->stptr, t1->stlen)); - di = (di == -1) ^ (pc->opcode != Op_nomatch); - if(pc->opcode != Op_match_rec) { - decr_sp(); - DEREF(t1); - } - r = make_number((AWKNUM) di); - PUSH(r); - break; - - case Op_nomatch: - /* fall through */ - case Op_match: - m = pc->memory; - t1 = TOP_STRING(); - if (m->type == Node_dynregex) { - unref(m->re_exp); - m->re_exp = t1; - decr_sp(); - t1 = TOP_STRING(); - } - goto match_re; - break; - - case Op_indirect_func_call: - { - int arg_count; - - f = NULL; - arg_count = (pc + 1)->expr_count; - t1 = PEEK(arg_count); /* indirect var */ - assert(t1->type == Node_val); /* @a[1](p) not allowed in grammar */ - (void) force_string(t1); - if (t1->stlen > 0) { - /* retrieve function definition node */ - f = pc->func_body; - if (f != NULL && strcmp(f->vname, t1->stptr) == 0) - /* indirect var hasn't been reassigned */ - goto func_call; - f = lookup(t1->stptr); - } - - if (f == NULL || f->type != Node_func) - fatal(_("function called indirectly through `%s' does not exist"), pc->func_name); - pc->func_body = f; /* save for next call */ - - goto func_call; - } - - case Op_func_call: - /* retrieve function definition node */ - f = pc->func_body; - if (f == NULL) { - f = lookup(pc->func_name); - if (f == NULL || f->type != Node_func) - fatal(_("function `%s' not defined"), pc->func_name); - pc->func_body = f; /* save for next call */ - } - - /* save current frame along with source */ - -func_call: - ni = setup_frame(pc); - - if (ni->opcode == Op_ext_func) { - /* dynamically set source and line numbers for an extension builtin. */ - ni->source_file = source; - ni->source_line = sourceline; - ni->nexti->source_line = sourceline; /* Op_builtin */ - ni->nexti->nexti->source_line = sourceline; /* Op_K_return */ - } - - /* run the function instructions */ - JUMPTO(ni); /* Op_func or Op_ext_func */ - - case Op_K_return: - m = POP_SCALAR(); /* return value */ - - ni = pop_fcall(); - - /* put the return value back on stack */ - PUSH(m); - - JUMPTO(ni); - - case Op_K_getline_redir: - if ((currule == BEGINFILE || currule == ENDFILE) - && pc->into_var == FALSE - && pc->redir_type == redirect_input) - fatal(_("`getline' invalid inside `%s' rule"), ruletab[currule]); - r = do_getline_redir(pc->into_var, pc->redir_type); - PUSH(r); - break; - - case Op_K_getline: /* no redirection */ - if (! currule || currule == BEGINFILE || currule == ENDFILE) - fatal(_("non-redirected `getline' invalid inside `%s' rule"), - ruletab[currule]); - - do { - int ret; - ret = nextfile(& curfile, FALSE); - if (ret <= 0) - r = do_getline(pc->into_var, curfile); - else { - - /* Save execution state so that we can return to it - * from Op_after_beginfile or Op_after_endfile. - */ - - push_exec_state(pc, currule, source, stack_ptr); - - if (curfile == NULL) - JUMPTO((pc + 1)->target_endfile); - else - JUMPTO((pc + 1)->target_beginfile); - } - } while (r == NULL); /* EOF */ - - PUSH(r); - break; - - case Op_after_endfile: - /* Find the execution state to return to */ - ni = pop_exec_state(& currule, & source, NULL); - - assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline); - JUMPTO(ni); - - case Op_after_beginfile: - after_beginfile(& curfile); - - /* Find the execution state to return to */ - ni = pop_exec_state(& currule, & source, NULL); - - assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline); - if (ni->opcode == Op_K_getline - || curfile == NULL /* skipping directory argument */ - ) - JUMPTO(ni); - - break; /* read a record, Op_get_record */ - - case Op_newfile: - { - int ret; - - ret = nextfile(& curfile, FALSE); - - if (ret < 0) /* end of input */ - JUMPTO(pc->target_jmp); /* end block or Op_atexit */ - - if (ret == 0) /* read a record */ - JUMPTO((pc + 1)->target_get_record); - - /* ret > 0 */ - /* Save execution state for use in Op_after_beginfile or Op_after_endfile. */ - - push_exec_state(pc, currule, source, stack_ptr); - - if (curfile == NULL) /* EOF */ - JUMPTO(pc->target_endfile); - /* else - execute beginfile block */ - } - break; - - case Op_get_record: - { - int errcode = 0; - - ni = pc->target_newfile; - if (curfile == NULL) { - /* from non-redirected getline, e.g.: - * { - * while (getline > 0) ; - * } - */ - - ni = ni->target_jmp; /* end_block or Op_atexit */ - JUMPTO(ni); - } - - if (inrec(curfile, & errcode) != 0) { - if (errcode > 0 && (do_traditional || ! pc->has_endfile)) - fatal(_("error reading input file `%s': %s"), - curfile->name, strerror(errcode)); - - JUMPTO(ni); - } /* else - prog (rule) block */ - } - break; - - case Op_K_nextfile: - { - int ret; - - if (currule != Rule && currule != BEGINFILE) - fatal(_("`nextfile' cannot be called from a `%s' rule"), - ruletab[currule]); - - ret = nextfile(& curfile, TRUE); /* skip current file */ - - if (currule == BEGINFILE) { - long stack_size; - - ni = pop_exec_state(& currule, & source, & stack_size); - - assert(ni->opcode == Op_K_getline || ni->opcode == Op_newfile); - - /* pop stack returning to the state of Op_K_getline or Op_newfile. */ - unwind_stack(stack_size); - - if (ret == 0) { - /* There was an error opening the file; - * don't run ENDFILE block(s). - */ - - JUMPTO(ni); - } else { - /* do run ENDFILE block(s) first. */ - - /* Execution state to return to in Op_after_endfile. */ - push_exec_state(ni, currule, source, stack_ptr); - - JUMPTO(pc->target_endfile); - } - } /* else - Start over with the first rule. */ - - /* empty the run-time stack to avoid memory leak */ - pop_stack(); - - /* Push an execution state for Op_after_endfile to return to */ - push_exec_state(pc->target_newfile, currule, source, stack_ptr); - - JUMPTO(pc->target_endfile); - } - break; - - case Op_K_exit: - /* exit not allowed in user-defined comparison functions for "sorted_in"; - * This is done so that END blocks aren't executed more than once. - */ - if (! currule) - fatal(_("`exit' cannot be called in the current context")); - - exiting = TRUE; - POP_NUMBER(x1); - exit_val = (int) x1; -#ifdef VMS - if (exit_val == 0) - exit_val = EXIT_SUCCESS; - else if (exit_val == 1) - exit_val = EXIT_FAILURE; - /* else - just pass anything else on through */ -#endif - - if (currule == BEGINFILE || currule == ENDFILE) { - - /* Find the rule of the saved execution state (Op_K_getline/Op_newfile). - * This is needed to prevent multiple execution of any END rules: - * gawk 'BEGINFILE { exit(1) } \ - * END { while (getline > 0); }' in1 in2 - */ - - (void) pop_exec_state(& currule, & source, NULL); - } - - pop_stack(); /* empty stack, don't leak memory */ - - /* Jump to either the first END block instruction - * or to Op_atexit. - */ - - if (currule == END) - ni = pc->target_atexit; - else - ni = pc->target_end; - JUMPTO(ni); - - case Op_K_next: - if (currule != Rule) - fatal(_("`next' cannot be called from a `%s' rule"), ruletab[currule]); - - pop_stack(); - JUMPTO(pc->target_jmp); /* Op_get_record, read next record */ - - case Op_pop: -#if defined(GAWKDEBUG) || defined(ARRAYDEBUG) - if (last_was_stopme) - last_was_stopme = FALSE; - else -#endif - { - r = POP_SCALAR(); - DEREF(r); - } - break; - - case Op_line_range: - if (pc->triggered) /* evaluate right expression */ - JUMPTO(pc->target_jmp); - /* else - evaluate left expression */ - break; - - case Op_cond_pair: - { - int result; - INSTRUCTION *ip; - - t1 = TOP_SCALAR(); /* from right hand side expression */ - di = (eval_condition(t1) != 0); - DEREF(t1); - - ip = pc->line_range; /* Op_line_range */ - - if (! ip->triggered && di) { - /* not already triggered and left expression is TRUE */ - decr_sp(); - ip->triggered = TRUE; - JUMPTO(ip->target_jmp); /* evaluate right expression */ - } - - result = ip->triggered || di; - ip->triggered ^= di; /* update triggered flag */ - r = make_number((AWKNUM) result); /* final value of condition pair */ - REPLACE(r); - JUMPTO(pc->target_jmp); - } + emalloc(stack_bottom, STACK_ITEM *, STACK_SIZE * sizeof(STACK_ITEM), "grow_stack"); + stack_ptr = stack_bottom - 1; + stack_top = stack_bottom + STACK_SIZE - 1; - case Op_exec_count: - INCREMENT(pc->exec_count); - break; + /* initialize frame pointer */ + getnode(frame_ptr); + frame_ptr->type = Node_frame; + frame_ptr->stack = NULL; + frame_ptr->func_node = NULL; /* in main */ + frame_ptr->num_tail_calls = 0; + frame_ptr->vname = NULL; - case Op_no_op: - case Op_K_do: - case Op_K_while: - case Op_K_for: - case Op_K_arrayfor: - case Op_K_switch: - case Op_K_default: - case Op_K_if: - case Op_K_else: - case Op_cond_exp: - break; + /* initialize TRUE and FALSE nodes */ + node_Boolean[FALSE] = make_number(0); + node_Boolean[FALSE]->flags |= NUMINT; + node_Boolean[TRUE] = make_number(1.0); + node_Boolean[TRUE]->flags |= NUMINT; - default: - fatal(_("Sorry, don't know how to interpret `%s'"), opcode2str(pc->opcode)); - } + /* select the interpreter routine */ + if (do_debug) + interpret = debug_interpret; + else + interpret = r_interpret; +} - JUMPTO(pc->nexti); -/* } forever */ +/* interpreter routine when not debugging */ +#include "interpret.h" - /* not reached */ - return 0; +/* interpreter routine when deubugging with gawk --debug */ +#define r_interpret debug_interpret +#define DEBUGGING 1 +#include "interpret.h" +#undef DEBUGGING +#undef r_interpret -#undef mk_sub -#undef JUMPTO -} |