4 * Copyright 1998--2000 Pavel Machek
6 * Can be freely distributed and used under the terms of the GNU GPL.
8 FIXME: priority of ! should be lower
15 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
16 static inline u32 pair_a(u32 p) { return p >> 16; }
17 static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
21 * Sets and their items are during parsing handled as lists, linked
22 * through left ptr. The first item in a list also contains a pointer
23 * to the last item in a list (right ptr). For convenience, even items
24 * are handled as one-item lists. Lists are merged by f_merge_items().
27 f_valid_set_type(int type)
46 static inline struct f_tree *
47 f_new_item(struct f_val from, struct f_val to)
49 struct f_tree *t = f_new_tree();
56 static inline struct f_tree *
57 f_merge_items(struct f_tree *a, struct f_tree *b)
66 static inline struct f_tree *
67 f_new_pair_item(int fa, int ta, int fb, int tb)
74 if ((ta < fa) || (tb < fb))
75 cf_error( "From value cannot be higher that To value in pair sets");
77 struct f_tree *t = f_new_tree();
79 t->from.type = t->to.type = T_PAIR;
80 t->from.val.i = pair(fa, fb);
81 t->to.val.i = pair(ta, tb);
85 static inline struct f_tree *
86 f_new_pair_set(int fa, int ta, int fb, int tb)
93 if ((ta < fa) || (tb < fb))
94 cf_error( "From value cannot be higher that To value in pair sets");
96 struct f_tree *lst = NULL;
99 for (i = fa; i <= ta; i++)
100 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
105 #define CC_ALL 0xFFFF
106 #define EC_ALL 0xFFFFFFFF
107 #define LC_ALL 0xFFFFFFFF
109 static struct f_tree *
110 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
114 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
122 if (kind == EC_GENERIC) {
123 fm = ec_generic(key, vf);
124 to = ec_generic(key, vt);
126 else if (ipv4_used) {
127 fm = ec_ip4(kind, key, vf);
128 to = ec_ip4(kind, key, vt);
130 else if (key < 0x10000) {
131 fm = ec_as2(kind, key, vf);
132 to = ec_as2(kind, key, vt);
135 fm = ec_as4(kind, key, vf);
136 to = ec_as4(kind, key, vt);
139 struct f_tree *t = f_new_tree();
141 t->from.type = t->to.type = T_EC;
147 static struct f_tree *
148 f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
150 struct f_tree *t = f_new_tree();
152 t->from.type = t->to.type = T_LC;
153 t->from.val.lc = (lcomm) {f1, f2, f3};
154 t->to.val.lc = (lcomm) {t1, t2, t3};
158 static inline struct f_inst *
159 f_generate_empty(struct f_dynamic_attr dyn)
161 struct f_inst *e = f_new_inst(FI_EMPTY);
163 switch (dyn.type & EAF_TYPE_MASK) {
164 case EAF_TYPE_AS_PATH:
167 case EAF_TYPE_INT_SET:
170 case EAF_TYPE_EC_SET:
173 case EAF_TYPE_LC_SET:
177 cf_error("Can't empty that attribute");
180 struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
186 static inline struct f_inst *
187 f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
191 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
192 if ((t1->aux != T_INT) || (t2->aux != T_INT))
193 cf_error( "Can't operate with value of non-integer type in pair constructor");
195 check_u16(t1->a[1].i);
196 check_u16(t2->a[1].i);
198 rv = f_new_inst(FI_CONSTANT);
200 rv->a[1].i = pair(t1->a[1].i, t2->a[1].i);
203 rv = f_new_inst(FI_PAIR_CONSTRUCT);
211 static inline struct f_inst *
212 f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
215 int c1 = 0, c2 = 0, ipv4_used = 0;
216 u32 key = 0, val2 = 0;
218 if (tk->fi_code == FI_CONSTANT) {
221 if (tk->aux == T_INT) {
222 ipv4_used = 0; key = tk->a[1].i;
224 else if (tk->aux == T_QUAD) {
225 ipv4_used = 1; key = tk->a[1].i;
228 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
231 /* IP->Quad implicit conversion */
232 else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
234 struct f_val *val = tk->a[0].p;
236 if (val->type == T_INT) {
237 ipv4_used = 0; key = val->val.i;
239 else if (val->type == T_QUAD) {
240 ipv4_used = 1; key = val->val.i;
242 else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
243 ipv4_used = 1; key = ipa_to_u32(val->val.ip);
246 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
249 if (tv->fi_code == FI_CONSTANT) {
250 if (tv->aux != T_INT)
251 cf_error("Can't operate with value of non-integer type in EC constructor");
259 if (kind == EC_GENERIC) {
260 ec = ec_generic(key, val2);
262 else if (ipv4_used) {
264 ec = ec_ip4(kind, key, val2);
266 else if (key < 0x10000) {
267 ec = ec_as2(kind, key, val2);
271 ec = ec_as4(kind, key, val2);
275 rv = f_new_inst(FI_CONSTANT_INDIRECT);
281 rv = f_new_inst(FI_EC_CONSTRUCT);
290 static inline struct f_inst *
291 f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
295 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
296 if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
297 cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
299 rv = f_new_inst(FI_CONSTANT_INDIRECT);
304 val->val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i };
308 rv = f_new_inst(FI_LC_CONSTRUCT);
317 static inline struct f_inst *
318 f_generate_path_mask(struct f_path_mask *t)
320 for (struct f_path_mask *tt = t; tt; tt = tt->next) {
321 if (tt->kind == PM_ASN_EXPR) {
322 struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
329 val->type = T_PATH_MASK;
330 val->val.path_mask = t;
332 struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
339 * Remove all new lines and doubled whitespaces
340 * and convert all tabulators to spaces
341 * and return a copy of string
344 assert_copy_expr(const char *start, size_t len)
346 /* XXX: Allocates maybe a little more memory than we really finally need */
347 char *str = cfg_alloc(len + 1);
350 const char *src = start - 1;
351 const char *end = start + len;
357 /* Skip doubled whitespaces */
360 const char *prev = src - 1;
361 if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
378 * assert_done - create f_instruction of bt_assert
379 * @expr: expression in bt_assert()
380 * @start: pointer to first char of test expression
381 * @end: pointer to the last char of test expression
383 static struct f_inst *
384 assert_done(struct f_inst *expr, const char *start, const char *end)
387 i = f_new_inst(FI_ASSERT);
392 i->a[1].p = assert_copy_expr(start, end - start + 1);
396 /* this is a break of lexer buffer */
405 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
406 ACCEPT, REJECT, ERROR, QUITBIRD,
407 INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
408 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
409 IF, THEN, ELSE, CASE,
410 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
411 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
417 ADD, DELETE, CONTAINS, RESET,
418 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
420 FILTER, WHERE, EVAL, ATTRIBUTE,
421 BT_ASSERT, BT_TEST_SUITE, FORMAT)
426 %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
427 %type <fda> dynamic_attr
428 %type <fsa> static_attr
429 %type <f> filter filter_body where_filter
430 %type <i> type break_command ec_kind
432 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
433 %type <trie> fprefix_set
434 %type <v> set_atom switch_atom fipa
436 %type <s> decls declsn one_decl function_params
437 %type <h> bgp_path bgp_path_tail
438 %type <t> get_cf_position
444 FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
448 DBG( "We have new filter defined (%s)\n", $2->name );
455 EVAL term { f_eval_int($2); }
459 custom_attr: ATTRIBUTE type SYM ';' {
460 cf_define_symbol($3, SYM_ATTRIBUTE, ca_lookup(new_config->pool, $3->name, $2)->fda);
463 conf: bt_test_suite ;
465 BT_TEST_SUITE '(' SYM ',' text ')' {
466 if (!($3->class & SYM_FUNCTION))
467 cf_error("Function expected");
469 struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
471 t->fn_name = $3->name;
474 add_tail(&new_config->tests, &t->n);
480 | BOOL { $$ = T_BOOL; }
483 | PREFIX { $$ = T_NET; }
484 | PAIR { $$ = T_PAIR; }
485 | QUAD { $$ = T_QUAD; }
488 | STRING { $$ = T_STRING; }
489 | BGPMASK { $$ = T_PATH_MASK; }
490 | BGPPATH { $$ = T_PATH; }
491 | CLIST { $$ = T_CLIST; }
492 | ECLIST { $$ = T_ECLIST; }
493 | LCLIST { $$ = T_LCLIST; }
511 cf_error( "You can't create sets of this type." );
518 struct f_val * val = cfg_alloc(sizeof(struct f_val));
520 $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
521 DBG( "New variable %s type %x\n", $2->name, $1 );
527 /* Decls with ';' at the end */
528 decls: /* EMPTY */ { $$ = NULL; }
529 | one_decl ';' decls {
535 /* Declarations that have no ';' at the end. */
536 declsn: one_decl { $$ = $1; }
537 | one_decl ';' declsn {
545 struct filter *f = cfg_alloc(sizeof(struct filter));
554 if ($1->class != SYM_FILTER) cf_error("No such filter.");
562 /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
563 struct filter *f = cfg_alloc(sizeof(struct filter));
564 struct f_inst *i, *acc, *rej;
565 acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
567 acc->a[1].i = F_ACCEPT;
568 rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
570 rej->a[1].i = F_REJECT;
571 i = f_new_inst(FI_CONDITION); /* IF */
582 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
583 | '(' ')' { $$=NULL; }
589 /* Prepend instruction to clear local variables */
590 $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
600 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
601 $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
603 } function_params function_body {
606 DBG("Hmm, we've got one function here - %s\n", $2->name);
613 /* Hack: $$ of cmds_int is the last node.
614 $$->next of cmds_int is temporary used for the first node */
616 cmds: /* EMPTY */ { $$ = NULL; }
617 | cmds_int { $$ = $1->next; $1->next = NULL; }
620 cmds_int: cmd { $$ = $1; $1->next = $1; }
621 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
634 * Complex types, their bison value is struct f_val
637 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
638 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
644 * Set constants. They are also used in switch cases. We use separate
645 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
646 * to elude a collision between symbol (in expr) in set_atom and symbol
647 * as a function call in switch case cmds.
651 NUM { $$.type = T_INT; $$.val.i = $1; }
653 | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
654 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
656 if (f_eval($2, cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error");
657 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
660 if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
661 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
662 $$ = *(struct f_val *)($1->def);
667 NUM { $$.type = T_INT; $$.val.i = $1; }
668 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
670 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
674 term { $$ = f_eval_int($1); }
677 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
678 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
679 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
680 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
681 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
682 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
683 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
684 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
685 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
686 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
687 { $$ = f_new_pair_item($2, $8, $4, $10); }
693 | UNKNOWN NUM { $$ = $2; }
694 | GENERIC { $$ = EC_GENERIC; }
698 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
699 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
700 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
704 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
705 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
706 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
707 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
708 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
709 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
710 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
711 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
712 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
719 | set_atom { $$ = f_new_item($1, $1); }
720 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
727 | switch_atom { $$ = f_new_item($1, $1); }
728 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
733 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
738 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
742 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
743 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
744 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
745 | net_ip_ '{' NUM ',' NUM '}' {
746 $$.net = $1; $$.lo = $3; $$.hi = $5;
747 if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
748 cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
753 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
754 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
757 switch_body: /* EMPTY */ { $$ = NULL; }
758 | switch_body switch_items ':' cmds {
759 /* Fill data fields */
761 for (t = $2; t; t = t->left)
763 $$ = f_merge_items($1, $2);
765 | switch_body ELSECOL cmds {
766 struct f_tree *t = f_new_tree();
767 t->from.type = t->to.type = T_VOID;
770 $$ = f_merge_items($1, t);
774 /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $3; } */
778 | '(' term ')' { $$ = $2; }
782 PO bgp_path_tail PC { $$ = $2; }
786 NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
787 | NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
788 | '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
789 | '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
790 | bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
795 NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a[1].i = $1; }
796 | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 1; }
797 | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a[1].i = 0; }
798 | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a[1].p = $1; }
799 | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a[0].p = val; *val = $1; }
800 | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a[0].p = val; }
801 | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a[0].p = val; }
802 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a[1].p = build_tree($2); DBG( "ook\n" ); }
803 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a[1].p = $2; }
804 | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a[1].i = $1 & 0xffff; }
808 '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
809 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
810 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
811 | bgp_path { $$ = f_generate_path_mask($1); }
815 rtadot: /* EMPTY, we are not permitted RTA. prefix */
819 SYM '(' var_list ')' {
821 struct f_inst *inst = $3;
822 if ($1->class != SYM_FUNCTION)
823 cf_error("You can't call something which is not a function. Really.");
824 DBG("You are calling function %s\n", $1->name);
825 $$ = f_new_inst(FI_CALL);
827 $$->a[1].p = $1->def;
829 while (sym || inst) {
831 cf_error("Wrong number of arguments for function %s.", $1->name);
832 DBG( "You should pass parameter called %s\n", sym->name);
842 switch ($1->class & 0xffff) {
843 case SYM_CONSTANT_RANGE:
844 $$ = f_new_inst(FI_CONSTANT_INDIRECT);
846 case SYM_VARIABLE_RANGE:
847 $$ = f_new_inst(FI_VARIABLE);
849 $$->a[0].p = $1->def;
850 $$->a[1].p = $1->name;
853 $$ = f_new_inst_da(FI_EA_GET, *((struct f_dynamic_attr *) $1->def));
856 cf_error("%s: variable expected.", $1->name);
861 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
862 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
863 | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
864 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
865 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
866 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
867 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
868 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); }
869 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
873 '(' term ')' { $$ = $2; }
874 | term '+' term { $$ = f_new_inst(FI_ADD); $$->a[0].p = $1; $$->a[1].p = $3; }
875 | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a[0].p = $1; $$->a[1].p = $3; }
876 | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a[0].p = $1; $$->a[1].p = $3; }
877 | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a[0].p = $1; $$->a[1].p = $3; }
878 | term AND term { $$ = f_new_inst(FI_AND); $$->a[0].p = $1; $$->a[1].p = $3; }
879 | term OR term { $$ = f_new_inst(FI_OR); $$->a[0].p = $1; $$->a[1].p = $3; }
880 | term '=' term { $$ = f_new_inst(FI_EQ); $$->a[0].p = $1; $$->a[1].p = $3; }
881 | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a[0].p = $1; $$->a[1].p = $3; }
882 | term '<' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $1; $$->a[1].p = $3; }
883 | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $1; $$->a[1].p = $3; }
884 | term '>' term { $$ = f_new_inst(FI_LT); $$->a[0].p = $3; $$->a[1].p = $1; }
885 | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a[0].p = $3; $$->a[1].p = $1; }
886 | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a[0].p = $1; $$->a[1].p = $3; }
887 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a[0].p = $1; $$->a[1].p = $3; }
888 | '!' term { $$ = f_new_inst(FI_NOT); $$->a[0].p = $2; }
889 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a[0].p = $3; }
891 | symbol { $$ = $1; }
892 | constant { $$ = $1; }
893 | constructor { $$ = $1; }
895 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
897 | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
899 | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
901 | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a[0].p = $1; }
902 | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a[0].p = $1; }
903 | term '.' IP { $$ = f_new_inst(FI_IP); $$->a[0].p = $1; $$->aux = T_IP; }
904 | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a[0].p = $1; $$->aux = T_RD; }
905 | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a[0].p = $1; }
906 | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a[0].p = $1; }
907 | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a[0].p = $1; }
908 | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC); $$->a[0].p = $1; }
909 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a[0].p = $1; $$->a[1].p = $5; }
910 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a[0].p = $1; }
911 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a[0].p = $1; }
912 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a[0].p = $1; }
915 /* This causes one shift/reduce conflict
916 | rtadot dynamic_attr '.' ADD '(' term ')' { }
917 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
918 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
919 | rtadot dynamic_attr '.' RESET{ }
922 | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
923 | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
924 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
925 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
926 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a[0].p = $3; $$->a[1].p = $5; }
927 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'a'; }
928 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'd'; }
929 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a[0].p = $3; $$->a[1].p = $5; $$->aux = 'f'; }
931 | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
932 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
934 | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a[0].p = $3; }
936 /* | term '.' LEN { $$->code = P('P','l'); } */
938 /* function_call is inlined here */
939 | SYM '(' var_list ')' {
941 struct f_inst *inst = $3;
942 if ($1->class != SYM_FUNCTION)
943 cf_error("You can't call something which is not a function. Really.");
944 DBG("You are calling function %s\n", $1->name);
945 $$ = f_new_inst(FI_CALL);
947 $$->a[1].p = $1->def;
949 while (sym || inst) {
951 cf_error("Wrong number of arguments for function %s.", $1->name);
952 DBG( "You should pass parameter called %s\n", sym->name);
961 QUITBIRD { $$ = F_QUITBIRD; }
962 | ACCEPT { $$ = F_ACCEPT; }
963 | REJECT { $$ = F_REJECT; }
964 | ERROR { $$ = F_ERROR; }
965 | PRINT { $$ = F_NOP; }
966 | PRINTN { $$ = F_NONL; }
970 term { $$ = f_new_inst(FI_PRINT); $$->a[0].p = $1; $$->a[1].p = NULL; }
973 print_list: /* EMPTY */ { $$ = NULL; }
974 | print_one { $$ = $1; }
975 | print_one ',' print_list {
984 $$ = f_new_inst(FI_SET);
989 | term ',' var_listn {
990 $$ = f_new_inst(FI_SET);
997 var_list: /* EMPTY */ { $$ = NULL; }
998 | var_listn { $$ = $1; }
1002 IF term THEN block {
1003 $$ = f_new_inst(FI_CONDITION);
1007 | IF term THEN block ELSE block {
1008 $$ = f_new_inst(FI_CONDITION);
1013 | SYM '=' term ';' {
1014 DBG( "Ook, we'll set value\n" );
1015 if ($1->class == SYM_ATTRIBUTE) {
1016 $$ = f_new_inst_da(FI_EA_SET, *((struct f_dynamic_attr *) $1->def));
1018 } else if (($1->class & ~T_MASK) == SYM_VARIABLE) {
1019 $$ = f_new_inst(FI_SET);
1023 cf_error( "Symbol `%s' is read-only.", $1->name );
1026 DBG( "Ook, we'll return the value\n" );
1027 $$ = f_new_inst(FI_RETURN);
1030 | rtadot dynamic_attr '=' term ';' {
1031 $$ = f_new_inst_da(FI_EA_SET, $2);
1034 | rtadot static_attr '=' term ';' {
1035 $$ = f_new_inst_sa(FI_RTA_SET, $2);
1037 cf_error( "This static attribute is read-only.");
1040 | PREFERENCE '=' term ';' {
1041 $$ = f_new_inst(FI_PREF_SET);
1044 | UNSET '(' rtadot dynamic_attr ')' ';' {
1045 $$ = f_new_inst_da(FI_EA_SET, $4);
1046 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
1049 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a[0].p = $2; $$->a[1].i = $1; }
1050 | function_call ';' { $$ = $1; }
1051 | CASE term '{' switch_body '}' {
1052 $$ = f_new_inst(FI_SWITCH);
1054 $$->a[1].p = build_tree( $4 );
1057 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
1058 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
1059 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
1060 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
1061 | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
1062 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }