📄 eval.c
字号:
case Node_mod: if (x2 == 0) fatal("division by zero attempted in mod");#ifndef FMOD_MISSING return tmp_number(fmod (x1, x2));#else (void) modf(x1 / x2, &x); return tmp_number(x1 - x * x2);#endif case Node_plus: return tmp_number(x1 + x2); case Node_minus: return tmp_number(x1 - x2); case Node_var_array: fatal("attempt to use an array in a scalar context"); default: fatal("illegal type (%d) in tree_eval", tree->type); } return 0;}/* Is TREE true or false? Returns 0==false, non-zero==true */static inteval_condition(tree)register NODE *tree;{ register NODE *t1; register int ret; if (tree == NULL) /* Null trees are the easiest kinds */ return 1; if (tree->type == Node_line_range) { /* * Node_line_range is kind of like Node_match, EXCEPT: the * lnode field (more properly, the condpair field) is a node * of a Node_cond_pair; whether we evaluate the lnode of that * node or the rnode depends on the triggered word. More * precisely: if we are not yet triggered, we tree_eval the * lnode; if that returns true, we set the triggered word. * If we are triggered (not ELSE IF, note), we tree_eval the * rnode, clear triggered if it succeeds, and perform our * action (regardless of success or failure). We want to be * able to begin and end on a single input record, so this * isn't an ELSE IF, as noted above. */ if (!tree->triggered) if (!eval_condition(tree->condpair->lnode)) return 0; else tree->triggered = 1; /* Else we are triggered */ if (eval_condition(tree->condpair->rnode)) tree->triggered = 0; return 1; } /* * Could just be J.random expression. in which case, null and 0 are * false, anything else is true */ t1 = tree_eval(tree); if (t1->flags & MAYBE_NUM) (void) force_number(t1); if (t1->flags & NUMBER) ret = t1->numbr != 0.0; else ret = t1->stlen != 0; free_temp(t1); return ret;}/* * compare two nodes, returning negative, 0, positive */intcmp_nodes(t1, t2)register NODE *t1, *t2;{ register int ret; register int len1, len2; if (t1 == t2) return 0; if (t1->flags & MAYBE_NUM) (void) force_number(t1); if (t2->flags & MAYBE_NUM) (void) force_number(t2); if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) { if (t1->numbr == t2->numbr) return 0; else if (t1->numbr - t2->numbr < 0) return -1; else return 1; } (void) force_string(t1); (void) force_string(t2); len1 = t1->stlen; len2 = t2->stlen; if (len1 == 0 || len2 == 0) return len1 - len2; ret = memcmp(t1->stptr, t2->stptr, len1 <= len2 ? len1 : len2); return ret == 0 ? len1-len2 : ret;}static NODE *op_assign(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, &after_assign); lval = force_number(*lhs); /* * Can't unref *lhs until we know the type; doing so * too early breaks x += x sorts of things. */ switch(tree->type) { case Node_preincrement: case Node_predecrement: unref(*lhs); *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: unref(*lhs); *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 */ } tmp = tree_eval(tree->rnode); rval = force_number(tmp); free_temp(tmp); unref(*lhs); switch(tree->type) { case Node_assign_exp: if ((ltemp = rval) == rval) { /* integer exponent */ if (ltemp == 0) *lhs = make_number((AWKNUM) 1); else if (ltemp == 1) *lhs = make_number(lval); else { /* doing it this way should be more precise */ for (t1 = t2 = lval; --ltemp; ) t1 *= t2; *lhs = make_number(t1); } } else *lhs = make_number((AWKNUM) pow((double) lval, (double) rval)); break; case Node_assign_times: *lhs = make_number(lval * rval); break; case Node_assign_quotient: if (rval == (AWKNUM) 0) fatal("division by zero attempted in /=");#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: if (rval == (AWKNUM) 0) fatal("division by zero attempted in %=");#ifndef FMOD_MISSING *lhs = make_number(fmod(lval, rval));#else (void) modf(lval / rval, &t1); t2 = lval - rval * t1; *lhs = make_number(t2);#endif break; case Node_assign_plus: *lhs = make_number(lval + rval); break; case Node_assign_minus: *lhs = make_number(lval - rval); break; default: cant_happen(); } if (after_assign) (*after_assign)(); return *lhs;}NODE **stack_ptr;static NODE *func_call(name, arg_list)NODE *name; /* name is a Node_val giving function name */NODE *arg_list; /* Node_expression_list of calling args. */{ register NODE *arg, *argp, *r; NODE *n, *f; jmp_buf volatile func_tag_stack; jmp_buf volatile loop_tag_stack; int volatile save_loop_tag_valid = 0; NODE **volatile save_stack, *save_ret_node; NODE **volatile local_stack = NULL, **sp; int count; extern NODE *ret_node; /* * retrieve function definition node */ 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; if (count) emalloc(local_stack, NODE **, count*sizeof(NODE *), "func_call"); sp = local_stack; /* * for each calling arg. add NODE * on stack */ for (argp = arg_list; count && argp != NULL; argp = argp->rnode) { arg = argp->lnode; getnode(r); r->type = Node_var; /* * call by reference for arrays; see below also */ if (arg->type == Node_param_list) arg = stack_ptr[arg->param_cnt]; if (arg->type == Node_var_array) *r = *arg; else { n = tree_eval(arg); r->lnode = dupnode(n); r->rnode = (NODE *) NULL; free_temp(n); } *sp++ = r; count--; } if (argp != NULL) /* left over calling args. */ warning( "function `%s' called with more arguments than declared", name->stptr); /* * add remaining params. on stack with null value */ while (count-- > 0) { getnode(r); r->type = Node_var; r->lnode = Nnull_string; r->rnode = (NODE *) NULL; *sp++ = r; } /* * Execute function body, saving context, as a return statement * will longjmp back here. * * Have to save and restore the loop_tag stuff so that a return * inside a loop in a function body doesn't scrog any loops going * on in the main program. We save the necessary info in variables * local to this function so that function nesting works OK. * We also only bother to save the loop stuff if we're in a loop * when the function is called. */ if (loop_tag_valid) { int junk = 0; save_loop_tag_valid = (volatile int) loop_tag_valid; PUSH_BINDING(loop_tag_stack, loop_tag, junk); loop_tag_valid = 0; } save_stack = stack_ptr; stack_ptr = local_stack; PUSH_BINDING(func_tag_stack, func_tag, func_tag_valid); save_ret_node = ret_node; ret_node = Nnull_string; /* default return value */ if (setjmp(func_tag) == 0) (void) interpret(f->rnode); r = ret_node; ret_node = (NODE *) save_ret_node; RESTORE_BINDING(func_tag_stack, func_tag, func_tag_valid); stack_ptr = (NODE **) save_stack; /* * here, we pop each parameter and check whether * it was an array. If so, and if the arg. passed in was * a simple variable, then the value should be copied back. * This achieves "call-by-reference" for arrays. */ sp = local_stack; 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) { /* should we free arg->var_value ? */ arg->var_array = n->var_array; arg->type = Node_var_array; } unref(n->lnode); freenode(n); count--; } while (count-- > 0) { n = *sp++; /* if n is an (local) array, all the elements should be freed */ if (n->type == Node_var_array) { assoc_clear(n); free(n->var_array); } unref(n->lnode); freenode(n); } if (local_stack) free((char *) local_stack); /* Restore the loop_tag stuff if necessary. */ if (save_loop_tag_valid) { int junk = 0; loop_tag_valid = (int) save_loop_tag_valid; RESTORE_BINDING(loop_tag_stack, loop_tag, junk); } if (!(r->flags & PERM)) r->flags |= TEMP; return r;}/* * This returns a POINTER to a node pointer. get_lhs(ptr) is the current * value of the var, or where to store the var's new value */NODE **get_lhs(ptr, assign)register NODE *ptr;Func_ptr *assign;{ register NODE **aptr = NULL; register NODE *n; switch (ptr->type) { case Node_var_array: fatal("attempt to use an array in a scalar context"); case Node_var: aptr = &(ptr->var_value);#ifdef DEBUG if (ptr->var_value->stref <= 0) cant_happen();#endif 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: 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); 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)); break; case Node_func: fatal ("`%s' is a function, assignment is not allowed", ptr->lnode->param); default: cant_happen(); } return aptr;}static NODE *match_op(tree)register NODE *tree;{ register NODE *t1; register Regexp *rp; int i; int match = 1; if (tree->type == Node_nomatch) match = 0; if (tree->type == Node_regex) t1 = *get_field(0, (Func_ptr *) 0); else { t1 = force_string(tree_eval(tree->lnode)); tree = tree->rnode; } rp = re_update(tree); i = research(rp, t1->stptr, 0, t1->stlen, 0); i = (i == -1) ^ (match == 1); free_temp(t1); return tmp_number((AWKNUM) i);}voidset_IGNORECASE(){ static int warned = 0; if ((do_lint || do_unix) && ! warned) { warned = 1; warning("IGNORECASE not supported in compatibility mode"); } IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); set_FS();}voidset_OFS(){ OFS = force_string(OFS_node->var_value)->stptr; OFSlen = OFS_node->var_value->stlen; OFS[OFSlen] = '\0';}voidset_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 P((NODE *n));static int fmt_index P((NODE *n));static intfmt_ok(n)NODE *n;{ /* to be done later */ return 1;}static intfmt_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++;}voidset_OFMT(){ OFMTidx = fmt_index(OFMT_node->var_value); OFMT = fmt_list[OFMTidx]->stptr;}voidset_CONVFMT(){ CONVFMTidx = fmt_index(CONVFMT_node->var_value); CONVFMT = fmt_list[CONVFMTidx]->stptr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -