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