]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Allow matching on enums:
[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 *
b9d70dc8
PM
8 */
9
10CF_HDR
11
2edb31b0
MM
12CF_DEFINES
13
2d496d20
PM
14#define P(a,b) ((a<<8) | b)
15
b9d70dc8
PM
16CF_DECLS
17
e4a73dbf 18CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ba921648 19 ACCEPT, REJECT, ERROR, QUITBIRD,
10a53608 20 INT, BOOL, IP, PREFIX, PAIR, SET, STRING, BGPMASK, BGPPATH, CLIST,
7db7b7db 21 IF, THEN, ELSE, CASE,
23b1539b 22 TRUE, FALSE,
0dc4431c 23 FROM, GW, NET, MASK, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
36bbfc70 24 LEN,
f4536657 25 DEFINED,
7f77e250 26 ADD, DELETE, CONTAINS, RESET,
e399b6f6 27 PREPEND, MATCH,
afc54517 28 EMPTY,
1c20608e 29 FILTER, WHERE, EVAL)
b9d70dc8 30
f4536657 31%nonassoc THEN
4ed8718a 32%nonassoc ELSE
f4536657 33
2bdb5e00 34%type <x> term block cmds cmd function_body constant print_one print_list var_list var_listn dynamic_attr static_attr function_call
430da60f 35%type <f> filter filter_body where_filter
4515bdba 36%type <i> type break_command pair
41be4444 37%type <e> set_item set_items switch_body
e3f2d5fc 38%type <v> set_atom fprefix fprefix_s fipa
6dc7a0cb 39%type <s> decls declsn one_decl function_params
77de6882
PM
40%type <h> bgp_path
41%type <i> bgp_one
b9d70dc8
PM
42
43CF_GRAMMAR
44
e0f2e42f
MM
45CF_ADDTO(conf, filter_def)
46filter_def:
cb8034f4 47 FILTER SYM { cf_push_scope( $2 ); } filter_body {
ae3e1af2
PM
48 cf_define_symbol($2, SYM_FILTER, $4);
49 $4->name = $2->name;
d4d75628 50 DBG( "We have new filter defined (%s)\n", $2->name );
ae3e1af2 51 cf_pop_scope();
b9d70dc8
PM
52 }
53 ;
54
1c20608e
MM
55CF_ADDTO(conf, filter_eval)
56filter_eval:
57 EVAL term { f_eval_int($2); }
58 ;
59
ba921648
PM
60type:
61 INT { $$ = T_INT; }
62 | BOOL { $$ = T_BOOL; }
63 | IP { $$ = T_IP; }
64 | PREFIX { $$ = T_PREFIX; }
65 | PAIR { $$ = T_PAIR; }
66 | STRING { $$ = T_STRING; }
10a53608
PM
67 | BGPMASK { $$ = T_PATH_MASK; }
68 | BGPPATH { $$ = T_PATH; }
69 | CLIST { $$ = T_CLIST; }
ba921648
PM
70 | type SET {
71 switch ($1) {
72 default:
ad9074e9 73 cf_error( "You can not create sets of this type" );
ba921648
PM
74 case T_INT: case T_IP: case T_PREFIX: case T_PAIR:
75 }
76 $$ = $1 | T_SET;
77 }
78 ;
79
6dc7a0cb
PM
80one_decl:
81 type SYM {
4107df1d 82 cf_define_symbol($2, SYM_VARIABLE | $1, NULL);
d4d75628 83 DBG( "New variable %s type %x\n", $2->name, $1 );
cb8034f4 84 $2->aux = 0;
d3dd620b
PM
85 {
86 struct f_val * val;
87 val = cfg_alloc(sizeof(struct f_val));
88 val->type = $1;
89 $2->aux2 = val;
90 }
6542ece9 91 $$=$2;
ba921648
PM
92 }
93 ;
94
6dc7a0cb
PM
95/* Decls with ';' at the end */
96decls: /* EMPTY */ { $$ = NULL; }
97 | one_decl ';' decls {
98 $$ = $1;
cb8034f4 99 $$->aux = (int) $3;
6dc7a0cb
PM
100 }
101 ;
102
3c989eb4 103/* Declarations that have no ';' at the end. */
6dc7a0cb
PM
104declsn: one_decl { $$ = $1; }
105 | declsn ';' one_decl {
4515bdba
PM
106 $$ = $1;
107 $$->aux = (int) $3;
6dc7a0cb
PM
108 }
109 ;
110
e0f2e42f 111filter_body:
ba921648 112 function_body {
e0f2e42f
MM
113 struct filter *f = cfg_alloc(sizeof(struct filter));
114 f->name = NULL;
ba921648 115 f->root = $1;
e0f2e42f
MM
116 $$ = f;
117 }
118 ;
119
120filter:
121 SYM {
122 if ($1->class != SYM_FILTER) cf_error("No such filter");
123 $$ = $1->def;
124 }
125 | filter_body
126 ;
127
430da60f
MM
128where_filter:
129 WHERE term {
130 /* Construct 'IF term THEN ACCEPT; REJECT;' */
131 struct filter *f = cfg_alloc(sizeof(struct filter));
132 struct f_inst *i, *acc, *rej;
133 acc = f_new_inst(); /* ACCEPT */
2d496d20 134 acc->code = P('p',',');
430da60f
MM
135 acc->a1.p = NULL;
136 acc->a2.i = F_ACCEPT;
137 rej = f_new_inst(); /* REJECT */
2d496d20 138 rej->code = P('p',',');
430da60f
MM
139 rej->a1.p = NULL;
140 rej->a2.i = F_REJECT;
141 i = f_new_inst(); /* IF */
142 i->code = '?';
143 i->a1.p = $2;
144 i->a2.p = acc;
145 i->next = rej;
146 f->name = NULL;
147 f->root = i;
148 $$ = f;
149 }
150 ;
151
ba921648 152function_params:
d4d75628 153 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
6dc7a0cb 154 | '(' ')' { $$=NULL; }
ba921648 155 ;
b9d70dc8 156
ba921648
PM
157function_body:
158 decls '{' cmds '}' {
159 $$ = $3;
84c7e194 160 }
ba921648
PM
161 ;
162
163CF_ADDTO(conf, function_def)
164function_def:
1c20608e 165 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name ); cf_push_scope($2); } function_params function_body {
ae3e1af2 166 cf_define_symbol($2, SYM_FUNCTION, $5);
cb8034f4 167 $2->aux = (int) $4;
ae3e1af2 168 $2->aux2 = $5;
d4d75628 169 DBG("Hmm, we've got one function here - %s\n", $2->name);
ae3e1af2 170 cf_pop_scope();
ba921648
PM
171 }
172 ;
173
174/* Programs */
175
176cmds: /* EMPTY */ { $$ = NULL; }
177 | cmd cmds {
84c7e194 178 if ($1) {
7db7b7db 179 if ($1->next)
ad9074e9 180 bug("Command has next already set");
ba921648 181 $1->next = $2;
84c7e194 182 $$ = $1;
ba921648 183 } else $$ = $2;
84c7e194
PM
184 }
185 ;
186
2575593e 187block:
ba921648 188 cmd {
2575593e
PM
189 $$=$1;
190 }
191 | '{' cmds '}' {
192 $$=$2;
193 }
194 ;
195
d3dd620b
PM
196/*
197 * Simple types, their bison value is int
198 */
199pair:
200 '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; }
201 ;
202
203/*
204 * Complex types, their bison value is struct f_val
205 */
758458be 206fprefix_s:
60de3356 207 IPA '/' NUM %prec '/' {
758458be
MM
208 if (!ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d", $1, $3);
209 $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
210 }
d3dd620b
PM
211 ;
212
758458be
MM
213fprefix:
214 fprefix_s { $$ = $1; }
215 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
216 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
217 | fprefix_s '{' NUM ',' NUM '}' { $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8); }
d3dd620b
PM
218 ;
219
e3f2d5fc 220fipa:
60de3356 221 IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
d3dd620b
PM
222 ;
223
38506f71 224set_atom:
d3dd620b
PM
225 NUM { $$.type = T_INT; $$.val.i = $1; }
226 | pair { $$.type = T_PAIR; $$.val.i = $1; }
e3f2d5fc 227 | fipa { $$ = $1; }
758458be 228 | fprefix { $$ = $1; }
1895e81e 229 | ENUM { $$.type = $1 >> 16; $$.val.i = $1 & 0xffff; }
38506f71
PM
230 ;
231
232set_item:
995e5894
PM
233 set_atom {
234 $$ = f_new_tree();
235 $$->from = $1;
236 if ($1.type != T_PREFIX)
237 $$->to = $1;
238 else {
239 $$->to = $1;
240 $$->to.val.px.ip = ipa_or( $$->to.val.px.ip, ipa_not( ipa_mkmask( $$->to.val.px.len ) ));
241 }
242 }
243 | set_atom '.' '.' set_atom {
244 $$ = f_new_tree();
245 $$->from = $1;
246 $$->to = $4;
247 if (($1.type == T_PREFIX) || ($4.type == T_PREFIX)) cf_error( "You can not use prefixes for range" );
248 }
38506f71
PM
249 ;
250
251set_items:
252 set_item { $$ = $1; }
253 | set_items ',' set_item { $$ = $3; $$->left = $1; }
254 ;
255
41be4444
PM
256switch_body: /* EMPTY */ { $$ = NULL; }
257 | set_item ':' cmds switch_body {
258 $$ = $1;
259 $$->data = $3;
260 $$->left = $4;
261 }
262 | ELSE ':' cmds {
263 $$ = f_new_tree();
264 $$->from.type = T_VOID;
265 $$->to.type = T_VOID;
266 $$->data = $3;
267 }
268 ;
d3dd620b 269
e4a73dbf
PM
270/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
271
77de6882
PM
272bgp_one:
273 NUM { $$ = $1; }
9a09a64b 274 | '?' { $$ = PM_ANY; }
77de6882
PM
275 ;
276
277bgp_path:
dcab7890
PM
278 bgp_one { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; }
279 | bgp_one bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = $1; }
77de6882
PM
280 ;
281
23b1539b 282constant:
e4a73dbf 283 NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
c7b43f33
PM
284 | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
285 | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
286 | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
287 | pair { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR; $$->a2.i = $1; }
e3f2d5fc 288 | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
758458be 289 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
d4d75628 290 | '[' 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 291 | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
f71bded6 292 | '/' bgp_path '/' { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $2; $$->a1.p = val; }
23b1539b
PM
293 ;
294
db1326aa
MM
295/*
296 * Maybe there are no dynamic attributes defined by protocols.
297 * For such cases, we force the dynamic_attr list to contain
298 * at least an invalid token, so it's syntantically correct.
299 */
300CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
f4536657 301
2e18b87d 302rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 303 ;
f4536657 304
2d496d20
PM
305function_call:
306 SYM '(' var_list ')' {
307 struct symbol *sym;
308 struct f_inst *inst = $3;
309 if ($1->class != SYM_FUNCTION)
310 cf_error("You can not call something which is not function. Really.");
d4d75628 311 DBG("You are calling function %s\n", $1->name);
2d496d20
PM
312 $$ = f_new_inst();
313 $$->code = P('c','a');
314 $$->a1.p = inst;
315 $$->a2.p = $1->aux2;
316 sym = (void *) $1->aux;
317 while (sym || inst) {
318 if (!sym || !inst)
319 cf_error("wrong number of arguments for function %s.", $1->name);
d4d75628 320 DBG( "You should pass parameter called %s\n", sym->name);
2d496d20
PM
321 inst->a1.p = sym;
322 sym = (void *) sym->aux;
323 inst = inst->next;
324 }
325 }
326 ;
327
2bdb5e00 328static_attr:
0dc4431c 329 FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); $$->a1.i = 1; }
26c09e1d 330
0dc4431c 331 | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); $$->a1.i = 1; }
26c09e1d
PM
332 | NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = 0x12345678; /* This is actually ok - T_PREFIX is special-cased. */ }
333 | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); }
0dc4431c 334 | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope); $$->a1.i = 1; }
26c09e1d
PM
335 | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = OFFSETOF(struct rta, cast); }
336 | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = OFFSETOF(struct rta, dest); }
2bdb5e00
PM
337 ;
338
84c7e194 339term:
f4536657 340 '(' term ')' { $$ = $2; }
d4d75628 341 | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
c5a06f65
PM
342 | term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; }
343 | term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; }
344 | term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; }
2d496d20 345 | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
d4d75628
PM
346 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
347 | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
348 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
349 | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
350 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
351 | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
995e5894 352 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
2d496d20 353 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
23b1539b 354
1183b6b2 355 | constant { $$ = $1; }
2575593e
PM
356 | SYM {
357 $$ = f_new_inst();
358 switch ($1->class) {
cbfd671f
PM
359 case SYM_NUMBER:
360 $$ = f_new_inst();
361 $$->code = 'c';
362 $$->aux = T_INT;
363 $$->a2.i = $1->aux;
364 break;
365 case SYM_IPA:
366 { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_IP; val->val.px.ip = * (ip_addr *) ($1->def); }
367 break;
ba921648 368 case SYM_VARIABLE | T_INT:
d3dd620b
PM
369 case SYM_VARIABLE | T_PAIR:
370 case SYM_VARIABLE | T_PREFIX:
371 case SYM_VARIABLE | T_IP:
dcab7890 372 case SYM_VARIABLE | T_PATH_MASK:
e399b6f6 373 case SYM_VARIABLE | T_PATH:
9c400ec9 374 case SYM_VARIABLE | T_CLIST:
d3dd620b
PM
375 $$->code = 'C';
376 $$->a1.p = $1->aux2;
2575593e
PM
377 break;
378 default:
1183b6b2 379 cf_error("Can not use this class of symbol (%s,%x) as variable.", $1->name, $1->class );
2575593e
PM
380 }
381 }
4515bdba 382
0dc4431c 383 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
2bdb5e00
PM
384
385 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
fe613ecd 386
db1326aa 387 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
36bbfc70 388
2d496d20 389 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
684c6f5a 390 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
2d496d20 391 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
7f77e250
PM
392
393/* Communities */
10a53608
PM
394/* This causes one shift/reduce conflict
395 | rtadot dynamic_attr '.' ADD '(' term ')' { }
396 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
397 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
a2d15746 398 | rtadot dynamic_attr '.' RESET{ }
10a53608 399*/
7f77e250 400
e399b6f6 401 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
9c400ec9 402 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
e399b6f6 403 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
4444ed2b
PM
404 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
405 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
afc54517 406
a2d15746 407/* | term '.' LEN { $$->code = P('P','l'); } */
7f77e250 408
995e5894
PM
409/* function_call is inlined here */
410 | SYM '(' var_list ')' {
411 struct symbol *sym;
412 struct f_inst *inst = $3;
413 if ($1->class != SYM_FUNCTION)
414 cf_error("You can not call something which is not function. Really.");
415 DBG("You are calling function %s\n", $1->name);
416 $$ = f_new_inst();
417 $$->code = P('c','a');
418 $$->a1.p = inst;
419 $$->a2.p = $1->aux2;
420 sym = (void *) $1->aux;
421 while (sym || inst) {
422 if (!sym || !inst)
423 cf_error("wrong number of arguments for function %s.", $1->name);
424 DBG( "You should pass parameter called %s\n", sym->name);
425 inst->a1.p = sym;
426 sym = (void *) sym->aux;
427 inst = inst->next;
428 }
429 }
ba921648
PM
430 ;
431
432break_command:
433 QUITBIRD { $$ = F_QUITBIRD }
434 | ACCEPT { $$ = F_ACCEPT }
435 | REJECT { $$ = F_REJECT }
436 | ERROR { $$ = F_ERROR }
23b1539b 437 | PRINT { $$ = F_NOP }
d3dd620b 438 | PRINTN { $$ = F_NONL }
ba921648
PM
439 ;
440
23b1539b 441print_one:
2db3b288 442 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
443 ;
444
445print_list: /* EMPTY */ { $$ = NULL; }
995e5894
PM
446 | print_one { $$ = $1; }
447 | print_one ',' print_list {
23b1539b 448 if ($1) {
995e5894 449 $1->next = $3;
23b1539b 450 $$ = $1;
995e5894 451 } else $$ = $3;
23b1539b 452 }
995e5894 453
23b1539b
PM
454 ;
455
6dc7a0cb 456var_listn: term {
d3dd620b
PM
457 $$ = f_new_inst();
458 $$->code = 's';
459 $$->a1.p = NULL;
460 $$->a2.p = $1;
461 $$->next = NULL;
462 }
6dc7a0cb 463 | term ',' var_listn {
6542ece9
PM
464 $$ = f_new_inst();
465 $$->code = 's';
466 $$->a1.p = NULL;
467 $$->a2.p = $1;
468 $$->next = $3;
469 }
470 ;
471
6dc7a0cb
PM
472var_list: /* EMPTY */ { $$ = NULL; }
473 | var_listn { $$ = $1; }
474 ;
475
23b1539b 476cmd:
49955645
MM
477 IF term THEN block {
478 $$ = f_new_inst();
479 $$->code = '?';
480 $$->a1.p = $2;
481 $$->a2.p = $4;
23b1539b 482 }
49955645
MM
483 | IF term THEN block ELSE block {
484 struct f_inst *i = f_new_inst();
485 i->code = '?';
486 i->a1.p = $2;
487 i->a2.p = $4;
23b1539b
PM
488 $$ = f_new_inst();
489 $$->code = '?';
49955645
MM
490 $$->a1.p = i;
491 $$->a2.p = $6;
23b1539b 492 }
ba921648 493 | SYM '=' term ';' {
84c7e194 494 $$ = f_new_inst();
d4d75628 495 DBG( "Ook, we'll set value\n" );
ba921648 496 if (($1->class & ~T_MASK) != SYM_VARIABLE)
ad9074e9 497 cf_error( "You may only set variables, and this is %x.", $1->class );
23b1539b 498 $$->code = 's';
2db3b288
PM
499 $$->a1.p = $1;
500 $$->a2.p = $3;
b9d70dc8 501 }
2d496d20
PM
502 | RETURN term ';' {
503 $$ = f_new_inst();
d4d75628 504 DBG( "Ook, we'll return the value\n" );
2d496d20
PM
505 $$->code = 'r';
506 $$->a1.p = $2;
507 }
db1326aa 508 | rtadot dynamic_attr '=' term ';' {
6c14255d 509 $$ = $2;
0dc4431c 510 $$->code = P('e','S');
6c14255d 511 $$->a1.p = $4;
f31156ca 512 }
0dc4431c
PM
513 | rtadot static_attr '=' term ';' {
514 $$ = $2;
515 if (!$$->a1.i)
516 cf_error( "This static attribute is read-only.");
517 $$->code = P('a','S');
518 $$->a1.p = $4;
519 }
520 | PREFERENCE '=' term ';' {
521 $$ = f_new_inst();
522 $$->code = P('P','S');
523 $$->a1.p = $3;
524 }
db1326aa 525 | UNSET '(' rtadot dynamic_attr ')' ';' {
6c14255d 526 $$ = $4;
9f4929e7 527 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
2d496d20 528 $$->code = P('e','S');
48f9e019 529 $$->a1.p = NULL;
c7b43f33 530 }
2d496d20
PM
531 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
532 | function_call ';' { $$ = $1; }
7db7b7db
PM
533 | CASE term '{' switch_body '}' {
534 $$ = f_new_inst();
2d496d20 535 $$->code = P('S','W');
7db7b7db 536 $$->a1.p = $2;
41be4444 537 $$->a2.p = build_tree( $4 );
7db7b7db 538 }
7d6eebae
PM
539
540
541 | rtadot dynamic_attr '.' EMPTY ';'
542 { struct f_inst *i = f_new_inst(); i->code = 'E'; i->aux = T_CLIST; $$ = $2; $$->code = P('e','S'); $$->a1.p = i; }
543 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
544 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
545 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
b9d70dc8
PM
546 ;
547
548CF_END