summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2022-03-06 02:18:01 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2022-06-27 21:13:31 +0200
commit26bc4f9904b014c9949489e8ae28366da473e85d (patch)
tree71b89917bb301831e8c77d4a1a8496a9ce84de9c /filter
parentfb1d8f65136aa6190b527b691f24abe16a461471 (diff)
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.
Diffstat (limited to 'filter')
-rw-r--r--filter/config.Y23
-rw-r--r--filter/decl.m42
-rw-r--r--filter/f-inst.c9
-rw-r--r--filter/f-inst.h2
-rw-r--r--filter/test.conf63
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");