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