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