diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2011-12-26 23:39:48 +0200 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2011-12-26 23:39:48 +0200 |
commit | 73d24cae0db6cc817db209e5e1ea93b0733d1cca (patch) | |
tree | dcb46bac28312a06162f390bfd0b90cd5e07d974 /eval.c | |
parent | 14828f8fd6f90f711d832f2c4d7120db4bef3770 (diff) | |
download | egawk-73d24cae0db6cc817db209e5e1ea93b0733d1cca.tar.gz egawk-73d24cae0db6cc817db209e5e1ea93b0733d1cca.tar.bz2 egawk-73d24cae0db6cc817db209e5e1ea93b0733d1cca.zip |
The grand merge: dgawk and pgawk folded into gawk.
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 1295 |
1 files changed, 57 insertions, 1238 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 @@ -649,8 +627,8 @@ cmp_nodes(NODE *t1, NODE *t2) return ret; } +/* push_frame --- push a frame NODE onto stack */ -#if defined(PROFILING) || defined(DEBUGGING) static void push_frame(NODE *f) { @@ -672,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 */ @@ -722,7 +693,6 @@ dump_fcall_stack(FILE *fp) fprintf(fp, "\t# %3ld. -- main --\n", k); } -#endif /* PROFILING */ /* set_IGNORECASE --- update IGNORECASE as appropriate */ @@ -1098,26 +1068,6 @@ NODE **args_array = NULL; STACK_ITEM * grow_stack() { - if (stack_ptr == NULL) { - long newval; - - if ((newval = getenv_long("GAWK_STACKSIZE")) > 0) - STACK_SIZE = newval; - - 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->num_tail_calls = 0; - 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; @@ -1260,10 +1210,9 @@ setup_frame(INSTRUCTION *pc) fp = f->fparms; arg_count = (pc + 1)->expr_count; -#ifndef DEBUGGING /* tail recursion optimization */ - tail_optimize = (do_optimize > 1 && (pc + 1)->tail_call); -#endif + tail_optimize = ((pc + 1)->tail_call && do_optimize > 1 + && ! do_debug && ! do_profile); if (tail_optimize) { /* free local vars of calling frame */ @@ -1367,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); @@ -1416,7 +1366,8 @@ restore_frame(NODE *fp) * resumes from ri->nexti. */ freenode(frame_ptr); - pop_frame(); + if (do_profile || do_debug) + pop_frame(); /* restore frame */ frame_ptr = fp; @@ -1519,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); @@ -1706,1185 +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) Stack operations: - * Use REPLACE[_XX] if last stack operation was TOP[_XX], - * PUSH[_XX] if last operation was POP[_XX] instead. - * 3) 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; - Regexp *rp; - 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_SCALAR() : 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: - 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; - if (! do_traditional && (m->flags & INTLSTR) != 0) { - char *orig, *trans, save; - - save = m->stptr[m->stlen]; - m->stptr[m->stlen] = '\0'; - orig = m->stptr; - trans = dgettext(TEXTDOMAIN, orig); - m->stptr[m->stlen] = save; - m = make_string(trans, strlen(trans)); - } else - UPREF(m); - PUSH(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) { - 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 = dupnode(Nnull_string); - if (do_lint) - lintwarn(isparam ? - _("reference to uninitialized argument `%s'") : - _("reference to uninitialized variable `%s'"), - save_symbol->vname); - m = dupnode(Nnull_string); - PUSH(m); - 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; - - 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(); - - if (do_lint && in_array(t1, t2) == NULL) { - t2 = force_string(t2); - lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"), - array_vname(t1), (int) t2->stlen, t2->stptr); - if (t2->stlen == 0) - lintwarn(_("subscript of array `%s' is null string"), array_vname(t1)); - } - - r = *assoc_lookup(t1, t2); - 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) { - r = make_array(); - r->parent_array = t1; - *assoc_lookup(t1, t2) = r; - t2 = force_string(t2); - r->vname = estrdup(t2->stptr, t2->stlen); /* the subscript in parent array */ - } else if (r->type != Node_var_array) { - t2 = force_string(t2); - 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(); - if (do_lint && in_array(t1, t2) == NULL) { - t2 = force_string(t2); - if (pc->do_reference) - lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"), - array_vname(t1), (int) t2->stlen, t2->stptr); - if (t2->stlen == 0) - lintwarn(_("subscript of array `%s' is null string"), array_vname(t1)); - } + long newval; - lhs = assoc_lookup(t1, t2); - if ((*lhs)->type == Node_var_array) { - t2 = force_string(t2); - 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); - 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; - - 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: - case Op_predecrement: - x2 = pc->opcode == Op_preincrement ? 1.0 : -1.0; - lhs = TOP_ADDRESS(); - t1 = *lhs; - x1 = force_number(t1); - if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) { - /* optimization */ - t1->numbr = x1 + x2; - } else { - unref(t1); - t1 = *lhs = make_number(x1 + x2); - } - UPREF(t1); - REPLACE(t1); - break; - - case Op_postincrement: - case Op_postdecrement: - x2 = pc->opcode == Op_postincrement ? 1.0 : -1.0; - lhs = TOP_ADDRESS(); - t1 = *lhs; - x1 = force_number(t1); - if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) { - /* optimization */ - t1->numbr = x1 + x2; - } else { - unref(t1); - *lhs = make_number(x1 + x2); - } - r = make_number(x1); - REPLACE(r); - break; - - 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); - if ((*lhs)->type == Node_var_array) { - t2 = force_string(t2); - 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); - r = pc->initval; /* constant initializer */ - if (r == NULL) - *lhs = POP_SCALAR(); - else { - UPREF(r); - *lhs = r; - } - 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 != *lhs) { - unref(*lhs); - *lhs = dupnode(t1); - } - - if (t1 != t2 && t1->valref == 1) { - 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'; - t1->flags &= ~(NUMCUR|NUMBER|NUMINT); - } 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); - } - DEREF(t2); - break; - - case Op_assign: - lhs = POP_ADDRESS(); - r = TOP_SCALAR(); - unref(*lhs); - *lhs = r; - UPREF(r); - REPLACE(r); - break; + if ((newval = getenv_long("GAWK_STACKSIZE")) > 0) + STACK_SIZE = newval; - /* 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 */ - t2 = 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 */ - - t2 = POP_SCALAR(); - 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_empty(array)) - 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); - -arrayfor: - getnode(r); - r->type = Node_arrayfor; - r->for_list = list; - r->for_list_size = num_elems; /* # of elements in list */ - r->cur_idx = -1; /* current index */ - r->for_array = array; /* array */ - PUSH(r); - - if (num_elems == 0) - JUMPTO(pc->target_jmp); /* Op_arrayfor_final */ - } - break; - - case Op_arrayfor_incr: - r = TOP(); /* Node_arrayfor */ - if (++r->cur_idx == r->for_list_size) { - NODE *array; - array = r->for_array; /* actual array */ - if (do_lint && array->table_size != r->for_list_size) - lintwarn(_("for loop: array `%s' changed size from %ld to %ld during loop execution"), - array_vname(array), (long) r->for_list_size, (long) array->table_size); - JUMPTO(pc->target_jmp); /* Op_arrayfor_final */ - } - - t1 = r->for_list[r->cur_idx]; - lhs = get_lhs(pc->array_var, FALSE); - unref(*lhs); - *lhs = dupnode(t1); - 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); - PUSH(r); - break; - - case Op_ext_builtin: - { - int arg_count = pc->expr_count; - - PUSH_CODE(pc); - r = pc->builtin(arg_count); - (void) POP_CODE(); - while (arg_count-- > 0) { - t1 = POP(); - if (t1->type == Node_val) - DEREF(t1); - } - 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 */ - t1 = force_string(t1); - if (t1->stlen > 0) { - /* retrieve function definition node */ - f = pc->func_body; - if (f != NULL && STREQ(f->vname, t1->stptr)) { - /* 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 && f->type != Node_ext_func)) - fatal(_("function `%s' not defined"), pc->func_name); - pc->func_body = f; /* save for next call */ - } - - if (f->type == Node_ext_func) { - INSTRUCTION *bc; - char *fname = pc->func_name; - int arg_count = (pc + 1)->expr_count; - - bc = f->code_ptr; - assert(bc->opcode == Op_symbol); - pc->opcode = Op_ext_builtin; /* self modifying code */ - pc->builtin = bc->builtin; - pc->expr_count = arg_count; /* actual argument count */ - (pc + 1)->func_name = fname; /* name of the builtin */ - (pc + 1)->expr_count = bc->expr_count; /* defined max # of arguments */ - ni = pc; - JUMPTO(ni); - } - -func_call: - ni = setup_frame(pc); - - /* run the function instructions */ - JUMPTO(ni); /* Op_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: - 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 -} |