mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 20:58:44 +00:00
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.
This commit is contained in:
parent
04ccb78d72
commit
77c41a72db
@ -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();
|
||||
}
|
||||
;
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
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()
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user