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