aboutsummaryrefslogtreecommitdiffstats
path: root/interpret.h
diff options
context:
space:
mode:
Diffstat (limited to 'interpret.h')
-rw-r--r--interpret.h104
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 */