aboutsummaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2011-12-26 23:39:48 +0200
committerArnold D. Robbins <arnold@skeeve.com>2011-12-26 23:39:48 +0200
commit73d24cae0db6cc817db209e5e1ea93b0733d1cca (patch)
treedcb46bac28312a06162f390bfd0b90cd5e07d974 /eval.c
parent14828f8fd6f90f711d832f2c4d7120db4bef3770 (diff)
downloadegawk-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.c1295
1 files changed, 57 insertions, 1238 deletions
diff --git a/eval.c b/eval.c
index 2a29eb9f..78598b21 100644
--- a/eval.c
+++ b/eval.c
@@ -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
-}