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
13 #include "filter/f-inst.h"
14 #include "filter/data.h"
18 static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
19 static inline u32 pair_a(u32 p) { return p >> 16; }
20 static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
22 static struct symbol *this_function;
24 static struct f_method_scope {
25 struct f_inst *object;
26 struct sym_scope *main;
27 struct sym_scope scope;
28 } f_method_scope_stack[32];
29 static int f_method_scope_pos = -1;
31 #define FM (f_method_scope_stack[f_method_scope_pos])
33 static inline void f_method_call_start(struct f_inst *object)
35 if (object->type == T_VOID)
36 cf_error("Can't infer type to properly call a method, please assign the value to a variable");
37 if (++f_method_scope_pos >= (int) ARRAY_SIZE(f_method_scope_stack))
38 cf_error("Too many nested method calls");
40 struct sym_scope *scope = f_type_method_scope(object->type);
42 cf_error("No methods defined for type %s", f_type_name(object->type));
44 FM = (struct f_method_scope) {
46 .main = new_config->current_scope,
55 new_config->current_scope = &FM.scope;
58 static inline void f_method_call_args(void)
60 ASSERT_DIE(FM.scope.active);
63 new_config->current_scope = FM.main;
66 static inline void f_method_call_end(void)
68 ASSERT_DIE(f_method_scope_pos >= 0);
69 if (FM.scope.active) {
70 ASSERT_DIE(&FM.scope == new_config->current_scope);
71 new_config->current_scope = FM.main;
80 f_new_var(struct sym_scope *s)
83 * - A variable is an offset on vstack from vbase.
84 * - Vbase is set on filter start / function call.
85 * - Scopes contain (non-frame) block scopes inside filter/function scope
86 * - Each scope knows number of vars in that scope
87 * - Offset is therefore a sum of 'slots' up to filter/function scope
88 * - New variables are added on top of vstk, so intermediate values cannot
89 * be there during FI_VAR_INIT. I.e. no 'var' inside 'term'.
90 * - Also, each f_line must always have its scope, otherwise a variable may
91 * be defined but not initialized if relevant f_line is not executed.
94 int offset = s->slots++;
104 cf_error("Too many variables, at most 255 allowed");
110 * Sets and their items are during parsing handled as lists, linked
111 * through left ptr. The first item in a list also contains a pointer
112 * to the last item in a list (right ptr). For convenience, even items
113 * are handled as one-item lists. Lists are merged by f_merge_items().
116 f_valid_set_type(int type)
135 static inline struct f_tree *
136 f_new_item(struct f_val from, struct f_val to)
138 struct f_tree *t = f_new_tree();
145 static inline struct f_tree *
146 f_merge_items(struct f_tree *a, struct f_tree *b)
155 static inline struct f_tree *
156 f_new_pair_item(int fa, int ta, int fb, int tb)
163 if ((ta < fa) || (tb < fb))
164 cf_error( "From value cannot be higher that To value in pair sets");
166 struct f_tree *t = f_new_tree();
168 t->from.type = t->to.type = T_PAIR;
169 t->from.val.i = pair(fa, fb);
170 t->to.val.i = pair(ta, tb);
174 static inline struct f_tree *
175 f_new_pair_set(int fa, int ta, int fb, int tb)
182 if ((ta < fa) || (tb < fb))
183 cf_error( "From value cannot be higher that To value in pair sets");
185 struct f_tree *lst = NULL;
188 for (i = fa; i <= ta; i++)
189 lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
194 #define CC_ALL 0xFFFF
195 #define EC_ALL 0xFFFFFFFF
196 #define LC_ALL 0xFFFFFFFF
198 static struct f_tree *
199 f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
203 if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
211 if (kind == EC_GENERIC) {
212 fm = ec_generic(key, vf);
213 to = ec_generic(key, vt);
215 else if (ipv4_used) {
216 fm = ec_ip4(kind, key, vf);
217 to = ec_ip4(kind, key, vt);
219 else if (key < 0x10000) {
220 fm = ec_as2(kind, key, vf);
221 to = ec_as2(kind, key, vt);
224 fm = ec_as4(kind, key, vf);
225 to = ec_as4(kind, key, vt);
228 struct f_tree *t = f_new_tree();
230 t->from.type = t->to.type = T_EC;
236 static struct f_tree *
237 f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
239 struct f_tree *t = f_new_tree();
241 t->from.type = t->to.type = T_LC;
242 t->from.val.lc = (lcomm) {f1, f2, f3};
243 t->to.val.lc = (lcomm) {t1, t2, t3};
247 static inline struct f_inst *
248 f_const_empty(enum f_type t)
255 return f_new_inst(FI_CONSTANT, (struct f_val) {
257 .val.ad = &null_adata,
260 return f_new_inst(FI_CONSTANT, (struct f_val) {});
265 * Remove all new lines and doubled whitespaces
266 * and convert all tabulators to spaces
267 * and return a copy of string
270 assert_copy_expr(const char *start, size_t len)
272 /* XXX: Allocates maybe a little more memory than we really finally need */
273 char *str = cfg_alloc(len + 1);
276 const char *src = start - 1;
277 const char *end = start + len;
283 /* Skip doubled whitespaces */
286 const char *prev = src - 1;
287 if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
304 * assert_done - create f_instruction of bt_assert
305 * @expr: expression in bt_assert()
306 * @start: pointer to first char of test expression
307 * @end: pointer to the last char of test expression
309 static struct f_inst *
310 assert_done(struct f_inst *expr, const char *start, const char *end)
312 return f_new_inst(FI_ASSERT, expr,
314 assert_copy_expr(start, end - start + 1)
318 static struct f_inst *
319 f_lval_getter(struct f_lval *lval)
321 switch (lval->type) {
322 case F_LVAL_VARIABLE: return f_new_inst(FI_VAR_GET, lval->sym);
323 case F_LVAL_SA: return f_new_inst(FI_RTA_GET, lval->sa);
324 case F_LVAL_EA: return f_new_inst(FI_EA_GET, lval->da);
325 default: bug("Unknown lval type");
329 static struct f_inst *
330 f_lval_setter(struct f_lval *lval, struct f_inst *expr)
332 switch (lval->type) {
333 case F_LVAL_VARIABLE: return f_new_inst(FI_VAR_SET, expr, lval->sym);
334 case F_LVAL_SA: return f_new_inst(FI_RTA_SET, expr, lval->sa);
335 case F_LVAL_EA: return f_new_inst(FI_EA_SET, expr, lval->da);
336 default: bug("Unknown lval type");
340 static struct f_inst *
341 assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end)
343 struct f_inst *setter = f_lval_setter(lval, expr),
344 *getter = f_lval_getter(lval);
346 struct f_inst *checker = f_new_inst(FI_EQ, expr, getter);
347 setter->next = checker;
349 return assert_done(setter, start, end);
354 CF_KEYWORDS_EXCLUSIVE(IN)
355 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
356 ACCEPT, REJECT, ERROR,
357 INT, BOOL, IP, PREFIX, RD, PAIR, QUAD, EC, LC,
358 SET, STRING, BYTESTRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
359 IF, THEN, ELSE, CASE,
361 TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
362 FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ONLINK,
369 FILTER, WHERE, EVAL, ATTRIBUTE,
371 BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
376 %type <xp> cmds_int cmd_prep
377 %type <x> term term_bs cmd cmd_var cmds cmds_scoped constant constructor var var_list var_list_r function_call symbol_value bgp_path_expr bgp_path bgp_path_tail term_dot_method method_name_cont
378 %type <fda> dynamic_attr
379 %type <fsa> static_attr
380 %type <f> filter where_filter
381 %type <fl> filter_body function_body
383 %type <i> type function_vars function_type
384 %type <fa> function_argsn function_args
386 %type <fret> break_command
388 %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
389 %type <trie> fprefix_set
390 %type <v> set_atom switch_atom fipa
392 %type <t> get_cf_position
400 $2 = cf_define_symbol(new_config, $2, SYM_FILTER, filter, NULL);
401 cf_push_scope( new_config, $2 );
402 this_function = NULL;
404 struct filter *f = cfg_alloc(sizeof(struct filter));
405 *f = (struct filter) { .sym = $2, .root = $4 };
408 cf_pop_scope(new_config);
414 EVAL term { cf_eval_int($2); }
418 custom_attr: ATTRIBUTE type symbol ';' {
419 cf_define_symbol(new_config, $3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda);
422 conf: bt_test_suite ;
424 BT_TEST_SUITE '(' symbol_known ',' text ')' {
425 cf_assert_symbol($3, SYM_FUNCTION);
426 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
427 t->fn = $3->function;
428 t->fn_name = $3->name;
431 add_tail(&new_config->tests, &t->n);
437 BT_TEST_SAME '(' symbol_known ',' symbol_known ',' NUM ')' {
438 cf_assert_symbol($3, SYM_FUNCTION);
439 cf_assert_symbol($5, SYM_FUNCTION);
440 struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite));
441 t->fn = $3->function;
442 t->cmp = $5->function;
444 t->fn_name = $3->name;
446 add_tail(&new_config->tests, &t->n);
452 | BOOL { $$ = T_BOOL; }
455 | PREFIX { $$ = T_NET; }
456 | PAIR { $$ = T_PAIR; }
457 | QUAD { $$ = T_QUAD; }
460 | STRING { $$ = T_STRING; }
461 | BYTESTRING { $$ = T_BYTESTRING; }
462 | BGPMASK { $$ = T_PATH_MASK; }
463 | BGPPATH { $$ = T_PATH; }
464 | CLIST { $$ = T_CLIST; }
465 | ECLIST { $$ = T_ECLIST; }
466 | LCLIST { $$ = T_LCLIST; }
484 cf_error( "You can't create sets of this type." );
490 /* EMPTY */ { $$ = NULL; }
491 | function_argsn type symbol ';' {
492 if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed");
493 $$ = cfg_alloc(sizeof(struct f_arg));
494 $$->arg = cf_define_symbol(new_config, $3, SYM_VARIABLE | $2, offset, sym_->scope->slots++);
500 '(' ')' { $$ = NULL; }
501 | '(' function_argsn type symbol ')' {
502 $$ = cfg_alloc(sizeof(struct f_arg));
503 $$->arg = cf_define_symbol(new_config, $4, SYM_VARIABLE | $3, offset, sym_->scope->slots++);
509 /* EMPTY */ { $$ = 0; }
510 | function_vars type symbol ';' {
511 cf_define_symbol(new_config, $3, SYM_VARIABLE | $2, offset, f_new_var(sym_->scope));
517 /* EMPTY */ { $$ = T_VOID; }
518 | IMP type { $$ = $2; }
521 filter_body: function_body ;
525 cf_assert_symbol($1, SYM_FILTER);
529 cf_push_scope(new_config, NULL);
530 this_function = NULL;
532 struct filter *f = cfg_alloc(sizeof(struct filter));
533 *f = (struct filter) { .root = $2 };
536 cf_pop_scope(new_config);
542 /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */
543 $$ = f_new_where($2);
548 function_vars '{' cmds '}' {
549 $$ = f_linearize($3, 0);
558 DBG( "Beginning of function %s\n", $2->name );
559 this_function = cf_define_symbol(new_config, $2, SYM_FUNCTION, function, NULL);
560 cf_push_scope(new_config, this_function);
561 } function_args function_type {
562 /* Make dummy f_line for storing function prototype */
563 struct f_line *dummy = cfg_allocz(sizeof(struct f_line));
564 this_function->function = dummy;
566 dummy->return_type = $5;
568 /* Revert the args */
570 struct f_arg *tmp = $4;
573 tmp->next = dummy->arg_list;
574 dummy->arg_list = tmp;
578 $7->args = this_function->function->args;
579 $7->arg_list = this_function->function->arg_list;
580 $7->return_type = this_function->function->return_type;
582 cf_pop_scope(new_config);
588 cmds: /* EMPTY */ { $$ = NULL; }
589 | cmds_int { $$ = $1.begin; }
592 cmds_scoped: { cf_push_soft_scope(new_config); } cmds { cf_pop_soft_scope(new_config); $$ = $2; } ;
597 $$.begin = $$.end = $1;
600 $$.end = $$.end->next;
605 | cmds_int cmd_prep {
613 $1.end->next = $2.begin;
619 * Complex types, their bison value is struct f_val
622 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
623 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
629 * Set constants. They are also used in switch cases. We use separate
630 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
631 * to elude a collision between symbol (in expr) in set_atom and symbol
632 * as a function call in switch case cmds.
636 NUM { $$.type = T_INT; $$.val.i = $1; }
638 | VPN_RD { $$.type = T_RD; $$.val.ec = $1; }
639 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
641 $$ = cf_eval($2, T_VOID);
642 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
645 cf_assert_symbol($1, SYM_CONSTANT);
646 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
652 NUM { $$.type = T_INT; $$.val.i = $1; }
653 | '(' term ')' { $$ = cf_eval($2, T_INT); }
655 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
659 term { $$ = cf_eval_int($1); }
662 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
663 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
664 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
665 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
666 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
667 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
668 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
669 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
670 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
671 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
672 { $$ = f_new_pair_item($2, $8, $4, $10); }
678 | UNKNOWN NUM { $$ = $2; }
679 | GENERIC { $$ = EC_GENERIC; }
683 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
684 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
685 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
689 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
690 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
691 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
692 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
693 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
694 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
695 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
696 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
697 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
704 | set_atom { $$ = f_new_item($1, $1); }
705 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
712 | switch_atom { $$ = f_new_item($1, $1); }
713 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
718 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
723 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
727 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
728 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
729 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
730 | net_ip_ '{' NUM ',' NUM '}' {
731 $$.net = $1; $$.lo = $3; $$.hi = $5;
732 if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
733 cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
738 fprefix { $$ = f_new_trie(cfg_mem, 0); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
739 | fprefix_set ',' fprefix { $$ = $1; if (!trie_add_prefix($$, &($3.net), $3.lo, $3.hi)) cf_error("Mixed IPv4/IPv6 prefixes in prefix set"); }
742 switch_body: /* EMPTY */ { $$ = NULL; }
743 | switch_body switch_items ':' cmds_scoped {
744 /* Fill data fields */
746 for (t = $2; t; t = t->left)
748 $$ = f_merge_items($1, $2);
750 | switch_body ELSECOL cmds_scoped {
751 struct f_tree *t = f_new_tree();
752 t->from.type = t->to.type = T_VOID;
755 $$ = f_merge_items($1, t);
760 symbol_value { $$ = $1; }
761 | '(' term ')' { $$ = $2; }
765 PO bgp_path_tail PC { $$ = $2; }
769 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; }
770 | 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; }
771 | '[' ']' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .set = NULL, .kind = PM_ASN_SET }, }); $$->next = $3; }
772 | '[' set_items ']' bgp_path_tail {
773 if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask");
774 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .set = build_tree($2), .kind = PM_ASN_SET }, }); $$->next = $4;
776 | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
777 | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
778 | '+' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; }
779 | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
784 NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); }
785 | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); }
786 | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); }
787 | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); }
788 | BYTETEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BYTESTRING, .val.bs = $1, }); }
789 | fipa { $$ = f_new_inst(FI_CONSTANT, $1); }
790 | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); }
791 | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); }
792 | '[' ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = NULL, }); }
793 | '[' set_items ']' {
794 DBG( "We've got a set here..." );
795 $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), });
798 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); }
799 | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); }
803 '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); }
804 | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); }
805 | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); }
806 | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); }
810 /* This generates the function_call variable list backwards */
812 /* EMPTY */ { $$ = NULL; }
814 | var_list_r ',' term { $$ = $3; $$->next = $1; }
821 /* Revert the var_list_r */
823 struct f_inst *tmp = $1;
833 symbol_known '(' var_list ')'
835 if ($1->class != SYM_FUNCTION)
836 cf_error("You can't call something which is not a function. Really.");
838 $$ = f_new_inst(FI_CALL, $3, $1);
842 symbol_value: symbol_known
845 case SYM_CONSTANT_RANGE:
846 $$ = f_new_inst(FI_CONSTANT, *($1->val));
848 case SYM_VARIABLE_RANGE:
849 $$ = f_new_inst(FI_VAR_GET, $1);
852 $$ = f_new_inst(FI_EA_GET, *$1->attribute);
855 cf_error("Can't get value of symbol %s", $1->name);
861 FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); }
862 | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); }
863 | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); }
864 | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); }
865 | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); }
866 | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); }
867 | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
868 | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
869 | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
870 | WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
871 | PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); }
872 | GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
873 | ONLINK { $$ = f_new_static_attr(T_BOOL, SA_ONLINK, 0); }
876 term_dot_method: term '.' { f_method_call_start($1); } method_name_cont { f_method_call_end(); $$ = $4; };
879 $$ = f_dispatch_method($1, FM.object, NULL, 1);
881 | CF_SYM_METHOD_ARGS {
882 f_method_call_args();
884 $$ = f_dispatch_method($1, FM.object, $4, 1);
889 '(' term ')' { $$ = $2; }
890 | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); }
891 | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); }
892 | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); }
893 | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); }
894 | term AND term { $$ = f_new_inst(FI_AND, $1, $3); }
895 | term OR term { $$ = f_new_inst(FI_OR, $1, $3); }
896 | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); }
897 | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); }
898 | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); }
899 | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); }
900 | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); }
901 | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); }
902 | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); }
903 | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); }
904 | '!' term { $$ = f_new_inst(FI_NOT, $2); }
905 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); }
907 | symbol_value { $$ = $1; }
908 | constant { $$ = $1; }
909 | constructor { $$ = $1; }
911 | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); }
913 | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); }
917 | '+' EMPTY '+' { $$ = f_const_empty(T_PATH); }
918 | '-' EMPTY '-' { $$ = f_const_empty(T_CLIST); }
919 | '-' '-' EMPTY '-' '-' { $$ = f_const_empty(T_ECLIST); }
920 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_const_empty(T_LCLIST); }
921 | PREPEND '(' term ',' term ')' { $$ = f_dispatch_method_x("prepend", $3->type, $3, $5); }
922 | ADD '(' term ',' term ')' { $$ = f_dispatch_method_x("add", $3->type, $3, $5); }
923 | DELETE '(' term ',' term ')' { $$ = f_dispatch_method_x("delete", $3->type, $3, $5); }
924 | FILTER '(' term ',' term ')' { $$ = f_dispatch_method_x("filter", $3->type, $3, $5); }
926 | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
927 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
929 | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
936 FROM_HEX '(' term ')' { $$ = f_new_inst(FI_FROM_HEX, $3); }
940 ACCEPT { $$ = F_ACCEPT; }
941 | REJECT { $$ = F_REJECT; }
942 | ERROR { $$ = F_ERROR; }
946 type symbol '=' term ';' {
947 struct symbol *sym = cf_define_symbol(new_config, $2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope));
948 $$ = f_new_inst(FI_VAR_INIT, $4, sym);
951 struct symbol *sym = cf_define_symbol(new_config, $2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope));
952 $$ = f_new_inst(FI_VAR_INIT0, sym);
957 type symbol { $$ = cf_define_symbol(new_config, $2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope)); }
958 | CF_SYM_KNOWN { $$ = $1; cf_assert_symbol($1, SYM_VARIABLE); }
962 '{' cmds_scoped '}' {
966 $$ = f_new_inst(FI_CONDITION, $2, $4, NULL);
968 | IF term THEN cmd ELSE cmd {
969 $$ = f_new_inst(FI_CONDITION, $2, $4, $6);
972 /* Reserve space for walk data on stack */
973 cf_push_block_scope(new_config);
974 new_config->current_scope->slots += 2;
976 /* Parse term in the parent scope */
977 { new_config->current_scope->active = 0; } term { new_config->current_scope->active = 1; }
979 cf_pop_block_scope(new_config);
980 $$ = f_for_cycle($3, $6, $9);
982 | symbol_known '=' term ';' {
984 case SYM_VARIABLE_RANGE:
985 $$ = f_new_inst(FI_VAR_SET, $3, $1);
988 $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute);
991 cf_error("Can't assign to symbol %s", $1->name);
995 DBG( "Ook, we'll return the value\n" );
997 cf_error("Can't return from a non-function, use accept or reject instead.");
998 if (this_function->function->return_type == T_VOID)
1000 if ($2->type != T_VOID)
1001 cf_warn("Inferring function %s return type from its return value: %s", this_function->name, f_type_name($2->type));
1002 ((struct f_line *) this_function->function)->return_type = $2->type;
1004 else if (this_function->function->return_type != $2->type)
1005 cf_error("Can't return type %s from function %s, expected %s",
1006 f_type_name($2->type), this_function->name, f_type_name(this_function->function->return_type));
1008 $$ = f_new_inst(FI_RETURN, $2);
1010 | dynamic_attr '=' term ';' {
1011 $$ = f_new_inst(FI_EA_SET, $3, $1);
1013 | static_attr '=' term ';' {
1015 cf_error( "This static attribute is read-only.");
1016 $$ = f_new_inst(FI_RTA_SET, $3, $1);
1018 | UNSET '(' dynamic_attr ')' ';' {
1019 $$ = f_new_inst(FI_EA_UNSET, $3);
1021 | break_command var_list_r ';' {
1022 $$ = f_print($2, !!$2, $1);
1024 | PRINT var_list_r ';' {
1025 $$ = f_print($2, 1, F_NOP);
1027 | PRINTN var_list_r ';' {
1028 $$ = f_print($2, 0, F_NOP);
1030 | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); }
1031 | CASE term '{' switch_body '}' {
1032 $$ = f_new_inst(FI_SWITCH, $2, $4);
1035 f_method_call_start(f_lval_getter(&$1));
1036 } method_name_cont ';' {
1037 f_method_call_end();
1038 $$ = f_lval_setter(&$1, $4);
1040 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
1041 | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); }
1053 case SYM_VARIABLE_RANGE:
1054 $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 };
1057 $$ = (struct f_lval) { .type = F_LVAL_EA, .da = *($1->attribute) };
1060 cf_error("Variable name or custom attribute name required");
1063 | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; }
1064 | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; };