"Fossies" - the Fresh Open Source Software Archive

Member "gawk-5.1.0/interpret.h" (6 Feb 2020, 36596 Bytes) of package /linux/misc/gawk-5.1.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "interpret.h" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.0.1_vs_5.1.0.

    1 /*
    2  * interpret.h ---  run a list of instructions.
    3  */
    4 
    5 /* 
    6  * Copyright (C) 1986, 1988, 1989, 1991-2020,
    7  * the Free Software Foundation, Inc.
    8  * 
    9  * This file is part of GAWK, the GNU implementation of the
   10  * AWK Programming Language.
   11  *
   12  * GAWK is free software; you can redistribute it and/or modify
   13  * it under the terms of the GNU General Public License as published by
   14  * the Free Software Foundation; either version 3 of the License, or
   15  * (at your option) any later version.
   16  *
   17  * GAWK is distributed in the hope that it will be useful,
   18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20  * GNU General Public License for more details.
   21  *
   22  * You should have received a copy of the GNU General Public License
   23  * along with this program; if not, write to the Free Software
   24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   25  */
   26 
   27 /*
   28  * If "r" is a field, valref should normally be > 1, because the field is
   29  * created initially with valref 1, and valref should be bumped when it is
   30  * pushed onto the stack by Op_field_spec. On the other hand, if we are
   31  * assigning to $n, then Op_store_field calls unref(*lhs) before assigning
   32  * the new value, so that decrements valref. So if the RHS is a field with
   33  * valref 1, that effectively means that this is an assignment like "$n = $n",
   34  * so a no-op, other than triggering $0 reconstitution.
   35  */
   36 
   37 // not a macro so we can step into it with a debugger
   38 #ifndef UNFIELD_DEFINED
   39 #define UNFIELD_DEFINED 1
   40 static inline void
   41 unfield(NODE **l, NODE **r)
   42 {
   43     /* if was a field, turn it into a var */
   44     if (((*r)->flags & MALLOC) != 0 || (*r)->valref == 1) {
   45         (*l) = (*r);
   46     } else {
   47         (*l) = dupnode(*r);
   48         DEREF(*r);
   49     }
   50 }
   51 
   52 #define UNFIELD(l, r)   unfield(& (l), & (r))
   53 #endif
   54 
   55 int
   56 r_interpret(INSTRUCTION *code)
   57 {
   58     INSTRUCTION *pc;   /* current instruction */
   59     OPCODE op;  /* current opcode */
   60     NODE *r = NULL;
   61     NODE *m;
   62     INSTRUCTION *ni;
   63     NODE *t1, *t2;
   64     NODE **lhs;
   65     AWKNUM x, x2;
   66     int di;
   67     Regexp *rp;
   68     NODE *set_array = NULL; /* array with a post-assignment routine */
   69     NODE *set_idx = NULL;   /* the index of the array element */
   70 
   71 
   72 /* array subscript */
   73 #define mk_sub(n)   (n == 1 ? POP_SCALAR() : concat_exp(n, true))
   74 
   75 #ifdef EXEC_HOOK
   76 #define JUMPTO(x)   do { if (post_execute) post_execute(pc); pc = (x); goto top; } while (false)
   77 #else
   78 #define JUMPTO(x)   do { pc = (x); goto top; } while (false)
   79 #endif
   80 
   81     pc = code;
   82 
   83     /* N.B.: always use JUMPTO for next instruction, otherwise bad things
   84      * may happen. DO NOT add a real loop (for/while) below to
   85      * replace ' forever {'; this catches failure to use JUMPTO to execute
   86      * next instruction (e.g. continue statement).
   87      */
   88 
   89     /* loop until hit Op_stop instruction */
   90 
   91     /* forever {  */
   92 top:
   93         if (pc->source_line > 0)
   94             sourceline = pc->source_line;
   95 
   96 #ifdef EXEC_HOOK
   97         for (di = 0; di < num_exec_hook; di++) {
   98             if (! pre_execute[di](& pc))
   99                 goto top;
  100         }
  101 #endif
  102 
  103         switch ((op = pc->opcode)) {
  104         case Op_rule:
  105             currule = pc->in_rule;   /* for sole use in Op_K_next, Op_K_nextfile, Op_K_getline */
  106             /* fall through */
  107         case Op_func:
  108             source = pc->source_file;
  109             break;
  110 
  111         case Op_atexit:
  112         {
  113             bool stdio_problem = false;
  114             bool got_EPIPE = false;
  115 
  116             /* avoid false source indications */
  117             source = NULL;
  118             sourceline = 0;
  119             (void) nextfile(& curfile, true);   /* close input data file */
  120             /*
  121              * This used to be:
  122              *
  123              * if (close_io() != 0 && ! exiting && exit_val == 0)
  124              *      exit_val = 1;
  125              *
  126              * Other awks don't care about problems closing open files
  127              * and pipes, in that it doesn't affect their exit status.
  128              * So we no longer do either.
  129              */
  130             (void) close_io(& stdio_problem, & got_EPIPE);
  131             /*
  132              * However, we do want to exit non-zero if there was a problem
  133              * with stdout/stderr, so we reinstate a slightly different
  134              * version of the above:
  135              */
  136             if (stdio_problem && ! exiting && exit_val == 0)
  137                 exit_val = 1;
  138 
  139             close_extensions();
  140 
  141             if (got_EPIPE)
  142                 die_via_sigpipe();
  143         }
  144             break;
  145 
  146         case Op_stop:
  147             return 0;
  148 
  149         case Op_push_i:
  150             m = pc->memory;
  151             if (! do_traditional && (m->flags & INTLSTR) != 0) {
  152                 char *orig, *trans, save;
  153 
  154                 save = m->stptr[m->stlen];
  155                 m->stptr[m->stlen] = '\0';
  156                 orig = m->stptr;
  157                 trans = dgettext(TEXTDOMAIN, orig);
  158                 m->stptr[m->stlen] = save;
  159                 if (trans != orig)  // got a translation
  160                     m = make_string(trans, strlen(trans));
  161                 else
  162                     UPREF(m);
  163             } else
  164                 UPREF(m);
  165             PUSH(m);
  166             break;
  167 
  168         case Op_push:
  169         case Op_push_arg:
  170         case Op_push_arg_untyped:
  171         {
  172             NODE *save_symbol;
  173             bool isparam = false;
  174 
  175             save_symbol = m = pc->memory;
  176             if (m->type == Node_param_list) {
  177                 isparam = true;
  178                 save_symbol = m = GET_PARAM(m->param_cnt);
  179                 if (m->type == Node_array_ref) {
  180                     if (m->orig_array->type == Node_var) {
  181                         /* gawk 'func f(x) { a = 10; print x; } BEGIN{ f(a) }' */
  182                         goto uninitialized_scalar;
  183                     }
  184                     m = m->orig_array;
  185                 }
  186             }
  187 
  188             switch (m->type) {
  189             case Node_var:
  190                 if (do_lint && var_uninitialized(m))
  191                     lintwarn(isparam ?
  192                         _("reference to uninitialized argument `%s'") :
  193                         _("reference to uninitialized variable `%s'"),
  194                                 save_symbol->vname);
  195                 m = m->var_value;
  196                 UPREF(m);
  197                 PUSH(m);
  198                 break;
  199 
  200             case Node_var_new:
  201 uninitialized_scalar:
  202                 if (op != Op_push_arg_untyped) {
  203                     /* convert untyped to scalar */
  204                     m->type = Node_var;
  205                     m->var_value = dupnode(Nnull_string);
  206                 }
  207                 if (do_lint)
  208                     lintwarn(isparam ?
  209                         _("reference to uninitialized argument `%s'") :
  210                         _("reference to uninitialized variable `%s'"),
  211                                 save_symbol->vname);
  212                 if (op != Op_push_arg_untyped)
  213                     m = dupnode(Nnull_string);
  214                 PUSH(m);
  215                 break;
  216 
  217             case Node_var_array:
  218                 if (op == Op_push_arg || op == Op_push_arg_untyped)
  219                     PUSH(m);
  220                 else
  221                     fatal(_("attempt to use array `%s' in a scalar context"),
  222                             array_vname(save_symbol));
  223                 break;
  224 
  225             default:
  226                 cant_happen();
  227             }
  228         }
  229             break;
  230 
  231         case Op_push_param:     /* function argument */
  232             m = pc->memory;
  233             if (m->type == Node_param_list)
  234                 m = GET_PARAM(m->param_cnt);
  235             if (m->type == Node_var) {
  236                 m = m->var_value;
  237                 UPREF(m);
  238                 PUSH(m);
  239                 break;
  240             }
  241             /* else
  242                 fall through */
  243         case Op_push_array:
  244             PUSH(pc->memory);
  245             break;
  246 
  247         case Op_push_lhs:
  248             lhs = get_lhs(pc->memory, pc->do_reference);
  249             PUSH_ADDRESS(lhs);
  250             break;
  251 
  252         case Op_subscript:
  253             t2 = mk_sub(pc->sub_count);
  254             t1 = POP_ARRAY(false);
  255 
  256             if (do_lint && in_array(t1, t2) == NULL) {
  257                 t2 = force_string(t2);
  258                 lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
  259                     array_vname(t1), (int) t2->stlen, t2->stptr);
  260                 if (t2->stlen == 0)
  261                     lintwarn(_("subscript of array `%s' is null string"), array_vname(t1));
  262             }
  263 
  264             /* for FUNCTAB, get the name as the element value */
  265             if (t1 == func_table) {
  266                 static bool warned = false;
  267 
  268                 if (do_lint_extensions && ! warned) {
  269                     warned = true;
  270                     lintwarn(_("FUNCTAB is a gawk extension"));
  271                 }
  272                 r = t2;
  273             } else {
  274                 /* make sure stuff like NF, NR, are up to date */
  275                 if (t1 == symbol_table)
  276                     update_global_values();
  277 
  278                 r = *assoc_lookup(t1, t2);
  279             }
  280             DEREF(t2);
  281 
  282             /* for SYMTAB, step through to the actual variable */
  283             if (t1 == symbol_table) {
  284                 static bool warned = false;
  285 
  286                 if (do_lint_extensions && ! warned) {
  287                     warned = true;
  288                     lintwarn(_("SYMTAB is a gawk extension"));
  289                 }
  290                 if (r->type == Node_var)
  291                     r = r->var_value;
  292                 else if (r->type == Node_var_new) {
  293                     // variable may exist but have never been set.
  294                     r->var_value = dupnode(Nnull_string);
  295                     r = r->var_value;
  296                 }
  297             }
  298 
  299             if (r->type == Node_val)
  300                 UPREF(r);
  301             PUSH(r);
  302             break;
  303 
  304         case Op_sub_array:
  305             t2 = mk_sub(pc->sub_count);
  306             t1 = POP_ARRAY(false);
  307             r = in_array(t1, t2);
  308             if (r == NULL) {
  309                 r = make_array();
  310                 r->parent_array = t1;
  311                 t2 = force_string(t2);
  312                 r->vname = estrdup(t2->stptr, t2->stlen);   /* the subscript in parent array */
  313                 assoc_set(t1, t2, r);
  314             } else if (r->type != Node_var_array) {
  315                 t2 = force_string(t2);
  316                 fatal(_("attempt to use scalar `%s[\"%.*s\"]' as an array"),
  317                         array_vname(t1), (int) t2->stlen, t2->stptr);
  318             } else
  319                 DEREF(t2);
  320 
  321             PUSH(r);
  322             break;
  323 
  324         case Op_subscript_lhs:
  325             t2 = mk_sub(pc->sub_count);
  326             t1 = POP_ARRAY(false);
  327             if (do_lint && in_array(t1, t2) == NULL) {
  328                 t2 = force_string(t2);
  329                 if (pc->do_reference)
  330                     lintwarn(_("reference to uninitialized element `%s[\"%.*s\"]'"),
  331                         array_vname(t1), (int) t2->stlen, t2->stptr);
  332                 if (t2->stlen == 0)
  333                     lintwarn(_("subscript of array `%s' is null string"), array_vname(t1));
  334             }
  335 
  336             lhs = assoc_lookup(t1, t2);
  337             if ((*lhs)->type == Node_var_array) {
  338                 t2 = force_string(t2);
  339                 fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
  340                         array_vname(t1), (int) t2->stlen, t2->stptr);
  341             }
  342 
  343             /*
  344              * Changing something in FUNCTAB is not allowed.
  345              *
  346              * SYMTAB is a little more messy.  Three kinds of values may
  347              * be stored in SYMTAB:
  348              *  1. Variables that don"t yet have a value (Node_var_new)
  349              *  2. Variables that have a value (Node_var)
  350              *  3. Values that awk code stuck into SYMTAB not related to variables (Node_value)
  351              * For 1, since we are giving it a value, we have to change the type to Node_var.
  352              * For 1 and 2, we have to step through the Node_var to get to the value.
  353              * For 3, we fatal out. This avoids confusion on things like
  354              * SYMTAB["a foo"] = 42 # variable with a space in its name?
  355              */
  356             if (t1 == func_table)
  357                 fatal(_("cannot assign to elements of FUNCTAB"));
  358             else if (t1 == symbol_table) {
  359                 if ((   (*lhs)->type == Node_var
  360                      || (*lhs)->type == Node_var_new)) {
  361                     update_global_values();     /* make sure stuff like NF, NR, are up to date */
  362                     (*lhs)->type = Node_var;    /* in case was Node_var_new */
  363                     lhs = & ((*lhs)->var_value);    /* extra level of indirection */
  364                 } else
  365                     fatal(_("cannot assign to arbitrary elements of SYMTAB"));
  366             }
  367 
  368             assert(set_idx == NULL);
  369 
  370             if (t1->astore) {
  371                 /* array has post-assignment routine */
  372                 set_array = t1;
  373                 set_idx = t2;
  374             } else
  375                 DEREF(t2);
  376 
  377             PUSH_ADDRESS(lhs);
  378             break;
  379 
  380         case Op_field_spec:
  381             t1 = TOP_SCALAR();
  382             lhs = r_get_field(t1, (Func_ptr *) 0, true);
  383             decr_sp();
  384             DEREF(t1);
  385             r = *lhs;
  386             UPREF(r);
  387             PUSH(r);
  388             break;
  389 
  390         case Op_field_spec_lhs:
  391             t1 = TOP_SCALAR();
  392             lhs = r_get_field(t1, &pc->target_assign->field_assign, pc->do_reference);
  393             decr_sp();
  394             DEREF(t1);
  395             PUSH_ADDRESS(lhs);
  396             break;
  397 
  398         case Op_lint:
  399             if (do_lint) {
  400                 switch (pc->lint_type) {
  401                 case LINT_assign_in_cond:
  402                     lintwarn(_("assignment used in conditional context"));
  403                     break;
  404 
  405                 case LINT_no_effect:
  406                     lintwarn(_("statement has no effect"));
  407                     break;
  408 
  409                 default:
  410                     cant_happen();
  411                 }
  412             }
  413             break;
  414 
  415         case Op_K_break:
  416         case Op_K_continue:
  417         case Op_jmp:
  418             assert(pc->target_jmp != NULL);
  419             JUMPTO(pc->target_jmp);
  420 
  421         case Op_jmp_false:
  422             r = POP_SCALAR();
  423             di = eval_condition(r);
  424             DEREF(r);
  425             if (! di)
  426                 JUMPTO(pc->target_jmp);
  427             break;
  428 
  429         case Op_jmp_true:
  430             r = POP_SCALAR();
  431             di = eval_condition(r);
  432             DEREF(r);
  433             if (di)
  434                 JUMPTO(pc->target_jmp);
  435             break;
  436 
  437         case Op_and:
  438         case Op_or:
  439             t1 = POP_SCALAR();
  440             di = eval_condition(t1);
  441             DEREF(t1);
  442             if ((op == Op_and && di) || (op == Op_or && ! di))
  443                 break;
  444             r = node_Boolean[di];
  445             UPREF(r);
  446             PUSH(r);
  447             ni = pc->target_jmp;
  448             JUMPTO(ni->nexti);
  449 
  450         case Op_and_final:
  451         case Op_or_final:
  452             t1 = TOP_SCALAR();
  453             r = node_Boolean[eval_condition(t1)];
  454             DEREF(t1);
  455             UPREF(r);
  456             REPLACE(r);
  457             break;
  458 
  459         case Op_not:
  460             t1 = TOP_SCALAR();
  461             r = node_Boolean[! eval_condition(t1)];
  462             DEREF(t1);
  463             UPREF(r);
  464             REPLACE(r);
  465             break;
  466 
  467         case Op_equal:
  468             r = node_Boolean[cmp_scalars(SCALAR_EQ_NEQ) == 0];
  469             UPREF(r);
  470             REPLACE(r);
  471             break;
  472 
  473         case Op_notequal:
  474             r = node_Boolean[cmp_scalars(SCALAR_EQ_NEQ) != 0];
  475             UPREF(r);
  476             REPLACE(r);
  477             break;
  478 
  479         case Op_less:
  480             r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) < 0];
  481             UPREF(r);
  482             REPLACE(r);
  483             break;
  484 
  485         case Op_greater:
  486             r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) > 0];
  487             UPREF(r);
  488             REPLACE(r);
  489             break;
  490 
  491         case Op_leq:
  492             r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) <= 0];
  493             UPREF(r);
  494             REPLACE(r);
  495             break;
  496 
  497         case Op_geq:
  498             r = node_Boolean[cmp_scalars(SCALAR_RELATIONAL) >= 0];
  499             UPREF(r);
  500             REPLACE(r);
  501             break;
  502 
  503         case Op_plus_i:
  504             x2 = force_number(pc->memory)->numbr;
  505             goto plus;
  506         case Op_plus:
  507             t2 = POP_NUMBER();
  508             x2 = t2->numbr;
  509             DEREF(t2);
  510 plus:
  511             t1 = TOP_NUMBER();
  512             r = make_number(t1->numbr + x2);
  513             DEREF(t1);
  514             REPLACE(r);
  515             break;
  516 
  517         case Op_minus_i:
  518             x2 = force_number(pc->memory)->numbr;
  519             goto minus;
  520         case Op_minus:
  521             t2 = POP_NUMBER();
  522             x2 = t2->numbr;
  523             DEREF(t2);
  524 minus:
  525             t1 = TOP_NUMBER();
  526             r = make_number(t1->numbr - x2);
  527             DEREF(t1);
  528             REPLACE(r);
  529             break;
  530 
  531         case Op_times_i:
  532             x2 = force_number(pc->memory)->numbr;
  533             goto times;
  534         case Op_times:
  535             t2 = POP_NUMBER();
  536             x2 = t2->numbr;
  537             DEREF(t2);
  538 times:
  539             t1 = TOP_NUMBER();
  540             r = make_number(t1->numbr * x2);
  541             DEREF(t1);
  542             REPLACE(r);
  543             break;
  544 
  545         case Op_exp_i:
  546             x2 = force_number(pc->memory)->numbr;
  547             goto exp;
  548         case Op_exp:
  549             t2 = POP_NUMBER();
  550             x2 = t2->numbr;
  551             DEREF(t2);
  552 exp:
  553             t1 = TOP_NUMBER();
  554             r = make_number(calc_exp(t1->numbr, x2));
  555             DEREF(t1);
  556             REPLACE(r);
  557             break;
  558 
  559         case Op_quotient_i:
  560             x2 = force_number(pc->memory)->numbr;
  561             goto quotient;
  562         case Op_quotient:
  563             t2 = POP_NUMBER();
  564             x2 = t2->numbr;
  565             DEREF(t2);
  566 quotient:
  567             t1 = TOP_NUMBER();
  568             if (x2 == 0)
  569                 fatal(_("division by zero attempted"));
  570             r = make_number(t1->numbr / x2);
  571             DEREF(t1);
  572             REPLACE(r);
  573             break;
  574 
  575         case Op_mod_i:
  576             x2 = force_number(pc->memory)->numbr;
  577             goto mod;
  578         case Op_mod:
  579             t2 = POP_NUMBER();
  580             x2 = t2->numbr;
  581             DEREF(t2);
  582 mod:
  583             t1 = TOP_NUMBER();
  584             if (x2 == 0)
  585                 fatal(_("division by zero attempted in `%%'"));
  586 #ifdef HAVE_FMOD
  587             x = fmod(t1->numbr, x2);
  588 #else   /* ! HAVE_FMOD */
  589             (void) modf(t1->numbr / x2, &x);
  590             x = t1->numbr - x * x2;
  591 #endif  /* ! HAVE_FMOD */
  592             r = make_number(x);
  593 
  594             DEREF(t1);
  595             REPLACE(r);
  596             break;
  597 
  598         case Op_preincrement:
  599         case Op_predecrement:
  600             x = op == Op_preincrement ? 1.0 : -1.0;
  601             lhs = TOP_ADDRESS();
  602             t1 = *lhs;
  603             force_number(t1);
  604             if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
  605                 /* optimization */
  606                 t1->numbr += x;
  607                 r = t1;
  608             } else {
  609                 r = *lhs = make_number(t1->numbr + x);
  610                 unref(t1);
  611             }
  612             UPREF(r);
  613             REPLACE(r);
  614             break;
  615 
  616         case Op_postincrement:
  617         case Op_postdecrement:
  618             x = op == Op_postincrement ? 1.0 : -1.0;
  619             lhs = TOP_ADDRESS();
  620             t1 = *lhs;
  621             force_number(t1);
  622             r = make_number(t1->numbr);
  623             if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
  624                 /* optimization */
  625                 t1->numbr += x;
  626             } else {
  627                 *lhs = make_number(t1->numbr + x);
  628                 unref(t1);
  629             }
  630             REPLACE(r);
  631             break;
  632 
  633         case Op_unary_minus:
  634             t1 = TOP_NUMBER();
  635             r = make_number(-t1->numbr);
  636             DEREF(t1);
  637             REPLACE(r);
  638             break;
  639 
  640         case Op_unary_plus:
  641             // Force argument to be numeric
  642             t1 = TOP_NUMBER();
  643             r = make_number(t1->numbr);
  644             DEREF(t1);
  645             REPLACE(r);
  646             break;
  647 
  648         case Op_store_sub:
  649             /*
  650              * array[sub] assignment optimization,
  651              * see awkgram.y (optimize_assignment)
  652              */
  653             t1 = force_array(pc->memory, true); /* array */
  654             t2 = mk_sub(pc->expr_count);    /* subscript */
  655             lhs = assoc_lookup(t1, t2);
  656             if ((*lhs)->type == Node_var_array) {
  657                 t2 = force_string(t2);
  658                 fatal(_("attempt to use array `%s[\"%.*s\"]' in a scalar context"),
  659                         array_vname(t1), (int) t2->stlen, t2->stptr);
  660             }
  661             DEREF(t2);
  662 
  663             /*
  664              * Changing something in FUNCTAB is not allowed.
  665              *
  666              * SYMTAB is a little more messy.  Three possibilities for SYMTAB:
  667              *  1. Variables that don"t yet have a value (Node_var_new)
  668              *  2. Variables that have a value (Node_var)
  669              *  3. Values that awk code stuck into SYMTAB not related to variables (Node_value)
  670              * For 1, since we are giving it a value, we have to change the type to Node_var.
  671              * For 1 and 2, we have to step through the Node_var to get to the value.
  672              * For 3, we fatal out. This avoids confusion on things like
  673              * SYMTAB["a foo"] = 42 # variable with a space in its name?
  674              */
  675             if (t1 == func_table)
  676                 fatal(_("cannot assign to elements of FUNCTAB"));
  677             else if (t1 == symbol_table) {
  678                 if ((   (*lhs)->type == Node_var
  679                      || (*lhs)->type == Node_var_new)) {
  680                     update_global_values();     /* make sure stuff like NF, NR, are up to date */
  681                     (*lhs)->type = Node_var;    /* in case was Node_var_new */
  682                     lhs = & ((*lhs)->var_value);    /* extra level of indirection */
  683                 } else
  684                     fatal(_("cannot assign to arbitrary elements of SYMTAB"));
  685             }
  686 
  687             unref(*lhs);
  688             r = POP_SCALAR();
  689             UNFIELD(*lhs, r);
  690 
  691             /* execute post-assignment routine if any */
  692             if (t1->astore != NULL)
  693                 (*t1->astore)(t1, t2);
  694 
  695             DEREF(t2);
  696             break;
  697 
  698         case Op_store_var:
  699             /*
  700              * simple variable assignment optimization,
  701              * see awkgram.y (optimize_assignment)
  702              */
  703 
  704             lhs = get_lhs(pc->memory, false);
  705             unref(*lhs);
  706             r = pc->initval;    /* constant initializer */
  707             if (r != NULL) {
  708                 UPREF(r);
  709                 *lhs = r;
  710             } else {
  711                 r = POP_SCALAR();
  712                 UNFIELD(*lhs, r);
  713             }
  714             break;
  715 
  716         case Op_store_field:
  717         {
  718             /* field assignment optimization,
  719              * see awkgram.y (optimize_assignment)
  720              */
  721 
  722             Func_ptr assign;
  723             t1 = TOP_SCALAR();
  724             lhs = r_get_field(t1, & assign, false);
  725             decr_sp();
  726             DEREF(t1);
  727             /*
  728              * N.B. We must call assign() before unref, since
  729              * we may need to copy $n values before freeing the
  730              * $0 buffer.
  731              */
  732             assert(assign != NULL);
  733             assign();
  734             unref(*lhs);
  735             r = POP_SCALAR();
  736             UNFIELD(*lhs, r);
  737             /* field variables need the string representation: */
  738             force_string(*lhs);
  739         }
  740             break;
  741 
  742         case Op_assign_concat:
  743             /* x = x ... string concatenation optimization */
  744             lhs = get_lhs(pc->memory, false);
  745             t1 = force_string(*lhs);
  746             t2 = POP_STRING();
  747 
  748             if (t1 != *lhs) {
  749                 unref(*lhs);
  750                 if (t1->valref == 1)
  751                     *lhs = t1;
  752                 else
  753                     *lhs = dupnode(t1);
  754             }
  755 
  756             if (t1 != t2 && t1->valref == 1 && (t1->flags & (MALLOC|MPFN|MPZN)) == MALLOC) {
  757                 size_t nlen = t1->stlen + t2->stlen;
  758 
  759                 erealloc(t1->stptr, char *, nlen + 1, "r_interpret");
  760                 memcpy(t1->stptr + t1->stlen, t2->stptr, t2->stlen);
  761                 t1->stlen = nlen;
  762                 t1->stptr[nlen] = '\0';
  763                 /* clear flags except WSTRCUR (used below) */
  764                 t1->flags &= WSTRCUR;
  765                 /* configure as a string as in make_str_node */
  766                 t1->flags |= (MALLOC|STRING|STRCUR);
  767                 t1->stfmt = STFMT_UNUSED;
  768 #ifdef HAVE_MPFR
  769                 t1->strndmode = MPFR_round_mode;
  770 #endif
  771 
  772                 if ((t1->flags & WSTRCUR) != 0 && (t2->flags & WSTRCUR) != 0) {
  773                     size_t wlen = t1->wstlen + t2->wstlen;
  774 
  775                     erealloc(t1->wstptr, wchar_t *,
  776                             sizeof(wchar_t) * (wlen + 1), "r_interpret");
  777                     memcpy(t1->wstptr + t1->wstlen, t2->wstptr, t2->wstlen * sizeof(wchar_t));
  778                     t1->wstlen = wlen;
  779                     t1->wstptr[wlen] = L'\0';
  780                 } else
  781                     free_wstr(*lhs);
  782             } else {
  783                 size_t nlen = t1->stlen + t2->stlen;
  784                 char *p;
  785 
  786                 emalloc(p, char *, nlen + 1, "r_interpret");
  787                 memcpy(p, t1->stptr, t1->stlen);
  788                 memcpy(p + t1->stlen, t2->stptr, t2->stlen);
  789                 /* N.B. No NUL-termination required, since make_str_node will do it. */
  790                 unref(*lhs);
  791                 t1 = *lhs = make_str_node(p, nlen, ALREADY_MALLOCED);
  792             }
  793             DEREF(t2);
  794             break;
  795 
  796         case Op_assign:
  797             lhs = POP_ADDRESS();
  798             r = TOP_SCALAR();
  799             unref(*lhs);
  800             UPREF(r);
  801             UNFIELD(*lhs, r);
  802             REPLACE(r);
  803             break;
  804 
  805         case Op_subscript_assign:
  806             /* conditionally execute post-assignment routine for an array element */
  807 
  808             if (set_idx != NULL) {
  809                 di = true;
  810                 if (pc->assign_ctxt == Op_sub_builtin
  811                     && (r = TOP())
  812                     && get_number_si(r) == 0    /* no substitution performed */
  813                 )
  814                     di = false;
  815                 else if ((pc->assign_ctxt == Op_K_getline
  816                         || pc->assign_ctxt == Op_K_getline_redir)
  817                     && (r = TOP())
  818                     && get_number_si(r) <= 0    /* EOF or error */
  819                 )
  820                     di = false;
  821 
  822                 if (di)
  823                     (*set_array->astore)(set_array, set_idx);
  824                 unref(set_idx);
  825                 set_idx = NULL;
  826             }
  827             break;
  828 
  829         /* numeric assignments */
  830         case Op_assign_plus:
  831         case Op_assign_minus:
  832         case Op_assign_times:
  833         case Op_assign_quotient:
  834         case Op_assign_mod:
  835         case Op_assign_exp:
  836             op_assign(op);
  837             break;
  838 
  839         case Op_var_update:        /* update value of NR, FNR or NF */
  840             pc->update_var();
  841             break;
  842 
  843         case Op_var_assign:
  844         case Op_field_assign:
  845             r = TOP();
  846             if (pc->assign_ctxt == Op_sub_builtin
  847                 && get_number_si(r) == 0    /* top of stack has a number == 0 */
  848             ) {
  849                 /* There wasn't any substitutions. If the target is a FIELD,
  850                  * this means no field re-splitting or $0 reconstruction.
  851                  * Skip the set_FOO routine if the target is a special variable.
  852                  */
  853 
  854                 break;
  855             } else if ((pc->assign_ctxt == Op_K_getline
  856                     || pc->assign_ctxt == Op_K_getline_redir)
  857                 && get_number_si(r) <= 0    /* top of stack has a number <= 0 */
  858             ) {
  859                 /* getline returned EOF or error */
  860 
  861                 break;
  862             }
  863 
  864             if (op == Op_var_assign)
  865                 pc->assign_var();
  866             else
  867                 pc->field_assign();
  868             break;
  869 
  870         case Op_concat:
  871             r = concat_exp(pc->expr_count, pc->concat_flag & CSUBSEP);
  872             PUSH(r);
  873             break;
  874 
  875         case Op_K_case:
  876             if ((pc + 1)->match_exp) {
  877                 /* match a constant regex against switch expression instead of $0. */
  878 
  879                 m = POP();  /* regex */
  880                 t2 = TOP_SCALAR();  /* switch expression */
  881                 t2 = force_string(t2);
  882                 rp = re_update(m);
  883                 di = (research(rp, t2->stptr, 0, t2->stlen, RE_NO_FLAGS) >= 0);
  884             } else {
  885                 t1 = POP_SCALAR();  /* case value */
  886                 t2 = TOP_SCALAR();  /* switch expression */
  887                 di = (cmp_nodes(t2, t1, true) == 0);
  888                 DEREF(t1);
  889             }
  890 
  891             if (di) {
  892                 /* match found */
  893                 t2 = POP_SCALAR();
  894                 DEREF(t2);
  895                 JUMPTO(pc->target_jmp);
  896             }
  897             break;
  898 
  899         case Op_K_delete:
  900             t1 = POP_ARRAY(false);
  901             do_delete(t1, pc->expr_count);
  902             stack_adj(-pc->expr_count);
  903             break;
  904 
  905         case Op_K_delete_loop:
  906             t1 = POP_ARRAY(false);
  907             lhs = POP_ADDRESS();    /* item */
  908             do_delete_loop(t1, lhs);
  909             break;
  910 
  911         case Op_in_array:
  912             t1 = POP_ARRAY(false);
  913             t2 = mk_sub(pc->expr_count);
  914             r = node_Boolean[(in_array(t1, t2) != NULL)];
  915             DEREF(t2);
  916             UPREF(r);
  917             PUSH(r);
  918             break;
  919 
  920         case Op_arrayfor_init:
  921         {
  922             NODE **list = NULL;
  923             NODE *array, *sort_str;
  924             size_t num_elems = 0;
  925             static NODE *sorted_in = NULL;
  926             const char *how_to_sort = "@unsorted";
  927             char save;
  928             bool saved_end = false;
  929 
  930             /* get the array */
  931             array = POP_ARRAY(true);
  932 
  933             /* sanity: check if empty */
  934             num_elems = assoc_length(array);
  935             if (num_elems == 0)
  936                 goto arrayfor;
  937 
  938             if (sorted_in == NULL)      /* do this once */
  939                 sorted_in = make_string("sorted_in", 9);
  940 
  941             sort_str = NULL;
  942             /*
  943              * If posix, or if there's no PROCINFO[],
  944              * there's no ["sorted_in"], so no sorting
  945              */
  946             if (! do_posix && PROCINFO_node != NULL)
  947                 sort_str = in_array(PROCINFO_node, sorted_in);
  948 
  949             if (sort_str != NULL) {
  950                 sort_str = force_string(sort_str);
  951                 if (sort_str->stlen > 0) {
  952                     how_to_sort = sort_str->stptr;
  953                     str_terminate(sort_str, save);
  954                     saved_end = true;
  955                 }
  956             }
  957 
  958             list = assoc_list(array, how_to_sort, SORTED_IN);
  959             if (saved_end)
  960                 str_restore(sort_str, save);
  961 
  962 arrayfor:
  963             getnode(r);
  964             r->type = Node_arrayfor;
  965             r->for_list = list;
  966             r->for_list_size = num_elems;       /* # of elements in list */
  967             r->cur_idx = -1;            /* current index */
  968             r->for_array = array;       /* array */
  969             PUSH(r);
  970 
  971             if (num_elems == 0)
  972                 JUMPTO(pc->target_jmp);   /* Op_arrayfor_final */
  973         }
  974             break;
  975 
  976         case Op_arrayfor_incr:
  977             r = TOP();  /* Node_arrayfor */
  978             if (++r->cur_idx == r->for_list_size) {
  979                 NODE *array;
  980                 array = r->for_array;   /* actual array */
  981                 if (do_lint && array->table_size != r->for_list_size)
  982                     lintwarn(_("for loop: array `%s' changed size from %ld to %ld during loop execution"),
  983                         array_vname(array), (long) r->for_list_size, (long) array->table_size);
  984                 JUMPTO(pc->target_jmp); /* Op_arrayfor_final */
  985             }
  986 
  987             t1 = r->for_list[r->cur_idx];
  988             lhs = get_lhs(pc->array_var, false);
  989             unref(*lhs);
  990             *lhs = dupnode(t1);
  991             break;
  992 
  993         case Op_arrayfor_final:
  994             r = POP();
  995             assert(r->type == Node_arrayfor);
  996             free_arrayfor(r);
  997             break;
  998 
  999         case Op_builtin:
 1000             r = pc->builtin(pc->expr_count);
 1001             PUSH(r);
 1002             break;
 1003 
 1004         case Op_ext_builtin:
 1005         {
 1006             size_t arg_count = pc->expr_count;
 1007             awk_ext_func_t *f = pc[1].c_function;
 1008             size_t min_req = f->min_required_args;
 1009             size_t max_expect = f->max_expected_args;
 1010             awk_value_t result;
 1011 
 1012             if (arg_count < min_req)
 1013                 fatal(_("%s: called with %lu arguments, expecting at least %lu"),
 1014                         pc[1].func_name,
 1015                         (unsigned long) arg_count,
 1016                         (unsigned long) min_req);
 1017 
 1018             if (do_lint && ! f->suppress_lint && arg_count > max_expect)
 1019                 lintwarn(_("%s: called with %lu arguments, expecting no more than %lu"),
 1020                         pc[1].func_name,
 1021                         (unsigned long) arg_count,
 1022                         (unsigned long) max_expect);
 1023 
 1024             PUSH_CODE(pc);
 1025             r = awk_value_to_node(pc->extfunc(arg_count, & result, f));
 1026             (void) POP_CODE();
 1027             while (arg_count-- > 0) {
 1028                 t1 = POP();
 1029                 if (t1->type == Node_val)
 1030                     DEREF(t1);
 1031             }
 1032             free_api_string_copies();
 1033             PUSH(r);
 1034         }
 1035             break;
 1036 
 1037         case Op_sub_builtin:    /* sub, gsub and gensub */
 1038             r = do_sub(pc->expr_count, pc->sub_flags);
 1039             PUSH(r);
 1040             break;
 1041 
 1042         case Op_K_print:
 1043             do_print(pc->expr_count, pc->redir_type);
 1044             break;
 1045 
 1046         case Op_K_printf:
 1047             do_printf(pc->expr_count, pc->redir_type);
 1048             break;
 1049 
 1050         case Op_K_print_rec:
 1051             do_print_rec(pc->expr_count, pc->redir_type);
 1052             break;
 1053 
 1054         case Op_push_re:
 1055             m = pc->memory;
 1056             if (m->type == Node_dynregex) {
 1057                 r = POP_STRING();
 1058                 unref(m->re_exp);
 1059                 m->re_exp = r;
 1060             } else if (m->type == Node_val) {
 1061                 assert((m->flags & REGEX) != 0);
 1062                 UPREF(m);
 1063             }
 1064             PUSH(m);
 1065             break;
 1066 
 1067         case Op_match_rec:
 1068             m = pc->memory;
 1069             t1 = *get_field(0, (Func_ptr *) 0);
 1070 match_re:
 1071             rp = re_update(m);
 1072             di = research(rp, t1->stptr, 0, t1->stlen, RE_NO_FLAGS);
 1073             di = (di == -1) ^ (op != Op_nomatch);
 1074             if (op != Op_match_rec) {
 1075                 decr_sp();
 1076                 DEREF(t1);
 1077                 if (m->type == Node_dynregex) {
 1078                     DEREF(m->re_exp);
 1079                     m->re_exp = NULL;
 1080                 }
 1081             }
 1082             r = node_Boolean[di];
 1083             UPREF(r);
 1084             PUSH(r);
 1085             break;
 1086 
 1087         case Op_nomatch:
 1088             /* fall through */
 1089         case Op_match:
 1090             m = pc->memory;
 1091             t1 = TOP_STRING();
 1092             if (m->type == Node_dynregex) {
 1093                 unref(m->re_exp);
 1094                 m->re_exp = t1;
 1095                 decr_sp();
 1096                 t1 = TOP_STRING();
 1097             }
 1098             goto match_re;
 1099             break;
 1100 
 1101         case Op_indirect_func_call:
 1102         {
 1103             NODE *f = NULL;
 1104             int arg_count;
 1105             char save;
 1106 
 1107             arg_count = (pc + 1)->expr_count;
 1108             t1 = PEEK(arg_count);   /* indirect var */
 1109 
 1110             if (t1->type != Node_val)   /* @a[1](p) not allowed in grammar */
 1111                 fatal(_("indirect function call requires a simple scalar value"));
 1112 
 1113             t1 = force_string(t1);
 1114             str_terminate(t1, save);
 1115             if (t1->stlen > 0) {
 1116                 /* retrieve function definition node */
 1117                 f = pc->func_body;
 1118                 if (f != NULL && strcmp(f->vname, t1->stptr) == 0) {
 1119                     /* indirect var hasn't been reassigned */
 1120 
 1121                     str_restore(t1, save);
 1122                     ni = setup_frame(pc);
 1123                     JUMPTO(ni); /* Op_func */
 1124                 }
 1125                 f = lookup(t1->stptr);
 1126             }
 1127 
 1128             if (f == NULL) {
 1129                 fatal(_("`%s' is not a function, so it cannot be called indirectly"),
 1130                         t1->stptr);
 1131             } else if (f->type == Node_builtin_func) {
 1132                 int arg_count = (pc + 1)->expr_count;
 1133                 builtin_func_t the_func = lookup_builtin(t1->stptr);
 1134 
 1135                 assert(the_func != NULL);
 1136 
 1137                 /* call it */
 1138                 if (the_func == (builtin_func_t) do_sub)
 1139                     r = call_sub(t1->stptr, arg_count);
 1140                 else if (the_func == do_match)
 1141                     r = call_match(arg_count);
 1142                 else if (the_func == do_split || the_func == do_patsplit)
 1143                     r = call_split_func(t1->stptr, arg_count);
 1144                 else
 1145                     r = the_func(arg_count);
 1146                 str_restore(t1, save);
 1147 
 1148                 PUSH(r);
 1149                 break;
 1150             } else if (f->type != Node_func) {
 1151                 str_restore(t1, save);
 1152                 if (f->type == Node_ext_func) {
 1153                     /* code copied from below, keep in sync */
 1154                     INSTRUCTION *bc;
 1155                     char *fname = pc->func_name;
 1156                     int arg_count = (pc + 1)->expr_count;
 1157                     static INSTRUCTION npc[2];
 1158 
 1159                     npc[0] = *pc;
 1160 
 1161                     bc = f->code_ptr;
 1162                     assert(bc->opcode == Op_symbol);
 1163                     npc[0].opcode = Op_ext_builtin; /* self modifying code */
 1164                     npc[0].extfunc = bc->extfunc;
 1165                     npc[0].expr_count = arg_count;      /* actual argument count */
 1166                     npc[1] = pc[1];
 1167                     npc[1].func_name = fname;   /* name of the builtin */
 1168                     npc[1].c_function = bc->c_function;
 1169                     ni = npc;
 1170                     JUMPTO(ni);
 1171                 } else
 1172                     fatal(_("function called indirectly through `%s' does not exist"),
 1173                             pc->func_name);
 1174             }
 1175             pc->func_body = f;     /* save for next call */
 1176             str_restore(t1, save);
 1177 
 1178             ni = setup_frame(pc);
 1179             JUMPTO(ni); /* Op_func */
 1180         }
 1181 
 1182         case Op_func_call:
 1183         {
 1184             NODE *f;
 1185 
 1186             /* retrieve function definition node */
 1187             f = pc->func_body;
 1188             if (f == NULL) {
 1189                 f = lookup(pc->func_name);
 1190                 if (f == NULL || (f->type != Node_func && f->type != Node_ext_func))
 1191                     fatal(_("function `%s' not defined"), pc->func_name);
 1192                 pc->func_body = f;     /* save for next call */
 1193             }
 1194 
 1195             if (f->type == Node_ext_func) {
 1196                 /* keep in sync with indirect call code */
 1197                 INSTRUCTION *bc;
 1198                 char *fname = pc->func_name;
 1199                 int arg_count = (pc + 1)->expr_count;
 1200 
 1201                 bc = f->code_ptr;
 1202                 assert(bc->opcode == Op_symbol);
 1203                 pc->opcode = Op_ext_builtin;    /* self modifying code */
 1204                 pc->extfunc = bc->extfunc;
 1205                 pc->expr_count = arg_count; /* actual argument count */
 1206                 (pc + 1)->func_name = fname;    /* name of the builtin */
 1207                 (pc + 1)->c_function = bc->c_function;  /* min and max args */
 1208                 ni = pc;
 1209                 JUMPTO(ni);
 1210             }
 1211 
 1212             ni = setup_frame(pc);
 1213             JUMPTO(ni); /* Op_func */
 1214         }
 1215 
 1216         case Op_K_return_from_eval:
 1217             cant_happen();
 1218             break;
 1219 
 1220         case Op_K_return:
 1221             m = POP_SCALAR();       /* return value */
 1222 
 1223             ni = pop_fcall();
 1224 
 1225             /* put the return value back on stack */
 1226             PUSH(m);
 1227 
 1228             JUMPTO(ni);
 1229 
 1230         case Op_K_getline_redir:
 1231             r = do_getline_redir(pc->into_var, pc->redir_type);
 1232             PUSH(r);
 1233             break;
 1234 
 1235         case Op_K_getline:  /* no redirection */
 1236             if (! currule || currule == BEGINFILE || currule == ENDFILE)
 1237                 fatal(_("non-redirected `getline' invalid inside `%s' rule"),
 1238                         ruletab[currule]);
 1239 
 1240             do {
 1241                 int ret;
 1242                 ret = nextfile(& curfile, false);
 1243                 if (ret <= 0)
 1244                     r = do_getline(pc->into_var, curfile);
 1245                 else {
 1246 
 1247                     /* Save execution state so that we can return to it
 1248                      * from Op_after_beginfile or Op_after_endfile.
 1249                      */
 1250 
 1251                     push_exec_state(pc, currule, source, stack_ptr);
 1252 
 1253                     if (curfile == NULL)
 1254                         JUMPTO((pc + 1)->target_endfile);
 1255                     else
 1256                         JUMPTO((pc + 1)->target_beginfile);
 1257                 }
 1258             } while (r == NULL);    /* EOF */
 1259 
 1260             PUSH(r);
 1261             break;
 1262 
 1263         case Op_after_endfile:
 1264             /* Find the execution state to return to */
 1265             ni = pop_exec_state(& currule, & source, NULL);
 1266 
 1267             assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline);
 1268             JUMPTO(ni);
 1269 
 1270         case Op_after_beginfile:
 1271             after_beginfile(& curfile);
 1272 
 1273             /* Find the execution state to return to */
 1274             ni = pop_exec_state(& currule, & source, NULL);
 1275 
 1276             assert(ni->opcode == Op_newfile || ni->opcode == Op_K_getline);
 1277             if (ni->opcode == Op_K_getline
 1278                     || curfile == NULL      /* skipping directory argument */
 1279             )
 1280                 JUMPTO(ni);
 1281 
 1282             break;  /* read a record, Op_get_record */
 1283 
 1284         case Op_newfile:
 1285         {
 1286             int ret;
 1287 
 1288             ret = nextfile(& curfile, false);
 1289 
 1290             if (ret < 0)    /* end of input */
 1291                 JUMPTO(pc->target_jmp); /* end block or Op_atexit */
 1292 
 1293             if (ret == 0) /* read a record */
 1294                 JUMPTO((pc + 1)->target_get_record);
 1295 
 1296             /* ret > 0 */
 1297             /* Save execution state for use in Op_after_beginfile or Op_after_endfile. */
 1298 
 1299             push_exec_state(pc, currule, source, stack_ptr);
 1300 
 1301             if (curfile == NULL)    /* EOF */
 1302                 JUMPTO(pc->target_endfile);
 1303             /* else
 1304                 execute beginfile block */
 1305         }
 1306             break;
 1307 
 1308         case Op_get_record:
 1309         {
 1310             int errcode = 0;
 1311 
 1312             ni = pc->target_newfile;
 1313             if (curfile == NULL) {
 1314                 /* from non-redirected getline, e.g.:
 1315                  *  {
 1316                  *      while (getline > 0) ;
 1317                  *  }
 1318                  */
 1319 
 1320                 ni = ni->target_jmp;    /* end_block or Op_atexit */
 1321                 JUMPTO(ni);
 1322             }
 1323 
 1324             if (! inrec(curfile, & errcode)) {
 1325                 if (errcode > 0) {
 1326                     update_ERRNO_int(errcode);
 1327                     if (do_traditional || ! pc->has_endfile)
 1328                         fatal(_("error reading input file `%s': %s"),
 1329                         curfile->public.name, strerror(errcode));
 1330                 }
 1331 
 1332                 JUMPTO(ni);
 1333             } /* else
 1334                 prog (rule) block */
 1335         }
 1336             break;
 1337 
 1338         case Op_K_nextfile:
 1339         {
 1340             int ret;
 1341 
 1342             if (currule != Rule && currule != BEGINFILE)
 1343                 fatal(_("`nextfile' cannot be called from a `%s' rule"),
 1344                     ruletab[currule]);
 1345 
 1346             ret = nextfile(& curfile, true);    /* skip current file */
 1347 
 1348             if (currule == BEGINFILE) {
 1349                 long stack_size = 0;
 1350 
 1351                 ni = pop_exec_state(& currule, & source, & stack_size);
 1352 
 1353                 assert(ni->opcode == Op_K_getline || ni->opcode == Op_newfile);
 1354 
 1355                 /* pop stack returning to the state of Op_K_getline or Op_newfile. */
 1356                 unwind_stack(stack_size);
 1357 
 1358                 if (ret == 0) {
 1359                     /* There was an error opening the file;
 1360                      * don't run ENDFILE block(s).
 1361                      */
 1362 
 1363                     JUMPTO(ni);
 1364                 } else {
 1365                     /* do run ENDFILE block(s) first. */
 1366 
 1367                     /* Execution state to return to in Op_after_endfile. */
 1368                     push_exec_state(ni, currule, source, stack_ptr);
 1369 
 1370                     JUMPTO(pc->target_endfile);
 1371                 }
 1372             } /* else
 1373                 Start over with the first rule. */
 1374 
 1375             /* empty the run-time stack to avoid memory leak */
 1376             pop_stack();
 1377 
 1378             /* Push an execution state for Op_after_endfile to return to */
 1379             push_exec_state(pc->target_newfile, currule, source, stack_ptr);
 1380 
 1381             JUMPTO(pc->target_endfile);
 1382         }
 1383             break;
 1384 
 1385         case Op_K_exit:
 1386             /* exit not allowed in user-defined comparison functions for "sorted_in";
 1387              * This is done so that END blocks aren't executed more than once.
 1388              */
 1389             if (! currule)
 1390                 fatal(_("`exit' cannot be called in the current context"));
 1391 
 1392             exiting = true;
 1393             if ((t1 = POP_NUMBER()) != Nnull_string) {
 1394                 exit_val = (int) get_number_si(t1);
 1395 #ifdef VMS
 1396                 if (exit_val == 0)
 1397                     exit_val = EXIT_SUCCESS;
 1398                 else if (exit_val == 1)
 1399                     exit_val = EXIT_FAILURE;
 1400                 /* else
 1401                     just pass anything else on through */
 1402 #endif
 1403             }
 1404             DEREF(t1);
 1405 
 1406             if (currule == BEGINFILE || currule == ENDFILE) {
 1407 
 1408                 /* Find the rule of the saved execution state (Op_K_getline/Op_newfile).
 1409                  * This is needed to prevent multiple execution of any END rules:
 1410                  *  gawk 'BEGINFILE { exit(1) } \
 1411                  *         END { while (getline > 0); }' in1 in2
 1412                  */
 1413 
 1414                 (void) pop_exec_state(& currule, & source, NULL);
 1415             }
 1416 
 1417             pop_stack();    /* empty stack, don't leak memory */
 1418 
 1419             /* Jump to either the first END block instruction
 1420              * or to Op_atexit.
 1421              */
 1422 
 1423             if (currule == END)
 1424                 ni = pc->target_atexit;
 1425             else
 1426                 ni = pc->target_end;
 1427             JUMPTO(ni);
 1428 
 1429         case Op_K_next:
 1430             if (currule != Rule)
 1431                 fatal(_("`next' cannot be called from a `%s' rule"), ruletab[currule]);
 1432 
 1433             pop_stack();
 1434             JUMPTO(pc->target_jmp); /* Op_get_record, read next record */
 1435 
 1436         case Op_pop:
 1437             r = POP_SCALAR();
 1438             DEREF(r);
 1439             break;
 1440 
 1441         case Op_line_range:
 1442             if (pc->triggered)      /* evaluate right expression */
 1443                 JUMPTO(pc->target_jmp);
 1444             /* else
 1445                 evaluate left expression */
 1446             break;
 1447 
 1448         case Op_cond_pair:
 1449         {
 1450             int result;
 1451             INSTRUCTION *ip;
 1452 
 1453             t1 = TOP_SCALAR();   /* from right hand side expression */
 1454             di = (eval_condition(t1) != 0);
 1455             DEREF(t1);
 1456 
 1457             ip = pc->line_range;            /* Op_line_range */
 1458 
 1459             if (! ip->triggered && di) {
 1460                 /* not already triggered and left expression is true */
 1461                 decr_sp();
 1462                 ip->triggered = true;
 1463                 JUMPTO(ip->target_jmp); /* evaluate right expression */
 1464             }
 1465 
 1466             result = ip->triggered || di;
 1467             ip->triggered ^= di;          /* update triggered flag */
 1468             r = node_Boolean[result];      /* final value of condition pair */
 1469             UPREF(r);
 1470             REPLACE(r);
 1471             JUMPTO(pc->target_jmp);
 1472         }
 1473 
 1474         case Op_exec_count:
 1475             if (do_profile)
 1476                 pc->exec_count++;
 1477             break;
 1478 
 1479         case Op_no_op:
 1480         case Op_K_do:
 1481         case Op_K_while:
 1482         case Op_K_for:
 1483         case Op_K_arrayfor:
 1484         case Op_K_switch:
 1485         case Op_K_default:
 1486         case Op_K_if:
 1487         case Op_K_else:
 1488         case Op_cond_exp:
 1489         case Op_comment:
 1490         case Op_parens:
 1491             break;
 1492 
 1493         default:
 1494             fatal(_("Sorry, don't know how to interpret `%s'"), opcode2str(op));
 1495         }
 1496 
 1497         JUMPTO(pc->nexti);
 1498 
 1499 /*  } forever */
 1500 
 1501     /* not reached */
 1502     return 0;
 1503 
 1504 #undef mk_sub
 1505 #undef JUMPTO
 1506 }