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