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)
45 static inline struct f_tree *
46 f_new_item(struct f_val from, struct f_val to)
48 struct f_tree *t = f_new_tree();
55 static inline struct f_tree *
56 f_merge_items(struct f_tree *a, struct f_tree *b)
65 static inline struct f_tree *
66 f_new_pair_item(int fa, int ta, int fb, int tb)
73 if ((ta < fa) || (tb < fb))
74 cf_error( "From value cannot be higher that To value in pair sets");
76 struct f_tree *t = f_new_tree();
78 t->from.type = t->to.type = T_PAIR;
79 t->from.val.i = pair(fa, fb);
80 t->to.val.i = pair(ta, tb);
84 static inline struct f_tree *
85 f_new_pair_set(int fa, int ta, int fb, int tb)
92 if ((ta < fa) || (tb < fb))
93 cf_error( "From value cannot be higher that To value in pair sets");
95 struct f_tree *lst = NULL;
98 for (i = fa; i <= ta; i++)
99 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
104 #define CC_ALL 0xFFFF
105 #define EC_ALL 0xFFFFFFFF
106 #define LC_ALL 0xFFFFFFFF
108 static struct f_tree *
109 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
113 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
121 if (kind == EC_GENERIC) {
122 fm = ec_generic(key, vf);
123 to = ec_generic(key, vt);
125 else if (ipv4_used) {
126 fm = ec_ip4(kind, key, vf);
127 to = ec_ip4(kind, key, vt);
129 else if (key < 0x10000) {
130 fm = ec_as2(kind, key, vf);
131 to = ec_as2(kind, key, vt);
134 fm = ec_as4(kind, key, vf);
135 to = ec_as4(kind, key, vt);
138 struct f_tree *t = f_new_tree();
140 t->from.type = t->to.type = T_EC;
146 static struct f_tree *
147 f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
149 struct f_tree *t = f_new_tree();
151 t->from.type = t->to.type = T_LC;
152 t->from.val.lc = (lcomm) {f1, f2, f3};
153 t->to.val.lc = (lcomm) {t1, t2, t3};
157 static inline struct f_inst *
158 f_generate_empty(struct f_dynamic_attr dyn)
160 struct f_inst *e = f_new_inst(FI_EMPTY);
162 switch (dyn.type & EAF_TYPE_MASK) {
163 case EAF_TYPE_AS_PATH:
166 case EAF_TYPE_INT_SET:
169 case EAF_TYPE_EC_SET:
172 case EAF_TYPE_LC_SET:
176 cf_error("Can't empty that attribute");
179 struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
185 static inline struct f_inst *
186 f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
190 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
191 if ((t1->aux != T_INT) || (t2->aux != T_INT))
192 cf_error( "Can't operate with value of non-integer type in pair constructor");
197 rv = f_new_inst(FI_CONSTANT);
199 rv->a2.i = pair(t1->a2.i, t2->a2.i);
202 rv = f_new_inst(FI_PAIR_CONSTRUCT);
210 static inline struct f_inst *
211 f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
214 int c1 = 0, c2 = 0, ipv4_used = 0;
215 u32 key = 0, val2 = 0;
217 if (tk->fi_code == FI_CONSTANT) {
220 if (tk->aux == T_INT) {
221 ipv4_used = 0; key = tk->a2.i;
223 else if (tk->aux == T_QUAD) {
224 ipv4_used = 1; key = tk->a2.i;
227 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->a1.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) {
243 ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
246 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
250 if (tv->fi_code == FI_CONSTANT) {
251 if (tv->aux != T_INT)
252 cf_error("Can't operate with value of non-integer type in EC constructor");
260 if (kind == EC_GENERIC) {
261 ec = ec_generic(key, val2);
263 else if (ipv4_used) {
265 ec = ec_ip4(kind, key, val2);
267 else if (key < 0x10000) {
268 ec = ec_as2(kind, key, val2);
272 ec = ec_as4(kind, key, val2);
276 rv = f_new_inst(FI_CONSTANT_INDIRECT);
282 rv = f_new_inst(FI_EC_CONSTRUCT);
291 static inline struct f_inst *
292 f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
296 if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
297 if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
298 cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
300 rv = f_new_inst(FI_CONSTANT_INDIRECT);
305 val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
309 rv = cfg_allocz(sizeof(struct f_inst3));
310 rv->lineno = ifs->lino;
311 rv->fi_code = FI_LC_CONSTRUCT;
320 static inline struct f_inst *
321 f_generate_path_mask(struct f_path_mask *t)
323 for (struct f_path_mask *tt = t; tt; tt = tt->next) {
324 if (tt->kind == PM_ASN_EXPR) {
325 struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
332 val->type = T_PATH_MASK;
333 val->val.path_mask = t;
335 struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
344 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
345 ACCEPT, REJECT, ERROR, QUITBIRD,
346 INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
347 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
348 IF, THEN, ELSE, CASE,
349 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
350 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
354 ADD, DELETE, CONTAINS, RESET,
355 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
363 %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
364 %type <fda> dynamic_attr
365 %type <fsa> static_attr
366 %type <f> filter filter_body where_filter
367 %type <i> type break_command ec_kind
369 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
370 %type <trie> fprefix_set
371 %type <v> set_atom switch_atom fprefix fprefix_s fipa
372 %type <s> decls declsn one_decl function_params
373 %type <h> bgp_path bgp_path_tail1 bgp_path_tail2
377 CF_ADDTO(conf, filter_def)
379 FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
383 DBG( "We have new filter defined (%s)\n", $2->name );
388 CF_ADDTO(conf, filter_eval)
390 EVAL term { f_eval_int($2); }
395 | BOOL { $$ = T_BOOL; }
397 | PREFIX { $$ = T_PREFIX; }
398 | PAIR { $$ = T_PAIR; }
399 | QUAD { $$ = T_QUAD; }
402 | STRING { $$ = T_STRING; }
403 | BGPMASK { $$ = T_PATH_MASK; }
404 | BGPPATH { $$ = T_PATH; }
405 | CLIST { $$ = T_CLIST; }
406 | ECLIST { $$ = T_ECLIST; }
407 | LCLIST { $$ = T_LCLIST; }
424 cf_error( "You can't create sets of this type." );
431 struct f_val * val = cfg_alloc(sizeof(struct f_val));
433 $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
434 DBG( "New variable %s type %x\n", $2->name, $1 );
440 /* Decls with ';' at the end */
441 decls: /* EMPTY */ { $$ = NULL; }
442 | one_decl ';' decls {
448 /* Declarations that have no ';' at the end. */
449 declsn: one_decl { $$ = $1; }
450 | one_decl ';' declsn {
458 struct filter *f = cfg_alloc(sizeof(struct filter));
467 if ($1->class != SYM_FILTER) cf_error("No such filter.");
475 /* Construct 'IF term THEN ACCEPT; REJECT;' */
476 struct filter *f = cfg_alloc(sizeof(struct filter));
477 struct f_inst *i, *acc, *rej;
478 acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
480 acc->a2.i = F_ACCEPT;
481 rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
483 rej->a2.i = F_REJECT;
484 i = f_new_inst(FI_CONDITION); /* IF */
495 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
496 | '(' ')' { $$=NULL; }
502 /* Prepend instruction to clear local variables */
503 $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
511 CF_ADDTO(conf, function_def)
513 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
514 $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
516 } function_params function_body {
519 DBG("Hmm, we've got one function here - %s\n", $2->name);
526 /* Hack: $$ of cmds_int is the last node.
527 $$->next of cmds_int is temporary used for the first node */
529 cmds: /* EMPTY */ { $$ = NULL; }
530 | cmds_int { $$ = $1->next; $1->next = NULL; }
533 cmds_int: cmd { $$ = $1; $1->next = $1; }
534 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
547 * Complex types, their bison value is struct f_val
550 IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
556 * Set constants. They are also used in switch cases. We use separate
557 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
558 * to elude a collision between symbol (in expr) in set_atom and symbol
559 * as a function call in switch case cmds.
563 NUM { $$.type = T_INT; $$.val.i = $1; }
564 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
566 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
568 $$ = f_eval($2, cfg_mem);
569 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
572 if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
573 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
574 $$ = *(struct f_val *)($1->def);
579 NUM { $$.type = T_INT; $$.val.i = $1; }
580 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
581 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
583 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
587 term { $$ = f_eval_int($1); }
590 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
591 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
592 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
593 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
594 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
595 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
596 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
597 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
598 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
599 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
600 { $$ = f_new_pair_item($2, $8, $4, $10); }
606 | UNKNOWN NUM { $$ = $2; }
607 | GENERIC { $$ = EC_GENERIC; }
611 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
612 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
613 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
617 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
618 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
619 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
620 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
621 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
622 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
623 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
624 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
625 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
632 | set_atom { $$ = f_new_item($1, $1); }
633 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
640 | switch_atom { $$ = f_new_item($1, $1); }
641 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
646 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
651 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
655 IPA '/' NUM %prec '/' {
656 if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
657 $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
662 fprefix_s { $$ = $1; }
663 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
664 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
665 | fprefix_s '{' NUM ',' NUM '}' {
666 if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
667 $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
672 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
673 | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
676 switch_body: /* EMPTY */ { $$ = NULL; }
677 | switch_body switch_items ':' cmds {
678 /* Fill data fields */
680 for (t = $2; t; t = t->left)
682 $$ = f_merge_items($1, $2);
684 | switch_body ELSECOL cmds {
685 struct f_tree *t = f_new_tree();
686 t->from.type = t->to.type = T_VOID;
689 $$ = f_merge_items($1, t);
693 /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
697 | '(' term ')' { $$ = $2; }
701 PO bgp_path_tail1 PC { $$ = $2; }
702 | '/' bgp_path_tail2 '/' { $$ = $2; }
706 NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
707 | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
708 | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
709 | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
710 | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
715 NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
716 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
721 NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
722 | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
723 | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
724 | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
725 | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
726 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
727 | RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; }
728 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
729 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
730 | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
734 '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
735 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
736 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
737 | bgp_path { $$ = f_generate_path_mask($1); }
742 * Maybe there are no dynamic attributes defined by protocols.
743 * For such cases, we force the dynamic_attr list to contain
744 * at least an invalid token, so it is syntantically correct.
746 CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
748 rtadot: /* EMPTY, we are not permitted RTA. prefix */
752 SYM '(' var_list ')' {
754 struct f_inst *inst = $3;
755 if ($1->class != SYM_FUNCTION)
756 cf_error("You can't call something which is not a function. Really.");
757 DBG("You are calling function %s\n", $1->name);
758 $$ = f_new_inst(FI_CALL);
762 while (sym || inst) {
764 cf_error("Wrong number of arguments for function %s.", $1->name);
765 DBG( "You should pass parameter called %s\n", sym->name);
775 switch ($1->class & 0xff00) {
776 case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
777 case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
778 default: cf_error("%s: variable expected.", $1->name);
786 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
787 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
788 | NET { $$ = f_new_static_attr(T_PREFIX, SA_NET, 0); }
789 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
790 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
791 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
792 | CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); }
793 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
794 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
795 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
799 '(' term ')' { $$ = $2; }
800 | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
801 | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
802 | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
803 | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
804 | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
805 | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
806 | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
807 | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
808 | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
809 | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
810 | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
811 | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
812 | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
813 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
814 | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; }
815 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
817 | symbol { $$ = $1; }
818 | constant { $$ = $1; }
819 | constructor { $$ = $1; }
821 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
823 | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
825 | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
827 | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
828 | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
829 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
830 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
831 | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
832 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
835 /* This causes one shift/reduce conflict
836 | rtadot dynamic_attr '.' ADD '(' term ')' { }
837 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
838 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
839 | rtadot dynamic_attr '.' RESET{ }
842 | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
843 | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
844 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
845 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
846 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
847 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
848 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
849 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
851 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
852 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
854 /* function_call is inlined here */
855 | SYM '(' var_list ')' {
857 struct f_inst *inst = $3;
858 if ($1->class != SYM_FUNCTION)
859 cf_error("You can't call something which is not a function. Really.");
860 DBG("You are calling function %s\n", $1->name);
861 $$ = f_new_inst(FI_CALL);
865 while (sym || inst) {
867 cf_error("Wrong number of arguments for function %s.", $1->name);
868 DBG( "You should pass parameter called %s\n", sym->name);
877 QUITBIRD { $$ = F_QUITBIRD; }
878 | ACCEPT { $$ = F_ACCEPT; }
879 | REJECT { $$ = F_REJECT; }
880 | ERROR { $$ = F_ERROR; }
881 | PRINT { $$ = F_NOP; }
882 | PRINTN { $$ = F_NONL; }
886 term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
889 print_list: /* EMPTY */ { $$ = NULL; }
890 | print_one { $$ = $1; }
891 | print_one ',' print_list {
900 $$ = f_new_inst(FI_SET);
905 | term ',' var_listn {
906 $$ = f_new_inst(FI_SET);
913 var_list: /* EMPTY */ { $$ = NULL; }
914 | var_listn { $$ = $1; }
919 $$ = f_new_inst(FI_CONDITION);
923 | IF term THEN block ELSE block {
924 struct f_inst *i = f_new_inst(FI_CONDITION);
927 $$ = f_new_inst(FI_CONDITION);
932 DBG( "Ook, we'll set value\n" );
933 if (($1->class & ~T_MASK) != SYM_VARIABLE)
934 cf_error( "You may set only variables." );
935 $$ = f_new_inst(FI_SET);
940 DBG( "Ook, we'll return the value\n" );
941 $$ = f_new_inst(FI_RETURN);
944 | rtadot dynamic_attr '=' term ';' {
945 $$ = f_new_inst_da(FI_EA_SET, $2);
948 | rtadot static_attr '=' term ';' {
949 $$ = f_new_inst_sa(FI_RTA_SET, $2);
951 cf_error( "This static attribute is read-only.");
954 | PREFERENCE '=' term ';' {
955 $$ = f_new_inst(FI_PREF_SET);
958 | UNSET '(' rtadot dynamic_attr ')' ';' {
959 $$ = f_new_inst_da(FI_EA_SET, $4);
960 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
963 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
964 | function_call ';' { $$ = $1; }
965 | CASE term '{' switch_body '}' {
966 $$ = f_new_inst(FI_SWITCH);
968 $$->a2.p = build_tree( $4 );
972 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
973 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
974 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
975 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
976 | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }