]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Implement direct recursion
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 6 Mar 2022 01:18:01 +0000 (02:18 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 27 Jun 2022 19:13:31 +0000 (21:13 +0200)
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
filter/decl.m4
filter/f-inst.c
filter/f-inst.h
filter/test.conf

index a4e82c7d9eff83b55f6a6aa2889bc39f1770fd7d..82a072abe38b410b545a2201c54baf423138c766 100644 (file)
@@ -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();
    }
  ;
index a2a8c88af2620335e141e0a9092847a8ad2c3962..3d118e34a8197f8cc4770db5773b9847dd2054e3 100644 (file)
@@ -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 */
index 500732c6bcfedf31beaa6237f5d55f905bc710d0..e75b5e017d279a636eed5910134ad93f079a3d8e 100644 (file)
     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()
index 12df40f68e5d9df33f0138e8169195770d7b7b4c..58563c7906f98f99cdaf72e795515cd19ad26c81 100644 (file)
@@ -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 */
index 401a999bca04b3e97e4b9b98f86d146dea3d1221..e8b6a663f895ee8a231b0780c1d109a9580dbb3b 100644 (file)
@@ -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");