]>
Commit | Line | Data |
---|---|---|
b9d70dc8 PM |
1 | /* |
2 | * BIRD - filters | |
3 | * | |
1c20608e | 4 | * Copyright 1998--2000 Pavel Machek |
b9d70dc8 PM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
c9f8c1a8 | 7 | * |
1877dab2 | 8 | FIXME: priority of ! should be lower |
b9d70dc8 PM |
9 | */ |
10 | ||
11 | CF_HDR | |
12 | ||
8bdb05ed | 13 | #include "filter/f-inst.h" |
4f082dfa | 14 | #include "filter/data.h" |
8bdb05ed | 15 | |
2edb31b0 MM |
16 | CF_DEFINES |
17 | ||
b8cc390e OZ |
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; } | |
21 | ||
a84b8b6e MM |
22 | #define f_generate_complex(fi_code, da, arg) \ |
23 | f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da) | |
24 | ||
1ac8e11b OZ |
25 | static int |
26 | f_new_var(struct sym_scope *s) | |
27 | { | |
28 | /* | |
29 | * - A variable is an offset on vstack from vbase. | |
30 | * - Vbase is set on filter start / function call. | |
e471f9e0 | 31 | * - Scopes contain (non-frame) block scopes inside filter/function scope |
1ac8e11b | 32 | * - Each scope knows number of vars in that scope |
e471f9e0 | 33 | * - Offset is therefore a sum of 'slots' up to filter/function scope |
1ac8e11b OZ |
34 | * - New variables are added on top of vstk, so intermediate values cannot |
35 | * be there during FI_VAR_INIT. I.e. no 'var' inside 'term'. | |
36 | * - Also, each f_line must always have its scope, otherwise a variable may | |
37 | * be defined but not initialized if relevant f_line is not executed. | |
38 | */ | |
39 | ||
40 | int offset = s->slots++; | |
41 | ||
e471f9e0 | 42 | while (s->block) |
1ac8e11b OZ |
43 | { |
44 | s = s->next; | |
45 | ASSERT(s); | |
46 | offset += s->slots; | |
47 | } | |
48 | ||
49 | if (offset >= 0xff) | |
50 | cf_error("Too many variables, at most 255 allowed"); | |
51 | ||
52 | return offset; | |
53 | } | |
54 | ||
b8cc390e OZ |
55 | /* |
56 | * Sets and their items are during parsing handled as lists, linked | |
57 | * through left ptr. The first item in a list also contains a pointer | |
58 | * to the last item in a list (right ptr). For convenience, even items | |
59 | * are handled as one-item lists. Lists are merged by f_merge_items(). | |
60 | */ | |
b2f00837 OZ |
61 | static int |
62 | f_valid_set_type(int type) | |
63 | { | |
64 | switch (type) | |
65 | { | |
66 | case T_INT: | |
67 | case T_PAIR: | |
68 | case T_QUAD: | |
69 | case T_ENUM: | |
70 | case T_IP: | |
71 | case T_EC: | |
66dbdbd9 | 72 | case T_LC: |
83715aa8 | 73 | case T_RD: |
b2f00837 OZ |
74 | return 1; |
75 | ||
76 | default: | |
77 | return 0; | |
78 | } | |
79 | } | |
b8cc390e OZ |
80 | |
81 | static inline struct f_tree * | |
82 | f_new_item(struct f_val from, struct f_val to) | |
92a72a4c | 83 | { |
b8cc390e OZ |
84 | struct f_tree *t = f_new_tree(); |
85 | t->right = t; | |
86 | t->from = from; | |
87 | t->to = to; | |
88 | return t; | |
89 | } | |
92a72a4c | 90 | |
b8cc390e OZ |
91 | static inline struct f_tree * |
92 | f_merge_items(struct f_tree *a, struct f_tree *b) | |
93 | { | |
94 | if (!a) return b; | |
95 | a->right->left = b; | |
96 | a->right = b->right; | |
97 | b->right = NULL; | |
98 | return a; | |
99 | } | |
92a72a4c | 100 | |
b8cc390e OZ |
101 | static inline struct f_tree * |
102 | f_new_pair_item(int fa, int ta, int fb, int tb) | |
103 | { | |
60566c5c OZ |
104 | check_u16(fa); |
105 | check_u16(ta); | |
106 | check_u16(fb); | |
107 | check_u16(tb); | |
108 | ||
109 | if ((ta < fa) || (tb < fb)) | |
110 | cf_error( "From value cannot be higher that To value in pair sets"); | |
111 | ||
b8cc390e OZ |
112 | struct f_tree *t = f_new_tree(); |
113 | t->right = t; | |
114 | t->from.type = t->to.type = T_PAIR; | |
115 | t->from.val.i = pair(fa, fb); | |
116 | t->to.val.i = pair(ta, tb); | |
117 | return t; | |
92a72a4c OZ |
118 | } |
119 | ||
b8cc390e OZ |
120 | static inline struct f_tree * |
121 | f_new_pair_set(int fa, int ta, int fb, int tb) | |
4fc36f39 | 122 | { |
60566c5c OZ |
123 | check_u16(fa); |
124 | check_u16(ta); | |
125 | check_u16(fb); | |
126 | check_u16(tb); | |
c454872f | 127 | |
b8cc390e OZ |
128 | if ((ta < fa) || (tb < fb)) |
129 | cf_error( "From value cannot be higher that To value in pair sets"); | |
c454872f | 130 | |
60566c5c OZ |
131 | struct f_tree *lst = NULL; |
132 | int i; | |
133 | ||
b8cc390e OZ |
134 | for (i = fa; i <= ta; i++) |
135 | lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb)); | |
136 | ||
137 | return lst; | |
4fc36f39 OF |
138 | } |
139 | ||
60566c5c | 140 | #define CC_ALL 0xFFFF |
42a0c054 | 141 | #define EC_ALL 0xFFFFFFFF |
60566c5c | 142 | #define LC_ALL 0xFFFFFFFF |
42a0c054 OZ |
143 | |
144 | static struct f_tree * | |
145 | f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) | |
146 | { | |
147 | u64 fm, to; | |
148 | ||
e46128fb | 149 | if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) { |
42a0c054 OZ |
150 | check_u16(vf); |
151 | if (vt == EC_ALL) | |
152 | vt = 0xFFFF; | |
153 | else | |
154 | check_u16(vt); | |
155 | } | |
156 | ||
157 | if (kind == EC_GENERIC) { | |
158 | fm = ec_generic(key, vf); | |
159 | to = ec_generic(key, vt); | |
160 | } | |
161 | else if (ipv4_used) { | |
162 | fm = ec_ip4(kind, key, vf); | |
163 | to = ec_ip4(kind, key, vt); | |
164 | } | |
165 | else if (key < 0x10000) { | |
166 | fm = ec_as2(kind, key, vf); | |
167 | to = ec_as2(kind, key, vt); | |
168 | } | |
169 | else { | |
170 | fm = ec_as4(kind, key, vf); | |
171 | to = ec_as4(kind, key, vt); | |
172 | } | |
173 | ||
174 | struct f_tree *t = f_new_tree(); | |
175 | t->right = t; | |
176 | t->from.type = t->to.type = T_EC; | |
177 | t->from.val.ec = fm; | |
178 | t->to.val.ec = to; | |
179 | return t; | |
180 | } | |
181 | ||
60566c5c OZ |
182 | static struct f_tree * |
183 | f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3) | |
184 | { | |
185 | struct f_tree *t = f_new_tree(); | |
186 | t->right = t; | |
187 | t->from.type = t->to.type = T_LC; | |
188 | t->from.val.lc = (lcomm) {f1, f2, f3}; | |
189 | t->to.val.lc = (lcomm) {t1, t2, t3}; | |
190 | return t; | |
191 | } | |
192 | ||
42a0c054 | 193 | static inline struct f_inst * |
5a14df39 | 194 | f_generate_empty(struct f_dynamic_attr dyn) |
5e173e9f | 195 | { |
9b46748d | 196 | struct f_val empty; |
42a0c054 | 197 | |
5a14df39 | 198 | switch (dyn.type & EAF_TYPE_MASK) { |
42a0c054 | 199 | case EAF_TYPE_AS_PATH: |
9b46748d | 200 | empty = f_const_empty_path; |
42a0c054 OZ |
201 | break; |
202 | case EAF_TYPE_INT_SET: | |
9b46748d | 203 | empty = f_const_empty_clist; |
42a0c054 OZ |
204 | break; |
205 | case EAF_TYPE_EC_SET: | |
9b46748d | 206 | empty = f_const_empty_eclist; |
42a0c054 | 207 | break; |
66dbdbd9 | 208 | case EAF_TYPE_LC_SET: |
9b46748d | 209 | empty = f_const_empty_lclist; |
66dbdbd9 | 210 | break; |
42a0c054 OZ |
211 | default: |
212 | cf_error("Can't empty that attribute"); | |
213 | } | |
214 | ||
a84b8b6e | 215 | return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn); |
42a0c054 OZ |
216 | } |
217 | ||
9b0a0ba9 OZ |
218 | /* |
219 | * Remove all new lines and doubled whitespaces | |
220 | * and convert all tabulators to spaces | |
221 | * and return a copy of string | |
222 | */ | |
223 | char * | |
224 | assert_copy_expr(const char *start, size_t len) | |
225 | { | |
226 | /* XXX: Allocates maybe a little more memory than we really finally need */ | |
227 | char *str = cfg_alloc(len + 1); | |
228 | ||
229 | char *dst = str; | |
230 | const char *src = start - 1; | |
231 | const char *end = start + len; | |
232 | while (++src < end) | |
233 | { | |
234 | if (*src == '\n') | |
235 | continue; | |
236 | ||
237 | /* Skip doubled whitespaces */ | |
238 | if (src != start) | |
239 | { | |
240 | const char *prev = src - 1; | |
241 | if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t')) | |
242 | continue; | |
243 | } | |
244 | ||
245 | if (*src == '\t') | |
246 | *dst = ' '; | |
247 | else | |
248 | *dst = *src; | |
249 | ||
250 | dst++; | |
251 | } | |
252 | *dst = '\0'; | |
253 | ||
254 | return str; | |
255 | } | |
256 | ||
257 | /* | |
258 | * assert_done - create f_instruction of bt_assert | |
259 | * @expr: expression in bt_assert() | |
260 | * @start: pointer to first char of test expression | |
261 | * @end: pointer to the last char of test expression | |
262 | */ | |
263 | static struct f_inst * | |
264 | assert_done(struct f_inst *expr, const char *start, const char *end) | |
265 | { | |
9b46748d MM |
266 | return f_new_inst(FI_ASSERT, expr, |
267 | (end >= start) ? | |
268 | assert_copy_expr(start, end - start + 1) | |
269 | : "???"); | |
9b0a0ba9 | 270 | } |
42a0c054 | 271 | |
c0e958e0 MM |
272 | static struct f_inst * |
273 | assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const char *end) | |
274 | { | |
a84b8b6e | 275 | struct f_inst *setter, *getter, *checker; |
c0e958e0 MM |
276 | switch (lval->type) { |
277 | case F_LVAL_VARIABLE: | |
a84b8b6e | 278 | setter = f_new_inst(FI_VAR_SET, expr, lval->sym); |
96d757c1 | 279 | getter = f_new_inst(FI_VAR_GET, lval->sym); |
c0e958e0 | 280 | break; |
c0e958e0 | 281 | case F_LVAL_SA: |
a84b8b6e | 282 | setter = f_new_inst(FI_RTA_SET, expr, lval->sa); |
c0e958e0 MM |
283 | getter = f_new_inst(FI_RTA_GET, lval->sa); |
284 | break; | |
285 | case F_LVAL_EA: | |
a84b8b6e | 286 | setter = f_new_inst(FI_EA_SET, expr, lval->da); |
c0e958e0 MM |
287 | getter = f_new_inst(FI_EA_GET, lval->da); |
288 | break; | |
a84b8b6e MM |
289 | default: |
290 | bug("Unknown lval type"); | |
c0e958e0 MM |
291 | } |
292 | ||
a84b8b6e | 293 | checker = f_new_inst(FI_EQ, expr, getter); |
4f082dfa | 294 | setter->next = checker; |
cb339a30 | 295 | |
c0e958e0 MM |
296 | return assert_done(setter, start, end); |
297 | } | |
298 | ||
b9d70dc8 PM |
299 | CF_DECLS |
300 | ||
e4a73dbf | 301 | CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, |
82bfee76 | 302 | ACCEPT, REJECT, ERROR, |
8c9986d3 | 303 | INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC, |
66dbdbd9 | 304 | SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, |
7db7b7db | 305 | IF, THEN, ELSE, CASE, |
cb339a30 | 306 | FOR, IN, DO, |
42a0c054 | 307 | TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, |
7144c9ca | 308 | FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ONLINK, |
a5fc5958 | 309 | PREFERENCE, |
ff2ca10c | 310 | ROA_CHECK, ASN, SRC, DST, |
61e501da | 311 | IS_V4, IS_V6, |
e58f8c28 | 312 | LEN, MAXLEN, |
a2a268da | 313 | DATA, DATA1, DATA2, |
f4536657 | 314 | DEFINED, |
7f77e250 | 315 | ADD, DELETE, CONTAINS, RESET, |
9c9cc35c | 316 | PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH, |
0e1fd7ea | 317 | MIN, MAX, |
afc54517 | 318 | EMPTY, |
265419a3 | 319 | FILTER, WHERE, EVAL, ATTRIBUTE, |
c73343de | 320 | BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT) |
b9d70dc8 | 321 | |
f4536657 | 322 | %nonassoc THEN |
4ed8718a | 323 | %nonassoc ELSE |
f4536657 | 324 | |
dfe63ed8 | 325 | %type <xp> cmds_int cmd_prep |
1ac8e11b | 326 | %type <x> term cmd cmd_var cmds cmds_scoped constant constructor print_list var var_init var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail |
5a14df39 MJM |
327 | %type <fda> dynamic_attr |
328 | %type <fsa> static_attr | |
0b39b1cb | 329 | %type <f> filter where_filter |
96d757c1 | 330 | %type <fl> filter_body function_body |
c0e958e0 | 331 | %type <flv> lvalue |
93d6096c OZ |
332 | %type <i> type function_vars |
333 | %type <fa> function_argsn function_args | |
9b46748d | 334 | %type <ecs> ec_kind |
93d6096c | 335 | %type <fret> break_command |
60566c5c OZ |
336 | %type <i32> cnum |
337 | %type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body | |
b1a597e0 | 338 | %type <trie> fprefix_set |
5e173e9f JMM |
339 | %type <v> set_atom switch_atom fipa |
340 | %type <px> fprefix | |
9b0a0ba9 | 341 | %type <t> get_cf_position |
cb339a30 | 342 | %type <s> for_var |
b9d70dc8 PM |
343 | |
344 | CF_GRAMMAR | |
345 | ||
f851f0d7 | 346 | conf: filter_def ; |
e0f2e42f | 347 | filter_def: |
2de1e206 | 348 | FILTER symbol { $2 = cf_define_symbol($2, SYM_FILTER, filter, NULL); cf_push_scope( $2 ); } |
b2b7bbfc | 349 | filter_body { |
0b39b1cb | 350 | struct filter *f = cfg_alloc(sizeof(struct filter)); |
f249d0b8 | 351 | *f = (struct filter) { .sym = $2, .root = $4 }; |
0b39b1cb MM |
352 | $2->filter = f; |
353 | ||
ae3e1af2 | 354 | cf_pop_scope(); |
b9d70dc8 PM |
355 | } |
356 | ; | |
357 | ||
f851f0d7 | 358 | conf: filter_eval ; |
1c20608e | 359 | filter_eval: |
a2527ee5 | 360 | EVAL term { f_eval_int(f_linearize($2, 1)); } |
1c20608e MM |
361 | ; |
362 | ||
265419a3 | 363 | conf: custom_attr ; |
2de1e206 | 364 | custom_attr: ATTRIBUTE type symbol ';' { |
0b39b1cb | 365 | cf_define_symbol($3, SYM_ATTRIBUTE, attribute, ca_lookup(new_config->pool, $3->name, $2)->fda); |
265419a3 MM |
366 | }; |
367 | ||
f851f0d7 | 368 | conf: bt_test_suite ; |
9b0a0ba9 | 369 | bt_test_suite: |
9eef9c64 MM |
370 | BT_TEST_SUITE '(' CF_SYM_KNOWN ',' text ')' { |
371 | cf_assert_symbol($3, SYM_FUNCTION); | |
132529ce | 372 | struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); |
0b39b1cb | 373 | t->fn = $3->function; |
9b0a0ba9 OZ |
374 | t->fn_name = $3->name; |
375 | t->dsc = $5; | |
376 | ||
377 | add_tail(&new_config->tests, &t->n); | |
378 | } | |
379 | ; | |
380 | ||
132529ce MM |
381 | conf: bt_test_same ; |
382 | bt_test_same: | |
9eef9c64 MM |
383 | BT_TEST_SAME '(' CF_SYM_KNOWN ',' CF_SYM_KNOWN ',' NUM ')' { |
384 | cf_assert_symbol($3, SYM_FUNCTION); | |
385 | cf_assert_symbol($5, SYM_FUNCTION); | |
132529ce | 386 | struct f_bt_test_suite *t = cfg_allocz(sizeof(struct f_bt_test_suite)); |
0b39b1cb MM |
387 | t->fn = $3->function; |
388 | t->cmp = $5->function; | |
132529ce MM |
389 | t->result = $7; |
390 | t->fn_name = $3->name; | |
391 | t->dsc = $5->name; | |
392 | add_tail(&new_config->tests, &t->n); | |
393 | } | |
394 | ; | |
395 | ||
ba921648 PM |
396 | type: |
397 | INT { $$ = T_INT; } | |
398 | | BOOL { $$ = T_BOOL; } | |
399 | | IP { $$ = T_IP; } | |
8c9986d3 | 400 | | RD { $$ = T_RD; } |
5e173e9f | 401 | | PREFIX { $$ = T_NET; } |
ba921648 | 402 | | PAIR { $$ = T_PAIR; } |
126683fe | 403 | | QUAD { $$ = T_QUAD; } |
42a0c054 | 404 | | EC { $$ = T_EC; } |
66dbdbd9 | 405 | | LC { $$ = T_LC; } |
ba921648 | 406 | | STRING { $$ = T_STRING; } |
10a53608 PM |
407 | | BGPMASK { $$ = T_PATH_MASK; } |
408 | | BGPPATH { $$ = T_PATH; } | |
409 | | CLIST { $$ = T_CLIST; } | |
42a0c054 | 410 | | ECLIST { $$ = T_ECLIST; } |
66dbdbd9 | 411 | | LCLIST { $$ = T_LCLIST; } |
c8cafc8e | 412 | | type SET { |
ba921648 | 413 | switch ($1) { |
b1a597e0 | 414 | case T_INT: |
b1a597e0 | 415 | case T_PAIR: |
126683fe | 416 | case T_QUAD: |
42a0c054 | 417 | case T_EC: |
66dbdbd9 | 418 | case T_LC: |
83715aa8 | 419 | case T_RD: |
126683fe | 420 | case T_IP: |
b1a597e0 OZ |
421 | $$ = T_SET; |
422 | break; | |
423 | ||
5e173e9f | 424 | case T_NET: |
b1a597e0 OZ |
425 | $$ = T_PREFIX_SET; |
426 | break; | |
427 | ||
ba921648 | 428 | default: |
a5a947d4 | 429 | cf_error( "You can't create sets of this type." ); |
ba921648 | 430 | } |
b1a597e0 | 431 | } |
ba921648 PM |
432 | ; |
433 | ||
c29d73a0 | 434 | function_argsn: |
93d6096c | 435 | /* EMPTY */ { $$ = NULL; } |
2de1e206 | 436 | | function_argsn type symbol ';' { |
c29d73a0 | 437 | if ($3->scope->slots >= 0xfe) cf_error("Too many declarations, at most 255 allowed"); |
93d6096c | 438 | $$ = cfg_alloc(sizeof(struct f_arg)); |
1e6acf34 | 439 | $$->arg = cf_define_symbol($3, SYM_VARIABLE | $2, offset, sym_->scope->slots++); |
93d6096c | 440 | $$->next = $1; |
c29d73a0 | 441 | } |
6dc7a0cb PM |
442 | ; |
443 | ||
c29d73a0 | 444 | function_args: |
93d6096c | 445 | '(' ')' { $$ = NULL; } |
2de1e206 | 446 | | '(' function_argsn type symbol ')' { |
93d6096c | 447 | $$ = cfg_alloc(sizeof(struct f_arg)); |
1e6acf34 | 448 | $$->arg = cf_define_symbol($4, SYM_VARIABLE | $3, offset, sym_->scope->slots++); |
93d6096c | 449 | $$->next = $2; |
e0f2e42f MM |
450 | } |
451 | ; | |
452 | ||
c29d73a0 MM |
453 | function_vars: |
454 | /* EMPTY */ { $$ = 0; } | |
2de1e206 | 455 | | function_vars type symbol ';' { |
1ac8e11b | 456 | cf_define_symbol($3, SYM_VARIABLE | $2, offset, f_new_var(sym_->scope)); |
c29d73a0 MM |
457 | $$ = $1 + 1; |
458 | } | |
459 | ; | |
460 | ||
63e76204 | 461 | filter_body: function_body ; |
96d757c1 | 462 | |
e0f2e42f | 463 | filter: |
9eef9c64 MM |
464 | CF_SYM_KNOWN { |
465 | cf_assert_symbol($1, SYM_FILTER); | |
0b39b1cb MM |
466 | $$ = $1->filter; |
467 | } | |
e471f9e0 | 468 | | { cf_push_scope(NULL); } filter_body { |
0b39b1cb | 469 | struct filter *f = cfg_alloc(sizeof(struct filter)); |
e471f9e0 | 470 | *f = (struct filter) { .root = $2 }; |
0b39b1cb | 471 | $$ = f; |
e471f9e0 OZ |
472 | |
473 | cf_pop_scope(); | |
e0f2e42f | 474 | } |
e0f2e42f MM |
475 | ; |
476 | ||
430da60f MM |
477 | where_filter: |
478 | WHERE term { | |
224b77d4 | 479 | /* Construct 'IF term THEN { ACCEPT; } ELSE { REJECT; }' */ |
9b46748d | 480 | $$ = f_new_where($2); |
4c553c5a | 481 | } |
430da60f MM |
482 | ; |
483 | ||
ba921648 | 484 | function_body: |
c29d73a0 | 485 | function_vars '{' cmds '}' { |
a2527ee5 | 486 | $$ = f_linearize($3, 0); |
63e76204 | 487 | $$->vars = $1; |
84c7e194 | 488 | } |
ba921648 PM |
489 | ; |
490 | ||
f851f0d7 | 491 | conf: function_def ; |
ba921648 | 492 | function_def: |
26bc4f99 OZ |
493 | FUNCTION symbol { |
494 | DBG( "Beginning of function %s\n", $2->name ); | |
0b39b1cb | 495 | $2 = cf_define_symbol($2, SYM_FUNCTION, function, NULL); |
bf3eb98e | 496 | cf_push_scope($2); |
26bc4f99 OZ |
497 | } function_args { |
498 | /* Make dummy f_line for storing function prototype */ | |
499 | struct f_line *dummy = cfg_allocz(sizeof(struct f_line)); | |
500 | $2->function = dummy; | |
93d6096c OZ |
501 | |
502 | /* Revert the args */ | |
503 | while ($4) { | |
504 | struct f_arg *tmp = $4; | |
505 | $4 = $4->next; | |
506 | ||
26bc4f99 OZ |
507 | tmp->next = dummy->arg_list; |
508 | dummy->arg_list = tmp; | |
509 | dummy->args++; | |
93d6096c | 510 | } |
26bc4f99 OZ |
511 | } function_body { |
512 | $6->args = $2->function->args; | |
513 | $6->arg_list = $2->function->arg_list; | |
514 | $2->function = $6; | |
ae3e1af2 | 515 | cf_pop_scope(); |
ba921648 PM |
516 | } |
517 | ; | |
518 | ||
519 | /* Programs */ | |
520 | ||
521 | cmds: /* EMPTY */ { $$ = NULL; } | |
0206c070 | 522 | | cmds_int { $$ = $1.begin; } |
5f47c4c1 OZ |
523 | ; |
524 | ||
1ac8e11b OZ |
525 | cmds_scoped: { cf_push_soft_scope(); } cmds { cf_pop_soft_scope(); $$ = $2; } ; |
526 | ||
527 | cmd_var: var | cmd ; | |
528 | ||
529 | cmd_prep: cmd_var { | |
0206c070 | 530 | $$.begin = $$.end = $1; |
dfe63ed8 MM |
531 | if ($1) |
532 | while ($$.end->next) | |
533 | $$.end = $$.end->next; | |
534 | } | |
535 | ; | |
536 | ||
537 | cmds_int: cmd_prep | |
538 | | cmds_int cmd_prep { | |
539 | if (!$1.begin) | |
540 | $$ = $2; | |
541 | else if (!$2.begin) | |
542 | $$ = $1; | |
543 | else { | |
544 | $$.begin = $1.begin; | |
545 | $$.end = $2.end; | |
546 | $1.end->next = $2.begin; | |
0206c070 | 547 | } |
0206c070 | 548 | } |
84c7e194 PM |
549 | ; |
550 | ||
d3dd620b PM |
551 | /* |
552 | * Complex types, their bison value is struct f_val | |
553 | */ | |
e3f2d5fc | 554 | fipa: |
04632fd7 OZ |
555 | IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); } |
556 | | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); } | |
d3dd620b PM |
557 | ; |
558 | ||
b8cc390e OZ |
559 | |
560 | ||
561 | /* | |
562 | * Set constants. They are also used in switch cases. We use separate | |
563 | * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...) | |
564 | * to elude a collision between symbol (in expr) in set_atom and symbol | |
565 | * as a function call in switch case cmds. | |
566 | */ | |
567 | ||
38506f71 | 568 | set_atom: |
83715aa8 OZ |
569 | NUM { $$.type = T_INT; $$.val.i = $1; } |
570 | | fipa { $$ = $1; } | |
571 | | VPN_RD { $$.type = T_RD; $$.val.ec = $1; } | |
572 | | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | |
b2f00837 | 573 | | '(' term ')' { |
a2527ee5 | 574 | if (f_eval(f_linearize($2, 1), cfg_mem, &($$)) > F_RETURN) cf_error("Runtime error"); |
b2f00837 OZ |
575 | if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); |
576 | } | |
9eef9c64 MM |
577 | | CF_SYM_KNOWN { |
578 | cf_assert_symbol($1, SYM_CONSTANT); | |
b2f00837 | 579 | if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); |
0b39b1cb | 580 | $$ = *$1->val; |
b2f00837 | 581 | } |
b8cc390e | 582 | ; |
38506f71 | 583 | |
b8cc390e OZ |
584 | switch_atom: |
585 | NUM { $$.type = T_INT; $$.val.i = $1; } | |
a2527ee5 | 586 | | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int(f_linearize($2, 1)); } |
b8cc390e OZ |
587 | | fipa { $$ = $1; } |
588 | | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | |
589 | ; | |
590 | ||
60566c5c | 591 | cnum: |
a2527ee5 | 592 | term { $$ = f_eval_int(f_linearize($1, 1)); } |
b8cc390e OZ |
593 | |
594 | pair_item: | |
60566c5c OZ |
595 | '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); } |
596 | | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); } | |
597 | | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); } | |
598 | | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); } | |
599 | | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); } | |
600 | | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); } | |
601 | | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); } | |
602 | | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); } | |
603 | | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); } | |
604 | | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')' | |
605 | { $$ = f_new_pair_item($2, $8, $4, $10); } | |
38506f71 PM |
606 | ; |
607 | ||
42a0c054 OZ |
608 | ec_kind: |
609 | RT { $$ = EC_RT; } | |
610 | | RO { $$ = EC_RO; } | |
611 | | UNKNOWN NUM { $$ = $2; } | |
612 | | GENERIC { $$ = EC_GENERIC; } | |
613 | ; | |
614 | ||
615 | ec_item: | |
60566c5c OZ |
616 | '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); } |
617 | | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); } | |
618 | | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); } | |
42a0c054 OZ |
619 | ; |
620 | ||
60566c5c OZ |
621 | lc_item: |
622 | '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); } | |
623 | | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); } | |
624 | | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); } | |
625 | | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); } | |
626 | | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); } | |
627 | | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); } | |
628 | | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); } | |
629 | | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')' | |
630 | { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); } | |
631 | ; | |
42a0c054 | 632 | |
b8cc390e OZ |
633 | set_item: |
634 | pair_item | |
42a0c054 | 635 | | ec_item |
60566c5c | 636 | | lc_item |
b8cc390e OZ |
637 | | set_atom { $$ = f_new_item($1, $1); } |
638 | | set_atom DDOT set_atom { $$ = f_new_item($1, $3); } | |
639 | ; | |
640 | ||
641 | switch_item: | |
642 | pair_item | |
42a0c054 | 643 | | ec_item |
60566c5c | 644 | | lc_item |
b8cc390e OZ |
645 | | switch_atom { $$ = f_new_item($1, $1); } |
646 | | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } | |
647 | ; | |
648 | ||
38506f71 | 649 | set_items: |
b8cc390e OZ |
650 | set_item |
651 | | set_items ',' set_item { $$ = f_merge_items($1, $3); } | |
652 | ; | |
653 | ||
654 | switch_items: | |
655 | switch_item | |
656 | | switch_items ',' switch_item { $$ = f_merge_items($1, $3); } | |
38506f71 PM |
657 | ; |
658 | ||
b1a597e0 | 659 | fprefix: |
04632fd7 OZ |
660 | net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; } |
661 | | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; } | |
662 | | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; } | |
663 | | net_ip_ '{' NUM ',' NUM '}' { | |
5e173e9f | 664 | $$.net = $1; $$.lo = $3; $$.hi = $5; |
6aaaa635 OZ |
665 | if (($3 > $5) || ($5 > net_max_prefix_length[$1.type])) |
666 | cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5); | |
b1a597e0 OZ |
667 | } |
668 | ; | |
669 | ||
670 | fprefix_set: | |
27550028 OZ |
671 | fprefix { $$ = f_new_trie(cfg_mem, 0); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); } |
672 | | fprefix_set ',' fprefix { $$ = $1; if (!trie_add_prefix($$, &($3.net), $3.lo, $3.hi)) cf_error("Mixed IPv4/IPv6 prefixes in prefix set"); } | |
b1a597e0 OZ |
673 | ; |
674 | ||
41be4444 | 675 | switch_body: /* EMPTY */ { $$ = NULL; } |
1ac8e11b | 676 | | switch_body switch_items ':' cmds_scoped { |
b8cc390e OZ |
677 | /* Fill data fields */ |
678 | struct f_tree *t; | |
679 | for (t = $2; t; t = t->left) | |
e20bef69 | 680 | t->data = $4; |
b8cc390e | 681 | $$ = f_merge_items($1, $2); |
41be4444 | 682 | } |
1ac8e11b | 683 | | switch_body ELSECOL cmds_scoped { |
b8cc390e OZ |
684 | struct f_tree *t = f_new_tree(); |
685 | t->from.type = t->to.type = T_VOID; | |
686 | t->right = t; | |
e20bef69 | 687 | t->data = $3; |
b8cc390e OZ |
688 | $$ = f_merge_items($1, t); |
689 | } | |
41be4444 | 690 | ; |
d3dd620b | 691 | |
92a72a4c | 692 | bgp_path_expr: |
c0e958e0 | 693 | symbol_value { $$ = $1; } |
92a72a4c OZ |
694 | | '(' term ')' { $$ = $2; } |
695 | ; | |
696 | ||
f9491630 | 697 | bgp_path: |
3e52d112 | 698 | PO bgp_path_tail PC { $$ = $2; } |
f9491630 OZ |
699 | ; |
700 | ||
3e52d112 | 701 | bgp_path_tail: |
4f082dfa MM |
702 | 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; } |
703 | | 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; } | |
b2d6d294 | 704 | | '[' ']' 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; } |
ef113c6f OZ |
705 | | '[' set_items ']' bgp_path_tail { |
706 | if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask"); | |
707 | $$ = 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; | |
708 | } | |
4f082dfa MM |
709 | | '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; } |
710 | | '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; } | |
ec430a7f | 711 | | '+' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; } |
4f082dfa | 712 | | bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; } |
122deb6d | 713 | | { $$ = NULL; } |
f9491630 | 714 | ; |
77de6882 | 715 | |
23b1539b | 716 | constant: |
9b46748d MM |
717 | NUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = $1, }); } |
718 | | TRUE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 1, }); } | |
719 | | FALSE { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BOOL, .val.i = 0, }); } | |
720 | | TEXT { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_STRING, .val.s = $1, }); } | |
721 | | fipa { $$ = f_new_inst(FI_CONSTANT, $1); } | |
722 | | VPN_RD { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_RD, .val.ec = $1, }); } | |
723 | | net_ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_NET, .val.net = $1, }); } | |
b2d6d294 | 724 | | '[' ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = NULL, }); } |
ca2ee91a MM |
725 | | '[' set_items ']' { |
726 | DBG( "We've got a set here..." ); | |
9b46748d | 727 | $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_SET, .val.t = build_tree($2), }); |
ca2ee91a MM |
728 | DBG( "ook\n" ); |
729 | } | |
9b46748d MM |
730 | | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); } |
731 | | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); } | |
23b1539b PM |
732 | ; |
733 | ||
42a0c054 | 734 | constructor: |
9b46748d MM |
735 | '(' term ',' term ')' { $$ = f_new_inst(FI_PAIR_CONSTRUCT, $2, $4); } |
736 | | '(' ec_kind ',' term ',' term ')' { $$ = f_new_inst(FI_EC_CONSTRUCT, $4, $6, $2); } | |
737 | | '(' term ',' term ',' term ')' { $$ = f_new_inst(FI_LC_CONSTRUCT, $2, $4, $6); } | |
c0999a14 | 738 | | bgp_path { $$ = f_new_inst(FI_PATHMASK_CONSTRUCT, $1); } |
42a0c054 OZ |
739 | ; |
740 | ||
92a72a4c | 741 | |
96d757c1 JMM |
742 | /* This generates the function_call variable list backwards. */ |
743 | var_list: /* EMPTY */ { $$ = NULL; } | |
744 | | term { $$ = $1; } | |
745 | | var_list ',' term { $$ = $3; $$->next = $1; } | |
746 | ||
2d496d20 | 747 | function_call: |
4c0c507b OZ |
748 | CF_SYM_KNOWN '(' var_list ')' |
749 | { | |
96d757c1 JMM |
750 | if ($1->class != SYM_FUNCTION) |
751 | cf_error("You can't call something which is not a function. Really."); | |
752 | ||
4c0c507b OZ |
753 | /* Revert the var_list */ |
754 | struct f_inst *args = NULL; | |
96d757c1 | 755 | while ($3) { |
4c0c507b OZ |
756 | struct f_inst *tmp = $3; |
757 | $3 = $3->next; | |
96d757c1 | 758 | |
4c0c507b OZ |
759 | tmp->next = args; |
760 | args = tmp; | |
96d757c1 JMM |
761 | } |
762 | ||
4c0c507b | 763 | $$ = f_new_inst(FI_CALL, args, $1); |
2d496d20 PM |
764 | } |
765 | ; | |
766 | ||
9eef9c64 MM |
767 | symbol_value: CF_SYM_KNOWN |
768 | { | |
769 | switch ($1->class) { | |
770 | case SYM_CONSTANT_RANGE: | |
30667d50 | 771 | $$ = f_new_inst(FI_CONSTANT, *($1->val)); |
96d757c1 | 772 | break; |
9eef9c64 | 773 | case SYM_VARIABLE_RANGE: |
96d757c1 | 774 | $$ = f_new_inst(FI_VAR_GET, $1); |
9eef9c64 MM |
775 | break; |
776 | case SYM_ATTRIBUTE: | |
777 | $$ = f_new_inst(FI_EA_GET, *$1->attribute); | |
778 | break; | |
779 | default: | |
780 | cf_error("Can't get value of symbol %s", $1->name); | |
781 | } | |
782 | } | |
c0e958e0 | 783 | ; |
92a72a4c | 784 | |
2bdb5e00 | 785 | static_attr: |
4c553c5a MM |
786 | FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 0); } |
787 | | GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); } | |
788 | | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); } | |
789 | | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); } | |
790 | | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); } | |
791 | | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 0); } | |
792 | | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); } | |
793 | | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); } | |
794 | | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); } | |
8cc5bb09 | 795 | | WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); } |
eb937358 | 796 | | PREFERENCE { $$ = f_new_static_attr(T_INT, SA_PREF, 0); } |
e5468d16 | 797 | | GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); } |
7144c9ca | 798 | | ONLINK { $$ = f_new_static_attr(T_BOOL, SA_ONLINK, 0); } |
2bdb5e00 PM |
799 | ; |
800 | ||
84c7e194 | 801 | term: |
5a14df39 | 802 | '(' term ')' { $$ = $2; } |
9b46748d MM |
803 | | term '+' term { $$ = f_new_inst(FI_ADD, $1, $3); } |
804 | | term '-' term { $$ = f_new_inst(FI_SUBTRACT, $1, $3); } | |
805 | | term '*' term { $$ = f_new_inst(FI_MULTIPLY, $1, $3); } | |
806 | | term '/' term { $$ = f_new_inst(FI_DIVIDE, $1, $3); } | |
807 | | term AND term { $$ = f_new_inst(FI_AND, $1, $3); } | |
808 | | term OR term { $$ = f_new_inst(FI_OR, $1, $3); } | |
809 | | term '=' term { $$ = f_new_inst(FI_EQ, $1, $3); } | |
810 | | term NEQ term { $$ = f_new_inst(FI_NEQ, $1, $3); } | |
811 | | term '<' term { $$ = f_new_inst(FI_LT, $1, $3); } | |
812 | | term LEQ term { $$ = f_new_inst(FI_LTE, $1, $3); } | |
813 | | term '>' term { $$ = f_new_inst(FI_LT, $3, $1); } | |
814 | | term GEQ term { $$ = f_new_inst(FI_LTE, $3, $1); } | |
815 | | term '~' term { $$ = f_new_inst(FI_MATCH, $1, $3); } | |
816 | | term NMA term { $$ = f_new_inst(FI_NOT_MATCH, $1, $3); } | |
817 | | '!' term { $$ = f_new_inst(FI_NOT, $2); } | |
818 | | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED, $3); } | |
23b1539b | 819 | |
c0e958e0 | 820 | | symbol_value { $$ = $1; } |
1183b6b2 | 821 | | constant { $$ = $1; } |
42a0c054 | 822 | | constructor { $$ = $1; } |
4515bdba | 823 | |
c0e958e0 | 824 | | static_attr { $$ = f_new_inst(FI_RTA_GET, $1); } |
fe613ecd | 825 | |
c0e958e0 | 826 | | dynamic_attr { $$ = f_new_inst(FI_EA_GET, $1); } |
36bbfc70 | 827 | |
9b46748d MM |
828 | | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4, $1); } |
829 | | term '.' TYPE { $$ = f_new_inst(FI_TYPE, $1); } | |
830 | | term '.' IP { $$ = f_new_inst(FI_IP, $1); } | |
831 | | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); } | |
832 | | term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); } | |
833 | | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); } | |
a2a268da | 834 | | term '.' ASN { $$ = f_new_inst(FI_ASN, $1); } |
ff2ca10c OZ |
835 | | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); } |
836 | | term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); } | |
9b46748d MM |
837 | | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); } |
838 | | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); } | |
839 | | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); } | |
840 | | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); } | |
a2a268da AZ |
841 | | term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); } |
842 | | term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); } | |
843 | | term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); } | |
0e1fd7ea AZ |
844 | | term '.' MIN { $$ = f_new_inst(FI_MIN, $1); } |
845 | | term '.' MAX { $$ = f_new_inst(FI_MAX, $1); } | |
7f77e250 PM |
846 | |
847 | /* Communities */ | |
10a53608 | 848 | /* This causes one shift/reduce conflict |
c0e958e0 MM |
849 | | dynamic_attr '.' ADD '(' term ')' { } |
850 | | dynamic_attr '.' DELETE '(' term ')' { } | |
851 | | dynamic_attr '.' CONTAINS '(' term ')' { } | |
852 | | dynamic_attr '.' RESET{ } | |
10a53608 | 853 | */ |
7f77e250 | 854 | |
9b46748d MM |
855 | | '+' EMPTY '+' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_path); } |
856 | | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); } | |
857 | | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); } | |
858 | | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_lclist); } | |
859 | | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); } | |
860 | | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD, $3, $5); } | |
861 | | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_DEL, $3, $5); } | |
862 | | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_FILTER, $3, $5); } | |
afc54517 | 863 | |
9b46748d MM |
864 | | ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); } |
865 | | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); } | |
af582c48 | 866 | |
9b46748d | 867 | | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); } |
9b0a0ba9 | 868 | |
a2d15746 | 869 | /* | term '.' LEN { $$->code = P('P','l'); } */ |
7f77e250 | 870 | |
4c553c5a | 871 | | function_call |
ba921648 PM |
872 | ; |
873 | ||
874 | break_command: | |
82bfee76 | 875 | ACCEPT { $$ = F_ACCEPT; } |
03e3d184 MM |
876 | | REJECT { $$ = F_REJECT; } |
877 | | ERROR { $$ = F_ERROR; } | |
ba921648 PM |
878 | ; |
879 | ||
23b1539b | 880 | print_list: /* EMPTY */ { $$ = NULL; } |
0206c070 MM |
881 | | term { $$ = $1; } |
882 | | term ',' print_list { | |
883 | ASSERT($1); | |
884 | ASSERT($1->next == NULL); | |
885 | $1->next = $3; | |
886 | $$ = $1; | |
23b1539b PM |
887 | } |
888 | ; | |
889 | ||
1ac8e11b OZ |
890 | var_init: |
891 | /* empty */ { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { }); } | |
892 | | '=' term { $$ = $2; } | |
893 | ; | |
894 | ||
895 | var: | |
896 | type symbol var_init ';' { | |
897 | struct symbol *sym = cf_define_symbol($2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope)); | |
898 | $$ = f_new_inst(FI_VAR_INIT, $3, sym); | |
899 | } | |
900 | ||
cb339a30 OZ |
901 | for_var: |
902 | type symbol { $$ = cf_define_symbol($2, SYM_VARIABLE | $1, offset, f_new_var(sym_->scope)); } | |
903 | | CF_SYM_KNOWN { $$ = $1; cf_assert_symbol($1, SYM_VARIABLE); } | |
904 | ; | |
905 | ||
23b1539b | 906 | cmd: |
1ac8e11b | 907 | '{' cmds_scoped '}' { |
f31f4e6e OZ |
908 | $$ = $2; |
909 | } | |
910 | | IF term THEN cmd { | |
9b46748d | 911 | $$ = f_new_inst(FI_CONDITION, $2, $4, NULL); |
23b1539b | 912 | } |
f31f4e6e | 913 | | IF term THEN cmd ELSE cmd { |
9b46748d | 914 | $$ = f_new_inst(FI_CONDITION, $2, $4, $6); |
23b1539b | 915 | } |
cb339a30 OZ |
916 | | FOR { |
917 | /* Reserve space for walk data on stack */ | |
e471f9e0 | 918 | cf_push_block_scope(); |
cb339a30 OZ |
919 | conf_this_scope->slots += 2; |
920 | } for_var IN | |
921 | /* Parse term in the parent scope */ | |
922 | { conf_this_scope->active = 0; } term { conf_this_scope->active = 1; } | |
923 | DO cmd { | |
e471f9e0 | 924 | cf_pop_block_scope(); |
cb339a30 OZ |
925 | $$ = f_new_inst(FI_FOR_INIT, $6, $3); |
926 | $$->next = f_new_inst(FI_FOR_NEXT, $3, $9); | |
927 | } | |
9eef9c64 MM |
928 | | CF_SYM_KNOWN '=' term ';' { |
929 | switch ($1->class) { | |
930 | case SYM_VARIABLE_RANGE: | |
a84b8b6e | 931 | $$ = f_new_inst(FI_VAR_SET, $3, $1); |
9eef9c64 MM |
932 | break; |
933 | case SYM_ATTRIBUTE: | |
a84b8b6e | 934 | $$ = f_new_inst(FI_EA_SET, $3, *$1->attribute); |
9eef9c64 MM |
935 | break; |
936 | default: | |
937 | cf_error("Can't assign to symbol %s", $1->name); | |
938 | } | |
b9d70dc8 | 939 | } |
2d496d20 | 940 | | RETURN term ';' { |
d4d75628 | 941 | DBG( "Ook, we'll return the value\n" ); |
a84b8b6e | 942 | $$ = f_new_inst(FI_RETURN, $2); |
2d496d20 | 943 | } |
c0e958e0 | 944 | | dynamic_attr '=' term ';' { |
a84b8b6e | 945 | $$ = f_new_inst(FI_EA_SET, $3, $1); |
f31156ca | 946 | } |
c0e958e0 MM |
947 | | static_attr '=' term ';' { |
948 | if ($1.readonly) | |
0dc4431c | 949 | cf_error( "This static attribute is read-only."); |
a84b8b6e | 950 | $$ = f_new_inst(FI_RTA_SET, $3, $1); |
0dc4431c | 951 | } |
c0e958e0 MM |
952 | | UNSET '(' dynamic_attr ')' ';' { |
953 | $$ = f_new_inst(FI_EA_UNSET, $3); | |
c7b43f33 | 954 | } |
0206c070 | 955 | | break_command print_list ';' { |
efd7c87b MM |
956 | struct f_inst *breaker = f_new_inst(FI_DIE, $1); |
957 | if ($2) { | |
958 | struct f_inst *printer = f_new_inst(FI_PRINT, $2); | |
959 | struct f_inst *flusher = f_new_inst(FI_FLUSH); | |
960 | printer->next = flusher; | |
961 | flusher->next = breaker; | |
0206c070 | 962 | $$ = printer; |
efd7c87b | 963 | } else |
0206c070 MM |
964 | $$ = breaker; |
965 | } | |
efd7c87b MM |
966 | | PRINT print_list ';' { |
967 | $$ = f_new_inst(FI_PRINT, $2); | |
968 | $$->next = f_new_inst(FI_FLUSH); | |
969 | } | |
970 | | PRINTN print_list ';' { | |
971 | $$ = f_new_inst(FI_PRINT, $2); | |
972 | } | |
1ac8e11b | 973 | | function_call ';' { $$ = f_new_inst(FI_DROP_RESULT, $1); } |
7db7b7db | 974 | | CASE term '{' switch_body '}' { |
e20bef69 | 975 | $$ = f_new_inst(FI_SWITCH, $2, $4); |
7db7b7db | 976 | } |
7d6eebae | 977 | |
c0e958e0 MM |
978 | | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); } |
979 | | dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, $1, $5 ); } | |
980 | | dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); } | |
981 | | dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_DEL, $1, $5 ); } | |
982 | | dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_FILTER, $1, $5 ); } | |
3ec0bedc | 983 | | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } |
c0e958e0 | 984 | | BT_CHECK_ASSIGN '(' get_cf_position lvalue get_cf_position ',' term ')' ';' { $$ = assert_assign(&$4, $7, $3 + 1, $5 - 1); } |
9b0a0ba9 OZ |
985 | ; |
986 | ||
987 | get_cf_position: | |
988 | { | |
989 | $$ = cf_text; | |
990 | }; | |
991 | ||
c0e958e0 | 992 | lvalue: |
9eef9c64 | 993 | CF_SYM_KNOWN { cf_assert_symbol($1, SYM_VARIABLE); $$ = (struct f_lval) { .type = F_LVAL_VARIABLE, .sym = $1 }; } |
c0e958e0 MM |
994 | | static_attr { $$ = (struct f_lval) { .type = F_LVAL_SA, .sa = $1 }; } |
995 | | dynamic_attr { $$ = (struct f_lval) { .type = F_LVAL_EA, .da = $1 }; }; | |
9b0a0ba9 | 996 | |
b9d70dc8 | 997 | CF_END |