]>
Commit | Line | Data |
---|---|---|
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 | ||
11 | CF_HDR | |
12 | ||
2edb31b0 MM |
13 | CF_DEFINES |
14 | ||
2d496d20 PM |
15 | #define P(a,b) ((a<<8) | b) |
16 | ||
92a72a4c OZ |
17 | static 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 |
28 | CF_DECLS |
29 | ||
e4a73dbf | 30 | CF_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 | |
55 | CF_GRAMMAR | |
56 | ||
e0f2e42f MM |
57 | CF_ADDTO(conf, filter_def) |
58 | filter_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 |
67 | CF_ADDTO(conf, filter_eval) |
68 | filter_eval: | |
69 | EVAL term { f_eval_int($2); } | |
70 | ; | |
71 | ||
ba921648 PM |
72 | type: |
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 |
100 | one_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 */ |
112 | decls: /* 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 |
120 | declsn: one_decl { $$ = $1; } |
121 | | declsn ';' one_decl { | |
4515bdba | 122 | $$ = $1; |
083c43e2 | 123 | $$->aux2 = $3; |
6dc7a0cb PM |
124 | } |
125 | ; | |
126 | ||
e0f2e42f | 127 | filter_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 | ||
136 | filter: | |
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 |
144 | where_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 | 168 | function_params: |
d4d75628 | 169 | '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; } |
6dc7a0cb | 170 | | '(' ')' { $$=NULL; } |
ba921648 | 171 | ; |
b9d70dc8 | 172 | |
ba921648 PM |
173 | function_body: |
174 | decls '{' cmds '}' { | |
175 | $$ = $3; | |
84c7e194 | 176 | } |
ba921648 PM |
177 | ; |
178 | ||
179 | CF_ADDTO(conf, function_def) | |
180 | function_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 | ||
194 | cmds: /* 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 | 205 | block: |
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 |
217 | cpair: |
218 | '(' NUM ',' NUM ')' { $$ = make_pair($2, $4); } | |
d3dd620b PM |
219 | ; |
220 | ||
221 | /* | |
222 | * Complex types, their bison value is struct f_val | |
223 | */ | |
e3f2d5fc | 224 | fipa: |
60de3356 | 225 | IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; } |
d3dd620b PM |
226 | ; |
227 | ||
38506f71 | 228 | set_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 | ||
235 | set_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 | ||
248 | set_items: | |
249 | set_item { $$ = $1; } | |
250 | | set_items ',' set_item { $$ = $3; $$->left = $1; } | |
251 | ; | |
252 | ||
b1a597e0 OZ |
253 | fprefix_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 | ||
260 | fprefix: | |
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 | ||
270 | fprefix_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 |
275 | switch_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 |
291 | bgp_path_expr: |
292 | symbol { $$ = $1; } | |
293 | | '(' term ')' { $$ = $2; } | |
294 | ; | |
295 | ||
f9491630 | 296 | bgp_path: |
cf186034 | 297 | PO bgp_path_tail1 PC { $$ = $2; } |
f9491630 | 298 | | '/' bgp_path_tail2 '/' { $$ = $2; } |
f9491630 OZ |
299 | ; |
300 | ||
301 | bgp_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 | 309 | bgp_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 |
315 | dpair: |
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 | 328 | constant: |
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 | */ | |
347 | CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; }) | |
f4536657 | 348 | |
2e18b87d | 349 | rtadot: /* EMPTY, we are not permitted RTA. prefix */ |
6c14255d | 350 | ; |
f4536657 | 351 | |
2d496d20 PM |
352 | function_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 |
375 | symbol: |
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 | 408 | static_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 | 420 | term: |
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 | ||
493 | break_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 | 502 | print_one: |
2db3b288 | 503 | term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; } |
23b1539b PM |
504 | ; |
505 | ||
506 | print_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 | 517 | var_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 |
533 | var_list: /* EMPTY */ { $$ = NULL; } |
534 | | var_listn { $$ = $1; } | |
535 | ; | |
536 | ||
23b1539b | 537 | cmd: |
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 | ||
609 | CF_END |