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 #define P(a,b) ((a << 8) | b)
17 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
18 static inline u32 pair_a(u32 p) { return p >> 16; }
19 static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
23 * Sets and their items are during parsing handled as lists, linked
24 * through left ptr. The first item in a list also contains a pointer
25 * to the last item in a list (right ptr). For convenience, even items
26 * are handled as one-item lists. Lists are merged by f_merge_items().
29 f_valid_set_type(int type)
47 static inline struct f_tree *
48 f_new_item(struct f_val from, struct f_val to)
50 struct f_tree *t = f_new_tree();
57 static inline struct f_tree *
58 f_merge_items(struct f_tree *a, struct f_tree *b)
67 static inline struct f_tree *
68 f_new_pair_item(int fa, int ta, int fb, int tb)
75 if ((ta < fa) || (tb < fb))
76 cf_error( "From value cannot be higher that To value in pair sets");
78 struct f_tree *t = f_new_tree();
80 t->from.type = t->to.type = T_PAIR;
81 t->from.val.i = pair(fa, fb);
82 t->to.val.i = pair(ta, tb);
86 static inline struct f_tree *
87 f_new_pair_set(int fa, int ta, int fb, int tb)
94 if ((ta < fa) || (tb < fb))
95 cf_error( "From value cannot be higher that To value in pair sets");
97 struct f_tree *lst = NULL;
100 for (i = fa; i <= ta; i++)
101 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
106 #define CC_ALL 0xFFFF
107 #define EC_ALL 0xFFFFFFFF
108 #define LC_ALL 0xFFFFFFFF
110 static struct f_tree *
111 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
115 if (ipv4_used || (key >= 0x10000)) {
123 if (kind == EC_GENERIC) {
124 fm = ec_generic(key, vf);
125 to = ec_generic(key, vt);
127 else if (ipv4_used) {
128 fm = ec_ip4(kind, key, vf);
129 to = ec_ip4(kind, key, vt);
131 else if (key < 0x10000) {
132 fm = ec_as2(kind, key, vf);
133 to = ec_as2(kind, key, vt);
136 fm = ec_as4(kind, key, vf);
137 to = ec_as4(kind, key, vt);
140 struct f_tree *t = f_new_tree();
142 t->from.type = t->to.type = T_EC;
148 static struct f_tree *
149 f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
151 struct f_tree *t = f_new_tree();
153 t->from.type = t->to.type = T_LC;
154 t->from.val.lc = (lcomm) {f1, f2, f3};
155 t->to.val.lc = (lcomm) {t1, t2, t3};
159 static inline struct f_inst *
160 f_generate_empty(struct f_inst *dyn)
162 struct f_inst *e = f_new_inst();
165 switch (dyn->aux & EAF_TYPE_MASK) {
166 case EAF_TYPE_AS_PATH:
169 case EAF_TYPE_INT_SET:
172 case EAF_TYPE_EC_SET:
175 case EAF_TYPE_LC_SET:
179 cf_error("Can't empty that attribute");
182 dyn->code = P('e','S');
188 static inline struct f_inst *
189 f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
193 if ((t1->code == 'c') && (t2->code == 'c')) {
194 if ((t1->aux != T_INT) || (t2->aux != T_INT))
195 cf_error( "Can't operate with value of non-integer type in pair constructor");
203 rv->a2.i = pair(t1->a2.i, t2->a2.i);
207 rv->code = P('m', 'p');
215 static inline struct f_inst *
216 f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
219 int c1 = 0, c2 = 0, ipv4_used = 0;
220 u32 key = 0, val2 = 0;
222 if (tk->code == 'c') {
225 if (tk->aux == T_INT) {
226 ipv4_used = 0; key = tk->a2.i;
228 else if (tk->aux == T_QUAD) {
229 ipv4_used = 1; key = tk->a2.i;
232 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
235 /* IP->Quad implicit conversion */
236 else if (tk->code == 'C') {
238 struct f_val *val = tk->a1.p;
240 if (val->type == T_INT) {
241 ipv4_used = 0; key = val->val.i;
243 else if (val->type == T_QUAD) {
244 ipv4_used = 1; key = val->val.i;
246 else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
247 ipv4_used = 1; key = ipa_to_u32(val->val.ip);
250 cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
253 if (tv->code == 'c') {
254 if (tv->aux != T_INT)
255 cf_error("Can't operate with value of non-integer type in EC constructor");
263 if (kind == EC_GENERIC) {
264 ec = ec_generic(key, val2);
266 else if (ipv4_used) {
268 ec = ec_ip4(kind, key, val2);
270 else if (key < 0x10000) {
271 ec = ec_as2(kind, key, val2);
275 ec = ec_as4(kind, key, val2);
287 rv->code = P('m','c');
296 static inline struct f_inst *
297 f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
301 if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) {
302 if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
303 cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
311 val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
315 rv = cfg_allocz(sizeof(struct f_inst3));
316 rv->lineno = ifs->lino;
317 rv->code = P('m','l');
327 * Remove all new lines and doubled whitespaces
328 * and convert all tabulators to spaces
329 * and return a copy of string
332 assert_copy_expr(const char *start, size_t len)
334 /* XXX: Allocates maybe a little more memory than we really finally need */
335 char *str = cfg_alloc(len + 1);
338 const char *src = start - 1;
339 const char *end = start + len;
345 /* Skip doubled whitespaces */
348 const char *prev = src - 1;
349 if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
366 * assert_done - create f_instruction of bt_assert
367 * @expr: expression in bt_assert()
368 * @start: pointer to first char of test expression
369 * @end: pointer to the last char of test expression
371 static struct f_inst *
372 assert_done(struct f_inst *expr, const char *start, const char *end)
376 i->code = P('a','s');
381 i->a2.p = assert_copy_expr(start, end - start + 1);
385 /* this is a break of lexer buffer */
394 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
395 ACCEPT, REJECT, ERROR, QUITBIRD,
396 INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
397 SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
398 IF, THEN, ELSE, CASE,
399 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
400 FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
405 ADD, DELETE, CONTAINS, RESET,
406 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
409 BT_ASSERT, BT_TEST_SUITE)
414 %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr bt_assert
415 %type <f> filter filter_body where_filter
416 %type <i> type break_command ec_kind
418 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
419 %type <trie> fprefix_set
420 %type <v> set_atom switch_atom fipa
422 %type <s> decls declsn one_decl function_params
423 %type <h> bgp_path bgp_path_tail1 bgp_path_tail2
424 %type <t> get_cf_position
428 CF_ADDTO(conf, filter_def)
430 FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
434 DBG( "We have new filter defined (%s)\n", $2->name );
439 CF_ADDTO(conf, filter_eval)
441 EVAL term { f_eval_int($2); }
444 CF_ADDTO(conf, bt_test_suite)
446 BT_TEST_SUITE '(' SYM ',' text ')' {
447 if (!($3->class & SYM_FUNCTION))
448 cf_error("Function expected");
450 struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
452 t->fn_name = $3->name;
455 add_tail(&new_config->tests, &t->n);
461 | BOOL { $$ = T_BOOL; }
463 | PREFIX { $$ = T_NET; }
464 | PAIR { $$ = T_PAIR; }
465 | QUAD { $$ = T_QUAD; }
468 | STRING { $$ = T_STRING; }
469 | BGPMASK { $$ = T_PATH_MASK; }
470 | BGPPATH { $$ = T_PATH; }
471 | CLIST { $$ = T_CLIST; }
472 | ECLIST { $$ = T_ECLIST; }
473 | LCLIST { $$ = T_LCLIST; }
490 cf_error( "You can't create sets of this type." );
497 struct f_val * val = cfg_alloc(sizeof(struct f_val));
499 $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
500 DBG( "New variable %s type %x\n", $2->name, $1 );
506 /* Decls with ';' at the end */
507 decls: /* EMPTY */ { $$ = NULL; }
508 | one_decl ';' decls {
514 /* Declarations that have no ';' at the end. */
515 declsn: one_decl { $$ = $1; }
516 | one_decl ';' declsn {
524 struct filter *f = cfg_alloc(sizeof(struct filter));
533 if ($1->class != SYM_FILTER) cf_error("No such filter.");
541 /* Construct 'IF term THEN ACCEPT; REJECT;' */
542 struct filter *f = cfg_alloc(sizeof(struct filter));
543 struct f_inst *i, *acc, *rej;
544 acc = f_new_inst(); /* ACCEPT */
545 acc->code = P('p',',');
547 acc->a2.i = F_ACCEPT;
548 rej = f_new_inst(); /* REJECT */
549 rej->code = P('p',',');
551 rej->a2.i = F_REJECT;
552 i = f_new_inst(); /* IF */
564 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
565 | '(' ')' { $$=NULL; }
571 /* Prepend instruction to clear local variables */
573 $$->code = P('c','v');
581 CF_ADDTO(conf, function_def)
583 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
584 $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
586 } function_params function_body {
589 DBG("Hmm, we've got one function here - %s\n", $2->name);
596 /* Hack: $$ of cmds_int is the last node.
597 $$->next of cmds_int is temporary used for the first node */
599 cmds: /* EMPTY */ { $$ = NULL; }
600 | cmds_int { $$ = $1->next; $1->next = NULL; }
603 cmds_int: cmd { $$ = $1; $1->next = $1; }
604 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
617 * Complex types, their bison value is struct f_val
620 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
621 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
627 * Set constants. They are also used in switch cases. We use separate
628 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
629 * to elude a collision between symbol (in expr) in set_atom and symbol
630 * as a function call in switch case cmds.
634 NUM { $$.type = T_INT; $$.val.i = $1; }
636 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
638 $$ = f_eval($2, cfg_mem);
639 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
642 if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
643 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
644 $$ = *(struct f_val *)($1->def);
649 NUM { $$.type = T_INT; $$.val.i = $1; }
650 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
652 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
656 term { $$ = f_eval_int($1); }
659 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
660 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
661 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
662 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
663 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
664 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
665 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
666 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
667 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
668 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
669 { $$ = f_new_pair_item($2, $8, $4, $10); }
675 | UNKNOWN NUM { $$ = $2; }
676 | GENERIC { $$ = EC_GENERIC; }
680 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
681 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
682 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
686 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
687 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
688 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
689 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
690 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
691 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
692 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
693 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
694 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
701 | set_atom { $$ = f_new_item($1, $1); }
702 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
709 | switch_atom { $$ = f_new_item($1, $1); }
710 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
715 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
720 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
724 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
725 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
726 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
727 | net_ip_ '{' NUM ',' NUM '}' {
728 $$.net = $1; $$.lo = $3; $$.hi = $5;
729 if ((0 > $3) || ($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
730 cf_error("Invalid prefix pattern range: {%d, %d}", $3, $5);
735 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
736 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
739 switch_body: /* EMPTY */ { $$ = NULL; }
740 | switch_body switch_items ':' cmds {
741 /* Fill data fields */
743 for (t = $2; t; t = t->left)
745 $$ = f_merge_items($1, $2);
747 | switch_body ELSECOL cmds {
748 struct f_tree *t = f_new_tree();
749 t->from.type = t->to.type = T_VOID;
752 $$ = f_merge_items($1, t);
756 /* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
760 | '(' term ')' { $$ = $2; }
764 PO bgp_path_tail1 PC { $$ = $2; }
765 | '/' bgp_path_tail2 '/' { $$ = $2; }
769 NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
770 | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
771 | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
772 | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
773 | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
778 NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
779 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
784 NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
785 | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
786 | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
787 | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
788 | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
789 | net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
790 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
791 | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
792 | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
793 | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
797 '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
798 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
799 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
804 * Maybe there are no dynamic attributes defined by protocols.
805 * For such cases, we force the dynamic_attr list to contain
806 * at least an invalid token, so it is syntantically correct.
808 CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
810 rtadot: /* EMPTY, we are not permitted RTA. prefix */
814 SYM '(' var_list ')' {
816 struct f_inst *inst = $3;
817 if ($1->class != SYM_FUNCTION)
818 cf_error("You can't call something which is not a function. Really.");
819 DBG("You are calling function %s\n", $1->name);
821 $$->code = P('c','a');
825 while (sym || inst) {
827 cf_error("Wrong number of arguments for function %s.", $1->name);
828 DBG( "You should pass parameter called %s\n", sym->name);
840 switch ($1->class & 0xff00) {
841 case SYM_CONSTANT: $$->code = 'C'; break;
842 case SYM_VARIABLE: $$->code = 'V'; break;
843 default: cf_error("%s: variable expected.", $1->name);
851 FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; }
852 | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; }
853 | NET { $$ = f_new_inst(); $$->aux = T_NET; $$->a2.i = SA_NET; }
854 | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
855 | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
856 | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
857 | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; }
858 | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
859 | IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
860 | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
864 '(' term ')' { $$ = $2; }
865 | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
866 | term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; }
867 | term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; }
868 | term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; }
869 | term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; }
870 | term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; }
871 | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
872 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
873 | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
874 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
875 | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
876 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
877 | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
878 | term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; }
879 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
880 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
882 | symbol { $$ = $1; }
883 | constant { $$ = $1; }
884 | constructor { $$ = $1; }
886 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
888 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
890 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
892 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
893 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
894 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
895 | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
896 | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
897 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
900 /* This causes one shift/reduce conflict
901 | rtadot dynamic_attr '.' ADD '(' term ')' { }
902 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
903 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
904 | rtadot dynamic_attr '.' RESET{ }
907 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
908 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
909 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
910 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
911 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
912 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
913 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
914 | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
916 | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
917 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
919 | bt_assert { $$ = $1; }
921 /* | term '.' LEN { $$->code = P('P','l'); } */
923 /* function_call is inlined here */
924 | SYM '(' var_list ')' {
926 struct f_inst *inst = $3;
927 if ($1->class != SYM_FUNCTION)
928 cf_error("You can't call something which is not a function. Really.");
929 DBG("You are calling function %s\n", $1->name);
931 $$->code = P('c','a');
935 while (sym || inst) {
937 cf_error("Wrong number of arguments for function %s.", $1->name);
938 DBG( "You should pass parameter called %s\n", sym->name);
947 QUITBIRD { $$ = F_QUITBIRD; }
948 | ACCEPT { $$ = F_ACCEPT; }
949 | REJECT { $$ = F_REJECT; }
950 | ERROR { $$ = F_ERROR; }
951 | PRINT { $$ = F_NOP; }
952 | PRINTN { $$ = F_NONL; }
956 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
959 print_list: /* EMPTY */ { $$ = NULL; }
960 | print_one { $$ = $1; }
961 | print_one ',' print_list {
976 | term ',' var_listn {
985 var_list: /* EMPTY */ { $$ = NULL; }
986 | var_listn { $$ = $1; }
996 | IF term THEN block ELSE block {
997 struct f_inst *i = f_new_inst();
1006 | SYM '=' term ';' {
1008 DBG( "Ook, we'll set value\n" );
1009 if (($1->class & ~T_MASK) != SYM_VARIABLE)
1010 cf_error( "You may set only variables." );
1017 DBG( "Ook, we'll return the value\n" );
1021 | rtadot dynamic_attr '=' term ';' {
1023 $$->code = P('e','S');
1026 | rtadot static_attr '=' term ';' {
1029 cf_error( "This static attribute is read-only.");
1030 $$->code = P('a','S');
1033 | PREFERENCE '=' term ';' {
1035 $$->code = P('P','S');
1038 | UNSET '(' rtadot dynamic_attr ')' ';' {
1040 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
1041 $$->code = P('e','S');
1044 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
1045 | function_call ';' { $$ = $1; }
1046 | CASE term '{' switch_body '}' {
1048 $$->code = P('S','W');
1050 $$->a2.p = build_tree( $4 );
1052 | bt_assert ';' { $$ = $1; }
1055 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
1056 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
1057 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
1058 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
1059 | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
1063 BT_ASSERT '(' get_cf_position term get_cf_position ')' { $$ = assert_done($4, $3 + 1, $5 - 1); }