diff options
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 816 |
1 files changed, 430 insertions, 386 deletions
@@ -3,7 +3,7 @@ */ /* - * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc. + * Copyright (C) 1986, 1988, 1989, 1991 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Progamming Language. @@ -25,33 +25,23 @@ #include "awk.h" -extern void do_print(); -extern void do_printf(); -extern NODE *do_match(); -extern NODE *do_sub(); -extern NODE *do_getline(); -extern NODE *concat_exp(); -extern int in_array(); -extern void do_delete(); -extern double pow(); - -static int eval_condition(); -static NODE *op_assign(); -static NODE *func_call(); -static NODE *match_op(); +extern double pow P((double x, double y)); +extern double modf P((double x, double *yp)); + +static int eval_condition P((NODE *tree)); +static NODE *op_assign P((NODE *tree)); +static NODE *func_call P((NODE *name, NODE *arg_list)); +static NODE *match_op P((NODE *tree)); NODE *_t; /* used as a temporary in macros */ #ifdef MSDOS double _msc51bug; /* to get around a bug in MSC 5.1 */ #endif NODE *ret_node; - -/* More of that debugging stuff */ -#ifdef DEBUG -#define DBG_P(X) print_debug X -#else -#define DBG_P(X) -#endif +int OFSlen; +int ORSlen; +int OFMTidx; +int CONVFMTidx; /* Macros and variables to save and restore function and loop bindings */ /* @@ -135,7 +125,7 @@ char casetable[] = { */ int interpret(tree) -NODE *tree; +register NODE *tree; { volatile jmp_buf loop_tag_stack; /* shallow binding stack for loop_tag */ static jmp_buf rule_tag;/* tag the rule currently being run, for NEXT @@ -143,53 +133,29 @@ NODE *tree; * there are no nested rules */ register NODE *t = NULL;/* temporary */ volatile NODE **lhs; /* lhs == Left Hand Side for assigns, etc */ - volatile struct search *l; /* For array_for */ volatile NODE *stable_tree; + int traverse = 1; /* True => loop thru tree (Node_rule_list) */ if (tree == NULL) return 1; sourceline = tree->source_line; source = tree->source_file; switch (tree->type) { + case Node_rule_node: + traverse = 0; /* False => one for-loop iteration only */ + /* FALL THROUGH */ case Node_rule_list: for (t = tree; t != NULL; t = t->rnode) { - tree = t->lnode; - /* FALL THROUGH */ - case Node_rule_node: + if (traverse) + tree = t->lnode; sourceline = tree->source_line; source = tree->source_file; switch (setjmp(rule_tag)) { case 0: /* normal non-jump */ /* test pattern, if any */ - if (tree->lnode == NULL - || eval_condition(tree->lnode)) { - DBG_P(("Found a rule", tree->rnode)); - if (tree->rnode == NULL) { - /* - * special case: pattern with - * no action is equivalent to - * an action of {print} - */ - NODE printnode; - - printnode.type = Node_K_print; - printnode.lnode = NULL; - printnode.rnode = NULL; - do_print(&printnode); - } else if (tree->rnode->type == Node_illegal) { - /* - * An empty statement - * (``{ }'') is different - * from a missing statement. - * A missing statement is - * equal to ``{ print }'' as - * above, but an empty - * statement is as in C, do - * nothing. - */ - } else - (void) interpret(tree->rnode); - } + if (tree->lnode == NULL || + eval_condition(tree->lnode)) + (void) interpret(tree->rnode); break; case TAG_CONTINUE: /* NEXT statement */ return 1; @@ -198,25 +164,20 @@ NODE *tree; default: cant_happen(); } - if (t == NULL) - break; + if (!traverse) /* case Node_rule_node */ + break; /* don't loop */ } break; case Node_statement_list: - for (t = tree; t != NULL; t = t->rnode) { - DBG_P(("Statements", t->lnode)); + for (t = tree; t != NULL; t = t->rnode) (void) interpret(t->lnode); - } break; case Node_K_if: - DBG_P(("IF", tree->lnode)); if (eval_condition(tree->lnode)) { - DBG_P(("True", tree->rnode->lnode)); (void) interpret(tree->rnode->lnode); } else { - DBG_P(("False", tree->rnode->rnode)); (void) interpret(tree->rnode->rnode); } break; @@ -224,12 +185,10 @@ NODE *tree; case Node_K_while: PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); - DBG_P(("WHILE", tree->lnode)); stable_tree = tree; while (eval_condition(stable_tree->lnode)) { switch (setjmp(loop_tag)) { case 0: /* normal non-jump */ - DBG_P(("DO", stable_tree->rnode)); (void) interpret(stable_tree->rnode); break; case TAG_CONTINUE: /* continue statement */ @@ -250,7 +209,6 @@ NODE *tree; do { switch (setjmp(loop_tag)) { case 0: /* normal non-jump */ - DBG_P(("DO", stable_tree->rnode)); (void) interpret(stable_tree->rnode); break; case TAG_CONTINUE: /* continue statement */ @@ -261,25 +219,20 @@ NODE *tree; default: cant_happen(); } - DBG_P(("WHILE", stable_tree->lnode)); } while (eval_condition(stable_tree->lnode)); RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); break; case Node_K_for: PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); - DBG_P(("FOR", tree->forloop->init)); (void) interpret(tree->forloop->init); - DBG_P(("FOR.WHILE", tree->forloop->cond)); stable_tree = tree; while (eval_condition(stable_tree->forloop->cond)) { switch (setjmp(loop_tag)) { case 0: /* normal non-jump */ - DBG_P(("FOR.DO", stable_tree->lnode)); (void) interpret(stable_tree->lnode); /* fall through */ case TAG_CONTINUE: /* continue statement */ - DBG_P(("FOR.INCR", stable_tree->forloop->incr)); (void) interpret(stable_tree->forloop->incr); break; case TAG_BREAK: /* break statement */ @@ -293,68 +246,67 @@ NODE *tree; break; case Node_K_arrayfor: + { + volatile struct search l; /* For array_for */ + Func_ptr after_assign = NULL; + #define hakvar forloop->init #define arrvar forloop->incr PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); - DBG_P(("AFOR.VAR", tree->hakvar)); - lhs = (volatile NODE **) get_lhs(tree->hakvar, 1); + lhs = (volatile NODE **) get_lhs(tree->hakvar, &after_assign); t = tree->arrvar; if (t->type == Node_param_list) t = stack_ptr[t->param_cnt]; stable_tree = tree; - for (l = assoc_scan(t); l; l = assoc_next((struct search *)l)) { - deref = *((NODE **) lhs); - do_deref(); - *lhs = dupnode(l->retval); - if (field_num == 0) - set_record(fields_arr[0]->stptr, - fields_arr[0]->stlen); - DBG_P(("AFOR.NEXTIS", *lhs)); + for (assoc_scan(t, (struct search *)&l); + l.retval; + assoc_next((struct search *)&l)) { + unref(*((NODE **) lhs)); + *lhs = dupnode(l.retval); + if (after_assign) + (*after_assign)(); switch (setjmp(loop_tag)) { case 0: - DBG_P(("AFOR.DO", stable_tree->lnode)); (void) interpret(stable_tree->lnode); case TAG_CONTINUE: break; case TAG_BREAK: RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); - field_num = -1; return 1; default: cant_happen(); } } - field_num = -1; RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid); break; + } case Node_K_break: - DBG_P(("BREAK", NULL)); if (loop_tag_valid == 0) fatal("unexpected break"); longjmp(loop_tag, TAG_BREAK); break; case Node_K_continue: - DBG_P(("CONTINUE", NULL)); if (loop_tag_valid == 0) fatal("unexpected continue"); longjmp(loop_tag, TAG_CONTINUE); break; case Node_K_print: - DBG_P(("PRINT", tree)); do_print(tree); break; case Node_K_printf: - DBG_P(("PRINTF", tree)); do_printf(tree); break; + case Node_K_delete: + do_delete(tree->lnode, tree->rnode); + break; + case Node_K_next: - DBG_P(("NEXT", NULL)); longjmp(rule_tag, TAG_CONTINUE); break; @@ -366,7 +318,6 @@ NODE *tree; * any are executed." This implies that the rest of the rules * are not done. So we immediately break out of the main loop. */ - DBG_P(("EXIT", NULL)); exiting = 1; if (tree) { t = tree_eval(tree->lnode); @@ -377,7 +328,6 @@ NODE *tree; break; case Node_K_return: - DBG_P(("RETURN", NULL)); t = tree_eval(tree->lnode); ret_node = dupnode(t); free_temp(t); @@ -389,7 +339,6 @@ NODE *tree; * Appears to be an expression statement. Throw away the * value. */ - DBG_P(("E", NULL)); t = tree_eval(tree); free_temp(t); break; @@ -397,92 +346,91 @@ NODE *tree; return 1; } -/* evaluate a subtree, allocating strings on a temporary stack. */ +/* evaluate a subtree */ NODE * r_tree_eval(tree) -NODE *tree; +register NODE *tree; { register NODE *r, *t1, *t2; /* return value & temporary subtrees */ - int i; register NODE **lhs; - int di; - AWKNUM x, x2; + register int di; + AWKNUM x, x1, x2; long lx; - extern NODE **fields_arr; +#ifdef CRAY + long lx2; +#endif - source = tree->source_file; - sourceline = tree->source_line; +#ifdef DEBUG + if (tree == NULL) + return Nnull_string; + if (tree->type == Node_val) { + if (tree->stref <= 0) cant_happen(); + return tree; + } + if (tree->type == Node_var) { + if (tree->var_value->stref <= 0) cant_happen(); + return tree->var_value; + } + if (tree->type == Node_param_list) + return (stack_ptr[(_t)->param_cnt])->var_value; +#endif switch (tree->type) { case Node_and: - DBG_P(("AND", tree)); return tmp_number((AWKNUM) (eval_condition(tree->lnode) && eval_condition(tree->rnode))); case Node_or: - DBG_P(("OR", tree)); return tmp_number((AWKNUM) (eval_condition(tree->lnode) || eval_condition(tree->rnode))); case Node_not: - DBG_P(("NOT", tree)); return tmp_number((AWKNUM) ! eval_condition(tree->lnode)); /* Builtins */ case Node_builtin: - DBG_P(("builtin", tree)); return ((*tree->proc) (tree->subnode)); case Node_K_getline: - DBG_P(("GETLINE", tree)); return (do_getline(tree)); case Node_in_array: - DBG_P(("IN_ARRAY", tree)); return tmp_number((AWKNUM) in_array(tree->lnode, tree->rnode)); case Node_func_call: - DBG_P(("func_call", tree)); return func_call(tree->rnode, tree->lnode); - case Node_K_delete: - DBG_P(("DELETE", tree)); - do_delete(tree->lnode, tree->rnode); - return Nnull_string; - /* unary operations */ - - case Node_var: - case Node_var_array: - case Node_param_list: - case Node_subscript: + case Node_NR: + case Node_FNR: + case Node_NF: + case Node_FIELDWIDTHS: + case Node_FS: + case Node_RS: case Node_field_spec: - DBG_P(("var_type ref", tree)); - lhs = get_lhs(tree, 0); - field_num = -1; - deref = 0; + case Node_subscript: + case Node_IGNORECASE: + case Node_OFS: + case Node_ORS: + case Node_OFMT: + case Node_CONVFMT: + lhs = get_lhs(tree, (Func_ptr *)0); return *lhs; case Node_unary_minus: - DBG_P(("UMINUS", tree)); t1 = tree_eval(tree->subnode); x = -force_number(t1); free_temp(t1); return tmp_number(x); case Node_cond_exp: - DBG_P(("?:", tree)); - if (eval_condition(tree->lnode)) { - DBG_P(("True", tree->rnode->lnode)); + if (eval_condition(tree->lnode)) return tree_eval(tree->rnode->lnode); - } - DBG_P(("False", tree->rnode->rnode)); return tree_eval(tree->rnode->rnode); case Node_match: case Node_nomatch: case Node_regex: - DBG_P(("[no]match_op", tree)); return match_op(tree); case Node_func: @@ -490,18 +438,55 @@ NODE *tree; tree->lnode->param, "or used in other expression context"); - /* assignments */ + /* assignments */ case Node_assign: - DBG_P(("ASSIGN", tree)); + { + Func_ptr after_assign = NULL; + r = tree_eval(tree->rnode); - lhs = get_lhs(tree->lnode, 1); + lhs = get_lhs(tree->lnode, &after_assign); + unref(*lhs); *lhs = dupnode(r); free_temp(r); - do_deref(); - if (field_num == 0) - set_record(fields_arr[0]->stptr, fields_arr[0]->stlen); - field_num = -1; + if (after_assign) + (*after_assign)(); return *lhs; + } + + case Node_concat: + { +#define STACKSIZE 10 + NODE *stack[STACKSIZE]; + register NODE **sp; + register int len; + char *str; + register char *dest; + + sp = stack; + len = 0; + while (tree->type == Node_concat) { + *sp = force_string(tree_eval(tree->lnode)); + tree = tree->rnode; + len += (*sp)->stlen; + if (++sp == &stack[STACKSIZE-2]) /* one more and NULL */ + break; + } + *sp = force_string(tree_eval(tree)); + len += (*sp)->stlen; + *++sp = NULL; + emalloc(str, char *, len+2, "tree_eval"); + dest = str; + sp = stack; + while (*sp) { + memcpy(dest, (*sp)->stptr, (*sp)->stlen); + dest += (*sp)->stlen; + free_temp(*sp); + sp++; + } + r = make_str_node(str, len, ALREADY_MALLOCED); + r->flags |= TEMP; + } + return r; /* other assignment types are easier because they are numeric */ case Node_preincrement: @@ -524,22 +509,6 @@ NODE *tree; t2 = tree_eval(tree->rnode); switch (tree->type) { - case Node_concat: - DBG_P(("CONCAT", tree)); - t1 = force_string(t1); - t2 = force_string(t2); - - r = newnode(Node_val); - r->flags |= (STR|TEMP); - r->stlen = t1->stlen + t2->stlen; - r->stref = 1; - emalloc(r->stptr, char *, r->stlen + 1, "tree_eval"); - memcpy(r->stptr, t1->stptr, t1->stlen); - memcpy(r->stptr + t1->stlen, t2->stptr, t2->stlen + 1); - free_temp(t1); - free_temp(t2); - return r; - case Node_geq: case Node_leq: case Node_greater: @@ -551,22 +520,16 @@ NODE *tree; free_temp(t2); switch (tree->type) { case Node_equal: - DBG_P(("EQUAL", tree)); return tmp_number((AWKNUM) (di == 0)); case Node_notequal: - DBG_P(("NOT_EQUAL", tree)); return tmp_number((AWKNUM) (di != 0)); case Node_less: - DBG_P(("LESS_THAN", tree)); return tmp_number((AWKNUM) (di < 0)); case Node_greater: - DBG_P(("GREATER_THAN", tree)); return tmp_number((AWKNUM) (di > 0)); case Node_leq: - DBG_P(("LESS_THAN_EQUAL", tree)); return tmp_number((AWKNUM) (di <= 0)); case Node_geq: - DBG_P(("GREATER_THAN_EQUAL", tree)); return tmp_number((AWKNUM) (di >= 0)); default: cant_happen(); @@ -576,74 +539,57 @@ NODE *tree; break; /* handled below */ } - (void) force_number(t1); - (void) force_number(t2); - + x1 = force_number(t1); + free_temp(t1); + x2 = force_number(t2); + free_temp(t2); switch (tree->type) { case Node_exp: - DBG_P(("EXPONENT", tree)); - if ((lx = t2->numbr) == t2->numbr) { /* integer exponent */ + if ((lx = x2) == x2) { /* integer exponent */ if (lx == 0) x = 1; else if (lx == 1) - x = t1->numbr; + x = x1; else { /* doing it this way should be more precise */ - for (x = x2 = t1->numbr; --lx; ) - x *= x2; + for (x = x1; --lx; ) + x *= x1; } } else - x = pow((double) t1->numbr, (double) t2->numbr); - free_temp(t1); - free_temp(t2); + x = pow((double) x1, (double) x2); return tmp_number(x); case Node_times: - DBG_P(("MULT", tree)); - x = t1->numbr * t2->numbr; - free_temp(t1); - free_temp(t2); - return tmp_number(x); + return tmp_number(x1 * x2); case Node_quotient: - DBG_P(("DIVIDE", tree)); - x = t2->numbr; - free_temp(t2); - if (x == (AWKNUM) 0) + if (x2 == 0) fatal("division by zero attempted"); - /* NOTREACHED */ - else { - x = t1->numbr / x; - free_temp(t1); - return tmp_number(x); - } +#ifdef _CRAY + /* + * special case for integer division, put in for Cray + */ + lx2 = x2; + if (lx2 == 0) + return tmp_number(x1 / x2); + lx = (long) x1 / lx2; + if (lx * x2 == x1) + return tmp_number((AWKNUM) lx); + else +#endif + return tmp_number(x1 / x2); case Node_mod: - DBG_P(("MODULUS", tree)); - x = t2->numbr; - free_temp(t2); - if (x == (AWKNUM) 0) + if (x2 == 0) fatal("division by zero attempted in mod"); - /* NOTREACHED */ - lx = t1->numbr / x; /* assignment to long truncates */ - x2 = lx * x; - x = t1->numbr - x2; - free_temp(t1); - return tmp_number(x); + (void) modf(x1 / x2, &x); + return tmp_number(x1 - x * x2); case Node_plus: - DBG_P(("PLUS", tree)); - x = t1->numbr + t2->numbr; - free_temp(t1); - free_temp(t2); - return tmp_number(x); + return tmp_number(x1 + x2); case Node_minus: - DBG_P(("MINUS", tree)); - x = t1->numbr - t2->numbr; - free_temp(t1); - free_temp(t2); - return tmp_number(x); + return tmp_number(x1 - x2); default: fatal("illegal type (%d) in tree_eval", tree->type); @@ -651,48 +597,13 @@ NODE *tree; return 0; } -/* - * This makes numeric operations slightly more efficient. Just change the - * value of a numeric node, if possible - */ -void -assign_number(ptr, value) -NODE **ptr; -AWKNUM value; -{ - extern NODE *deref; - register NODE *n = *ptr; - -#ifdef DEBUG - if (n->type != Node_val) - cant_happen(); -#endif - if (n == Nnull_string) { - *ptr = make_number(value); - deref = 0; - return; - } - if (n->stref > 1) { - *ptr = make_number(value); - return; - } - if ((n->flags & STR) && (n->flags & (MALLOC|TEMP))) - free(n->stptr); - n->numbr = value; - n->flags |= (NUM|NUMERIC); - n->flags &= ~STR; - n->stref = 0; - deref = 0; -} - - /* Is TREE true or false? Returns 0==false, non-zero==true */ static int eval_condition(tree) -NODE *tree; +register NODE *tree; { register NODE *t1; - int ret; + register int ret; if (tree == NULL) /* Null trees are the easiest kinds */ return 1; @@ -727,6 +638,8 @@ NODE *tree; */ t1 = tree_eval(tree); + if (t1->flags & MAYBE_NUM) + (void) force_number(t1); if (t1->flags & NUMERIC) ret = t1->numbr != 0.0; else @@ -735,79 +648,84 @@ NODE *tree; return ret; } +/* + * compare two nodes, returning negative, 0, positive + */ int cmp_nodes(t1, t2) -NODE *t1, *t2; +register NODE *t1, *t2; { - AWKNUM d; - AWKNUM d1; - AWKNUM d2; - int ret; - int len1, len2; + AWKNUM diff; + register int ret; + register int len1, len2; + int donum; if (t1 == t2) return 0; - d1 = force_number(t1); - d2 = force_number(t2); + if (t1->flags & MAYBE_NUM) + (void) force_number(t1); + if (t2->flags & MAYBE_NUM) + (void) force_number(t2); +#ifdef maybe if ((t1->flags & NUMERIC) && (t2->flags & NUMERIC)) { - d = d1 - d2; - if (d == 0.0) /* from profiling, this is most common */ - return 0; - if (d > 0.0) - return 1; - return -1; +#else + donum = 0; + if ((t1->flags & NUMBER)) { + (void) force_number(t2); + if (t2->flags & NUMERIC) + donum = 1; + } else if ((t2->flags & NUMBER)) { + (void) force_number(t1); + if (t1->flags & NUMERIC) + donum = 1; + } + if (donum) { +#endif + diff = t1->numbr - t2->numbr; + if (diff == 0) return 0; + else if (diff < 0) return -1; + else return 1; } - t1 = force_string(t1); - t2 = force_string(t2); + (void) force_string(t1); + (void) force_string(t2); len1 = t1->stlen; len2 = t2->stlen; - if (len1 == 0) { - if (len2 == 0) - return 0; - else - return -1; - } else if (len2 == 0) - return 1; + if (len1 == 0 || len2 == 0) + return len1 - len2; ret = memcmp(t1->stptr, t2->stptr, len1 <= len2 ? len1 : len2); - if (ret == 0 && len1 != len2) - return len1 < len2 ? -1: 1; - return ret; + return ret == 0 ? len1-len2 : ret; } static NODE * op_assign(tree) -NODE *tree; +register NODE *tree; { AWKNUM rval, lval; NODE **lhs; AWKNUM t1, t2; long ltemp; NODE *tmp; + Func_ptr after_assign = NULL; - lhs = get_lhs(tree->lnode, 1); + lhs = get_lhs(tree->lnode, &after_assign); lval = force_number(*lhs); + unref(*lhs); switch(tree->type) { case Node_preincrement: case Node_predecrement: - DBG_P(("+-X", tree)); - assign_number(lhs, - lval + (tree->type == Node_preincrement ? 1.0 : -1.0)); - do_deref(); - if (field_num == 0) - set_record(fields_arr[0]->stptr, fields_arr[0]->stlen); - field_num = -1; + *lhs = make_number(lval + + (tree->type == Node_preincrement ? 1.0 : -1.0)); + if (after_assign) + (*after_assign)(); return *lhs; case Node_postincrement: case Node_postdecrement: - DBG_P(("X+-", tree)); - assign_number(lhs, - lval + (tree->type == Node_postincrement ? 1.0 : -1.0)); - do_deref(); - if (field_num == 0) - set_record(fields_arr[0]->stptr, fields_arr[0]->stlen); - field_num = -1; + *lhs = make_number(lval + + (tree->type == Node_postincrement ? 1.0 : -1.0)); + if (after_assign) + (*after_assign)(); return tmp_number(lval); default: break; /* handled below */ @@ -818,60 +736,65 @@ NODE *tree; free_temp(tmp); switch(tree->type) { case Node_assign_exp: - DBG_P(("ASSIGN_exp", tree)); if ((ltemp = rval) == rval) { /* integer exponent */ if (ltemp == 0) - assign_number(lhs, (AWKNUM) 1); + *lhs = make_number((AWKNUM) 1); else if (ltemp == 1) - assign_number(lhs, lval); + *lhs = make_number(lval); else { /* doing it this way should be more precise */ for (t1 = t2 = lval; --ltemp; ) t1 *= t2; - assign_number(lhs, t1); + *lhs = make_number(t1); } } else - assign_number(lhs, (AWKNUM) pow((double) lval, (double) rval)); + *lhs = make_number((AWKNUM) pow((double) lval, (double) rval)); break; case Node_assign_times: - DBG_P(("ASSIGN_times", tree)); - assign_number(lhs, lval * rval); + *lhs = make_number(lval * rval); break; case Node_assign_quotient: - DBG_P(("ASSIGN_quotient", tree)); if (rval == (AWKNUM) 0) fatal("division by zero attempted in /="); - assign_number(lhs, lval / rval); +#ifdef _CRAY + /* + * special case for integer division, put in for Cray + */ + ltemp = rval; + if (ltemp == 0) { + *lhs = make_number(lval / rval); + break; + } + ltemp = (long) lval / ltemp; + if (ltemp * lval == rval) + *lhs = make_number((AWKNUM) ltemp); + else +#endif + *lhs = make_number(lval / rval); break; case Node_assign_mod: - DBG_P(("ASSIGN_mod", tree)); if (rval == (AWKNUM) 0) fatal("division by zero attempted in %="); - ltemp = lval / rval; /* assignment to long truncates */ - t1 = ltemp * rval; - t2 = lval - t1; - assign_number(lhs, t2); + (void) modf(lval / rval, &t1); + t2 = lval - rval * t1; + *lhs = make_number(t2); break; case Node_assign_plus: - DBG_P(("ASSIGN_plus", tree)); - assign_number(lhs, lval + rval); + *lhs = make_number(lval + rval); break; case Node_assign_minus: - DBG_P(("ASSIGN_minus", tree)); - assign_number(lhs, lval - rval); + *lhs = make_number(lval - rval); break; default: cant_happen(); } - do_deref(); - if (field_num == 0) - set_record(fields_arr[0]->stptr, fields_arr[0]->stlen); - field_num = -1; + if (after_assign) + (*after_assign)(); return *lhs; } @@ -888,21 +811,22 @@ NODE *arg_list; /* Node_expression_list of calling args. */ volatile jmp_buf loop_tag_stack; volatile int save_loop_tag_valid = 0; volatile NODE **save_stack, *save_ret_node; - NODE **local_stack, **sp; + NODE **local_stack = NULL, **sp; int count; extern NODE *ret_node; /* * retrieve function definition node */ - f = lookup(variables, name->stptr); + f = lookup(name->stptr); if (!f || f->type != Node_func) fatal("function `%s' not defined", name->stptr); #ifdef FUNC_TRACE fprintf(stderr, "function %s called\n", name->stptr); #endif count = f->lnode->param_cnt; - emalloc(local_stack, NODE **, count * sizeof(NODE *), "func_call"); + if (count) + emalloc(local_stack, NODE **, count*sizeof(NODE *), "func_call"); sp = local_stack; /* @@ -910,7 +834,8 @@ NODE *arg_list; /* Node_expression_list of calling args. */ */ for (argp = arg_list; count && argp != NULL; argp = argp->rnode) { arg = argp->lnode; - r = newnode(Node_var); + getnode(r); + r->type = Node_var; /* * call by reference for arrays; see below also */ @@ -935,7 +860,8 @@ NODE *arg_list; /* Node_expression_list of calling args. */ * add remaining params. on stack with null value */ while (count-- > 0) { - r = newnode(Node_var); + getnode(r); + r->type = Node_var; r->lnode = Nnull_string; r->rnode = (NODE *) NULL; *sp++ = r; @@ -982,23 +908,24 @@ NODE *arg_list; /* Node_expression_list of calling args. */ count = f->lnode->param_cnt; for (argp = arg_list; count > 0 && argp != NULL; argp = argp->rnode) { arg = argp->lnode; + if (arg->type == Node_param_list) + arg = stack_ptr[arg->param_cnt]; n = *sp++; if (arg->type == Node_var && n->type == Node_var_array) { arg->var_array = n->var_array; arg->type = Node_var_array; } - deref = n->lnode; - do_deref(); + unref(n->lnode); freenode(n); count--; } while (count-- > 0) { n = *sp++; - deref = n->lnode; - do_deref(); + unref(n->lnode); freenode(n); } - free((char *) local_stack); + if (local_stack) + free((char *) local_stack); /* Restore the loop_tag stuff if necessary. */ if (save_loop_tag_valid) { @@ -1020,120 +947,237 @@ NODE *arg_list; /* Node_expression_list of calling args. */ NODE ** get_lhs(ptr, assign) -NODE *ptr; -int assign; /* this is being called for the LHS of an assign. */ +register NODE *ptr; +Func_ptr *assign; { - register NODE **aptr; - NODE *n; + register NODE **aptr = NULL; + register NODE *n; -#ifdef DEBUG - if (ptr == NULL) - cant_happen(); -#endif - deref = NULL; - field_num = -1; switch (ptr->type) { - case Node_var: case Node_var_array: - if (ptr == NF_node && (int) NF_node->var_value->numbr == -1) - (void) get_field(HUGE-1, assign); /* parse record */ - deref = ptr->var_value; + fatal("attempt to use an array in a scalar context"); + case Node_var: + aptr = &(ptr->var_value); #ifdef DEBUG - if (deref->type != Node_val) - cant_happen(); - if (deref->flags == 0) + if (ptr->var_value->stref <= 0) cant_happen(); #endif - return &(ptr->var_value); + break; + + case Node_FIELDWIDTHS: + aptr = &(FIELDWIDTHS_node->var_value); + if (assign) + *assign = set_FIELDWIDTHS; + break; + + case Node_RS: + aptr = &(RS_node->var_value); + if (assign) + *assign = set_RS; + break; + + case Node_FS: + aptr = &(FS_node->var_value); + if (assign) + *assign = set_FS; + break; + + case Node_FNR: + unref(FNR_node->var_value); + FNR_node->var_value = make_number((AWKNUM) FNR); + aptr = &(FNR_node->var_value); + if (assign) + *assign = set_FNR; + break; + + case Node_NR: + unref(NR_node->var_value); + NR_node->var_value = make_number((AWKNUM) NR); + aptr = &(NR_node->var_value); + if (assign) + *assign = set_NR; + break; + + case Node_NF: + if (NF == -1) + (void) get_field(HUGE-1, assign); /* parse record */ + unref(NF_node->var_value); + NF_node->var_value = make_number((AWKNUM) NF); + aptr = &(NF_node->var_value); + if (assign) + *assign = set_NF; + break; + + case Node_IGNORECASE: + unref(IGNORECASE_node->var_value); + IGNORECASE_node->var_value = make_number((AWKNUM) IGNORECASE); + aptr = &(IGNORECASE_node->var_value); + if (assign) + *assign = set_IGNORECASE; + break; + + case Node_OFMT: + aptr = &(OFMT_node->var_value); + if (assign) + *assign = set_OFMT; + break; + + case Node_CONVFMT: + aptr = &(CONVFMT_node->var_value); + if (assign) + *assign = set_CONVFMT; + break; + + case Node_ORS: + aptr = &(ORS_node->var_value); + if (assign) + *assign = set_ORS; + break; + + case Node_OFS: + aptr = &(OFS_node->var_value); + if (assign) + *assign = set_OFS; + break; case Node_param_list: - n = stack_ptr[ptr->param_cnt]; - deref = n->var_value; -#ifdef DEBUG - if (deref->type != Node_val) - cant_happen(); - if (deref->flags == 0) - cant_happen(); -#endif - return &(n->var_value); + aptr = &(stack_ptr[ptr->param_cnt]->var_value); + break; case Node_field_spec: + { + int field_num; + n = tree_eval(ptr->lnode); field_num = (int) force_number(n); free_temp(n); if (field_num < 0) fatal("attempt to access field %d", field_num); + if (field_num == 0 && field0_valid) { /* short circuit */ + aptr = &fields_arr[0]; + if (assign) + *assign = reset_record; + break; + } aptr = get_field(field_num, assign); - deref = *aptr; - return aptr; - + break; + } case Node_subscript: n = ptr->lnode; if (n->type == Node_param_list) n = stack_ptr[n->param_cnt]; aptr = assoc_lookup(n, concat_exp(ptr->rnode)); - deref = *aptr; -#ifdef DEBUG - if (deref->type != Node_val) - cant_happen(); - if (deref->flags == 0) - cant_happen(); -#endif - return aptr; + break; + case Node_func: fatal ("`%s' is a function, assignment is not allowed", ptr->lnode->param); default: cant_happen(); } - return 0; + return aptr; } static NODE * match_op(tree) -NODE *tree; +register NODE *tree; { - NODE *t1; - struct re_pattern_buffer *rp; + register NODE *t1; + register Regexp *rp; int i; int match = 1; if (tree->type == Node_nomatch) match = 0; if (tree->type == Node_regex) - t1 = WHOLELINE; + t1 = *get_field(0, (Func_ptr *) 0); else { - if (tree->lnode) - t1 = force_string(tree_eval(tree->lnode)); - else - t1 = WHOLELINE; + t1 = force_string(tree_eval(tree->lnode)); tree = tree->rnode; } - if (tree->type == Node_regex) { - rp = tree->rereg; - if (!strict && ((IGNORECASE_node->var_value->numbr != 0) - ^ (tree->re_case != 0))) { - /* recompile since case sensitivity differs */ - rp = tree->rereg = - mk_re_parse(tree->re_text, - (IGNORECASE_node->var_value->numbr != 0)); - tree->re_case = - (IGNORECASE_node->var_value->numbr != 0); - } - } else { - rp = make_regexp(force_string(tree_eval(tree)), - (IGNORECASE_node->var_value->numbr != 0)); - if (rp == NULL) - cant_happen(); - } - i = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, - (struct re_registers *) NULL); + rp = re_update(tree); + i = research(rp, t1->stptr, t1->stlen, 0); i = (i == -1) ^ (match == 1); free_temp(t1); - if (tree->type != Node_regex) { - free(rp->buffer); - free(rp->fastmap); - free((char *) rp); - } return tmp_number((AWKNUM) i); } + +void +set_IGNORECASE() +{ + static int warned = 0; + + if ((do_lint || strict) && ! warned) { + warned = 1; + warning("IGNORECASE not supported in compatibility mode"); + } + IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); +} + +void +set_OFS() +{ + OFS = force_string(OFS_node->var_value)->stptr; + OFSlen = OFS_node->var_value->stlen; + OFS[OFSlen] = '\0'; +} + +void +set_ORS() +{ + ORS = force_string(ORS_node->var_value)->stptr; + ORSlen = ORS_node->var_value->stlen; + ORS[ORSlen] = '\0'; +} + +static NODE **fmt_list = NULL; + +static int +fmt_ok(n) +NODE *n; +{ + /* to be done later */ + return 1; +} + +static int +fmt_index(n) +NODE *n; +{ + register int ix = 0; + static int fmt_num = 4; + static int fmt_hiwater = 0; + + if (fmt_list == NULL) + emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), "fmt_index"); + (void) force_string(n); + while (ix < fmt_hiwater) { + if (cmp_nodes(fmt_list[ix], n) == 0) + return ix; + ix++; + } + /* not found */ + n->stptr[n->stlen] = '\0'; + if (!fmt_ok(n)) + warning("bad FMT specification"); + if (fmt_hiwater >= fmt_num) { + fmt_num *= 2; + emalloc(fmt_list, NODE **, fmt_num, "fmt_index"); + } + fmt_list[fmt_hiwater] = dupnode(n); + return fmt_hiwater++; +} + +void +set_OFMT() +{ + OFMTidx = fmt_index(OFMT_node->var_value); + OFMT = fmt_list[OFMTidx]->stptr; +} + +void +set_CONVFMT() +{ + CONVFMTidx = fmt_index(CONVFMT_node->var_value); + CONVFMT = fmt_list[CONVFMTidx]->stptr; +} |