diff --git a/awk.h b/awk.h index d9da3b9..1421203 100644 --- a/awk.h +++ b/awk.h @@ -631,10 +631,7 @@ typedef struct exp_instruction { #define sub_flags d.dl #define GSUB 0x01 /* builtin is gsub */ #define GENSUB 0x02 /* builtin is gensub */ -#define AFTER_ASSIGN 0x04 /* (g)sub target is a field or a special var with - * set_XX routine. - */ -#define LITERAL 0x08 /* target is a literal string */ +#define LITERAL 0x04 /* target is a literal string */ /* Op_K_exit */ @@ -717,6 +714,9 @@ typedef struct exp_instruction { /* Op_field_assign */ #define field_assign x.aptr +/* Op_field_assign, Op_var_assign */ +#define assign_ctxt d.dl + /* Op_concat */ #define concat_flag d.dl #define CSUBSEP 1 @@ -1192,7 +1192,7 @@ extern NODE *do_cos(int nargs); extern NODE *do_rand(int nargs); extern NODE *do_srand(int nargs); extern NODE *do_match(int nargs); -extern NODE *do_sub(int nargs, unsigned int flags, int *num_matches); +extern NODE *do_sub(int nargs, unsigned int flags); extern NODE *format_tree(const char *, size_t, NODE **, long); extern NODE *do_lshift(int nargs); extern NODE *do_rshift(int nargs); diff --git a/awkgram.y b/awkgram.y index 3ef6382..fb917c2 100644 --- a/awkgram.y +++ b/awkgram.y @@ -750,7 +750,6 @@ regular_loop: /* add update_FOO instruction if necessary */ if ($4->array_var->type == Node_var && $4->array_var->var_update) { (void) list_append(ip, instruction(Op_var_update)); - ip->lasti->memory = $4->array_var; ip->lasti->update_var = $4->array_var->var_update; } (void) list_append(ip, $4); @@ -758,7 +757,6 @@ regular_loop: /* add set_FOO instruction if necessary */ if ($4->array_var->type == Node_var && $4->array_var->var_assign) { (void) list_append(ip, instruction(Op_var_assign)); - ip->lasti->memory = $4->array_var; ip->lasti->assign_var = $4->array_var->var_assign; } @@ -1726,7 +1724,6 @@ variable && ip->memory->var_update ) { $$ = list_prepend($1, instruction(Op_var_update)); - $$->nexti->memory = ip->memory; $$->nexti->update_var = ip->memory->var_update; } else $$ = $1; @@ -3654,14 +3651,13 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) /* add after_assign code */ if (ip->opcode == Op_push_lhs && ip->memory->type == Node_var && ip->memory->var_assign) { (void) list_append(subn, instruction(Op_var_assign)); - subn->lasti->memory = ip->memory; + subn->lasti->assign_ctxt = Op_sub_builtin; subn->lasti->assign_var = ip->memory->var_assign; - r->sub_flags |= AFTER_ASSIGN; } else if (ip->opcode == Op_field_spec_lhs) { (void) list_append(subn, instruction(Op_field_assign)); + subn->lasti->assign_ctxt = Op_sub_builtin; subn->lasti->field_assign = (Func_ptr) 0; ip->target_assign = subn->lasti; - r->sub_flags |= AFTER_ASSIGN; } return subn; @@ -5126,7 +5122,6 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op) * for a special variable. */ (void) list_append(ip, instruction(Op_var_assign)); - ip->lasti->memory = tp->memory; ip->lasti->assign_var = tp->memory->var_assign; } else if (tp->opcode == Op_field_spec_lhs) { (void) list_append(ip, instruction(Op_field_assign)); @@ -5323,10 +5318,11 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype) && tp->memory->var_assign ) { asgn = instruction(Op_var_assign); - asgn->memory = tp->memory; + asgn->assign_ctxt = op->opcode; asgn->assign_var = tp->memory->var_assign; } else if (tp->opcode == Op_field_spec_lhs) { asgn = instruction(Op_field_assign); + asgn->assign_ctxt = op->opcode; asgn->field_assign = (Func_ptr) 0; /* determined at run time */ tp->target_assign = asgn; } diff --git a/builtin.c b/builtin.c index 5b75979..8685d29 100644 --- a/builtin.c +++ b/builtin.c @@ -2412,7 +2412,7 @@ do_match(int nargs) */ NODE * -do_sub(int nargs, unsigned int flags, int *num_matches) +do_sub(int nargs, unsigned int flags) { char *scan; char *bp, *cp; @@ -2680,7 +2680,6 @@ set_how_many: done: DEREF(s); - *num_matches = matches; if ((matches == 0 || (flags & LITERAL) != 0) && buf != NULL) efree(buf); diff --git a/debug.c b/debug.c index 404042c..4cda95c 100644 --- a/debug.c +++ b/debug.c @@ -39,6 +39,7 @@ extern long fcall_count; extern FILE *output_fp; extern IOBUF *curfile; extern const char *command_file; +extern const char *get_spec_varname(Func_ptr fptr); extern int r_interpret(INSTRUCTION *); extern int zzparse(void); #define read_command() (void) zzparse() @@ -3736,20 +3737,19 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) switch (pc->opcode) { case Op_var_update: - print_func(fp, "[update_%s]\n", pc->memory->vname); + print_func(fp, "[update_%s()]\n", get_spec_varname(pc->update_var)); break; case Op_var_assign: - if (pc->assign_var) - print_func(fp, "[set_%s()]", pc->memory->vname); + print_func(fp, "[set_%s()]", get_spec_varname(pc->assign_var)); + if (pc->assign_ctxt != 0) + print_func(fp, " [assign_ctxt = %s]", opcode2str(pc->assign_ctxt)); print_func(fp, "\n"); break; case Op_field_assign: - if (pc->field_assign) - print_func(fp, "[%s]", pc->field_assign == reset_record ? + print_func(fp, "[%s]\n", pc->field_assign == reset_record ? "reset_record()" : "invalidate_field0()"); - print_func(fp, "\n"); break; case Op_field_spec_lhs: @@ -3843,9 +3843,8 @@ print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump) { const char *fname = "sub"; static const struct flagtab values[] = { - { GSUB, "GSUB" }, + { GSUB, "GSUB" }, { GENSUB, "GENSUB" }, - { AFTER_ASSIGN, "AFTER_ASSIGN" }, { LITERAL, "LITERAL" }, { 0, NULL } }; diff --git a/eval.c b/eval.c index bdbd04b..bd3e027 100644 --- a/eval.c +++ b/eval.c @@ -2115,12 +2115,27 @@ post: break; case Op_var_assign: - if (pc->assign_var) - pc->assign_var(); - break; - case Op_field_assign: - if (pc->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 + && 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; @@ -2260,31 +2275,9 @@ arrayfor: PUSH(r); break; - case Op_sub_builtin: - { - /* sub, gsub and gensub */ - - int matches = 0; - - r = do_sub(pc->expr_count, pc->sub_flags, & matches); + case Op_sub_builtin: /* sub, gsub and gensub */ + r = do_sub(pc->expr_count, pc->sub_flags); PUSH(r); - - if (matches == 0 && (pc->sub_flags & AFTER_ASSIGN) != 0) { - - /* For sub and gsub, must not execute after_assign code; - * If the target is a FIELD, this means no field re-splitting or - * $0 reconstruction. For a special variable as target, - * set_XX routine is not called. - */ - - ni = pc->nexti; - assert(ni->opcode == Op_field_assign || ni->opcode == Op_var_assign); - if (ni->opcode == Op_field_assign) - ni->field_assign = (Func_ptr) 0; - else - ni->assign_var = (Func_ptr) 0; - } - } break; case Op_K_print: @@ -2458,6 +2451,7 @@ func_call: JUMPTO((pc + 1)->target_beginfile); } } while (r == NULL); /* EOF */ + PUSH(r); break; diff --git a/main.c b/main.c index 120d9ff..657de32 100644 --- a/main.c +++ b/main.c @@ -1127,6 +1127,26 @@ is_std_var(const char *var) return FALSE; } + +/* get_spec_varname --- return the name of a special variable + with the given assign or update routine. +*/ + +const char * +get_spec_varname(Func_ptr fptr) +{ + const struct varinit *vp; + + if (! fptr) + return NULL; + for (vp = varinit; vp->name != NULL; vp++) { + if (vp->assign == fptr || vp->update == fptr) + return vp->name; + } + return NULL; +} + + /* arg_assign --- process a command-line assignment */ int