]>
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 | ||
b9d70dc8 PM |
17 | CF_DECLS |
18 | ||
e4a73dbf | 19 | CF_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 | |
44 | CF_GRAMMAR | |
45 | ||
e0f2e42f MM |
46 | CF_ADDTO(conf, filter_def) |
47 | filter_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 |
56 | CF_ADDTO(conf, filter_eval) |
57 | filter_eval: | |
58 | EVAL term { f_eval_int($2); } | |
59 | ; | |
60 | ||
ba921648 PM |
61 | type: |
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 |
81 | one_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 */ |
97 | decls: /* 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 |
105 | declsn: one_decl { $$ = $1; } |
106 | | declsn ';' one_decl { | |
4515bdba PM |
107 | $$ = $1; |
108 | $$->aux = (int) $3; | |
6dc7a0cb PM |
109 | } |
110 | ; | |
111 | ||
e0f2e42f | 112 | filter_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 | ||
121 | filter: | |
122 | SYM { | |
123 | if ($1->class != SYM_FILTER) cf_error("No such filter"); | |
124 | $$ = $1->def; | |
125 | } | |
126 | | filter_body | |
127 | ; | |
128 | ||
430da60f MM |
129 | where_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 | 153 | function_params: |
d4d75628 | 154 | '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; } |
6dc7a0cb | 155 | | '(' ')' { $$=NULL; } |
ba921648 | 156 | ; |
b9d70dc8 | 157 | |
ba921648 PM |
158 | function_body: |
159 | decls '{' cmds '}' { | |
160 | $$ = $3; | |
84c7e194 | 161 | } |
ba921648 PM |
162 | ; |
163 | ||
164 | CF_ADDTO(conf, function_def) | |
165 | function_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 | ||
180 | cmds: /* 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 | 191 | block: |
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 | */ | |
203 | pair: | |
204 | '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; } | |
205 | ; | |
206 | ||
207 | /* | |
208 | * Complex types, their bison value is struct f_val | |
209 | */ | |
758458be | 210 | fprefix_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 |
217 | fprefix: |
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 | 224 | fipa: |
60de3356 | 225 | IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; } |
d3dd620b PM |
226 | ; |
227 | ||
38506f71 | 228 | set_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 | ||
236 | set_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 | ||
255 | set_items: | |
256 | set_item { $$ = $1; } | |
257 | | set_items ',' set_item { $$ = $3; $$->left = $1; } | |
258 | ; | |
259 | ||
41be4444 PM |
260 | switch_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 |
276 | bgp_one: |
277 | NUM { $$ = $1; } | |
9a09a64b | 278 | | '?' { $$ = PM_ANY; } |
77de6882 PM |
279 | ; |
280 | ||
281 | bgp_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 | 286 | constant: |
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 | */ | |
304 | CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; }) | |
f4536657 | 305 | |
2e18b87d | 306 | rtadot: /* EMPTY, we are not permitted RTA. prefix */ |
6c14255d | 307 | ; |
f4536657 | 308 | |
2d496d20 PM |
309 | function_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 | 332 | static_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 | 343 | term: |
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 | ||
438 | break_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 | 447 | print_one: |
2db3b288 | 448 | term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; } |
23b1539b PM |
449 | ; |
450 | ||
451 | print_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 | 462 | var_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 |
478 | var_list: /* EMPTY */ { $$ = NULL; } |
479 | | var_listn { $$ = $1; } | |
480 | ; | |
481 | ||
23b1539b | 482 | cmd: |
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 | ||
554 | CF_END |