diff --git a/filter/config.Y b/filter/config.Y index 340053ba..ff1d3cb3 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -447,7 +447,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, %nonassoc ELSE %type cmds_int cmd_prep -%type term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail +%type term block cmd cmds constant constructor print_list args function_call symbol_value bgp_path_expr bgp_path bgp_path_tail %type dynamic_attr %type static_attr %type filter where_filter @@ -844,33 +844,17 @@ constructor: ; -/* This generates the function_call variable list backwards. */ -var_list: /* EMPTY */ { $$ = NULL; } +args: + /* EMPTY */ { $$ = NULL; } | term { $$ = $1; } - | var_list ',' term { $$ = $3; $$->next = $1; } + | term ',' args { $$ = $1; $$->next = $3; } function_call: - CF_SYM_KNOWN '(' var_list ')' { + CF_SYM_KNOWN '(' args ')' { if ($1->class != SYM_FUNCTION) cf_error("You can't call something which is not a function. Really."); - struct f_inst *fc = f_new_inst(FI_CALL, $1); - uint args = 0; - while ($3) { - args++; - struct f_inst *tmp = $3->next; - $3->next = fc; - - fc = $3; - $3 = tmp; - } - - if (args != $1->function->args) - cf_error("Function call '%s' got %u arguments, need %u arguments.", - $1->name, args, $1->function->args); - - $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); - $$->next = fc; + $$ = f_new_inst(FI_CALL, $3, $1); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index 4d5b70dc..a2ddcf3d 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -274,7 +274,8 @@ m4_undivert(102)m4_dnl [[m4_dnl The one case in The Big Switch inside interpreter case INST_NAME(): #define whati (&(what->i_]]INST_NAME()[[)) - m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); fstk->vcnt -= INST_INVAL(); ]]) + m4_ifelse(m4_eval(INST_INVAL() > 0), 1, [[ if (fstk->vcnt < INST_INVAL()) runtime("Stack underflow"); + fstk->vcnt -= INST_INVAL(); ]]) m4_undivert(108)m4_dnl #undef whati break; diff --git a/filter/f-inst.c b/filter/f-inst.c index 385d18d0..ad3ef3f6 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -895,25 +895,36 @@ INST(FI_CALL, 0, 1) { NEVER_CONSTANT; + VARARG; SYMBOL; + FID_NEW_BODY() + if (whati->varcount != sym->function->args) + cf_error("Function call '%s' got %u arguments, needs %u arguments", + sym->name, whati->varcount, sym->function->args); + + /* Add void slot for return value (requires [[NEVER_CONSTANT]]) */ + struct f_inst *rv = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID }); + rv->next = whati->fvar; + whati->fvar = rv; + what->size += rv->size; + FID_SAME_BODY() if (!(f2->sym->flags & SYM_FLAG_SAME)) return 0; + FID_INTERPRET_BODY() /* Push the body on stack */ LINEX(sym->function); curline.emask |= FE_RETURN; - /* Before this instruction was called, there was the T_VOID - * automatic return value pushed on value stack and also - * sym->function->args function arguments. Setting the - * vbase to point to first argument. */ - ASSERT(curline.ventry >= sym->function->args); - curline.ventry -= sym->function->args; + /* Set new base for local variables */ curline.vbase = curline.ventry; + /* Arguments were substracted by [[VARARG]], now add them back */ + fstk->vcnt += whati->varcount; + /* Storage for local variables */ memset(&(fstk->vstk[fstk->vcnt]), 0, sizeof(struct f_val) * sym->function->vars); fstk->vcnt += sym->function->vars;