void define() { register int start_token; /* the 1st token in the function definition */ register struct udvt_entry *udv; register struct udft_entry *udf; if (equals(c_token + 1, "(")) { /* function ! */ int dummy_num = 0; struct at_type *at_tmp; char save_dummy[MAX_NUM_VAR][MAX_ID_LEN + 1]; memcpy(save_dummy, c_dummy_var, sizeof(save_dummy)); start_token = c_token; do { c_token += 2; /* skip to the next dummy */ copy_str(c_dummy_var[dummy_num++], c_token, MAX_ID_LEN); } while (equals(c_token + 1, ",") && (dummy_num < MAX_NUM_VAR)); if (equals(c_token + 1, ",")) int_error("function contains too many parameters", c_token + 2); c_token += 3; /* skip (, dummy, ) and = */ if (END_OF_COMMAND) int_error("function definition expected", c_token); udf = dummy_func = add_udf(start_token); if ((at_tmp = perm_at()) == (struct at_type *) NULL) int_error("not enough memory for function", start_token); if (udf->at) /* already a dynamic a.t. there */ free((char *) udf->at); /* so free it first */ udf->at = at_tmp; /* before re-assigning it. */ memcpy(c_dummy_var, save_dummy, sizeof(save_dummy)); m_capture(&(udf->definition), start_token, c_token - 1); dummy_func = NULL; /* dont let anyone else use our workspace */ } else { /* variable ! */ start_token = c_token; c_token += 2; udv = add_udv(start_token); (void) const_express(&(udv->udv_value)); udv->udv_undef = FALSE; } }
/* add action table entries for primary expressions, i.e. either a * parenthesized expression, a variable name, a numeric constant, a * function evaluation, a power operator or postfix '!' (factorial) * expression */ static void parse_primary_expression() { if (equals(c_token, "(")) { c_token++; parse_expression(); /* Expressions may be separated by a comma */ while (equals(c_token,",")) { c_token++; (void) add_action(POP); parse_expression(); } if (!equals(c_token, ")")) int_error(c_token, "')' expected"); c_token++; } else if (equals(c_token, "$")) { struct value a; c_token++; if (equals(c_token,"N")) { /* $N == pseudocolumn -3 means "last column" */ c_token++; Ginteger(&a, -3); at_highest_column_used = -3; } else if (!isanumber(c_token)) { int_error(c_token, "Column number expected"); } else { convert(&a, c_token++); if (a.type != INTGR || a.v.int_val < 0) int_error(c_token, "Positive integer expected"); if (at_highest_column_used < a.v.int_val) at_highest_column_used = a.v.int_val; } add_action(DOLLARS)->v_arg = a; } else if (isanumber(c_token)) { /* work around HP 9000S/300 HP-UX 9.10 cc limitation ... */ /* HBB 20010724: use this code for all platforms, then */ union argument *foo = add_action(PUSHC); convert(&(foo->v_arg), c_token); c_token++; } else if (isletter(c_token)) { /* Found an identifier --- check whether its a function or a * variable by looking for the parentheses of a function * argument list */ if (equals(c_token + 1, "(")) { enum operators whichfunc = is_builtin_function(c_token); struct value num_params; num_params.type = INTGR; #if (1) /* DEPRECATED */ if (whichfunc && (strcmp(ft[whichfunc].f_name,"defined")==0)) { /* Deprecated syntax: if (defined(foo)) ... */ /* New syntax: if (exists("foo")) ... */ struct udvt_entry *udv = add_udv(c_token+2); union argument *foo = add_action(PUSHC); foo->v_arg.type = INTGR; foo->v_arg.v.int_val = udv->udv_undef ? 0 : 1; c_token += 4; /* skip past "defined ( <foo> ) " */ return; } #endif if (whichfunc) { c_token += 2; /* skip fnc name and '(' */ parse_expression(); /* parse fnc argument */ num_params.v.int_val = 1; while (equals(c_token, ",")) { c_token++; num_params.v.int_val++; parse_expression(); } if (!equals(c_token, ")")) int_error(c_token, "')' expected"); c_token++; /* So far sprintf is the only built-in function */ /* with a variable number of arguments. */ if (!strcmp(ft[whichfunc].f_name,"sprintf")) add_action(PUSHC)->v_arg = num_params; /* The column() function has side effects requiring special handling */ if (!strcmp(ft[whichfunc].f_name,"column")) { set_up_columnheader_parsing( &(at->actions[at->a_count-1]) ); } (void) add_action(whichfunc); } else { /* it's a call to a user-defined function */ enum operators call_type = (int) CALL; int tok = c_token; c_token += 2; /* skip func name and '(' */ parse_expression(); if (equals(c_token, ",")) { /* more than 1 argument? */ num_params.v.int_val = 1; while (equals(c_token, ",")) { num_params.v.int_val += 1; c_token += 1; parse_expression(); } add_action(PUSHC)->v_arg = num_params; call_type = (int) CALLN; } if (!equals(c_token, ")")) int_error(c_token, "')' expected"); c_token++; add_action(call_type)->udf_arg = add_udf(tok); } } else if (equals(c_token, "sum") && equals(c_token+1, "[")) { parse_sum_expression(); /* dummy_func==NULL is a flag to say no dummy variables active */ } else if (dummy_func) { if (equals(c_token, c_dummy_var[0])) { c_token++; add_action(PUSHD1)->udf_arg = dummy_func; fit_dummy_var[0]++; } else if (equals(c_token, c_dummy_var[1])) { c_token++; add_action(PUSHD2)->udf_arg = dummy_func; fit_dummy_var[1]++; } else { int i, param = 0; for (i = 2; i < MAX_NUM_VAR; i++) { if (equals(c_token, c_dummy_var[i])) { struct value num_params; num_params.type = INTGR; num_params.v.int_val = i; param = 1; c_token++; add_action(PUSHC)->v_arg = num_params; add_action(PUSHD)->udf_arg = dummy_func; fit_dummy_var[i]++; break; } } if (!param) { /* defined variable */ add_action(PUSH)->udv_arg = add_udv(c_token); c_token++; } } /* its a variable, with no dummies active - div */ } else { add_action(PUSH)->udv_arg = add_udv(c_token); c_token++; } } /* end if letter */ /* Maybe it's a string constant */ else if (isstring(c_token)) { union argument *foo = add_action(PUSHC); foo->v_arg.type = STRING; foo->v_arg.v.string_val = NULL; /* this dynamically allocated string will be freed by free_at() */ m_quote_capture(&(foo->v_arg.v.string_val), c_token, c_token); c_token++; } else int_error(c_token, "invalid expression "); /* add action code for ! (factorial) operator */ while (equals(c_token, "!")) { c_token++; (void) add_action(FACTORIAL); } /* add action code for ** operator */ if (equals(c_token, "**")) { c_token++; parse_unary_expression(); (void) add_action(POWER); } /* Parse and add actions for range specifier applying to previous entity. * Currently only used to generate substrings, but could also be used to * extract vector slices. */ if (equals(c_token, "[") && !isanumber(c_token-1)) { /* handle '*' or empty start of range */ if (equals(++c_token,"*") || equals(c_token,":")) { union argument *empty = add_action(PUSHC); empty->v_arg.type = INTGR; empty->v_arg.v.int_val = 1; if (equals(c_token,"*")) c_token++; } else parse_expression(); if (!equals(c_token, ":")) int_error(c_token, "':' expected"); /* handle '*' or empty end of range */ if (equals(++c_token,"*") || equals(c_token,"]")) { union argument *empty = add_action(PUSHC); empty->v_arg.type = INTGR; empty->v_arg.v.int_val = 65535; /* should be INT_MAX */ if (equals(c_token,"*")) c_token++; } else parse_expression(); if (!equals(c_token, "]")) int_error(c_token, "']' expected"); c_token++; (void) add_action(RANGE); } }