]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Sending of update messages works!
[thirdparty/bird.git] / filter / config.Y
CommitLineData
b9d70dc8
PM
1/*
2 * BIRD - filters
3 *
6542ece9 4 * Copyright 1998,1999 Pavel Machek
b9d70dc8
PM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
c9f8c1a8 7 *
f4536657 8 FIXME (nonurgent): define keyword
2d496d20 9 FIXME (for BGP): whole system of paths, path ~ string, path.prepend(), path.originate
c9f8c1a8 10 FIXME: create community lists
60d7d10e 11 FIXME: IP addresses in ipv6
0a06a9b8
PM
12
13
7f77e250
PM
14 FIXME: check messages for \n at the end
15
0a06a9b8
PM
16(1) Cesty
17
18 AS paths budtez interne reprezentovany stejne jako v BGP (viz RFC 1771),
19to znamena jako posloupnost segmentu, z nichz kazdy je budto posloupnost nebo
20mnozina cisel ASu. Na cestach nadefinuji nasledujici operace:
21
22 - zformatovani do stringu
23 - append dalsiho AS k ceste
24
25Filtry by mely podporovat:
26
77de6882 27 - operator pridani AS k ceste [bgppath_prepend]
0a06a9b8
PM
28 - matchovani na pritomnost podposloupnosti v ceste (pricemz vyskytne-li
29 se tam mnozina, tak si ji lze predstavit prerovnanou v libovolnem
30 poradi)
7f77e250 31
0a06a9b8
PM
32 - operator zjisteni delky cesty (pro vypocet metrik)
33
34Byl bych rad, kdyby se samotne matchovaci funkce objevily v proto/bgp/attrs.c.
35
7f77e250
PM
36Jsou v sitove endianite. [lib/unaligned.h]
37
0a06a9b8
PM
38
39(2) Community-listy
40
7f77e250
PM
41posloupnost 32bitovych cisel s delkou.
42
0a06a9b8
PM
43Community list budiz interne reprezentovan jako posloupnost 32-bitovych cisel.
44
45Filtry by se mely na communities divat jako na usporadane dvojice 16-bitovych
46cisel (prvni je cislo AS, ktery community definoval, druhe pak community ID
47v ramci AS) a melo by byt mozne definovat si konstanty typu community.
48K dispozici by mely byt nasledujici operace:
49
7f77e250
PM
50 - zjisteni pritomnosti community v listu [linearni pruchod]
51 - pridani community do listu [s kopii]
52 - odebrani community z listu [s kopii]
0a06a9b8
PM
53 - zresetovani listu
54
55Pro operace na cestach i na community listech by se mela pouzivat `teckova'
56notace pouzita v mem puvodnim navrhu syntaxe.
57
b9d70dc8
PM
58 */
59
60CF_HDR
61
2d496d20
PM
62#define P(a,b) ((a<<8) | b)
63
b9d70dc8
PM
64CF_DECLS
65
e4a73dbf 66CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ba921648 67 ACCEPT, REJECT, ERROR, QUITBIRD,
10a53608 68 INT, BOOL, IP, PREFIX, PAIR, SET, STRING, BGPMASK, BGPPATH, CLIST,
7db7b7db 69 IF, THEN, ELSE, CASE,
23b1539b 70 TRUE, FALSE,
db1326aa 71 FROM, GW, NET, MASK, SOURCE,
36bbfc70 72 LEN,
f4536657 73 DEFINED,
7f77e250
PM
74 ADD, DELETE, CONTAINS, RESET,
75 APPEND, MATCH,
430da60f 76 FILTER, WHERE)
b9d70dc8 77
f4536657 78%nonassoc THEN
4ed8718a 79%nonassoc ELSE
f4536657 80
db1326aa 81%type <x> term block cmds cmd function_body constant print_one print_list var_list var_listn dynamic_attr function_call
430da60f 82%type <f> filter filter_body where_filter
4515bdba 83%type <i> type break_command pair
41be4444 84%type <e> set_item set_items switch_body
d3dd620b 85%type <v> set_atom prefix prefix_s ipa
6dc7a0cb 86%type <s> decls declsn one_decl function_params
77de6882
PM
87%type <h> bgp_path
88%type <i> bgp_one
b9d70dc8
PM
89
90CF_GRAMMAR
91
e0f2e42f
MM
92CF_ADDTO(conf, filter_def)
93filter_def:
cb8034f4 94 FILTER SYM { cf_push_scope( $2 ); } filter_body {
ae3e1af2
PM
95 cf_define_symbol($2, SYM_FILTER, $4);
96 $4->name = $2->name;
d4d75628 97 DBG( "We have new filter defined (%s)\n", $2->name );
ae3e1af2 98 cf_pop_scope();
b9d70dc8
PM
99 }
100 ;
101
ba921648
PM
102type:
103 INT { $$ = T_INT; }
104 | BOOL { $$ = T_BOOL; }
105 | IP { $$ = T_IP; }
106 | PREFIX { $$ = T_PREFIX; }
107 | PAIR { $$ = T_PAIR; }
108 | STRING { $$ = T_STRING; }
10a53608
PM
109 | BGPMASK { $$ = T_PATH_MASK; }
110 | BGPPATH { $$ = T_PATH; }
111 | CLIST { $$ = T_CLIST; }
ba921648
PM
112 | type SET {
113 switch ($1) {
114 default:
115 cf_error( "You can not create sets of this type\n" );
116 case T_INT: case T_IP: case T_PREFIX: case T_PAIR:
117 }
118 $$ = $1 | T_SET;
119 }
120 ;
121
6dc7a0cb
PM
122one_decl:
123 type SYM {
4107df1d 124 cf_define_symbol($2, SYM_VARIABLE | $1, NULL);
d4d75628 125 DBG( "New variable %s type %x\n", $2->name, $1 );
cb8034f4 126 $2->aux = 0;
d3dd620b
PM
127 {
128 struct f_val * val;
129 val = cfg_alloc(sizeof(struct f_val));
130 val->type = $1;
131 $2->aux2 = val;
132 }
6542ece9 133 $$=$2;
ba921648
PM
134 }
135 ;
136
6dc7a0cb
PM
137/* Decls with ';' at the end */
138decls: /* EMPTY */ { $$ = NULL; }
139 | one_decl ';' decls {
140 $$ = $1;
cb8034f4 141 $$->aux = (int) $3;
6dc7a0cb
PM
142 }
143 ;
144
3c989eb4 145/* Declarations that have no ';' at the end. */
6dc7a0cb
PM
146declsn: one_decl { $$ = $1; }
147 | declsn ';' one_decl {
4515bdba
PM
148 $$ = $1;
149 $$->aux = (int) $3;
6dc7a0cb
PM
150 }
151 ;
152
e0f2e42f 153filter_body:
ba921648 154 function_body {
e0f2e42f
MM
155 struct filter *f = cfg_alloc(sizeof(struct filter));
156 f->name = NULL;
ba921648 157 f->root = $1;
e0f2e42f
MM
158 $$ = f;
159 }
160 ;
161
162filter:
163 SYM {
164 if ($1->class != SYM_FILTER) cf_error("No such filter");
165 $$ = $1->def;
166 }
167 | filter_body
168 ;
169
430da60f
MM
170where_filter:
171 WHERE term {
172 /* Construct 'IF term THEN ACCEPT; REJECT;' */
173 struct filter *f = cfg_alloc(sizeof(struct filter));
174 struct f_inst *i, *acc, *rej;
175 acc = f_new_inst(); /* ACCEPT */
2d496d20 176 acc->code = P('p',',');
430da60f
MM
177 acc->a1.p = NULL;
178 acc->a2.i = F_ACCEPT;
179 rej = f_new_inst(); /* REJECT */
2d496d20 180 rej->code = P('p',',');
430da60f
MM
181 rej->a1.p = NULL;
182 rej->a2.i = F_REJECT;
183 i = f_new_inst(); /* IF */
184 i->code = '?';
185 i->a1.p = $2;
186 i->a2.p = acc;
187 i->next = rej;
188 f->name = NULL;
189 f->root = i;
190 $$ = f;
191 }
192 ;
193
ba921648 194function_params:
d4d75628 195 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
6dc7a0cb 196 | '(' ')' { $$=NULL; }
ba921648 197 ;
b9d70dc8 198
ba921648
PM
199function_body:
200 decls '{' cmds '}' {
201 $$ = $3;
84c7e194 202 }
ba921648
PM
203 ;
204
205CF_ADDTO(conf, function_def)
206function_def:
d4d75628 207 FUNCTION SYM { DBG( "Begining of function %s\n", $2->name ); cf_push_scope($2); } function_params function_body {
ba921648 208 extern struct f_inst *startup_func;
ae3e1af2 209 cf_define_symbol($2, SYM_FUNCTION, $5);
ba921648 210 if (!strcasecmp($2->name, "startup"))
ae3e1af2 211 startup_func = $5;
cb8034f4 212 $2->aux = (int) $4;
ae3e1af2 213 $2->aux2 = $5;
d4d75628 214 DBG("Hmm, we've got one function here - %s\n", $2->name);
ae3e1af2 215 cf_pop_scope();
ba921648
PM
216 }
217 ;
218
219/* Programs */
220
221cmds: /* EMPTY */ { $$ = NULL; }
222 | cmd cmds {
84c7e194 223 if ($1) {
7db7b7db
PM
224 if ($1->next)
225 bug("Command has next already set\n");
ba921648 226 $1->next = $2;
84c7e194 227 $$ = $1;
ba921648 228 } else $$ = $2;
84c7e194
PM
229 }
230 ;
231
2575593e 232block:
ba921648 233 cmd {
2575593e
PM
234 $$=$1;
235 }
236 | '{' cmds '}' {
237 $$=$2;
238 }
239 ;
240
d3dd620b
PM
241/*
242 * Simple types, their bison value is int
243 */
244pair:
245 '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; }
246 ;
247
248/*
249 * Complex types, their bison value is struct f_val
250 */
251prefix_s:
455ca441 252 IPA '/' NUM { $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3; if (ipa_nonzero(ipa_and($$.val.px.ip, ipa_not(ipa_mkmask($$.val.px.len))))) cf_error( "%I/%d is not really prefix\n", $$.val.px.ip, $$.val.px.len ); }
d3dd620b
PM
253 ;
254
255prefix:
256 prefix_s { $$ = $1; }
257 | prefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
258 | prefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
6dc7a0cb 259 | prefix_s '{' NUM ',' NUM '}' { $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8); }
d3dd620b
PM
260 ;
261
262ipa:
6dc7a0cb 263 IPA { $$.type = T_IP; $$.val.px.ip = $1; }
d3dd620b
PM
264 ;
265
38506f71 266set_atom:
d3dd620b
PM
267 NUM { $$.type = T_INT; $$.val.i = $1; }
268 | pair { $$.type = T_PAIR; $$.val.i = $1; }
269 | ipa { $$ = $1; }
270 | prefix { $$ = $1; }
38506f71
PM
271 ;
272
273set_item:
995e5894
PM
274 set_atom {
275 $$ = f_new_tree();
276 $$->from = $1;
277 if ($1.type != T_PREFIX)
278 $$->to = $1;
279 else {
280 $$->to = $1;
281 $$->to.val.px.ip = ipa_or( $$->to.val.px.ip, ipa_not( ipa_mkmask( $$->to.val.px.len ) ));
282 }
283 }
284 | set_atom '.' '.' set_atom {
285 $$ = f_new_tree();
286 $$->from = $1;
287 $$->to = $4;
288 if (($1.type == T_PREFIX) || ($4.type == T_PREFIX)) cf_error( "You can not use prefixes for range" );
289 }
38506f71
PM
290 ;
291
292set_items:
293 set_item { $$ = $1; }
294 | set_items ',' set_item { $$ = $3; $$->left = $1; }
295 ;
296
41be4444
PM
297switch_body: /* EMPTY */ { $$ = NULL; }
298 | set_item ':' cmds switch_body {
299 $$ = $1;
300 $$->data = $3;
301 $$->left = $4;
302 }
303 | ELSE ':' cmds {
304 $$ = f_new_tree();
305 $$->from.type = T_VOID;
306 $$->to.type = T_VOID;
307 $$->data = $3;
308 }
309 ;
d3dd620b 310
e4a73dbf
PM
311/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
312
77de6882
PM
313bgp_one:
314 NUM { $$ = $1; }
315 ;
316
317bgp_path:
dcab7890
PM
318 bgp_one { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; }
319 | bgp_one bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = $1; }
77de6882
PM
320 ;
321
23b1539b 322constant:
e4a73dbf 323 NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
c7b43f33
PM
324 | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
325 | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
326 | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
327 | pair { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR; $$->a2.i = $1; }
d3dd620b 328 | ipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
2f702671 329 | prefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
d4d75628 330 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
c7b43f33 331 | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
dcab7890 332 | '/' bgp_path '/' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PATH_MASK; $$->a2.p = $2; }
23b1539b
PM
333 ;
334
db1326aa
MM
335/*
336 * Maybe there are no dynamic attributes defined by protocols.
337 * For such cases, we force the dynamic_attr list to contain
338 * at least an invalid token, so it's syntantically correct.
339 */
340CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
f4536657 341
2e18b87d 342rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 343 ;
f4536657 344
2d496d20
PM
345function_call:
346 SYM '(' var_list ')' {
347 struct symbol *sym;
348 struct f_inst *inst = $3;
349 if ($1->class != SYM_FUNCTION)
350 cf_error("You can not call something which is not function. Really.");
d4d75628 351 DBG("You are calling function %s\n", $1->name);
2d496d20
PM
352 $$ = f_new_inst();
353 $$->code = P('c','a');
354 $$->a1.p = inst;
355 $$->a2.p = $1->aux2;
356 sym = (void *) $1->aux;
357 while (sym || inst) {
358 if (!sym || !inst)
359 cf_error("wrong number of arguments for function %s.", $1->name);
d4d75628 360 DBG( "You should pass parameter called %s\n", sym->name);
2d496d20
PM
361 inst->a1.p = sym;
362 sym = (void *) sym->aux;
363 inst = inst->next;
364 }
365 }
366 ;
367
84c7e194 368term:
f4536657 369 '(' term ')' { $$ = $2; }
d4d75628 370 | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
2d496d20 371 | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
d4d75628
PM
372 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
373 | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
374 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
375 | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
376 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
377 | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
995e5894 378 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
2d496d20 379 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
23b1539b 380
1183b6b2 381 | constant { $$ = $1; }
2575593e
PM
382 | SYM {
383 $$ = f_new_inst();
384 switch ($1->class) {
ba921648 385 case SYM_VARIABLE | T_INT:
d3dd620b
PM
386 case SYM_VARIABLE | T_PAIR:
387 case SYM_VARIABLE | T_PREFIX:
388 case SYM_VARIABLE | T_IP:
dcab7890 389 case SYM_VARIABLE | T_PATH_MASK:
d3dd620b
PM
390 $$->code = 'C';
391 $$->a1.p = $1->aux2;
2575593e
PM
392 break;
393 default:
1183b6b2 394 cf_error("Can not use this class of symbol (%s,%x) as variable.", $1->name, $1->class );
2575593e
PM
395 }
396 }
4515bdba 397
6c14255d 398 | rtadot FROM { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); }
36bbfc70 399
6c14255d
PM
400 | rtadot GW { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); }
401 | rtadot NET { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_PREFIX; $$->a2.i = 0x12345678; }
b1573615 402 | rtadot SOURCE { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); }
6dc7a0cb 403
db1326aa 404 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
36bbfc70 405
2d496d20
PM
406 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
407 | term '.' LEN { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_INT; }
408 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
7f77e250
PM
409
410/* Communities */
10a53608
PM
411/* This causes one shift/reduce conflict
412 | rtadot dynamic_attr '.' ADD '(' term ')' { }
413 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
414 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
a2d15746 415 | rtadot dynamic_attr '.' RESET{ }
10a53608 416*/
7f77e250
PM
417
418/* Paths */
a2d15746
PM
419 | term '.' APPEND '(' term ')' { }
420 | term '.' RESET { }
421/* | term '.' LEN { $$->code = P('P','l'); } */
7f77e250 422
995e5894
PM
423/* function_call is inlined here */
424 | SYM '(' var_list ')' {
425 struct symbol *sym;
426 struct f_inst *inst = $3;
427 if ($1->class != SYM_FUNCTION)
428 cf_error("You can not call something which is not function. Really.");
429 DBG("You are calling function %s\n", $1->name);
430 $$ = f_new_inst();
431 $$->code = P('c','a');
432 $$->a1.p = inst;
433 $$->a2.p = $1->aux2;
434 sym = (void *) $1->aux;
435 while (sym || inst) {
436 if (!sym || !inst)
437 cf_error("wrong number of arguments for function %s.", $1->name);
438 DBG( "You should pass parameter called %s\n", sym->name);
439 inst->a1.p = sym;
440 sym = (void *) sym->aux;
441 inst = inst->next;
442 }
443 }
ba921648
PM
444 ;
445
446break_command:
447 QUITBIRD { $$ = F_QUITBIRD }
448 | ACCEPT { $$ = F_ACCEPT }
449 | REJECT { $$ = F_REJECT }
450 | ERROR { $$ = F_ERROR }
23b1539b 451 | PRINT { $$ = F_NOP }
d3dd620b 452 | PRINTN { $$ = F_NONL }
ba921648
PM
453 ;
454
23b1539b 455print_one:
2db3b288 456 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
457 ;
458
459print_list: /* EMPTY */ { $$ = NULL; }
995e5894
PM
460 | print_one { $$ = $1; }
461 | print_one ',' print_list {
23b1539b 462 if ($1) {
995e5894 463 $1->next = $3;
23b1539b 464 $$ = $1;
995e5894 465 } else $$ = $3;
23b1539b 466 }
995e5894 467
23b1539b
PM
468 ;
469
6dc7a0cb 470var_listn: term {
d3dd620b
PM
471 $$ = f_new_inst();
472 $$->code = 's';
473 $$->a1.p = NULL;
474 $$->a2.p = $1;
475 $$->next = NULL;
476 }
6dc7a0cb 477 | term ',' var_listn {
6542ece9
PM
478 $$ = f_new_inst();
479 $$->code = 's';
480 $$->a1.p = NULL;
481 $$->a2.p = $1;
482 $$->next = $3;
483 }
484 ;
485
6dc7a0cb
PM
486var_list: /* EMPTY */ { $$ = NULL; }
487 | var_listn { $$ = $1; }
488 ;
489
23b1539b 490cmd:
49955645
MM
491 IF term THEN block {
492 $$ = f_new_inst();
493 $$->code = '?';
494 $$->a1.p = $2;
495 $$->a2.p = $4;
23b1539b 496 }
49955645
MM
497 | IF term THEN block ELSE block {
498 struct f_inst *i = f_new_inst();
499 i->code = '?';
500 i->a1.p = $2;
501 i->a2.p = $4;
23b1539b
PM
502 $$ = f_new_inst();
503 $$->code = '?';
49955645
MM
504 $$->a1.p = i;
505 $$->a2.p = $6;
23b1539b 506 }
ba921648 507 | SYM '=' term ';' {
84c7e194 508 $$ = f_new_inst();
d4d75628 509 DBG( "Ook, we'll set value\n" );
ba921648
PM
510 if (($1->class & ~T_MASK) != SYM_VARIABLE)
511 cf_error( "You may only set variables, and this is %x.\n", $1->class );
23b1539b 512 $$->code = 's';
2db3b288
PM
513 $$->a1.p = $1;
514 $$->a2.p = $3;
b9d70dc8 515 }
2d496d20
PM
516 | RETURN term ';' {
517 $$ = f_new_inst();
d4d75628 518 DBG( "Ook, we'll return the value\n" );
2d496d20
PM
519 $$->code = 'r';
520 $$->a1.p = $2;
521 }
db1326aa 522 | rtadot dynamic_attr '=' term ';' {
6c14255d 523 $$ = $2;
2d496d20 524 $$->code = P('e','S');
6c14255d 525 $$->a1.p = $4;
f31156ca 526 }
db1326aa 527 | UNSET '(' rtadot dynamic_attr ')' ';' {
6c14255d 528 $$ = $4;
9f4929e7 529 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
2d496d20 530 $$->code = P('e','S');
48f9e019 531 $$->a1.p = NULL;
c7b43f33 532 }
2d496d20
PM
533 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
534 | function_call ';' { $$ = $1; }
7db7b7db
PM
535 | CASE term '{' switch_body '}' {
536 $$ = f_new_inst();
2d496d20 537 $$->code = P('S','W');
7db7b7db 538 $$->a1.p = $2;
41be4444 539 $$->a2.p = build_tree( $4 );
7db7b7db 540 }
b9d70dc8
PM
541 ;
542
543CF_END