From 77c41a72dbf8369dacdff9ee17aaf386449b3e14 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Sun, 6 Mar 2022 02:18:01 +0100 Subject: [PATCH] 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. --- filter/config.Y | 23 ++++++++++-------- filter/decl.m4 | 2 ++ filter/f-inst.c | 9 +++++-- filter/f-inst.h | 2 +- filter/test.conf | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 13 deletions(-) diff --git a/filter/config.Y b/filter/config.Y index a4e82c7d..82a072ab 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 a2a8c88a..3d118e34 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 500732c6..e75b5e01 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 12df40f6..58563c79 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 401a999b..e8b6a663 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");