]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Enable ECMP and Link detection by default
[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
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
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,
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
427CF_GRAMMAR
428
e0f2e42f
MM
429CF_ADDTO(conf, filter_def)
430filter_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
440CF_ADDTO(conf, filter_eval)
441filter_eval:
442 EVAL term { f_eval_int($2); }
443 ;
444
9b0a0ba9
OZ
445CF_ADDTO(conf, bt_test_suite)
446bt_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
460type:
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
497one_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 */
509decls: /* 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 517declsn: one_decl { $$ = $1; }
736fd730 518 | one_decl ';' declsn {
4515bdba 519 $$ = $1;
083c43e2 520 $$->aux2 = $3;
6dc7a0cb
PM
521 }
522 ;
523
e0f2e42f 524filter_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
533filter:
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
541where_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 565function_params:
d4d75628 566 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
6dc7a0cb 567 | '(' ')' { $$=NULL; }
ba921648 568 ;
b9d70dc8 569
ba921648
PM
570function_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
583CF_ADDTO(conf, function_def)
584function_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 601cmds: /* EMPTY */ { $$ = NULL; }
5f47c4c1
OZ
602 | cmds_int { $$ = $1->next; $1->next = NULL; }
603 ;
604
605cmds_int: cmd { $$ = $1; $1->next = $1; }
606 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
84c7e194
PM
607 ;
608
2575593e 609block:
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 621fipa:
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 635set_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
650switch_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
657cnum:
658 term { $$ = f_eval_int($1); }
b8cc390e
OZ
659
660pair_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
674ec_kind:
675 RT { $$ = EC_RT; }
676 | RO { $$ = EC_RO; }
677 | UNKNOWN NUM { $$ = $2; }
678 | GENERIC { $$ = EC_GENERIC; }
679 ;
680
681ec_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
687lc_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
699set_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
707switch_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 715set_items:
b8cc390e
OZ
716 set_item
717 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
718 ;
719
720switch_items:
721 switch_item
722 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
38506f71
PM
723 ;
724
b1a597e0 725fprefix:
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
736fprefix_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 741switch_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 760bgp_path_expr:
c8cafc8e 761 symbol { $$ = $1; }
92a72a4c
OZ
762 | '(' term ')' { $$ = $2; }
763 ;
764
f9491630 765bgp_path:
cf186034 766 PO bgp_path_tail1 PC { $$ = $2; }
f9491630 767 | '/' bgp_path_tail2 '/' { $$ = $2; }
f9491630
OZ
768 ;
769
770bgp_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 779bgp_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 785constant:
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 799constructor:
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 */
811CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
f4536657 812
2e18b87d 813rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 814 ;
f4536657 815
2d496d20
PM
816function_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
839symbol:
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 853static_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 865term:
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
953break_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 962print_one:
2db3b288 963 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
964 ;
965
966print_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 976var_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
992var_list: /* EMPTY */ { $$ = NULL; }
993 | var_listn { $$ = $1; }
994 ;
995
23b1539b 996cmd:
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
1068get_cf_position:
1069{
1070 $$ = cf_text;
1071};
1072
1073
b9d70dc8 1074CF_END