CF_HDR
+#include "filter/f-inst.h"
+#include "filter/data.h"
+
CF_DEFINES
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
+#define f_generate_complex(fi_code, da, arg) \
+ f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
/*
* Sets and their items are during parsing handled as lists, linked
static inline struct f_inst *
f_generate_empty(struct f_dynamic_attr dyn)
{
- struct f_inst *e = f_new_inst(FI_CONSTANT);
+ struct f_val empty;
switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH:
- e->val = f_const_empty_path;
+ empty = f_const_empty_path;
break;
case EAF_TYPE_INT_SET:
- e->val = f_const_empty_clist;
+ empty = f_const_empty_clist;
break;
case EAF_TYPE_EC_SET:
- e->val = f_const_empty_eclist;
+ empty = f_const_empty_eclist;
break;
case EAF_TYPE_LC_SET:
- e->val = f_const_empty_lclist;
+ empty = f_const_empty_lclist;
break;
default:
cf_error("Can't empty that attribute");
}
- struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
- s->a[0].p = e;
- return s;
+ return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
}
+#if 0
static inline struct f_inst *
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
return pmc;
}
+#endif
+
/*
* Remove all new lines and doubled whitespaces
* and convert all tabulators to spaces
static struct f_inst *
assert_done(struct f_inst *expr, const char *start, const char *end)
{
- struct f_inst *i;
- i = f_new_inst(FI_ASSERT);
- i->a[0].p = expr;
+ return f_new_inst(FI_ASSERT, expr,
+ (end >= start) ?
+ assert_copy_expr(start, end - start + 1)
+ : "???");
+}
- if (end >= start)
- {
- i->a[1].p = assert_copy_expr(start, end - start + 1);
- }
- else
- {
- /* this is a break of lexer buffer */
- i->a[1].p = "???";
+static struct f_inst *
+assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
+{
+ struct f_inst *setter, *getter, *checker;
+ switch (lval->type) {
+ case F_LVAL_VARIABLE:
+ setter = f_new_inst(FI_VAR_SET, expr, lval->sym);
+ getter = f_new_inst(FI_VAR_GET, lval->sym);
+ break;
+ case F_LVAL_PREFERENCE:
+ setter = f_new_inst(FI_PREF_SET, expr);
+ getter = f_new_inst(FI_PREF_GET);
+ break;
+ case F_LVAL_SA:
+ setter = f_new_inst(FI_RTA_SET, expr, lval->sa);
+ getter = f_new_inst(FI_RTA_GET, lval->sa);
+ break;
+ case F_LVAL_EA:
+ setter = f_new_inst(FI_EA_SET, expr, lval->da);
+ getter = f_new_inst(FI_EA_GET, lval->da);
+ break;
+ default:
+ bug("Unknown lval type");
}
- return i;
+ checker = f_new_inst(FI_EQ, expr, getter);
+ setter->next = checker;
+
+ return assert_done(setter, start, end);
}
CF_DECLS
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
- BT_ASSERT, BT_TEST_SUITE, FORMAT)
+ BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
%nonassoc THEN
%nonassoc ELSE
-%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr bgp_path bgp_path_tail
+%type <xp> cmds_int
+%type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
%type <fda> dynamic_attr
%type <fsa> static_attr
-%type <f> filter filter_body where_filter
-%type <i> type break_command ec_kind
+%type <f> filter where_filter
+%type <fl> filter_body function_body
+%type <flv> lvalue
+%type <i> type function_params declsn decls
+%type <ecs> ec_kind
+%type <fret> break_command
%type <i32> cnum
%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
%type <trie> fprefix_set
%type <v> set_atom switch_atom fipa
%type <px> fprefix
-%type <s> decls declsn one_decl function_params
%type <t> get_cf_position
CF_GRAMMAR
conf: filter_def ;
filter_def:
- FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
+ FILTER CF_SYM_VOID { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); }
filter_body {
- $2->def = $4;
- $4->name = $2->name;
- DBG( "We have new filter defined (%s)\n", $2->name );
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ *f = (struct filter) { .sym = $2, .root = $4 };
+ $2->filter = f;
+
cf_pop_scope();
}
;
conf: filter_eval ;
filter_eval:
- EVAL term { f_eval_int(f_postfixify($2)); }
+ EVAL term { f_eval_int(f_linearize($2)); }
;
conf: custom_attr ;
-custom_attr: ATTRIBUTE type SYM ';' {
- cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda);
+custom_attr: ATTRIBUTE type CF_SYM_VOID ';' {
+ cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
};
conf: bt_test_suite ;
bt_test_suite:
- BT_TEST_SUITE '(' SYM ',' text ')' {
- if (!($3->class & SYM_FUNCTION))
- cf_error("Function expected");
-
- struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
- t->fn = $3->def;
+ BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' {
+ cf_assert_symbol($3, SYM_FUNCTION);
+ struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
+ t->fn = $3->function;
t->fn_name = $3->name;
t->dsc = $5;
}
;
+conf: bt_test_same ;
+bt_test_same:
+ BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' {
+ cf_assert_symbol($3, SYM_FUNCTION);
+ cf_assert_symbol($5, SYM_FUNCTION);
+ struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
+ t->fn = $3->function;
+ t->cmp = $5->function;
+ t->result = $7;
+ t->fn_name = $3->name;
+ t->dsc = $5->name;
+ add_tail(&new_config->tests, &t->n);
+ }
+ ;
+
type:
INT { $$ = T_INT; }
| BOOL { $$ = T_BOOL; }
}
;
-one_decl:
- type SYM {
- struct f_val * val = cfg_alloc(sizeof(struct f_val));
- val->type = T_VOID;
- $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
- DBG( "New variable %s type %x\n", $2->name, $1 );
- $2->aux2 = NULL;
- $$=$2;
- }
- ;
-
-/* Decls with ';' at the end */
-decls: /* EMPTY */ { $$ = NULL; }
- | one_decl ';' decls {
- $$ = $1;
- $$->aux2 = $3;
- }
+/* Declarations with ';' at the end */
+decls:
+ /* EMPTY */ { $$ = 0; }
+ | declsn ';' { $$ = $1; }
;
/* Declarations that have no ';' at the end. */
-declsn: one_decl { $$ = $1; }
- | one_decl ';' declsn {
- $$ = $1;
- $$->aux2 = $3;
+declsn:
+ type CF_SYM_VOID {
+ cf_define_symbol($2, SYM_VARIABLE | $1, offset, $2->scope->slots++);
+ $$ = $2->scope->slots;
}
- ;
-
-filter_body:
- function_body {
- struct filter *f = cfg_alloc(sizeof(struct filter));
- f->name = NULL;
- f->root = f_postfixify($1);
- $$ = f;
+ | declsn ';' type CF_SYM_VOID {
+ if ($4->scope->slots >= 0xff) cf_error("Too many declarations, at most 255 allowed");
+ cf_define_symbol($4, SYM_VARIABLE | $3, offset, $4->scope->slots++);
+ $$ = $4->scope->slots;
}
;
+filter_body: function_body ;
+
filter:
- SYM {
- if ($1->class != SYM_FILTER) cf_error("No such filter.");
- $$ = $1->def;
+ CF_SYM_KNOWN {
+ cf_assert_symbol($1, SYM_FILTER);
+ $$ = $1->filter;
+ }
+ | filter_body {
+ struct filter *f = cfg_alloc(sizeof(struct filter));
+ *f = (struct filter) { .root = $1 };
+ $$ = f;
}
- | filter_body
;
where_filter:
WHERE term {
/* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
- struct filter *f = cfg_alloc(sizeof(struct filter));
- struct f_inst acc = {
- .fi_code = FI_PRINT_AND_DIE,
- .a = { { .p = NULL }, { .i = F_ACCEPT } },
- .lineno = ifs->lino,
- };
- struct f_inst rej = {
- .fi_code = FI_PRINT_AND_DIE,
- .a = { { .p = NULL }, { .i = F_REJECT } },
- .lineno = ifs->lino,
- };
- struct f_inst i = {
- .fi_code = FI_CONDITION,
- .a = { { .p = $2 }, { .p = &acc }, { .p = &rej } },
- .lineno = ifs->lino,
- };
- f->name = NULL;
- f->root = f_postfixify(&i);
- $$ = f;
+ $$ = f_new_where($2);
}
;
function_params:
- '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
- | '(' ')' { $$=NULL; }
+ '(' declsn ')' { $$ = $2; }
+ | '(' ')' { $$ = 0; }
;
function_body:
decls '{' cmds '}' {
- if ($1) {
- /* Prepend instruction to clear local variables */
- $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
- $$->a[0].p = $1;
- $$->next = $3;
- } else
- $$ = $3;
+ $$ = f_linearize($3);
+ $$->vars = $1;
}
;
conf: function_def ;
function_def:
- FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
- $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
+ FUNCTION CF_SYM_VOID { DBG( "Beginning of function %s\n", $2->name );
+ $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL);
cf_push_scope($2);
} function_params function_body {
- struct f_inst *vc = f_new_inst(FI_CONSTANT);
- vc->val = (struct f_val) { .type = T_VOID };
- $2->def = f_postfixify_concat($5, vc, NULL);
- $2->aux2 = $4;
- DBG("Hmm, we've got one function here - %s\n", $2->name);
+ $5->vars -= $4;
+ $5->args = $4;
+ $2->function = $5;
cf_pop_scope();
}
;
/* Programs */
-/* Hack: $$ of cmds_int is the last node.
- $$->next of cmds_int is temporary used for the first node */
-
cmds: /* EMPTY */ { $$ = NULL; }
- | cmds_int { $$ = $1->next; $1->next = NULL; }
+ | cmds_int { $$ = $1.begin; }
;
-cmds_int: cmd { $$ = $1; $1->next = $1; }
- | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
+cmds_int: cmd {
+ $$.begin = $$.end = $1;
+ while ($$.end->next)
+ $$.end = $$.end->next;
+ }
+ | cmds_int cmd {
+ $$.begin = $1.begin;
+ $1.end->next = $2;
+ $$.end = $2;
+ while ($$.end->next)
+ $$.end = $$.end->next;
+ }
;
block:
| VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' {
- if (f_eval(f_postfixify($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
+ if (f_eval(f_linearize($2), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
- | SYM {
- if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
+ | CF_SYM_KNOWN {
+ cf_assert_symbol($1, SYM_CONSTANT);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
- $$ = *(struct f_val *)($1->def);
+ $$ = *$1->val;
}
;
switch_atom:
NUM { $$.type = T_INT; $$.val.i = $1; }
- | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_postfixify($2)); }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2)); }
| fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
;
cnum:
- term { $$ = f_eval_int(f_postfixify($1)); }
+ term { $$ = f_eval_int(f_linearize($1)); }
pair_item:
'(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
| switch_body switch_items ':' cmds {
/* Fill data fields */
struct f_tree *t;
- struct f_line *line = f_postfixify($4);
+ struct f_line *line = f_linearize($4);
for (t = $2; t; t = t->left)
t->data = line;
$$ = f_merge_items($1, $2);
struct f_tree *t = f_new_tree();
t->from.type = t->to.type = T_VOID;
t->right = t;
- t->data = f_postfixify($3);
+ t->data = f_linearize($3);
$$ = f_merge_items($1, t);
}
;
bgp_path_expr:
- symbol { $$ = $1; }
+ symbol_value { $$ = $1; }
| '(' term ')' { $$ = $2; }
;
;
bgp_path_tail:
- NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }; }
- | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $4; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }; }
- | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }; }
- | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT); $$->next = $2; $$->val = (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }; }
+ NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); $$->next = $2; }
+ | NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); $$->next = $4; }
+ | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
+ | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
| bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
| { $$ = NULL; }
;
constant:
- NUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_INT, .val.i = $1, }; }
- | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 1, }; }
- | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_BOOL, .val.i = 0, }; }
- | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_STRING, .val.s = $1, }; }
- | fipa { $$ = f_new_inst(FI_CONSTANT); $$->val = $1; }
- | VPN_RD { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_RD, .val.ec = $1, }; }
- | net_ { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_NET, .val.net = $1, }; }
+ NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
+ | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
+ | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
+ | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
+ | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
+ | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
+ | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
| '[' set_items ']' {
DBG( "We've got a set here..." );
- $$ = f_new_inst(FI_CONSTANT);
- $$->val = (struct f_val) { .type = T_SET, .val.t = build_tree($2), };
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
DBG( "ook\n" );
}
- | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }; }
- | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->val = (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }; }
+ | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
+ | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
;
constructor:
- '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
- | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
- | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
- | bgp_path { $$ = f_generate_path_mask($1); }
+ '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
+ | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
+ | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
+ | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1, 0); }
;
-rtadot: /* EMPTY, we are not permitted RTA. prefix */
- ;
+/* This generates the function_call variable list backwards. */
+var_list: /* EMPTY */ { $$ = NULL; }
+ | term { $$ = $1; }
+ | var_list ',' term { $$ = $3; $$->next = $1; }
function_call:
- SYM '(' var_list ')' {
- struct symbol *sym;
- struct f_inst *inst = $3;
+ CF_SYM_KNOWN '(' var_list ')' {
if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really.");
- DBG("You are calling function %s\n", $1->name);
- $$ = f_new_inst(FI_CALL);
- $$->a[0].p = inst;
- $$->a[1].p = $1->def;
- sym = $1->aux2;
- while (sym || inst) {
- if (!sym || !inst)
- cf_error("Wrong number of arguments for function %s.", $1->name);
- DBG( "You should pass parameter called %s\n", sym->name);
- inst->a[0].p = sym;
- sym = sym->aux2;
- inst = inst->next;
+
+ struct f_inst *fc = f_new_inst(FI_CALL, $1);
+ uint args = 0;
+ while ($3) {
+ args++;
+ struct f_inst *tmp = $3->next;
+ $3->next = fc;
+
+ fc = $3;
+ $3 = tmp;
}
+
+ if (args != $1->function->args)
+ cf_error("Function call '%s' got %u arguments, need %u arguments.",
+ $1->name, args, $1->function->args);
+
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_VOID });
+ $$->next = fc;
}
;
-symbol:
- SYM {
- switch ($1->class & 0xffff) {
- case SYM_CONSTANT_RANGE:
- $$ = f_new_inst(FI_CONSTANT_INDIRECT);
- $$->a[0].p = $1;
- break;
- case SYM_VARIABLE_RANGE:
- $$ = f_new_inst(FI_VARIABLE);
- $$->a[0].p = $1;
- break;
- case SYM_ATTRIBUTE:
- $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
- break;
- default:
- cf_error("%s: variable expected.", $1->name);
- }
- }
+symbol_value: CF_SYM_KNOWN
+ {
+ switch ($1->class) {
+ case SYM_CONSTANT_RANGE:
+ $$ = f_new_inst(FI_CONSTANT, *($1->val));
+ break;
+ case SYM_VARIABLE_RANGE:
+ $$ = f_new_inst(FI_VAR_GET, $1);
+ break;
+ case SYM_ATTRIBUTE:
+ $$ = f_new_inst(FI_EA_GET, *$1->attribute);
+ break;
+ default:
+ cf_error("Can't get value of symbol %s", $1->name);
+ }
+ }
+ ;
static_attr:
FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
term:
'(' term ')' { $$ = $2; }
- | term '+' term { $$ = f_new_inst(FI_ADD); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term AND term { $$ = f_new_inst(FI_AND); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term OR term { $$ = f_new_inst(FI_OR); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '=' term { $$ = f_new_inst(FI_EQ); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '<' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term '>' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $3; $$->a[1].p = $1; }
- | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $3; $$->a[1].p = $1; }
- | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a[0].p = $1; $$->a[1].p = $3; }
- | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a[0].p = $1; $$->a[1].p = $3; }
- | '!' term { $$ = f_new_inst(FI_NOT); $$->a[0].p = $2; }
- | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a[0].p = $3; }
-
- | symbol { $$ = $1; }
+ | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
+ | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
+ | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
+ | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
+ | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
+ | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
+ | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
+ | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
+ | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
+ | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
+ | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
+ | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
+ | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
+ | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
+ | '!' term { $$ = f_new_inst(FI_NOT, $2); }
+ | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
+
+ | symbol_value { $$ = $1; }
| constant { $$ = $1; }
| constructor { $$ = $1; }
| PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
- | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
+ | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
- | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
+ | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
- | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a[0].p = $1; }
- | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a[0].p = $1; }
- | term '.' IP { $$ = f_new_inst(FI_IP); $$->a[0].p = $1; $$->aux = T_IP; }
- | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a[0].p = $1; $$->aux = T_RD; }
- | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a[0].p = $1; }
- | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a[0].p = $1; }
- | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a[0].p = $1; }
- | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a[0].p = $1; }
- | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a[0].p = $1; $$->a[1].p = $5; }
- | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a[0].p = $1; }
- | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a[0].p = $1; }
- | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a[0].p = $1; }
+ | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); }
+ | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); }
+ | term '.' IP { $$ = f_new_inst(FI_IP, $1); }
+ | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
+ | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
+ | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
+ | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
+ | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
+ | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
+ | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
+ | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
+ | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
/* Communities */
/* This causes one shift/reduce conflict
- | rtadot dynamic_attr '.' ADD '(' term ')' { }
- | rtadot dynamic_attr '.' DELETE '(' term ')' { }
- | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
- | rtadot dynamic_attr '.' RESET{ }
+ | dynamic_attr '.' ADD '(' term ')' { }
+ | dynamic_attr '.' DELETE '(' term ')' { }
+ | dynamic_attr '.' CONTAINS '(' term ')' { }
+ | dynamic_attr '.' RESET{ }
*/
- | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_path; }
- | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_clist; }
- | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_eclist; }
- | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT); $$->val = f_const_empty_lclist; }
- | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; }
- | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD); $$->a[0].p = $3; $$->a[1].p = $5; }
- | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL); $$->a[0].p = $3; $$->a[1].p = $5; }
- | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER); $$->a[0].p = $3; $$->a[1].p = $5; }
+ | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); }
+ | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
+ | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); }
+ | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
+ | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); }
+ | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); }
+ | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); }
- | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT); $$->a[0].rtc = $3; }
- | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT); $$->a[2].rtc = $3; $$->a[0].p = $5; $$->a[1].p = $7; }
+ | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
- | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; }
+ | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
/* | term '.' LEN { $$->code = P('P','l'); } */
| PRINTN { $$ = F_NONL; }
;
-print_one:
- term { $$ = f_new_inst(FI_PRINT); $$->a[0].p = $1; $$->a[1].p = NULL; }
- ;
-
print_list: /* EMPTY */ { $$ = NULL; }
- | print_one { $$ = $1; }
- | print_one ',' print_list {
- if ($1) {
- $1->next = $3;
- $$ = $1;
- } else $$ = $3;
- }
- ;
-
-var_listn: term {
- $$ = f_new_inst(FI_SET);
- $$->a[0].p = NULL;
- $$->a[1].p = $1;
- $$->next = NULL;
- }
- | term ',' var_listn {
- $$ = f_new_inst(FI_SET);
- $$->a[0].p = NULL;
- $$->a[1].p = $1;
- $$->next = $3;
+ | term { $$ = $1; }
+ | term ',' print_list {
+ ASSERT($1);
+ ASSERT($1->next == NULL);
+ $1->next = $3;
+ $$ = $1;
}
;
-var_list: /* EMPTY */ { $$ = NULL; }
- | var_listn { $$ = $1; }
- ;
-
cmd:
IF term THEN block {
- $$ = f_new_inst(FI_CONDITION);
- $$->a[0].p = $2;
- $$->a[1].p = $4;
+ $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
}
| IF term THEN block ELSE block {
- $$ = f_new_inst(FI_CONDITION);
- $$->a[0].p = $2;
- $$->a[1].p = $4;
- $$->a[2].p = $6;
+ $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
}
- | SYM '=' term ';' {
- DBG( "Ook, we'll set value\n" );
- if ($1->class == SYM_ATTRIBUTE) {
- $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def));
- $$->a[0].p = $3;
- } else if (($1->class & ~T_MASK) == SYM_VARIABLE) {
- $$ = f_new_inst(FI_SET);
- $$->a[0].p = $1;
- $$->a[1].p = $3;
- } else
- cf_error( "Symbol `%s' is read-only.", $1->name );
+ | CF_SYM_KNOWN '=' term ';' {
+ switch ($1->class) {
+ case SYM_VARIABLE_RANGE:
+ $$ = f_new_inst(FI_VAR_SET, $3, $1);
+ break;
+ case SYM_ATTRIBUTE:
+ $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
+ break;
+ default:
+ cf_error("Can't assign to symbol %s", $1->name);
+ }
}
| RETURN term ';' {
DBG( "Ook, we'll return the value\n" );
- $$ = f_new_inst(FI_RETURN);
- $$->a[0].p = $2;
+ $$ = f_new_inst(FI_RETURN, $2);
}
- | rtadot dynamic_attr '=' term ';' {
- $$ = f_new_inst_da(FI_EA_SET, $2);
- $$->a[0].p = $4;
+ | dynamic_attr '=' term ';' {
+ $$ = f_new_inst(FI_EA_SET, $3, $1);
}
- | rtadot static_attr '=' term ';' {
- $$ = f_new_inst_sa(FI_RTA_SET, $2);
- if ($$->sa.readonly)
+ | static_attr '=' term ';' {
+ if ($1.readonly)
cf_error( "This static attribute is read-only.");
- $$->a[0].p = $4;
+ $$ = f_new_inst(FI_RTA_SET, $3, $1);
}
| PREFERENCE '=' term ';' {
- $$ = f_new_inst(FI_PREF_SET);
- $$->a[0].p = $3;
+ $$ = f_new_inst(FI_PREF_SET, $3);
}
- | UNSET '(' rtadot dynamic_attr ')' ';' {
- $$ = f_new_inst_da(FI_EA_SET, $4);
- $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
- $$->a[0].p = NULL;
+ | UNSET '(' dynamic_attr ')' ';' {
+ $$ = f_new_inst(FI_EA_UNSET, $3);
+ }
+ | break_command print_list ';' {
+ struct f_inst *breaker = NULL;
+ struct f_inst *printer = NULL;
+ if ($2)
+ printer = f_new_inst(FI_PRINT, $2);
+ if ($1 != F_NONL)
+ breaker = f_new_inst(FI_DIE, $1);
+
+ if (printer && breaker)
+ printer->next = breaker;
+
+ if (printer)
+ $$ = printer;
+ else
+ $$ = breaker;
}
- | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; }
- | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT); $$->a[0].p = $1; }
+ | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
| CASE term '{' switch_body '}' {
- $$ = f_new_inst(FI_SWITCH);
- $$->a[0].p = $2;
- $$->a[1].p = build_tree( $4 );
+ $$ = f_new_inst(FI_SWITCH, $2, build_tree($4));
}
- | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
- | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $2, $6 ); }
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $2, $6 ); }
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $2, $6 ); }
+ | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
+ | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); }
+ | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }
+ | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); }
+ | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
+ | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
;
get_cf_position:
$$ = cf_text;
};
+lvalue:
+ CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; }
+ | PREFERENCE { $$ = (struct f_lval) { .type = F_LVAL_PREFERENCE }; }
+ | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
+ | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };
CF_END