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