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