]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Filter: ROA check test and mixed prefix test
[thirdparty/bird.git] / filter / config.Y
CommitLineData
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
11CF_HDR
12
2edb31b0
MM
13CF_DEFINES
14
b8cc390e 15#define P(a,b) ((a << 8) | b)
2d496d20 16
b8cc390e
OZ
17static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
18static inline u32 pair_a(u32 p) { return p >> 16; }
19static 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
28static int
29f_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
47static inline struct f_tree *
48f_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
57static inline struct f_tree *
58f_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
67static inline struct f_tree *
68f_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
86static inline struct f_tree *
87f_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
110static struct f_tree *
111f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
112{
113 u64 fm, to;
114
115 if (ipv4_used || (key >= 0x10000)) {
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
148static struct f_tree *
149f_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
159static inline struct f_inst *
160f_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
188static inline struct f_inst *
189f_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
215static inline struct f_inst *
216f_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
296static inline struct f_inst *
297f_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 */
331char *
332assert_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 */
371static struct f_inst *
372assert_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
392CF_DECLS
393
e4a73dbf 394CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ba921648 395 ACCEPT, REJECT, ERROR, QUITBIRD,
66dbdbd9
OZ
396 INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
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,
e58f8c28 403 LEN, MAXLEN,
f4536657 404 DEFINED,
7f77e250 405 ADD, DELETE, CONTAINS, RESET,
9c9cc35c 406 PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
afc54517 407 EMPTY,
9b0a0ba9 408 FILTER, WHERE, EVAL,
4b135d09 409 BT_ASSERT, BT_TEST_SUITE, FORMAT)
b9d70dc8 410
f4536657 411%nonassoc THEN
4ed8718a 412%nonassoc ELSE
f4536657 413
3ec0bedc 414%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
430da60f 415%type <f> filter filter_body where_filter
60566c5c
OZ
416%type <i> type break_command ec_kind
417%type <i32> cnum
418%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
b1a597e0 419%type <trie> fprefix_set
5e173e9f
JMM
420%type <v> set_atom switch_atom fipa
421%type <px> fprefix
422%type <s> decls declsn one_decl function_params
f9491630 423%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
9b0a0ba9 424%type <t> get_cf_position
b9d70dc8
PM
425
426CF_GRAMMAR
427
e0f2e42f
MM
428CF_ADDTO(conf, filter_def)
429filter_def:
b2b7bbfc
OZ
430 FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
431 filter_body {
432 $2->def = $4;
ae3e1af2 433 $4->name = $2->name;
d4d75628 434 DBG( "We have new filter defined (%s)\n", $2->name );
ae3e1af2 435 cf_pop_scope();
b9d70dc8
PM
436 }
437 ;
438
1c20608e
MM
439CF_ADDTO(conf, filter_eval)
440filter_eval:
441 EVAL term { f_eval_int($2); }
442 ;
443
9b0a0ba9
OZ
444CF_ADDTO(conf, bt_test_suite)
445bt_test_suite:
446 BT_TEST_SUITE '(' SYM ',' text ')' {
447 if (!($3->class & SYM_FUNCTION))
448 cf_error("Function expected");
449
450 struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
451 t->fn = $3->def;
452 t->fn_name = $3->name;
453 t->dsc = $5;
454
455 add_tail(&new_config->tests, &t->n);
456 }
457 ;
458
ba921648
PM
459type:
460 INT { $$ = T_INT; }
461 | BOOL { $$ = T_BOOL; }
462 | IP { $$ = T_IP; }
5e173e9f 463 | PREFIX { $$ = T_NET; }
ba921648 464 | PAIR { $$ = T_PAIR; }
126683fe 465 | QUAD { $$ = T_QUAD; }
42a0c054 466 | EC { $$ = T_EC; }
66dbdbd9 467 | LC { $$ = T_LC; }
ba921648 468 | STRING { $$ = T_STRING; }
10a53608
PM
469 | BGPMASK { $$ = T_PATH_MASK; }
470 | BGPPATH { $$ = T_PATH; }
471 | CLIST { $$ = T_CLIST; }
42a0c054 472 | ECLIST { $$ = T_ECLIST; }
66dbdbd9 473 | LCLIST { $$ = T_LCLIST; }
c8cafc8e 474 | type SET {
ba921648 475 switch ($1) {
b1a597e0 476 case T_INT:
b1a597e0 477 case T_PAIR:
126683fe 478 case T_QUAD:
42a0c054 479 case T_EC:
66dbdbd9 480 case T_LC:
126683fe 481 case T_IP:
b1a597e0
OZ
482 $$ = T_SET;
483 break;
484
5e173e9f 485 case T_NET:
b1a597e0
OZ
486 $$ = T_PREFIX_SET;
487 break;
488
ba921648 489 default:
a5a947d4 490 cf_error( "You can't create sets of this type." );
ba921648 491 }
b1a597e0 492 }
ba921648
PM
493 ;
494
6dc7a0cb
PM
495one_decl:
496 type SYM {
4ee39ff2
OZ
497 struct f_val * val = cfg_alloc(sizeof(struct f_val));
498 val->type = T_VOID;
083c43e2 499 $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
d4d75628 500 DBG( "New variable %s type %x\n", $2->name, $1 );
083c43e2 501 $2->aux2 = NULL;
6542ece9 502 $$=$2;
ba921648
PM
503 }
504 ;
505
6dc7a0cb
PM
506/* Decls with ';' at the end */
507decls: /* EMPTY */ { $$ = NULL; }
508 | one_decl ';' decls {
509 $$ = $1;
083c43e2 510 $$->aux2 = $3;
6dc7a0cb
PM
511 }
512 ;
513
3c989eb4 514/* Declarations that have no ';' at the end. */
6dc7a0cb 515declsn: one_decl { $$ = $1; }
736fd730 516 | one_decl ';' declsn {
4515bdba 517 $$ = $1;
083c43e2 518 $$->aux2 = $3;
6dc7a0cb
PM
519 }
520 ;
521
e0f2e42f 522filter_body:
ba921648 523 function_body {
e0f2e42f
MM
524 struct filter *f = cfg_alloc(sizeof(struct filter));
525 f->name = NULL;
ba921648 526 f->root = $1;
e0f2e42f
MM
527 $$ = f;
528 }
529 ;
530
531filter:
532 SYM {
a5a947d4 533 if ($1->class != SYM_FILTER) cf_error("No such filter.");
e0f2e42f
MM
534 $$ = $1->def;
535 }
536 | filter_body
537 ;
538
430da60f
MM
539where_filter:
540 WHERE term {
541 /* Construct 'IF term THEN ACCEPT; REJECT;' */
542 struct filter *f = cfg_alloc(sizeof(struct filter));
543 struct f_inst *i, *acc, *rej;
544 acc = f_new_inst(); /* ACCEPT */
2d496d20 545 acc->code = P('p',',');
430da60f
MM
546 acc->a1.p = NULL;
547 acc->a2.i = F_ACCEPT;
548 rej = f_new_inst(); /* REJECT */
2d496d20 549 rej->code = P('p',',');
430da60f
MM
550 rej->a1.p = NULL;
551 rej->a2.i = F_REJECT;
552 i = f_new_inst(); /* IF */
553 i->code = '?';
554 i->a1.p = $2;
555 i->a2.p = acc;
556 i->next = rej;
557 f->name = NULL;
558 f->root = i;
559 $$ = f;
560 }
561 ;
562
ba921648 563function_params:
d4d75628 564 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
6dc7a0cb 565 | '(' ')' { $$=NULL; }
ba921648 566 ;
b9d70dc8 567
ba921648
PM
568function_body:
569 decls '{' cmds '}' {
aa461248
OZ
570 if ($1) {
571 /* Prepend instruction to clear local variables */
572 $$ = f_new_inst();
573 $$->code = P('c','v');
574 $$->a1.p = $1;
575 $$->next = $3;
576 } else
577 $$ = $3;
84c7e194 578 }
ba921648
PM
579 ;
580
581CF_ADDTO(conf, function_def)
582function_def:
bf3eb98e
MM
583 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
584 $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
585 cf_push_scope($2);
586 } function_params function_body {
587 $2->def = $5;
083c43e2 588 $2->aux2 = $4;
c8cafc8e 589 DBG("Hmm, we've got one function here - %s\n", $2->name);
ae3e1af2 590 cf_pop_scope();
ba921648
PM
591 }
592 ;
593
594/* Programs */
595
5f47c4c1
OZ
596/* Hack: $$ of cmds_int is the last node.
597 $$->next of cmds_int is temporary used for the first node */
598
ba921648 599cmds: /* EMPTY */ { $$ = NULL; }
5f47c4c1
OZ
600 | cmds_int { $$ = $1->next; $1->next = NULL; }
601 ;
602
603cmds_int: cmd { $$ = $1; $1->next = $1; }
604 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
84c7e194
PM
605 ;
606
2575593e 607block:
ba921648 608 cmd {
2575593e
PM
609 $$=$1;
610 }
611 | '{' cmds '}' {
612 $$=$2;
613 }
614 ;
615
d3dd620b
PM
616/*
617 * Complex types, their bison value is struct f_val
618 */
e3f2d5fc 619fipa:
04632fd7
OZ
620 IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
621 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
d3dd620b
PM
622 ;
623
b8cc390e
OZ
624
625
626/*
627 * Set constants. They are also used in switch cases. We use separate
628 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
629 * to elude a collision between symbol (in expr) in set_atom and symbol
630 * as a function call in switch case cmds.
631 */
632
38506f71 633set_atom:
b2f00837 634 NUM { $$.type = T_INT; $$.val.i = $1; }
92a72a4c 635 | fipa { $$ = $1; }
b8cc390e 636 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
b2f00837
OZ
637 | '(' term ')' {
638 $$ = f_eval($2, cfg_mem);
639 if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
640 }
641 | SYM {
642 if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
643 if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
644 $$ = *(struct f_val *)($1->def);
645 }
b8cc390e 646 ;
38506f71 647
b8cc390e
OZ
648switch_atom:
649 NUM { $$.type = T_INT; $$.val.i = $1; }
650 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
b8cc390e
OZ
651 | fipa { $$ = $1; }
652 | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
653 ;
654
60566c5c
OZ
655cnum:
656 term { $$ = f_eval_int($1); }
b8cc390e
OZ
657
658pair_item:
60566c5c
OZ
659 '(' cnum ',' cnum ')' { $$ = f_new_pair_item($2, $2, $4, $4); }
660 | '(' cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_item($2, $2, $4, $6); }
661 | '(' cnum ',' '*' ')' { $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
662 | '(' cnum DDOT cnum ',' cnum ')' { $$ = f_new_pair_set($2, $4, $6, $6); }
663 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
664 | '(' cnum DDOT cnum ',' '*' ')' { $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
665 | '(' '*' ',' cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
666 | '(' '*' ',' cnum DDOT cnum ')' { $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
667 | '(' '*' ',' '*' ')' { $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
668 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
669 { $$ = f_new_pair_item($2, $8, $4, $10); }
38506f71
PM
670 ;
671
42a0c054
OZ
672ec_kind:
673 RT { $$ = EC_RT; }
674 | RO { $$ = EC_RO; }
675 | UNKNOWN NUM { $$ = $2; }
676 | GENERIC { $$ = EC_GENERIC; }
677 ;
678
679ec_item:
60566c5c
OZ
680 '(' ec_kind ',' cnum ',' cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
681 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
682 | '(' ec_kind ',' cnum ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
42a0c054
OZ
683 ;
684
60566c5c
OZ
685lc_item:
686 '(' cnum ',' cnum ',' cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
687 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
688 | '(' cnum ',' cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
689 | '(' cnum ',' cnum DDOT cnum ',' '*' ')' { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
690 | '(' cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
691 | '(' cnum DDOT cnum ',' '*' ',' '*' ')' { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
692 | '(' '*' ',' '*' ',' '*' ')' { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
693 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
694 { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
695;
42a0c054 696
b8cc390e
OZ
697set_item:
698 pair_item
42a0c054 699 | ec_item
60566c5c 700 | lc_item
b8cc390e
OZ
701 | set_atom { $$ = f_new_item($1, $1); }
702 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
703 ;
704
705switch_item:
706 pair_item
42a0c054 707 | ec_item
60566c5c 708 | lc_item
b8cc390e
OZ
709 | switch_atom { $$ = f_new_item($1, $1); }
710 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
711 ;
712
38506f71 713set_items:
b8cc390e
OZ
714 set_item
715 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
716 ;
717
718switch_items:
719 switch_item
720 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
38506f71
PM
721 ;
722
b1a597e0 723fprefix:
04632fd7
OZ
724 net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
725 | net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
726 | net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
727 | net_ip_ '{' NUM ',' NUM '}' {
5e173e9f 728 $$.net = $1; $$.lo = $3; $$.hi = $5;
04632fd7 729 if ((0 > $3) || ($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
5e173e9f 730 cf_error("Invalid prefix pattern range: {%d, %d}", $3, $5);
b1a597e0
OZ
731 }
732 ;
733
734fprefix_set:
04632fd7
OZ
735 fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
736 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
b1a597e0
OZ
737 ;
738
41be4444 739switch_body: /* EMPTY */ { $$ = NULL; }
b8cc390e
OZ
740 | switch_body switch_items ':' cmds {
741 /* Fill data fields */
742 struct f_tree *t;
743 for (t = $2; t; t = t->left)
744 t->data = $4;
745 $$ = f_merge_items($1, $2);
41be4444 746 }
5e173e9f 747 | switch_body ELSECOL cmds {
b8cc390e
OZ
748 struct f_tree *t = f_new_tree();
749 t->from.type = t->to.type = T_VOID;
750 t->right = t;
751 t->data = $3;
752 $$ = f_merge_items($1, t);
753 }
41be4444 754 ;
d3dd620b 755
e4a73dbf
PM
756/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
757
92a72a4c 758bgp_path_expr:
c8cafc8e 759 symbol { $$ = $1; }
92a72a4c
OZ
760 | '(' term ')' { $$ = $2; }
761 ;
762
f9491630 763bgp_path:
cf186034 764 PO bgp_path_tail1 PC { $$ = $2; }
f9491630 765 | '/' bgp_path_tail2 '/' { $$ = $2; }
f9491630
OZ
766 ;
767
768bgp_path_tail1:
122deb6d
OZ
769 NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
770 | NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
771 | '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
772 | '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
773 | bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
774 | { $$ = NULL; }
f9491630 775 ;
77de6882 776
f9491630 777bgp_path_tail2:
122deb6d
OZ
778 NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
779 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
f9491630 780 | { $$ = NULL; }
77de6882
PM
781 ;
782
23b1539b 783constant:
e4a73dbf 784 NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
c7b43f33
PM
785 | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
786 | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
787 | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
5e173e9f 788 | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
04632fd7 789 | net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
d4d75628 790 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
b1a597e0 791 | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
c7b43f33 792 | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
f9491630 793 | 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
794 ;
795
42a0c054 796constructor:
78e33c29
OZ
797 '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
798 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
66dbdbd9 799 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
42a0c054
OZ
800 ;
801
92a72a4c 802
db1326aa
MM
803/*
804 * Maybe there are no dynamic attributes defined by protocols.
805 * For such cases, we force the dynamic_attr list to contain
b8cc390e 806 * at least an invalid token, so it is syntantically correct.
db1326aa
MM
807 */
808CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
f4536657 809
2e18b87d 810rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 811 ;
f4536657 812
2d496d20
PM
813function_call:
814 SYM '(' var_list ')' {
815 struct symbol *sym;
816 struct f_inst *inst = $3;
817 if ($1->class != SYM_FUNCTION)
a5a947d4 818 cf_error("You can't call something which is not a function. Really.");
d4d75628 819 DBG("You are calling function %s\n", $1->name);
2d496d20
PM
820 $$ = f_new_inst();
821 $$->code = P('c','a');
822 $$->a1.p = inst;
083c43e2
OZ
823 $$->a2.p = $1->def;
824 sym = $1->aux2;
2d496d20
PM
825 while (sym || inst) {
826 if (!sym || !inst)
a5a947d4 827 cf_error("Wrong number of arguments for function %s.", $1->name);
d4d75628 828 DBG( "You should pass parameter called %s\n", sym->name);
2d496d20 829 inst->a1.p = sym;
083c43e2 830 sym = sym->aux2;
2d496d20
PM
831 inst = inst->next;
832 }
833 }
834 ;
835
92a72a4c
OZ
836symbol:
837 SYM {
838 $$ = f_new_inst();
1103b32e
OZ
839
840 switch ($1->class & 0xff00) {
841 case SYM_CONSTANT: $$->code = 'C'; break;
842 case SYM_VARIABLE: $$->code = 'V'; break;
843 default: cf_error("%s: variable expected.", $1->name);
92a72a4c 844 }
1103b32e
OZ
845
846 $$->a1.p = $1->def;
847 $$->a2.p = $1->name;
92a72a4c
OZ
848 }
849
2bdb5e00 850static_attr:
a5fc5958
OZ
851 FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; }
852 | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; }
5e173e9f 853 | NET { $$ = f_new_inst(); $$->aux = T_NET; $$->a2.i = SA_NET; }
a5fc5958
OZ
854 | PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
855 | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
856 | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
a5fc5958
OZ
857 | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
858 | IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
859 | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
2bdb5e00
PM
860 ;
861
84c7e194 862term:
f4536657 863 '(' term ')' { $$ = $2; }
d4d75628 864 | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
c5a06f65
PM
865 | term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; }
866 | term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; }
867 | term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; }
5f4aee76
PM
868 | term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; }
869 | term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; }
2d496d20 870 | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
d4d75628
PM
871 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
872 | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
873 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
874 | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
875 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
876 | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
768d5e10 877 | term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; }
995e5894 878 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
2d496d20 879 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
23b1539b 880
92a72a4c 881 | symbol { $$ = $1; }
1183b6b2 882 | constant { $$ = $1; }
42a0c054 883 | constructor { $$ = $1; }
4515bdba 884
0dc4431c 885 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
2bdb5e00
PM
886
887 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
fe613ecd 888
db1326aa 889 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
36bbfc70 890
2d496d20 891 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
684c6f5a 892 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
e58f8c28 893 | term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; }
69ae5784 894 | term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; }
2d496d20 895 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
7ea5b00f
OZ
896 | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
897 | term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
9c9cc35c 898 | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
7f77e250
PM
899
900/* Communities */
10a53608
PM
901/* This causes one shift/reduce conflict
902 | rtadot dynamic_attr '.' ADD '(' term ')' { }
903 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
904 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
a2d15746 905 | rtadot dynamic_attr '.' RESET{ }
10a53608 906*/
7f77e250 907
e399b6f6 908 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
9c400ec9 909 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
42a0c054 910 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
66dbdbd9 911 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
c8cafc8e
OZ
912 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
913 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
4444ed2b 914 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
e08d2ff0 915 | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
afc54517 916
0264ccf6
PT
917 | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
918 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
af582c48 919
4b135d09 920 | FORMAT '(' term ')' { $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; }
9b0a0ba9 921
a2d15746 922/* | term '.' LEN { $$->code = P('P','l'); } */
7f77e250 923
995e5894
PM
924/* function_call is inlined here */
925 | SYM '(' var_list ')' {
926 struct symbol *sym;
927 struct f_inst *inst = $3;
928 if ($1->class != SYM_FUNCTION)
a5a947d4 929 cf_error("You can't call something which is not a function. Really.");
995e5894
PM
930 DBG("You are calling function %s\n", $1->name);
931 $$ = f_new_inst();
932 $$->code = P('c','a');
933 $$->a1.p = inst;
083c43e2
OZ
934 $$->a2.p = $1->def;
935 sym = $1->aux2;
995e5894
PM
936 while (sym || inst) {
937 if (!sym || !inst)
a5a947d4 938 cf_error("Wrong number of arguments for function %s.", $1->name);
995e5894
PM
939 DBG( "You should pass parameter called %s\n", sym->name);
940 inst->a1.p = sym;
083c43e2 941 sym = sym->aux2;
995e5894
PM
942 inst = inst->next;
943 }
944 }
ba921648
PM
945 ;
946
947break_command:
03e3d184
MM
948 QUITBIRD { $$ = F_QUITBIRD; }
949 | ACCEPT { $$ = F_ACCEPT; }
950 | REJECT { $$ = F_REJECT; }
951 | ERROR { $$ = F_ERROR; }
952 | PRINT { $$ = F_NOP; }
953 | PRINTN { $$ = F_NONL; }
ba921648
PM
954 ;
955
23b1539b 956print_one:
2db3b288 957 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
958 ;
959
960print_list: /* EMPTY */ { $$ = NULL; }
995e5894
PM
961 | print_one { $$ = $1; }
962 | print_one ',' print_list {
23b1539b 963 if ($1) {
995e5894 964 $1->next = $3;
23b1539b 965 $$ = $1;
995e5894 966 } else $$ = $3;
23b1539b
PM
967 }
968 ;
969
c8cafc8e 970var_listn: term {
d3dd620b
PM
971 $$ = f_new_inst();
972 $$->code = 's';
973 $$->a1.p = NULL;
974 $$->a2.p = $1;
975 $$->next = NULL;
976 }
6dc7a0cb 977 | term ',' var_listn {
6542ece9
PM
978 $$ = f_new_inst();
979 $$->code = 's';
980 $$->a1.p = NULL;
981 $$->a2.p = $1;
982 $$->next = $3;
983 }
984 ;
985
6dc7a0cb
PM
986var_list: /* EMPTY */ { $$ = NULL; }
987 | var_listn { $$ = $1; }
988 ;
989
23b1539b 990cmd:
49955645
MM
991 IF term THEN block {
992 $$ = f_new_inst();
993 $$->code = '?';
994 $$->a1.p = $2;
995 $$->a2.p = $4;
23b1539b 996 }
49955645
MM
997 | IF term THEN block ELSE block {
998 struct f_inst *i = f_new_inst();
999 i->code = '?';
1000 i->a1.p = $2;
1001 i->a2.p = $4;
23b1539b
PM
1002 $$ = f_new_inst();
1003 $$->code = '?';
49955645
MM
1004 $$->a1.p = i;
1005 $$->a2.p = $6;
23b1539b 1006 }
ba921648 1007 | SYM '=' term ';' {
84c7e194 1008 $$ = f_new_inst();
d4d75628 1009 DBG( "Ook, we'll set value\n" );
ba921648 1010 if (($1->class & ~T_MASK) != SYM_VARIABLE)
a5a947d4 1011 cf_error( "You may set only variables." );
23b1539b 1012 $$->code = 's';
2db3b288
PM
1013 $$->a1.p = $1;
1014 $$->a2.p = $3;
b9d70dc8 1015 }
2d496d20
PM
1016 | RETURN term ';' {
1017 $$ = f_new_inst();
d4d75628 1018 DBG( "Ook, we'll return the value\n" );
2d496d20
PM
1019 $$->code = 'r';
1020 $$->a1.p = $2;
1021 }
db1326aa 1022 | rtadot dynamic_attr '=' term ';' {
6c14255d 1023 $$ = $2;
0dc4431c 1024 $$->code = P('e','S');
6c14255d 1025 $$->a1.p = $4;
f31156ca 1026 }
0dc4431c
PM
1027 | rtadot static_attr '=' term ';' {
1028 $$ = $2;
1029 if (!$$->a1.i)
1030 cf_error( "This static attribute is read-only.");
1031 $$->code = P('a','S');
1032 $$->a1.p = $4;
1033 }
1034 | PREFERENCE '=' term ';' {
1035 $$ = f_new_inst();
1036 $$->code = P('P','S');
1037 $$->a1.p = $3;
c8cafc8e 1038 }
db1326aa 1039 | UNSET '(' rtadot dynamic_attr ')' ';' {
6c14255d 1040 $$ = $4;
9f4929e7 1041 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
2d496d20 1042 $$->code = P('e','S');
48f9e019 1043 $$->a1.p = NULL;
c7b43f33 1044 }
2d496d20
PM
1045 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
1046 | function_call ';' { $$ = $1; }
7db7b7db
PM
1047 | CASE term '{' switch_body '}' {
1048 $$ = f_new_inst();
2d496d20 1049 $$->code = P('S','W');
7db7b7db 1050 $$->a1.p = $2;
41be4444 1051 $$->a2.p = build_tree( $4 );
7db7b7db 1052 }
7d6eebae 1053
42a0c054 1054 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
7d6eebae 1055 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
42a0c054
OZ
1056 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
1057 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
1058 | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
3ec0bedc 1059 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
9b0a0ba9
OZ
1060 ;
1061
1062get_cf_position:
1063{
1064 $$ = cf_text;
1065};
1066
1067
b9d70dc8 1068CF_END