Define a filter. You can learn more about filters in the following
chapter.
- <tag><label id="opt-function">function <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag>
+ <tag><label id="opt-function">function <m/type/ <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag>
Define a function. You can learn more about functions in the following chapter.
<tag><label id="opt-protocol">protocol rip|ospf|bgp|<m/.../ [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag>
<p>BIRD supports functions, so that you don't have to repeat the same blocks of
code over and over. Functions can have zero or more parameters and they can have
-local variables. Recursion is not allowed. Function definitions look like this:
+local variables. You should always specify the function return type and always
+return it. No-return functions and multiple-type returning functions are deprecated.
+Direct recursion is possible. Function definitions look like this:
<code>
-function name ()
+function int name ()
{
int local_variable;
int another_variable = 5;
+ return 42;
}
-function with_parameters (int parameter)
+function pair with_parameters (int parameter)
{
print parameter;
+ return (1, 2);
}
</code>
value exits from current function (this is similar to C).
<p>Filters are defined in a way similar to functions except they cannot have
-explicit parameters. They get a route table entry as an implicit parameter, it
+explicit parameters and cannot return. They get a route table entry as an implicit parameter, it
is also passed automatically to any functions called. The filter must terminate
with either <cf/accept/ or <cf/reject/ statement. If there is a runtime error in
filter, the route is rejected.
static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
+static struct symbol *this_function;
+
static struct f_method_scope {
struct f_inst *object;
struct sym_scope scope;
%type <f> filter where_filter
%type <fl> filter_body function_body
%type <flv> lvalue
-%type <i> type function_vars
+%type <i> type maybe_type function_vars
%type <fa> function_argsn function_args
%type <ecs> ec_kind
%type <fret> break_command
conf: filter_def ;
filter_def:
- FILTER symbol { $2 = cf_define_symbol(new_config, $2, SYM_FILTER, filter, NULL); cf_push_scope( new_config, $2 ); }
- filter_body {
+ FILTER symbol {
+ $2 = cf_define_symbol(new_config, $2, SYM_FILTER, filter, NULL);
+ cf_push_scope( new_config, $2 );
+ this_function = NULL;
+ } filter_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .sym = $2, .root = $4 };
$2->filter = f;
cf_assert_symbol($1, SYM_FILTER);
$$ = $1->filter;
}
- | { cf_push_scope(new_config, NULL); } filter_body {
+ | {
+ cf_push_scope(new_config, NULL);
+ this_function = NULL;
+ } filter_body {
struct filter *f = cfg_alloc(sizeof(struct filter));
*f = (struct filter) { .root = $2 };
$$ = f;
;
conf: function_def ;
+maybe_type:
+ /* EMPTY */ { $$ = T_VOID; }
+ | type { $$ = $1; }
+ ;
+
function_def:
- FUNCTION symbol {
- DBG( "Beginning of function %s\n", $2->name );
- $2 = cf_define_symbol(new_config, $2, SYM_FUNCTION, function, NULL);
- cf_push_scope(new_config, $2);
+ FUNCTION maybe_type symbol {
+ DBG( "Beginning of function %s\n", $3->name );
+ this_function = cf_define_symbol(new_config, $3, SYM_FUNCTION, function, NULL);
+/* if ($2 == T_VOID) log(L_WARN "Support for functions without explicit return type will be removed soon" ); */
+ cf_push_scope(new_config, this_function);
} function_args {
/* Make dummy f_line for storing function prototype */
struct f_line *dummy = cfg_allocz(sizeof(struct f_line));
- $2->function = dummy;
+ this_function->function = dummy;
+
+ dummy->return_type = $2;
/* Revert the args */
- while ($4) {
- struct f_arg *tmp = $4;
- $4 = $4->next;
+ while ($5) {
+ struct f_arg *tmp = $5;
+ $5 = $5->next;
tmp->next = dummy->arg_list;
dummy->arg_list = tmp;
dummy->args++;
}
} function_body {
- $6->args = $2->function->args;
- $6->arg_list = $2->function->arg_list;
- $2->function = $6;
+ $7->args = this_function->function->args;
+ $7->arg_list = this_function->function->arg_list;
+ $7->return_type = this_function->function->return_type;
+ $3->function = $7;
cf_pop_scope(new_config);
}
;
}
| RETURN term ';' {
DBG( "Ook, we'll return the value\n" );
+ if (!this_function)
+ cf_error("Can't return from a non-function, use accept or reject instead.");
+ if (this_function->function->return_type == T_VOID)
+ {
+ if ($2->type != T_VOID)
+ log(L_WARN "Inferring function %s return type from its return value: %s", this_function->name, f_type_name($2->type));
+ ((struct f_line *) this_function->function)->return_type = $2->type;
+ }
+ else if (this_function->function->return_type != $2->type)
+ cf_error("Can't return type %s from function %s, expected %s",
+ f_type_name($2->type), this_function->name, f_type_name(this_function->function->return_type));
+
$$ = f_new_inst(FI_RETURN, $2);
}
| dynamic_attr '=' term ';' {
define one = 1;
define ten = 10;
-function onef(int a)
+function int onef(int a)
{
return 1;
}
-function twof(int a)
+function int twof(int a)
{
return 2;
}
-function oneg(int a)
+function int oneg(int a)
{
return 1;
}
* -------------
*/
-function 'mkpair-a'(int a)
+function pair 'mkpair-a'(int a)
{
return (1, a);
}
* -------------
*/
-function mkpath(int a; int b)
+function bgpmask mkpath(int a; int b)
{
return [= a b 3 2 1 =];
}
* -------------------------
*/
-function mktrip(int a)
+function lc mktrip(int a)
{
return (a, 2*a, 3*a);
}
* -------------------------
*/
-function callme(int arg1; int arg2)
+function int callme(int arg1; int arg2)
int i;
{
case arg1 {
return 0;
}
-function callmeagain(int a; int b; int c)
+function int callmeagain(int a; int b; int c)
{
return a + b + c;
}
-function fifteen()
+function int fifteen()
{
return 15;
}
bt_assert(j = 35 && k = 20 && m = 100);
}
-function factorial(int x)
+function int 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)
+function int 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)
+function bgppath 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)
+function bgppath hanoi_solve(int n; bgppath h_src; bgppath h_dst; bgppath h_aux; bool x; bool y)
{
# x -> return src or dst
# y -> print state