diff options
Diffstat (limited to 'interpret.h')
-rw-r--r-- | interpret.h | 104 |
1 files changed, 91 insertions, 13 deletions
diff --git a/interpret.h b/interpret.h index 21cd9a80..228a3f3e 100644 --- a/interpret.h +++ b/interpret.h @@ -37,6 +37,9 @@ r_interpret(INSTRUCTION *code) AWKNUM x, x2; int di; Regexp *rp; + NODE *set_array = NULL; /* array with a post-assignment routine */ + NODE *set_idx = NULL; /* the index of the array element */ + /* array subscript */ #define mk_sub(n) (n == 1 ? POP_SCALAR() : concat_exp(n, true)) @@ -103,6 +106,8 @@ top: */ if (stdio_problem && ! exiting && exit_val == 0) exit_val = 1; + + close_extensions(); } break; @@ -248,9 +253,15 @@ top: if (r == NULL) { r = make_array(); r->parent_array = t1; - *assoc_lookup(t1, t2) = r; + lhs = assoc_lookup(t1, t2); + unref(*lhs); + *lhs = r; t2 = force_string(t2); r->vname = estrdup(t2->stptr, t2->stlen); /* the subscript in parent array */ + + /* execute post-assignment routine if any */ + if (t1->astore != NULL) + (*t1->astore)(t1, t2); } else if (r->type != Node_var_array) { t2 = force_string(t2); fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"), @@ -280,7 +291,36 @@ top: array_vname(t1), (int) t2->stlen, t2->stptr); } - DEREF(t2); + /* + * Changing something in FUNCTAB is not allowed. + * + * SYMTAB is a little more messy. Three kinds of values may + * be stored in SYMTAB: + * 1. Variables that don"t yet have a value (Node_var_new) + * 2. Variables that have a value (Node_var) + * 3. Values that awk code stuck into SYMTAB not related to variables (Node_value) + * For 1, since we are giving it a value, we have to change the type to Node_var. + * For 1 and 2, we have to step through the Node_var to get to the value. + * For 3, we just us the value we got from assoc_lookup(), above. + */ + if (t1 == func_table) + fatal(_("cannot assign to elements of FUNCTAB")); + else if ( t1 == symbol_table + && ( (*lhs)->type == Node_var + || (*lhs)->type == Node_var_new)) { + (*lhs)->type = Node_var; /* in case was Node_var_new */ + lhs = & ((*lhs)->var_value); /* extra level of indirection */ + } + + assert(set_idx == NULL); + + if (t1->astore) { + /* array has post-assignment routine */ + set_array = t1; + set_idx = t2; + } else + DEREF(t2); + PUSH_ADDRESS(lhs); break; @@ -544,10 +584,11 @@ mod: break; case Op_store_sub: - /* array[sub] assignment optimization, + /* + * array[sub] assignment optimization, * see awkgram.y (optimize_assignment) */ - t1 = get_array(pc->memory, true); /* array */ + t1 = force_array(pc->memory, true); /* array */ t2 = mk_sub(pc->expr_count); /* subscript */ lhs = assoc_lookup(t1, t2); if ((*lhs)->type == Node_var_array) { @@ -580,10 +621,17 @@ mod: unref(*lhs); *lhs = POP_SCALAR(); + + /* execute post-assignment routine if any */ + if (t1->astore != NULL) + (*t1->astore)(t1, t2); + + DEREF(t2); break; case Op_store_var: - /* simple variable assignment optimization, + /* + * simple variable assignment optimization, * see awkgram.y (optimize_assignment) */ @@ -671,6 +719,30 @@ mod: REPLACE(r); break; + case Op_subscript_assign: + /* conditionally execute post-assignment routine for an array element */ + + if (set_idx != NULL) { + di = true; + if (pc->assign_ctxt == Op_sub_builtin + && (r = TOP()) + && get_number_si(r) == 0 /* no substitution performed */ + ) + di = false; + else if ((pc->assign_ctxt == Op_K_getline + || pc->assign_ctxt == Op_K_getline_redir) + && (r = TOP()) + && get_number_si(r) <= 0 /* EOF or error */ + ) + di = false; + + if (di) + (*set_array->astore)(set_array, set_idx); + unref(set_idx); + set_idx = NULL; + } + break; + /* numeric assignments */ case Op_assign_plus: case Op_assign_minus: @@ -775,11 +847,10 @@ mod: array = POP_ARRAY(); /* sanity: check if empty */ - if (array_empty(array)) + num_elems = assoc_length(array); + if (num_elems == 0) goto arrayfor; - num_elems = array->table_size; - if (sorted_in == NULL) /* do this once */ sorted_in = make_string("sorted_in", 9); @@ -842,12 +913,16 @@ arrayfor: break; case Op_ext_builtin: + case Op_old_ext_builtin: { int arg_count = pc->expr_count; awk_value_t result; PUSH_CODE(pc); - r = awk_value_to_node(pc->extfunc(arg_count, & result)); + if (op == Op_ext_builtin) + r = awk_value_to_node(pc->extfunc(arg_count, & result)); + else + r = pc->builtin(arg_count); (void) POP_CODE(); while (arg_count-- > 0) { t1 = POP(); @@ -953,7 +1028,7 @@ match_re: } if (f == NULL || f->type != Node_func) { - if (f->type == Node_ext_func) + if (f->type == Node_ext_func || f->type == Node_old_ext_func) fatal(_("cannot (yet) call extension functions indirectly")); else fatal(_("function called indirectly through `%s' does not exist"), @@ -973,19 +1048,22 @@ match_re: f = pc->func_body; if (f == NULL) { f = lookup(pc->func_name); - if (f == NULL || (f->type != Node_func && f->type != Node_ext_func)) + if (f == NULL || (f->type != Node_func && f->type != Node_ext_func && f->type != Node_old_ext_func)) fatal(_("function `%s' not defined"), pc->func_name); pc->func_body = f; /* save for next call */ } - if (f->type == Node_ext_func) { + if (f->type == Node_ext_func || f->type == Node_old_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 */ + if (f->type == Node_ext_func) + pc->opcode = Op_ext_builtin; /* self modifying code */ + else + pc->opcode = Op_old_ext_builtin; /* self modifying code */ pc->extfunc = bc->extfunc; pc->expr_count = arg_count; /* actual argument count */ (pc + 1)->func_name = fname; /* name of the builtin */ |