Main Page | Class List | Directories | File List | Class Members | File Members

eval.c File Reference

#include "awk.h"
#include "You lose. You will need a translation table for your character set."

Go to the source code of this file.

Classes

struct  loop_info
struct  fcall

Defines

#define INCREMENT(n)
#define PUSH_BINDING(stack, x, val)   (memcpy((char *)(stack), (const char *)(x), sizeof(jmp_buf)), val++)
#define RESTORE_BINDING(stack, x, val)   (memcpy((char *)(x), (const char *)(stack), sizeof(jmp_buf)), val--)
#define C(c)   ((char)c)
#define hakvar   forloop->init
#define arrvar   forloop->incr
#define NLOOPS   4

Functions

double pow P ((double x, double y))
const char * nodetype2str (NODETYPE type)
const char * flags2str (int flagval)
const char * genflags2str (int flagval, const struct flagtab *tab)
int interpret (register NODE *volatile tree)
NODEr_tree_eval (register NODE *tree, int iscond)
static int eval_condition (register NODE *tree)
int cmp_nodes (register NODE *t1, register NODE *t2)
static NODEop_assign (register NODE *tree)
static void pop_forloop ()
static void pop_all_forloops ()
static void push_forloop (const char *varname, NODE **elems, size_t nelems)
static void pop_fcall ()
static void pop_fcall_stack ()
static void push_args (int count, NODE *argp, NODE **oldstack, const char *func_name, char **varnames)
static NODEfunc_call (NODE *tree)
NODE ** r_get_lhs (register NODE *ptr, Func_ptr *assign, int reference)
static NODEmatch_op (register NODE *tree)
void set_IGNORECASE ()
void set_BINMODE ()
void set_OFS ()
void set_ORS ()
static int fmt_ok (NODE *n)
static int fmt_index (NODE *n)
void set_OFMT ()
void set_CONVFMT ()
void set_LINT ()
void set_TEXTDOMAIN ()
NODEassign_val (NODE **lhs_p, NODE *rhs)
void update_ERRNO ()
static int comp_func (const void *p1, const void *p2)

Variables

NODE_t
NODEret_node
int OFSlen
int ORSlen
int OFMTidx
int CONVFMTidx
static jmp_buf loop_tag
static int loop_tag_valid = FALSE
static int func_tag_valid = FALSE
static jmp_buf func_tag
int exiting
int exit_val
static const char *const nodetypes []
static struct loop_infoloop_stack
size_t nloops_active = 0
static struct fcallfcall_list
static long fcall_list_size = 0
static long curfcall = -1
NODE ** stack_ptr
NODE ** fmt_list = NULL


Define Documentation

#define arrvar   forloop->incr
 

#define C  )     ((char)c)
 

Definition at line 82 of file eval.c.

#define hakvar   forloop->init
 

#define INCREMENT n   ) 
 

Definition at line 61 of file eval.c.

#define NLOOPS   4
 

Referenced by push_forloop().

#define PUSH_BINDING stack,
x,
val   )     (memcpy((char *)(stack), (const char *)(x), sizeof(jmp_buf)), val++)
 

Definition at line 69 of file eval.c.

Referenced by func_call(), and interpret().

#define RESTORE_BINDING stack,
x,
val   )     (memcpy((char *)(x), (const char *)(stack), sizeof(jmp_buf)), val--)
 

Definition at line 70 of file eval.c.

Referenced by func_call(), and interpret().


Function Documentation

NODE* assign_val NODE **  lhs_p,
NODE rhs
 

Definition at line 2196 of file eval.c.

References dupnode, and unref().

Referenced by r_tree_eval(), and update_PROCINFO().

02197 {
02198         if (rhs != *lhs_p) {
02199                 /*
02200                  * Since we know that the nodes are different,
02201                  * we can do the unref() before the dupnode().
02202                  */
02203                 unref(*lhs_p);
02204                 *lhs_p = dupnode(rhs);
02205         }
02206         return *lhs_p;
02207 }

int cmp_nodes register NODE t1,
register NODE t2
 

Definition at line 1212 of file eval.c.

References force_number, force_string, IGNORECASE, MAYBE_NUM, memcmp(), memset(), and NUMBER.

Referenced by fmt_index(), interpret(), merge(), r_tree_eval(), and re_update().

01213 {
01214         register int ret;
01215         register size_t len1, len2;
01216         register int l;
01217         int ldiff;
01218 
01219         if (t1 == t2)
01220                 return 0;
01221         if (t1->flags & MAYBE_NUM)
01222                 (void) force_number(t1);
01223         if (t2->flags & MAYBE_NUM)
01224                 (void) force_number(t2);
01225         if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) {
01226                 if (t1->numbr == t2->numbr)
01227                         return 0;
01228                 /* don't subtract, in case one or both are infinite */
01229                 else if (t1->numbr < t2->numbr)
01230                         return -1;
01231                 else
01232                         return 1;
01233         }
01234         (void) force_string(t1);
01235         (void) force_string(t2);
01236         len1 = t1->stlen;
01237         len2 = t2->stlen;
01238         ldiff = len1 - len2;
01239         if (len1 == 0 || len2 == 0)
01240                 return ldiff;
01241         l = (ldiff <= 0 ? len1 : len2);
01242         if (IGNORECASE) {
01243                 const unsigned char *cp1 = (const unsigned char *) t1->stptr;
01244                 const unsigned char *cp2 = (const unsigned char *) t2->stptr;
01245 
01246 #ifdef MBS_SUPPORT
01247                 if (gawk_mb_cur_max > 1) {
01248                         mbstate_t mbs;
01249                         memset(&mbs, 0, sizeof(mbstate_t));
01250                         ret = strncasecmpmbs((const char *) cp1, mbs,
01251                                              (const char *) cp2, mbs, l);
01252                 } else
01253 #endif
01254                 for (ret = 0; l-- > 0 && ret == 0; cp1++, cp2++)
01255                         ret = casetable[*cp1] - casetable[*cp2];
01256         } else
01257                 ret = memcmp(t1->stptr, t2->stptr, l);
01258         return (ret == 0 ? ldiff : ret);
01259 }

static int comp_func const void *  p1,
const void *  p2
[static]
 

Definition at line 2225 of file eval.c.

References memcmp().

Referenced by interpret().

02226 {
02227         size_t len1, len2;
02228         const char *str1, *str2;
02229         const NODE *t1, *t2;
02230         int cmp1;
02231 
02232         t1 = *((const NODE *const *) p1);
02233         t2 = *((const NODE *const *) p2);
02234 
02235 /*
02236         t1 = force_string(t1);
02237         t2 = force_string(t2);
02238 */
02239         len1 = t1->ahname_len;
02240         str1 = t1->ahname_str;
02241 
02242         len2 = t2->ahname_len;
02243         str2 = t2->ahname_str;
02244 
02245         /* Array indexes are strings, compare as such, always! */
02246         cmp1 = memcmp(str1, str2, len1 < len2 ? len1 : len2);
02247         /* if prefixes are equal, size matters */
02248         return (cmp1 != 0 ? cmp1 :
02249                 len1 < len2 ? -1 : (len1 > len2));
02250 }

static int eval_condition register NODE tree  )  [static]
 

Definition at line 1160 of file eval.c.

References FALSE, exp_node::flags, force_number, free_temp, m_tree_eval, MAYBE_NUM, Node_line_range, NULL, NUMBER, and TRUE.

Referenced by eval_condition(), interpret(), pprint(), r_tree_eval(), and tree_eval().

01161 {
01162         register NODE *t1;
01163         register int ret;
01164 
01165         if (tree == NULL)       /* Null trees are the easiest kinds */
01166                 return TRUE;
01167         if (tree->type == Node_line_range) {
01168                 /*
01169                  * Node_line_range is kind of like Node_match, EXCEPT: the
01170                  * lnode field (more properly, the condpair field) is a node
01171                  * of a Node_cond_pair; whether we evaluate the lnode of that
01172                  * node or the rnode depends on the triggered word.  More
01173                  * precisely:  if we are not yet triggered, we tree_eval the
01174                  * lnode; if that returns true, we set the triggered word. 
01175                  * If we are triggered (not ELSE IF, note), we tree_eval the
01176                  * rnode, clear triggered if it succeeds, and perform our
01177                  * action (regardless of success or failure).  We want to be
01178                  * able to begin and end on a single input record, so this
01179                  * isn't an ELSE IF, as noted above.
01180                  */
01181                 if (! tree->triggered) {
01182                         if (! eval_condition(tree->condpair->lnode))
01183                                 return FALSE;
01184                         else
01185                                 tree->triggered = TRUE;
01186                 }
01187                 /* Else we are triggered */
01188                 if (eval_condition(tree->condpair->rnode))
01189                         tree->triggered = FALSE;
01190                 return TRUE;
01191         }
01192 
01193         /*
01194          * Could just be J.random expression. in which case, null and 0 are
01195          * false, anything else is true 
01196          */
01197 
01198         t1 = m_tree_eval(tree, TRUE);
01199         if (t1->flags & MAYBE_NUM)
01200                 (void) force_number(t1);
01201         if (t1->flags & NUMBER)
01202                 ret = (t1->numbr != 0.0);
01203         else
01204                 ret = (t1->stlen != 0);
01205         free_temp(t1);
01206         return ret;
01207 }

const char* flags2str int  flagval  ) 
 

Definition at line 273 of file eval.c.

References ARRAYMAXED, FIELD, FUNC, genflags2str(), INTLSTR, MALLOC, MAYBE_NUM, NULL, NUMBER, NUMCUR, PERM, STRCUR, STRING, and TEMP.

Referenced by valinfo().

00274 {
00275         static const struct flagtab values[] = {
00276                 { MALLOC, "MALLOC" },
00277                 { TEMP, "TEMP" },
00278                 { PERM, "PERM" },
00279                 { STRING, "STRING" },
00280                 { STRCUR, "STRCUR" },
00281                 { NUMCUR, "NUMCUR" },
00282                 { NUMBER, "NUMBER" },
00283                 { MAYBE_NUM, "MAYBE_NUM" },
00284                 { ARRAYMAXED, "ARRAYMAXED" },
00285                 { FUNC, "FUNC" },
00286                 { FIELD, "FIELD" },
00287                 { INTLSTR, "INTLSTR" },
00288                 { 0,    NULL },
00289         };
00290 
00291         return genflags2str(flagval, values);
00292 }

static int fmt_index NODE n  )  [static]
 

Definition at line 2075 of file eval.c.

References _, cmp_nodes(), CONVFMT_node, do_lint, dupnode, emalloc, erealloc, fmt_ok(), force_string, lintwarn, NULL, and OFMT_node.

Referenced by set_CONVFMT(), and set_OFMT().

02076 {
02077         register int ix = 0;
02078         static int fmt_num = 4;
02079         static int fmt_hiwater = 0;
02080 
02081         if (fmt_list == NULL)
02082                 emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index");
02083         (void) force_string(n);
02084         while (ix < fmt_hiwater) {
02085                 if (cmp_nodes(fmt_list[ix], n) == 0)
02086                         return ix;
02087                 ix++;
02088         }
02089         /* not found */
02090         n->stptr[n->stlen] = '\0';
02091         if (do_lint && ! fmt_ok(n))
02092                 lintwarn(_("bad `%sFMT' specification `%s'"),
02093                             n == CONVFMT_node->var_value ? "CONV"
02094                           : n == OFMT_node->var_value ? "O"
02095                           : "", n->stptr);
02096 
02097         if (fmt_hiwater >= fmt_num) {
02098                 fmt_num *= 2;
02099                 erealloc(fmt_list, NODE **, fmt_num * sizeof(*fmt_list), "fmt_index");
02100         }
02101         fmt_list[fmt_hiwater] = dupnode(n);
02102         return fmt_hiwater++;
02103 }

static int fmt_ok NODE n  )  [static]
 

Definition at line 2048 of file eval.c.

References force_string, ISDIGIT, NULL, and strchr().

Referenced by fmt_index().

02049 {
02050         NODE *tmp = force_string(n);
02051         const char *p = tmp->stptr;
02052 
02053         if (*p++ != '%')
02054                 return 0;
02055         while (*p && strchr(" +-#", *p) != NULL)        /* flags */
02056                 p++;
02057         while (*p && ISDIGIT(*p))       /* width - %*.*g is NOT allowed */
02058                 p++;
02059         if (*p == '\0' || (*p != '.' && ! ISDIGIT(*p)))
02060                 return 0;
02061         if (*p == '.')
02062                 p++;
02063         while (*p && ISDIGIT(*p))       /* precision */
02064                 p++;
02065         if (*p == '\0' || strchr("efgEG", *p) == NULL)
02066                 return 0;
02067         if (*++p != '\0')
02068                 return 0;
02069         return 1;
02070 }

static NODE* func_call NODE tree  )  [static]
 

Definition at line 1611 of file eval.c.

References _, FALSE, fatal, exp_node::flags, INCREMENT, interpret(), lookup(), name, Nnull_string, Node_func, NULL, PERM, pop_fcall(), push_args(), PUSH_BINDING, RESTORE_BINDING, TEMP, and exp_node::type.

Referenced by r_tree_eval().

01612 {
01613         register NODE *r;
01614         NODE *name, *arg_list;
01615         NODE *f;
01616         jmp_buf volatile func_tag_stack;
01617         jmp_buf volatile loop_tag_stack;
01618         int volatile save_loop_tag_valid = FALSE;
01619         NODE *save_ret_node;
01620         extern NODE *ret_node;
01621 
01622         /* tree->rnode is a Node_val giving function name */
01623         /* tree->lnode is Node_expression_list of calling args. */
01624         name = tree->rnode;
01625         arg_list = tree->lnode;
01626 
01627         /* retrieve function definition node */
01628         if (tree->funcbody != NULL)
01629                 f = tree->funcbody;
01630         else {
01631                 f = lookup(name->stptr);
01632                 if (f == NULL || f->type != Node_func)
01633                         fatal(_("function `%s' not defined"), name->stptr);
01634 
01635                 tree->funcbody = f;     /* save for next call */
01636         }
01637 
01638 #ifdef FUNC_TRACE
01639         fprintf(stderr, _("function %s called\n"), name->stptr);
01640 #endif
01641         push_args(f->lnode->param_cnt, arg_list, stack_ptr, name->stptr,
01642                         f->parmlist);
01643 
01644         /*
01645          * Execute function body, saving context, as a return statement
01646          * will longjmp back here.
01647          *
01648          * Have to save and restore the loop_tag stuff so that a return
01649          * inside a loop in a function body doesn't scrog any loops going
01650          * on in the main program.  We save the necessary info in variables
01651          * local to this function so that function nesting works OK.
01652          * We also only bother to save the loop stuff if we're in a loop
01653          * when the function is called.
01654          */
01655         if (loop_tag_valid) {
01656                 int junk = 0;
01657 
01658                 save_loop_tag_valid = (volatile int) loop_tag_valid;
01659                 PUSH_BINDING(loop_tag_stack, loop_tag, junk);
01660                 loop_tag_valid = FALSE;
01661         }
01662         PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid);
01663         save_ret_node = ret_node;
01664         ret_node = Nnull_string;        /* default return value */
01665         INCREMENT(f->exec_count);       /* count function calls */
01666         if (setjmp(func_tag) == 0)
01667                 (void) interpret(f->rnode);
01668 
01669         r = ret_node;
01670         ret_node = (NODE *) save_ret_node;
01671         RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid);
01672         pop_fcall();
01673 
01674         /* Restore the loop_tag stuff if necessary. */
01675         if (save_loop_tag_valid) {
01676                 int junk = 0;
01677 
01678                 loop_tag_valid = (int) save_loop_tag_valid;
01679                 RESTORE_BINDING(loop_tag_stack, loop_tag, junk);
01680         }
01681 
01682         if ((r->flags & PERM) == 0)
01683                 r->flags |= TEMP;
01684         return r;
01685 }

const char* genflags2str int  flagval,
const struct flagtab tab
 

Definition at line 297 of file eval.c.

References _, fatal, i, name, NULL, and flagtab::val.

Referenced by flags2str(), iopflags2str(), redflags2str(), and reflags2str().

00298 {
00299         static char buffer[BUFSIZ];
00300         char *sp;
00301         int i, space_left, space_needed;
00302 
00303         sp = buffer;
00304         space_left = BUFSIZ;
00305         for (i = 0; tab[i].name != NULL; i++) {
00306                 /*
00307                  * note the trick, we want 1 or 0 for whether we need
00308                  * the '|' character.
00309                  */
00310                 space_needed = (strlen(tab[i].name) + (sp != buffer));
00311                 if (space_left < space_needed)
00312                         fatal(_("buffer overflow in genflags2str"));
00313 
00314                 if ((flagval & tab[i].val) != 0) {
00315                         if (sp != buffer) {
00316                                 *sp++ = '|';
00317                                 space_left--;
00318                         }
00319                         strcpy(sp, tab[i].name);
00320                         /* note ordering! */
00321                         space_left -= strlen(sp);
00322                         sp += strlen(sp);
00323                 }
00324         }
00325 
00326         return buffer;
00327 }

int interpret register NODE *volatile  tree  ) 
 

Definition at line 335 of file eval.c.

References _, ahname_len, ahname_str, array_size, array_vname(), cant_happen, cmp_nodes(), comp_func(), do_delete(), do_delete_loop(), do_lint, do_nextfile(), do_posix, do_print(), do_print_rec(), do_printf(), do_traditional, dupnode, emalloc, eval_condition(), FALSE, fatal, force_number, force_string, free_temp, get_array, get_lhs, i, in_begin_rule, in_end_rule, INCREMENT, lintwarn, make_string, Node_K_arrayfor, Node_K_break, Node_K_continue, Node_K_default, Node_K_delete, Node_K_delete_loop, Node_K_do, Node_K_exit, Node_K_for, Node_K_if, Node_K_next, Node_K_nextfile, Node_K_print, Node_K_print_rec, Node_K_printf, Node_K_return, Node_K_switch, Node_K_while, Node_regex, Node_rule_list, Node_rule_node, Node_statement_list, Node_var, Node_var_new, NULL, pop_all_forloops(), pop_fcall_stack(), pop_forloop(), PUSH_BINDING, push_forloop(), re_update(), research(), RESTORE_BINDING, source, sourceline, TAG_BREAK, TAG_CONTINUE, TAG_RETURN, tree_eval, TRUE, exp_node::type, unref(), and whiny_users.

Referenced by do_input(), func_call(), and main().

00336 {
00337         jmp_buf volatile loop_tag_stack; /* shallow binding stack for loop_tag */
00338         static jmp_buf rule_tag; /* tag the rule currently being run, for NEXT
00339                                   * and EXIT statements.  It is static because
00340                                   * there are no nested rules */
00341         register NODE *volatile t = NULL;       /* temporary */
00342         NODE **volatile lhs;    /* lhs == Left Hand Side for assigns, etc */
00343         NODE *volatile stable_tree;
00344         int volatile traverse = TRUE;   /* True => loop thru tree (Node_rule_list) */
00345 
00346         /* avoid false source indications */
00347         source = NULL;
00348         sourceline = 0;
00349 
00350         if (tree == NULL)
00351                 return 1;
00352         sourceline = tree->source_line;
00353         source = tree->source_file;
00354         switch (tree->type) {
00355         case Node_rule_node:
00356                 traverse = FALSE;  /* False => one for-loop iteration only */
00357                 /* FALL THROUGH */
00358         case Node_rule_list:
00359                 for (t = tree; t != NULL; t = t->rnode) {
00360                         if (traverse)
00361                                 tree = t->lnode;
00362                         sourceline = tree->source_line;
00363                         source = tree->source_file;
00364                         INCREMENT(tree->exec_count);
00365                         switch (setjmp(rule_tag)) {
00366                         case 0: /* normal non-jump */
00367                                 /* test pattern, if any */
00368                                 if (tree->lnode == NULL ||
00369                                     eval_condition(tree->lnode)) {
00370                                         /* using the lnode exec_count is kludgey */
00371                                         if (tree->lnode != NULL)
00372                                                 INCREMENT(tree->lnode->exec_count);
00373                                         (void) interpret(tree->rnode);
00374                                 }
00375                                 break;
00376                         case TAG_CONTINUE:      /* NEXT statement */
00377                                 pop_all_forloops();
00378                                 pop_fcall_stack();
00379                                 return 1;
00380                         case TAG_BREAK:         /* EXIT statement */
00381                                 pop_all_forloops();
00382                                 pop_fcall_stack();
00383                                 return 0;
00384                         default:
00385                                 cant_happen();
00386                         }
00387                         if (! traverse)         /* case Node_rule_node */
00388                                 break;          /* don't loop */
00389                 }
00390                 break;
00391 
00392         case Node_statement_list:
00393                 for (t = tree; t != NULL; t = t->rnode)
00394                         (void) interpret(t->lnode);
00395                 break;
00396 
00397         case Node_K_if:
00398                 INCREMENT(tree->exec_count);
00399                 if (eval_condition(tree->lnode)) {
00400                         INCREMENT(tree->rnode->exec_count);
00401                         (void) interpret(tree->rnode->lnode);
00402                 } else {
00403                         (void) interpret(tree->rnode->rnode);
00404                 }
00405                 break;
00406 
00407         case Node_K_switch:
00408                 {
00409                 NODE *switch_value;
00410                 NODE *switch_body;
00411                 NODE *case_list;
00412                 NODE *default_list;
00413                 NODE *case_stmt;
00414 
00415                 int match_found = FALSE;
00416 
00417                 PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00418                 INCREMENT(tree->exec_count);
00419                 stable_tree = tree;
00420 
00421                 switch_value = tree_eval(stable_tree->lnode);
00422                 switch_body = stable_tree->rnode;
00423                 case_list = switch_body->lnode;
00424                 default_list  = switch_body->rnode;
00425 
00426                 for (; case_list != NULL; case_list = case_list->rnode) {
00427                         case_stmt = case_list->lnode;
00428 
00429                         /*
00430                          * Once a match is found, all cases will be processed as they fall through,
00431                          * so continue to execute statements until a break is reached.
00432                          */
00433                         if (! match_found) {
00434                                 if (case_stmt->type == Node_K_default)
00435                                         ;       /* do nothing */
00436                                 else if (case_stmt->lnode->type == Node_regex) {
00437                                         NODE *t1;
00438                                         Regexp *rp;
00439 
00440                                         t1 = force_string(switch_value);
00441                                         rp = re_update(case_stmt->lnode);
00442 
00443                                         match_found = (research(rp, t1->stptr, 0, t1->stlen, FALSE) >= 0);
00444                                         if (t1 != switch_value)
00445                                                 free_temp(t1);
00446                                 } else {
00447                                         match_found = (cmp_nodes(switch_value, case_stmt->lnode) == 0);
00448                                 }
00449                         }
00450 
00451                         /* If a match was found, execute the statements associated with the case. */
00452                         if (match_found) {
00453                                 INCREMENT(case_stmt->exec_count);
00454                                 switch (setjmp(loop_tag)) {
00455                                 case 0:                /* Normal non-jump    */
00456                                         (void) interpret(case_stmt->rnode);
00457                                         break;
00458                                 case TAG_CONTINUE:     /* continue statement */
00459                                         free_temp(switch_value);
00460                                         RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00461                                         longjmp(loop_tag, TAG_CONTINUE);
00462                                         break;
00463                                 case TAG_BREAK:        /* break statement    */
00464                                         free_temp(switch_value);
00465                                         RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00466                                         return 1;
00467                                 default:
00468                                         cant_happen();
00469                                 }
00470                         }
00471 
00472                 }
00473 
00474                 free_temp(switch_value);
00475 
00476                 /*
00477                  * If a default section was found, execute the statements associated with it
00478                  * and execute any trailing case statements if the default falls through.
00479                  */
00480                 if (! match_found && default_list != NULL) {
00481                         for (case_list = default_list;
00482                                         case_list != NULL; case_list = case_list->rnode) {
00483                                 case_stmt = case_list->lnode;
00484 
00485                                 INCREMENT(case_stmt->exec_count);
00486                                 switch (setjmp(loop_tag)) {
00487                                 case 0:                /* Normal non-jump    */
00488                                         (void) interpret(case_stmt->rnode);
00489                                         break;
00490                                 case TAG_CONTINUE:     /* continue statement */
00491                                         RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00492                                         longjmp(loop_tag, TAG_CONTINUE);
00493                                         break;
00494                                 case TAG_BREAK:        /* break statement    */
00495                                         RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00496                                         return 1;
00497                                 default:
00498                                         cant_happen();
00499                                 }
00500                         }
00501                 }
00502 
00503                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00504                 }
00505                 break;
00506 
00507         case Node_K_while:
00508                 PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00509 
00510                 stable_tree = tree;
00511                 while (eval_condition(stable_tree->lnode)) {
00512                         INCREMENT(stable_tree->exec_count);
00513                         switch (setjmp(loop_tag)) {
00514                         case 0: /* normal non-jump */
00515                                 (void) interpret(stable_tree->rnode);
00516                                 break;
00517                         case TAG_CONTINUE:      /* continue statement */
00518                                 break;
00519                         case TAG_BREAK: /* break statement */
00520                                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00521                                 return 1;
00522                         default:
00523                                 cant_happen();
00524                         }
00525                 }
00526                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00527                 break;
00528 
00529         case Node_K_do:
00530                 PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00531                 stable_tree = tree;
00532                 do {
00533                         INCREMENT(stable_tree->exec_count);
00534                         switch (setjmp(loop_tag)) {
00535                         case 0: /* normal non-jump */
00536                                 (void) interpret(stable_tree->rnode);
00537                                 break;
00538                         case TAG_CONTINUE:      /* continue statement */
00539                                 break;
00540                         case TAG_BREAK: /* break statement */
00541                                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00542                                 return 1;
00543                         default:
00544                                 cant_happen();
00545                         }
00546                 } while (eval_condition(stable_tree->lnode));
00547                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00548                 break;
00549 
00550         case Node_K_for:
00551                 PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00552                 (void) interpret(tree->forloop->init);
00553                 stable_tree = tree;
00554                 while (eval_condition(stable_tree->forloop->cond)) {
00555                         INCREMENT(stable_tree->exec_count);
00556                         switch (setjmp(loop_tag)) {
00557                         case 0: /* normal non-jump */
00558                                 (void) interpret(stable_tree->lnode);
00559                                 /* fall through */
00560                         case TAG_CONTINUE:      /* continue statement */
00561                                 (void) interpret(stable_tree->forloop->incr);
00562                                 break;
00563                         case TAG_BREAK: /* break statement */
00564                                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00565                                 return 1;
00566                         default:
00567                                 cant_happen();
00568                         }
00569                 }
00570                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00571                 break;
00572 
00573         case Node_K_arrayfor:
00574                 {
00575                 Func_ptr after_assign = NULL;
00576                 NODE **list = NULL;
00577                 NODE *volatile array;
00578                 NODE *volatile save_array;
00579                 volatile size_t i, num_elems;
00580                 size_t j;
00581                 volatile int retval = 0;
00582                 int sort_indices = whiny_users;
00583 
00584 #define hakvar forloop->init
00585 #define arrvar forloop->incr
00586                 /* get the array */
00587                 save_array = tree->arrvar;
00588                 array = get_array(save_array);
00589 
00590                 /* sanity: do nothing if empty */
00591                 if (array->var_array == NULL || array->table_size == 0)
00592                         break;  /* from switch */
00593 
00594                 /* allocate space for array */
00595                 num_elems = array->table_size;
00596                 emalloc(list, NODE **, num_elems * sizeof(NODE *), "for_loop");
00597 
00598                 /* populate it */
00599                 for (i = j = 0; i < array->array_size; i++) {
00600                         NODE *t = array->var_array[i];
00601 
00602                         if (t == NULL)
00603                                 continue;
00604 
00605                         for (; t != NULL; t = t->ahnext) {
00606                                 list[j++] = dupnode(t);
00607                                 assert(list[j-1] == t);
00608                         }
00609                 }
00610 
00611 
00612                 if (sort_indices)
00613                         qsort(list, num_elems, sizeof(NODE *), comp_func); /* shazzam! */
00614 
00615                 /* now we can run the loop */
00616                 push_forloop(array->vname, list, num_elems);
00617                 PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00618 
00619                 lhs = get_lhs(tree->hakvar, &after_assign, FALSE);
00620                 stable_tree = tree;
00621                 for (i = 0; i < num_elems; i++) {
00622                         INCREMENT(stable_tree->exec_count);
00623                         unref(*((NODE **) lhs));
00624                         *lhs = make_string(list[i]->ahname_str, list[i]->ahname_len);
00625                         if (after_assign)
00626                                 (*after_assign)();
00627                         switch (setjmp(loop_tag)) {
00628                         case 0:
00629                                 (void) interpret(stable_tree->lnode);
00630                         case TAG_CONTINUE:
00631                                 break;
00632 
00633                         case TAG_BREAK:
00634                                 retval = 1;
00635                                 goto done;
00636 
00637                         default:
00638                                 cant_happen();
00639                         }
00640                 }
00641 
00642         done:
00643                 RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
00644                 pop_forloop();
00645 
00646                 if (do_lint && num_elems != array->table_size)
00647                         lintwarn(_("for loop: array `%s' changed size from %ld to %ld during loop execution"),
00648                                 array_vname(save_array), (long) num_elems, (long) array->table_size);
00649                 
00650                 if (retval == 1)
00651                         return 1;
00652                 break;
00653                 }
00654 #undef hakvar
00655 #undef arrvar
00656 
00657         case Node_K_break:
00658                 INCREMENT(tree->exec_count);
00659                 if (! loop_tag_valid) {
00660                         /*
00661                          * Old AT&T nawk treats break outside of loops like
00662                          * next. New ones catch it at parse time. Allow it if
00663                          * do_traditional is on, and complain if lint.
00664                          */
00665                         static int warned = FALSE;
00666 
00667                         if (do_lint && ! warned) {
00668                                 lintwarn(_("`break' outside a loop is not portable"));
00669                                 warned = TRUE;
00670                         }
00671                         if (! do_traditional || do_posix)
00672                                 fatal(_("`break' outside a loop is not allowed"));
00673                         longjmp(rule_tag, TAG_CONTINUE);
00674                 } else
00675                         longjmp(loop_tag, TAG_BREAK);
00676                 break;
00677 
00678         case Node_K_continue:
00679                 INCREMENT(tree->exec_count);
00680                 if (! loop_tag_valid) {
00681                         /*
00682                          * Old AT&T nawk treats continue outside of loops like
00683                          * next. New ones catch it at parse time. Allow it if
00684                          * do_traditional is on, and complain if lint.
00685                          */
00686                         static int warned = FALSE;
00687 
00688                         if (do_lint && ! warned) {
00689                                 lintwarn(_("`continue' outside a loop is not portable"));
00690                                 warned = TRUE;
00691                         }
00692                         if (! do_traditional || do_posix)
00693                                 fatal(_("`continue' outside a loop is not allowed"));
00694                         longjmp(rule_tag, TAG_CONTINUE);
00695                 } else
00696                         longjmp(loop_tag, TAG_CONTINUE);
00697                 break;
00698 
00699         case Node_K_print:
00700                 INCREMENT(tree->exec_count);
00701                 do_print(tree);
00702                 break;
00703 
00704         case Node_K_print_rec:
00705                 INCREMENT(tree->exec_count);
00706                 do_print_rec(tree);
00707                 break;
00708 
00709         case Node_K_printf:
00710                 INCREMENT(tree->exec_count);
00711                 do_printf(tree);
00712                 break;
00713 
00714         case Node_K_delete:
00715                 INCREMENT(tree->exec_count);
00716                 do_delete(tree->lnode, tree->rnode);
00717                 break;
00718 
00719         case Node_K_delete_loop:
00720                 INCREMENT(tree->exec_count);
00721                 do_delete_loop(tree->lnode, tree->rnode);
00722                 break;
00723 
00724         case Node_K_next:
00725                 INCREMENT(tree->exec_count);
00726                 if (in_begin_rule)
00727                         fatal(_("`next' cannot be called from a BEGIN rule"));
00728                 else if (in_end_rule)
00729                         fatal(_("`next' cannot be called from an END rule"));
00730 
00731                 /* could add a lint check here for in a loop or function */
00732                 longjmp(rule_tag, TAG_CONTINUE);
00733                 break;
00734 
00735         case Node_K_nextfile:
00736                 INCREMENT(tree->exec_count);
00737                 if (in_begin_rule)
00738                         fatal(_("`nextfile' cannot be called from a BEGIN rule"));
00739                 else if (in_end_rule)
00740                         fatal(_("`nextfile' cannot be called from an END rule"));
00741 
00742                 /* could add a lint check here for in a loop or function */
00743                 /*
00744                  * Have to do this cleanup here, since we don't longjump
00745                  * back to the main awk rule loop (rule_tag).
00746                  */
00747                 pop_all_forloops();
00748                 pop_fcall_stack();
00749 
00750                 do_nextfile();
00751                 break;
00752 
00753         case Node_K_exit:
00754                 INCREMENT(tree->exec_count);
00755                 /*
00756                  * In A,K,&W, p. 49, it says that an exit statement "...
00757                  * causes the program to behave as if the end of input had
00758                  * occurred; no more input is read, and the END actions, if
00759                  * any are executed." This implies that the rest of the rules
00760                  * are not done. So we immediately break out of the main loop.
00761                  */
00762                 exiting = TRUE;
00763                 if (tree->lnode != NULL) {
00764                         t = tree_eval(tree->lnode);
00765                         exit_val = (int) force_number(t);
00766                         free_temp(t);
00767                 }
00768                 longjmp(rule_tag, TAG_BREAK);
00769                 break;
00770 
00771         case Node_K_return:
00772                 INCREMENT(tree->exec_count);
00773                 t = tree_eval(tree->lnode);
00774                 ret_node = dupnode(t);
00775                 free_temp(t);
00776                 longjmp(func_tag, TAG_RETURN);
00777                 break;
00778 
00779         default:
00780                 /*
00781                  * Appears to be an expression statement.  Throw away the
00782                  * value. 
00783                  */
00784                 if (do_lint && (tree->type == Node_var || tree->type ==