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