From: Ondrej Zajicek (work) Date: Sun, 6 Mar 2022 01:18:01 +0000 (+0100) Subject: Filter: Implement direct recursion X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77c41a72dbf8369dacdff9ee17aaf386449b3e14;p=thirdparty%2Fbird.git Filter: Implement direct recursion Direct recursion almost worked, just crashed on function signature check. Split function parsing such that function signature is saved before function body is processed. Recursive calls are marked so they can be avoided during f_same() and similar code walking. Also, include tower of hanoi solver as a test case. --- diff --git a/filter/config.Y b/filter/config.Y index a4e82c7d9..82a072abe 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -460,25 +460,28 @@ function_body: conf: function_def ; function_def: - FUNCTION symbol { DBG( "Beginning of function %s\n", $2->name ); + FUNCTION symbol { + DBG( "Beginning of function %s\n", $2->name ); $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); cf_push_scope($2); - } function_args function_body - { - $5->arg_list = NULL; - $5->args = 0; + } function_args { + /* Make dummy f_line for storing function prototype */ + struct f_line *dummy = cfg_allocz(sizeof(struct f_line)); + $2->function = dummy; /* Revert the args */ while ($4) { struct f_arg *tmp = $4; $4 = $4->next; - tmp->next = $5->arg_list; - $5->arg_list = tmp; - $5->args++; + tmp->next = dummy->arg_list; + dummy->arg_list = tmp; + dummy->args++; } - - $2->function = $5; + } function_body { + $6->args = $2->function->args; + $6->arg_list = $2->function->arg_list; + $2->function = $6; cf_pop_scope(); } ; diff --git a/filter/decl.m4 b/filter/decl.m4 index a2a8c88af..3d118e34a 100644 --- a/filter/decl.m4 +++ b/filter/decl.m4 @@ -376,6 +376,7 @@ case INST_NAME(): { #undef whati #undef item dest->items[pos].fi_code = what->fi_code; + dest->items[pos].flags = what->flags; dest->items[pos].lineno = what->lineno; break; } @@ -647,6 +648,7 @@ FID_WR_PUT(4)m4_dnl struct f_inst { struct f_inst *next; /* Next instruction */ enum f_instruction_code fi_code; /* Instruction code */ + enum f_instruction_flags flags; /* Flags, instruction-specific */ enum f_type type; /* Type of returned value, if known */ int size; /* How many instructions are underneath */ int lineno; /* Line number */ diff --git a/filter/f-inst.c b/filter/f-inst.c index 500732c6b..e75b5e017 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -1165,11 +1165,16 @@ whati->fvar = tmp; what->size += tmp->size; + /* Mark recursive calls, they have dummy f_line */ + if (!sym->function->len) + what->flags |= FIF_RECURSIVE; + FID_SAME_BODY() - if (!(f1->sym->flags & SYM_FLAG_SAME)) - return 0; + if (!(f1->sym->flags & SYM_FLAG_SAME) && !(f1_->flags & FIF_RECURSIVE)) + return 0; FID_ITERATE_BODY() + if (!(what->flags & FIF_RECURSIVE)) BUFFER_PUSH(fit->lines) = whati->sym->function; FID_INTERPRET_BODY() diff --git a/filter/f-inst.h b/filter/f-inst.h index 12df40f68..58563c790 100644 --- a/filter/f-inst.h +++ b/filter/f-inst.h @@ -22,7 +22,7 @@ /* Flags for instructions */ enum f_instruction_flags { - FIF_PRINTED = 1, /* FI_PRINT_AND_DIE: message put in buffer */ + FIF_RECURSIVE = 1, /* FI_CALL: function is directly recursive */ } PACKED; /* Include generated filter instruction declarations */ diff --git a/filter/test.conf b/filter/test.conf index 401a999bc..e8b6a663f 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -1290,7 +1290,60 @@ function fifteen() return 15; } +function factorial(int x) +{ + if x = 0 then return 0; + if x = 1 then return 1; + else return x * factorial(x - 1); +} + +function fibonacci(int x) +{ + if x = 0 then return 0; + if x = 1 then return 1; + else return fibonacci(x - 1) + fibonacci(x - 2); +} + +function hanoi_init(int a; int b) +{ + if b = 0 + then return +empty+; + else return prepend(hanoi_init(a + 1, b - 1), a); +} + +function hanoi_solve(int n; bgppath h_src; bgppath h_dst; bgppath h_aux; bool x; bool y) +bgppath tmp1; +bgppath tmp2; +int v; +{ + # x -> return src or dst + # y -> print state + + if n = 0 then { if x then return h_src; else return h_dst; } + + tmp1 = hanoi_solve(n - 1, h_src, h_aux, h_dst, true, y); + tmp2 = hanoi_solve(n - 1, h_src, h_aux, h_dst, false, false); + h_src = tmp1; + h_aux = tmp2; + + v = h_src.first; + # bt_assert(h_dst = +empty+ || v < h_dst.first); + h_src = delete(h_src, v); + h_dst = prepend(h_dst, v); + + if y then + print "move: ", v, " src: ", h_src, " dst:", h_dst, " aux:", h_aux; + + tmp1 = hanoi_solve(n - 1, h_aux, h_dst, h_src, true, y); + tmp2 = hanoi_solve(n - 1, h_aux, h_dst, h_src, false, false); + h_aux = tmp1; + h_dst = tmp2; + + if x then return h_src; else return h_dst; +} + function t_call_function() +bgppath h_src; { bt_assert(fifteen() = 15); @@ -1302,6 +1355,16 @@ function t_call_function() bt_assert(callme(4, 4) = 16); bt_assert(callme(7, 2) = 14); bt_assert(callmeagain(1, 2, 3) = 6); + + bt_assert(factorial(5) = 120); + bt_assert(factorial(10) = 3628800); + + bt_assert(fibonacci(10) = 55); + bt_assert(fibonacci(20) = 6765); + + h_src = hanoi_init(1, 6); + bt_assert(format(h_src) = "(path 1 2 3 4 5 6)"); + bt_assert(hanoi_solve(6, h_src, +empty+, +empty+, false, false) = h_src); } bt_test_suite(t_call_function, "Testing calling functions");