]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
Nested scopes could never have worked. My fault I wrote such a buggy code,
[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 {
ae3e1af2
PM
49 cf_define_symbol($2, SYM_FILTER, $4);
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 {
4107df1d 83 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:
1c20608e 166 FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name ); cf_push_scope($2); } function_params function_body {
ae3e1af2 167 cf_define_symbol($2, SYM_FUNCTION, $5);
cb8034f4 168 $2->aux = (int) $4;
ae3e1af2 169 $2->aux2 = $5;
d4d75628 170 DBG("Hmm, we've got one function here - %s\n", $2->name);
ae3e1af2 171 cf_pop_scope();
ba921648
PM
172 }
173 ;
174
175/* Programs */
176
177cmds: /* EMPTY */ { $$ = NULL; }
178 | cmd cmds {
84c7e194 179 if ($1) {
7db7b7db 180 if ($1->next)
ad9074e9 181 bug("Command has next already set");
ba921648 182 $1->next = $2;
84c7e194 183 $$ = $1;
ba921648 184 } else $$ = $2;
84c7e194
PM
185 }
186 ;
187
2575593e 188block:
ba921648 189 cmd {
2575593e
PM
190 $$=$1;
191 }
192 | '{' cmds '}' {
193 $$=$2;
194 }
195 ;
196
d3dd620b
PM
197/*
198 * Simple types, their bison value is int
199 */
200pair:
201 '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; }
202 ;
203
204/*
205 * Complex types, their bison value is struct f_val
206 */
758458be 207fprefix_s:
60de3356 208 IPA '/' NUM %prec '/' {
758458be
MM
209 if (!ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d", $1, $3);
210 $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
211 }
d3dd620b
PM
212 ;
213
758458be
MM
214fprefix:
215 fprefix_s { $$ = $1; }
216 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
217 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
218 | fprefix_s '{' NUM ',' NUM '}' { $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8); }
d3dd620b
PM
219 ;
220
e3f2d5fc 221fipa:
60de3356 222 IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
d3dd620b
PM
223 ;
224
38506f71 225set_atom:
d3dd620b
PM
226 NUM { $$.type = T_INT; $$.val.i = $1; }
227 | pair { $$.type = T_PAIR; $$.val.i = $1; }
e3f2d5fc 228 | fipa { $$ = $1; }
758458be 229 | fprefix { $$ = $1; }
1895e81e 230 | ENUM { $$.type = $1 >> 16; $$.val.i = $1 & 0xffff; }
38506f71
PM
231 ;
232
233set_item:
995e5894
PM
234 set_atom {
235 $$ = f_new_tree();
236 $$->from = $1;
237 if ($1.type != T_PREFIX)
238 $$->to = $1;
239 else {
240 $$->to = $1;
241 $$->to.val.px.ip = ipa_or( $$->to.val.px.ip, ipa_not( ipa_mkmask( $$->to.val.px.len ) ));
242 }
243 }
244 | set_atom '.' '.' set_atom {
245 $$ = f_new_tree();
246 $$->from = $1;
247 $$->to = $4;
248 if (($1.type == T_PREFIX) || ($4.type == T_PREFIX)) cf_error( "You can not use prefixes for range" );
249 }
38506f71
PM
250 ;
251
252set_items:
253 set_item { $$ = $1; }
254 | set_items ',' set_item { $$ = $3; $$->left = $1; }
255 ;
256
41be4444
PM
257switch_body: /* EMPTY */ { $$ = NULL; }
258 | set_item ':' cmds switch_body {
259 $$ = $1;
260 $$->data = $3;
261 $$->left = $4;
262 }
263 | ELSE ':' cmds {
264 $$ = f_new_tree();
265 $$->from.type = T_VOID;
266 $$->to.type = T_VOID;
267 $$->data = $3;
268 }
269 ;
d3dd620b 270
e4a73dbf
PM
271/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
272
77de6882
PM
273bgp_one:
274 NUM { $$ = $1; }
9a09a64b 275 | '?' { $$ = PM_ANY; }
77de6882
PM
276 ;
277
278bgp_path:
dcab7890
PM
279 bgp_one { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; }
280 | bgp_one bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = $1; }
77de6882
PM
281 ;
282
23b1539b 283constant:
e4a73dbf 284 NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
c7b43f33
PM
285 | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
286 | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
287 | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
288 | pair { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR; $$->a2.i = $1; }
e3f2d5fc 289 | fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
758458be 290 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
d4d75628 291 | '[' 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 292 | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
f71bded6 293 | '/' 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
294 ;
295
db1326aa
MM
296/*
297 * Maybe there are no dynamic attributes defined by protocols.
298 * For such cases, we force the dynamic_attr list to contain
299 * at least an invalid token, so it's syntantically correct.
300 */
301CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
f4536657 302
2e18b87d 303rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 304 ;
f4536657 305
2d496d20
PM
306function_call:
307 SYM '(' var_list ')' {
308 struct symbol *sym;
309 struct f_inst *inst = $3;
310 if ($1->class != SYM_FUNCTION)
311 cf_error("You can not call something which is not function. Really.");
d4d75628 312 DBG("You are calling function %s\n", $1->name);
2d496d20
PM
313 $$ = f_new_inst();
314 $$->code = P('c','a');
315 $$->a1.p = inst;
316 $$->a2.p = $1->aux2;
317 sym = (void *) $1->aux;
318 while (sym || inst) {
319 if (!sym || !inst)
320 cf_error("wrong number of arguments for function %s.", $1->name);
d4d75628 321 DBG( "You should pass parameter called %s\n", sym->name);
2d496d20
PM
322 inst->a1.p = sym;
323 sym = (void *) sym->aux;
324 inst = inst->next;
325 }
326 }
327 ;
328
2bdb5e00 329static_attr:
0dc4431c 330 FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); $$->a1.i = 1; }
26c09e1d 331
0dc4431c 332 | GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); $$->a1.i = 1; }
26c09e1d
PM
333 | NET { $$ = f_new_inst(); $$->aux = T_PREFIX; $$->a2.i = 0x12345678; /* This is actually ok - T_PREFIX is special-cased. */ }
334 | SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); }
0dc4431c 335 | SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope); $$->a1.i = 1; }
26c09e1d
PM
336 | CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = OFFSETOF(struct rta, cast); }
337 | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = OFFSETOF(struct rta, dest); }
2bdb5e00
PM
338 ;
339
84c7e194 340term:
f4536657 341 '(' term ')' { $$ = $2; }
d4d75628 342 | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
c5a06f65
PM
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; }
345 | term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; }
5f4aee76
PM
346 | term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; }
347 | term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; }
2d496d20 348 | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
d4d75628
PM
349 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
350 | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
351 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
352 | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
353 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
354 | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
995e5894 355 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
2d496d20 356 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
23b1539b 357
1183b6b2 358 | constant { $$ = $1; }
2575593e
PM
359 | SYM {
360 $$ = f_new_inst();
361 switch ($1->class) {
cbfd671f
PM
362 case SYM_NUMBER:
363 $$ = f_new_inst();
364 $$->code = 'c';
365 $$->aux = T_INT;
366 $$->a2.i = $1->aux;
367 break;
368 case SYM_IPA:
369 { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_IP; val->val.px.ip = * (ip_addr *) ($1->def); }
370 break;
ba921648 371 case SYM_VARIABLE | T_INT:
d3dd620b
PM
372 case SYM_VARIABLE | T_PAIR:
373 case SYM_VARIABLE | T_PREFIX:
374 case SYM_VARIABLE | T_IP:
dcab7890 375 case SYM_VARIABLE | T_PATH_MASK:
e399b6f6 376 case SYM_VARIABLE | T_PATH:
9c400ec9 377 case SYM_VARIABLE | T_CLIST:
d3dd620b
PM
378 $$->code = 'C';
379 $$->a1.p = $1->aux2;
2575593e
PM
380 break;
381 default:
1183b6b2 382 cf_error("Can not use this class of symbol (%s,%x) as variable.", $1->name, $1->class );
2575593e
PM
383 }
384 }
4515bdba 385
0dc4431c 386 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
2bdb5e00
PM
387
388 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
fe613ecd 389
db1326aa 390 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
36bbfc70 391
2d496d20 392 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
684c6f5a 393 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
2d496d20 394 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
7f77e250
PM
395
396/* Communities */
10a53608
PM
397/* This causes one shift/reduce conflict
398 | rtadot dynamic_attr '.' ADD '(' term ')' { }
399 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
400 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
a2d15746 401 | rtadot dynamic_attr '.' RESET{ }
10a53608 402*/
7f77e250 403
e399b6f6 404 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
9c400ec9 405 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
e399b6f6 406 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
4444ed2b
PM
407 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
408 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
afc54517 409
a2d15746 410/* | term '.' LEN { $$->code = P('P','l'); } */
7f77e250 411
995e5894
PM
412/* function_call is inlined here */
413 | SYM '(' var_list ')' {
414 struct symbol *sym;
415 struct f_inst *inst = $3;
416 if ($1->class != SYM_FUNCTION)
417 cf_error("You can not call something which is not function. Really.");
418 DBG("You are calling function %s\n", $1->name);
419 $$ = f_new_inst();
420 $$->code = P('c','a');
421 $$->a1.p = inst;
422 $$->a2.p = $1->aux2;
423 sym = (void *) $1->aux;
424 while (sym || inst) {
425 if (!sym || !inst)
426 cf_error("wrong number of arguments for function %s.", $1->name);
427 DBG( "You should pass parameter called %s\n", sym->name);
428 inst->a1.p = sym;
429 sym = (void *) sym->aux;
430 inst = inst->next;
431 }
432 }
ba921648
PM
433 ;
434
435break_command:
436 QUITBIRD { $$ = F_QUITBIRD }
437 | ACCEPT { $$ = F_ACCEPT }
438 | REJECT { $$ = F_REJECT }
439 | ERROR { $$ = F_ERROR }
23b1539b 440 | PRINT { $$ = F_NOP }
d3dd620b 441 | PRINTN { $$ = F_NONL }
ba921648
PM
442 ;
443
23b1539b 444print_one:
2db3b288 445 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
446 ;
447
448print_list: /* EMPTY */ { $$ = NULL; }
995e5894
PM
449 | print_one { $$ = $1; }
450 | print_one ',' print_list {
23b1539b 451 if ($1) {
995e5894 452 $1->next = $3;
23b1539b 453 $$ = $1;
995e5894 454 } else $$ = $3;
23b1539b 455 }
995e5894 456
23b1539b
PM
457 ;
458
6dc7a0cb 459var_listn: term {
d3dd620b
PM
460 $$ = f_new_inst();
461 $$->code = 's';
462 $$->a1.p = NULL;
463 $$->a2.p = $1;
464 $$->next = NULL;
465 }
6dc7a0cb 466 | term ',' var_listn {
6542ece9
PM
467 $$ = f_new_inst();
468 $$->code = 's';
469 $$->a1.p = NULL;
470 $$->a2.p = $1;
471 $$->next = $3;
472 }
473 ;
474
6dc7a0cb
PM
475var_list: /* EMPTY */ { $$ = NULL; }
476 | var_listn { $$ = $1; }
477 ;
478
23b1539b 479cmd:
49955645
MM
480 IF term THEN block {
481 $$ = f_new_inst();
482 $$->code = '?';
483 $$->a1.p = $2;
484 $$->a2.p = $4;
23b1539b 485 }
49955645
MM
486 | IF term THEN block ELSE block {
487 struct f_inst *i = f_new_inst();
488 i->code = '?';
489 i->a1.p = $2;
490 i->a2.p = $4;
23b1539b
PM
491 $$ = f_new_inst();
492 $$->code = '?';
49955645
MM
493 $$->a1.p = i;
494 $$->a2.p = $6;
23b1539b 495 }
ba921648 496 | SYM '=' term ';' {
84c7e194 497 $$ = f_new_inst();
d4d75628 498 DBG( "Ook, we'll set value\n" );
ba921648 499 if (($1->class & ~T_MASK) != SYM_VARIABLE)
ad9074e9 500 cf_error( "You may only set variables, and this is %x.", $1->class );
23b1539b 501 $$->code = 's';
2db3b288
PM
502 $$->a1.p = $1;
503 $$->a2.p = $3;
b9d70dc8 504 }
2d496d20
PM
505 | RETURN term ';' {
506 $$ = f_new_inst();
d4d75628 507 DBG( "Ook, we'll return the value\n" );
2d496d20
PM
508 $$->code = 'r';
509 $$->a1.p = $2;
510 }
db1326aa 511 | rtadot dynamic_attr '=' term ';' {
6c14255d 512 $$ = $2;
0dc4431c 513 $$->code = P('e','S');
6c14255d 514 $$->a1.p = $4;
f31156ca 515 }
0dc4431c
PM
516 | rtadot static_attr '=' term ';' {
517 $$ = $2;
518 if (!$$->a1.i)
519 cf_error( "This static attribute is read-only.");
520 $$->code = P('a','S');
521 $$->a1.p = $4;
522 }
523 | PREFERENCE '=' term ';' {
524 $$ = f_new_inst();
525 $$->code = P('P','S');
526 $$->a1.p = $3;
527 }
db1326aa 528 | UNSET '(' rtadot dynamic_attr ')' ';' {
6c14255d 529 $$ = $4;
9f4929e7 530 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
2d496d20 531 $$->code = P('e','S');
48f9e019 532 $$->a1.p = NULL;
c7b43f33 533 }
2d496d20
PM
534 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
535 | function_call ';' { $$ = $1; }
7db7b7db
PM
536 | CASE term '{' switch_body '}' {
537 $$ = f_new_inst();
2d496d20 538 $$->code = P('S','W');
7db7b7db 539 $$->a1.p = $2;
41be4444 540 $$->a2.p = build_tree( $4 );
7db7b7db 541 }
7d6eebae
PM
542
543
544 | rtadot dynamic_attr '.' EMPTY ';'
545 { struct f_inst *i = f_new_inst(); i->code = 'E'; i->aux = T_CLIST; $$ = $2; $$->code = P('e','S'); $$->a1.p = i; }
546 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
547 | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
548 | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
b9d70dc8
PM
549 ;
550
551CF_END