]>
Commit | Line | Data |
---|---|---|
b9d70dc8 PM |
1 | /* |
2 | * BIRD - filters | |
3 | * | |
6542ece9 | 4 | * Copyright 1998,1999 Pavel Machek |
b9d70dc8 PM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
c9f8c1a8 | 7 | * |
f4536657 | 8 | FIXME (nonurgent): define keyword |
2d496d20 | 9 | FIXME (for BGP): whole system of paths, path ~ string, path.prepend(), path.originate |
c9f8c1a8 | 10 | FIXME: create community lists |
60d7d10e | 11 | FIXME: IP addresses in ipv6 |
0a06a9b8 PM |
12 | |
13 | ||
14 | (1) Cesty | |
15 | ||
16 | AS paths budtez interne reprezentovany stejne jako v BGP (viz RFC 1771), | |
17 | to znamena jako posloupnost segmentu, z nichz kazdy je budto posloupnost nebo | |
18 | mnozina cisel ASu. Na cestach nadefinuji nasledujici operace: | |
19 | ||
20 | - zformatovani do stringu | |
21 | - append dalsiho AS k ceste | |
22 | ||
23 | Filtry by mely podporovat: | |
24 | ||
25 | - operator pridani AS k ceste | |
26 | - matchovani na pritomnost podposloupnosti v ceste (pricemz vyskytne-li | |
27 | se tam mnozina, tak si ji lze predstavit prerovnanou v libovolnem | |
28 | poradi) | |
29 | - operator zjisteni delky cesty (pro vypocet metrik) | |
30 | ||
31 | Byl bych rad, kdyby se samotne matchovaci funkce objevily v proto/bgp/attrs.c. | |
32 | ||
33 | ||
34 | (2) Community-listy | |
35 | ||
36 | Community list budiz interne reprezentovan jako posloupnost 32-bitovych cisel. | |
37 | ||
38 | Filtry by se mely na communities divat jako na usporadane dvojice 16-bitovych | |
39 | cisel (prvni je cislo AS, ktery community definoval, druhe pak community ID | |
40 | v ramci AS) a melo by byt mozne definovat si konstanty typu community. | |
41 | K dispozici by mely byt nasledujici operace: | |
42 | ||
43 | - zjisteni pritomnosti community v listu | |
44 | - pridani community do listu | |
45 | - odebrani community z listu | |
46 | - zresetovani listu | |
47 | ||
48 | Pro operace na cestach i na community listech by se mela pouzivat `teckova' | |
49 | notace pouzita v mem puvodnim navrhu syntaxe. | |
50 | ||
51 | ||
52 | (3) Zmeny v semantice dynamickych atributu | |
53 | ||
54 | Aby se nemusely neustale kopirovat seznamy atributu, rad bych provedl jeste | |
55 | jednu zmenu v tom, jak filtry nakladaji s atributy (pevne doufam, ze posledni, | |
56 | ale uznavam, ze u te predchozi jsem to take tvrdil): Funkci f_run budiz | |
57 | pridan jeste jeden parametr, ktery prepina mezi dvema mody: | |
58 | ||
59 | (a) [incoming filter mode] Jako nyni. | |
60 | ||
61 | (b) [outgoing filter mode] Pokud se hleda atribut, hleda se nejdrive | |
62 | v tmp_attrs a pokud to selze, tak v rta->attrs. Pokud se nastavuje, | |
63 | dava se _vzdy_ do tmp_attrs. | |
64 | ||
65 | Diky tomu filtry pri exportu routes nebudou vubec muset modifikovat rta a | |
66 | protokoly, ktere v import_control potrebuji nastavovat i non-temporary | |
67 | atributy, je budou moci pridat do tmp_attrs, aniz by sahly na rta. | |
68 | ||
69 | ||
b9d70dc8 PM |
70 | */ |
71 | ||
72 | CF_HDR | |
73 | ||
2d496d20 PM |
74 | #define P(a,b) ((a<<8) | b) |
75 | ||
b9d70dc8 PM |
76 | CF_DECLS |
77 | ||
e4a73dbf | 78 | CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, |
ba921648 PM |
79 | ACCEPT, REJECT, ERROR, QUITBIRD, |
80 | INT, BOOL, IP, PREFIX, PAIR, SET, STRING, | |
7db7b7db | 81 | IF, THEN, ELSE, CASE, |
23b1539b | 82 | TRUE, FALSE, |
db1326aa | 83 | FROM, GW, NET, MASK, SOURCE, |
36bbfc70 | 84 | LEN, |
f4536657 | 85 | DEFINED, |
430da60f | 86 | FILTER, WHERE) |
b9d70dc8 | 87 | |
f4536657 | 88 | %nonassoc THEN |
4ed8718a | 89 | %nonassoc ELSE |
f4536657 | 90 | |
db1326aa | 91 | %type <x> term block cmds cmd function_body constant print_one print_list var_list var_listn dynamic_attr function_call |
430da60f | 92 | %type <f> filter filter_body where_filter |
4515bdba | 93 | %type <i> type break_command pair |
41be4444 | 94 | %type <e> set_item set_items switch_body |
d3dd620b | 95 | %type <v> set_atom prefix prefix_s ipa |
6dc7a0cb | 96 | %type <s> decls declsn one_decl function_params |
b9d70dc8 PM |
97 | |
98 | CF_GRAMMAR | |
99 | ||
e0f2e42f MM |
100 | CF_ADDTO(conf, filter_def) |
101 | filter_def: | |
cb8034f4 | 102 | FILTER SYM { cf_push_scope( $2 ); } filter_body { |
ae3e1af2 PM |
103 | cf_define_symbol($2, SYM_FILTER, $4); |
104 | $4->name = $2->name; | |
d4d75628 | 105 | DBG( "We have new filter defined (%s)\n", $2->name ); |
ae3e1af2 | 106 | cf_pop_scope(); |
b9d70dc8 PM |
107 | } |
108 | ; | |
109 | ||
ba921648 PM |
110 | type: |
111 | INT { $$ = T_INT; } | |
112 | | BOOL { $$ = T_BOOL; } | |
113 | | IP { $$ = T_IP; } | |
114 | | PREFIX { $$ = T_PREFIX; } | |
115 | | PAIR { $$ = T_PAIR; } | |
116 | | STRING { $$ = T_STRING; } | |
117 | | type SET { | |
118 | switch ($1) { | |
119 | default: | |
120 | cf_error( "You can not create sets of this type\n" ); | |
121 | case T_INT: case T_IP: case T_PREFIX: case T_PAIR: | |
122 | } | |
123 | $$ = $1 | T_SET; | |
124 | } | |
125 | ; | |
126 | ||
6dc7a0cb PM |
127 | one_decl: |
128 | type SYM { | |
4107df1d | 129 | cf_define_symbol($2, SYM_VARIABLE | $1, NULL); |
d4d75628 | 130 | DBG( "New variable %s type %x\n", $2->name, $1 ); |
cb8034f4 | 131 | $2->aux = 0; |
d3dd620b PM |
132 | { |
133 | struct f_val * val; | |
134 | val = cfg_alloc(sizeof(struct f_val)); | |
135 | val->type = $1; | |
136 | $2->aux2 = val; | |
137 | } | |
6542ece9 | 138 | $$=$2; |
ba921648 PM |
139 | } |
140 | ; | |
141 | ||
6dc7a0cb PM |
142 | /* Decls with ';' at the end */ |
143 | decls: /* EMPTY */ { $$ = NULL; } | |
144 | | one_decl ';' decls { | |
145 | $$ = $1; | |
cb8034f4 | 146 | $$->aux = (int) $3; |
6dc7a0cb PM |
147 | } |
148 | ; | |
149 | ||
3c989eb4 | 150 | /* Declarations that have no ';' at the end. */ |
6dc7a0cb PM |
151 | declsn: one_decl { $$ = $1; } |
152 | | declsn ';' one_decl { | |
4515bdba PM |
153 | $$ = $1; |
154 | $$->aux = (int) $3; | |
6dc7a0cb PM |
155 | } |
156 | ; | |
157 | ||
e0f2e42f | 158 | filter_body: |
ba921648 | 159 | function_body { |
e0f2e42f MM |
160 | struct filter *f = cfg_alloc(sizeof(struct filter)); |
161 | f->name = NULL; | |
ba921648 | 162 | f->root = $1; |
e0f2e42f MM |
163 | $$ = f; |
164 | } | |
165 | ; | |
166 | ||
167 | filter: | |
168 | SYM { | |
169 | if ($1->class != SYM_FILTER) cf_error("No such filter"); | |
170 | $$ = $1->def; | |
171 | } | |
172 | | filter_body | |
173 | ; | |
174 | ||
430da60f MM |
175 | where_filter: |
176 | WHERE term { | |
177 | /* Construct 'IF term THEN ACCEPT; REJECT;' */ | |
178 | struct filter *f = cfg_alloc(sizeof(struct filter)); | |
179 | struct f_inst *i, *acc, *rej; | |
180 | acc = f_new_inst(); /* ACCEPT */ | |
2d496d20 | 181 | acc->code = P('p',','); |
430da60f MM |
182 | acc->a1.p = NULL; |
183 | acc->a2.i = F_ACCEPT; | |
184 | rej = f_new_inst(); /* REJECT */ | |
2d496d20 | 185 | rej->code = P('p',','); |
430da60f MM |
186 | rej->a1.p = NULL; |
187 | rej->a2.i = F_REJECT; | |
188 | i = f_new_inst(); /* IF */ | |
189 | i->code = '?'; | |
190 | i->a1.p = $2; | |
191 | i->a2.p = acc; | |
192 | i->next = rej; | |
193 | f->name = NULL; | |
194 | f->root = i; | |
195 | $$ = f; | |
196 | } | |
197 | ; | |
198 | ||
ba921648 | 199 | function_params: |
d4d75628 | 200 | '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; } |
6dc7a0cb | 201 | | '(' ')' { $$=NULL; } |
ba921648 | 202 | ; |
b9d70dc8 | 203 | |
ba921648 PM |
204 | function_body: |
205 | decls '{' cmds '}' { | |
206 | $$ = $3; | |
84c7e194 | 207 | } |
ba921648 PM |
208 | ; |
209 | ||
210 | CF_ADDTO(conf, function_def) | |
211 | function_def: | |
d4d75628 | 212 | FUNCTION SYM { DBG( "Begining of function %s\n", $2->name ); cf_push_scope($2); } function_params function_body { |
ba921648 | 213 | extern struct f_inst *startup_func; |
ae3e1af2 | 214 | cf_define_symbol($2, SYM_FUNCTION, $5); |
ba921648 | 215 | if (!strcasecmp($2->name, "startup")) |
ae3e1af2 | 216 | startup_func = $5; |
cb8034f4 | 217 | $2->aux = (int) $4; |
ae3e1af2 | 218 | $2->aux2 = $5; |
d4d75628 | 219 | DBG("Hmm, we've got one function here - %s\n", $2->name); |
ae3e1af2 | 220 | cf_pop_scope(); |
ba921648 PM |
221 | } |
222 | ; | |
223 | ||
224 | /* Programs */ | |
225 | ||
226 | cmds: /* EMPTY */ { $$ = NULL; } | |
227 | | cmd cmds { | |
84c7e194 | 228 | if ($1) { |
7db7b7db PM |
229 | if ($1->next) |
230 | bug("Command has next already set\n"); | |
ba921648 | 231 | $1->next = $2; |
84c7e194 | 232 | $$ = $1; |
ba921648 | 233 | } else $$ = $2; |
84c7e194 PM |
234 | } |
235 | ; | |
236 | ||
2575593e | 237 | block: |
ba921648 | 238 | cmd { |
2575593e PM |
239 | $$=$1; |
240 | } | |
241 | | '{' cmds '}' { | |
242 | $$=$2; | |
243 | } | |
244 | ; | |
245 | ||
d3dd620b PM |
246 | /* |
247 | * Simple types, their bison value is int | |
248 | */ | |
249 | pair: | |
250 | '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; } | |
251 | ; | |
252 | ||
253 | /* | |
254 | * Complex types, their bison value is struct f_val | |
255 | */ | |
256 | prefix_s: | |
455ca441 | 257 | IPA '/' NUM { $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3; if (ipa_nonzero(ipa_and($$.val.px.ip, ipa_not(ipa_mkmask($$.val.px.len))))) cf_error( "%I/%d is not really prefix\n", $$.val.px.ip, $$.val.px.len ); } |
d3dd620b PM |
258 | ; |
259 | ||
260 | prefix: | |
261 | prefix_s { $$ = $1; } | |
262 | | prefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; } | |
263 | | prefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; } | |
6dc7a0cb | 264 | | prefix_s '{' NUM ',' NUM '}' { $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8); } |
d3dd620b PM |
265 | ; |
266 | ||
267 | ipa: | |
6dc7a0cb | 268 | IPA { $$.type = T_IP; $$.val.px.ip = $1; } |
d3dd620b PM |
269 | ; |
270 | ||
38506f71 | 271 | set_atom: |
d3dd620b PM |
272 | NUM { $$.type = T_INT; $$.val.i = $1; } |
273 | | pair { $$.type = T_PAIR; $$.val.i = $1; } | |
274 | | ipa { $$ = $1; } | |
275 | | prefix { $$ = $1; } | |
38506f71 PM |
276 | ; |
277 | ||
278 | set_item: | |
995e5894 PM |
279 | set_atom { |
280 | $$ = f_new_tree(); | |
281 | $$->from = $1; | |
282 | if ($1.type != T_PREFIX) | |
283 | $$->to = $1; | |
284 | else { | |
285 | $$->to = $1; | |
286 | $$->to.val.px.ip = ipa_or( $$->to.val.px.ip, ipa_not( ipa_mkmask( $$->to.val.px.len ) )); | |
287 | } | |
288 | } | |
289 | | set_atom '.' '.' set_atom { | |
290 | $$ = f_new_tree(); | |
291 | $$->from = $1; | |
292 | $$->to = $4; | |
293 | if (($1.type == T_PREFIX) || ($4.type == T_PREFIX)) cf_error( "You can not use prefixes for range" ); | |
294 | } | |
38506f71 PM |
295 | ; |
296 | ||
297 | set_items: | |
298 | set_item { $$ = $1; } | |
299 | | set_items ',' set_item { $$ = $3; $$->left = $1; } | |
300 | ; | |
301 | ||
41be4444 PM |
302 | switch_body: /* EMPTY */ { $$ = NULL; } |
303 | | set_item ':' cmds switch_body { | |
304 | $$ = $1; | |
305 | $$->data = $3; | |
306 | $$->left = $4; | |
307 | } | |
308 | | ELSE ':' cmds { | |
309 | $$ = f_new_tree(); | |
310 | $$->from.type = T_VOID; | |
311 | $$->to.type = T_VOID; | |
312 | $$->data = $3; | |
313 | } | |
314 | ; | |
d3dd620b | 315 | |
e4a73dbf PM |
316 | /* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */ |
317 | ||
23b1539b | 318 | constant: |
e4a73dbf | 319 | NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; } |
c7b43f33 PM |
320 | | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } |
321 | | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; } | |
322 | | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; } | |
323 | | pair { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR; $$->a2.i = $1; } | |
d3dd620b | 324 | | ipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } |
2f702671 | 325 | | prefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } |
d4d75628 | 326 | | '[' 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 | 327 | | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } |
23b1539b PM |
328 | ; |
329 | ||
db1326aa MM |
330 | /* |
331 | * Maybe there are no dynamic attributes defined by protocols. | |
332 | * For such cases, we force the dynamic_attr list to contain | |
333 | * at least an invalid token, so it's syntantically correct. | |
334 | */ | |
335 | CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; }) | |
f4536657 | 336 | |
2e18b87d | 337 | rtadot: /* EMPTY, we are not permitted RTA. prefix */ |
6c14255d | 338 | ; |
f4536657 | 339 | |
2d496d20 PM |
340 | function_call: |
341 | SYM '(' var_list ')' { | |
342 | struct symbol *sym; | |
343 | struct f_inst *inst = $3; | |
344 | if ($1->class != SYM_FUNCTION) | |
345 | cf_error("You can not call something which is not function. Really."); | |
d4d75628 | 346 | DBG("You are calling function %s\n", $1->name); |
2d496d20 PM |
347 | $$ = f_new_inst(); |
348 | $$->code = P('c','a'); | |
349 | $$->a1.p = inst; | |
350 | $$->a2.p = $1->aux2; | |
351 | sym = (void *) $1->aux; | |
352 | while (sym || inst) { | |
353 | if (!sym || !inst) | |
354 | cf_error("wrong number of arguments for function %s.", $1->name); | |
d4d75628 | 355 | DBG( "You should pass parameter called %s\n", sym->name); |
2d496d20 PM |
356 | inst->a1.p = sym; |
357 | sym = (void *) sym->aux; | |
358 | inst = inst->next; | |
359 | } | |
360 | } | |
361 | ; | |
362 | ||
84c7e194 | 363 | term: |
f4536657 | 364 | '(' term ')' { $$ = $2; } |
d4d75628 | 365 | | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } |
2d496d20 | 366 | | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; } |
d4d75628 PM |
367 | | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; } |
368 | | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; } | |
369 | | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; } | |
370 | | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; } | |
371 | | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; } | |
372 | | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; } | |
995e5894 | 373 | | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; } |
2d496d20 | 374 | | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; } |
23b1539b | 375 | |
1183b6b2 | 376 | | constant { $$ = $1; } |
2575593e PM |
377 | | SYM { |
378 | $$ = f_new_inst(); | |
379 | switch ($1->class) { | |
ba921648 | 380 | case SYM_VARIABLE | T_INT: |
d3dd620b PM |
381 | case SYM_VARIABLE | T_PAIR: |
382 | case SYM_VARIABLE | T_PREFIX: | |
383 | case SYM_VARIABLE | T_IP: | |
384 | $$->code = 'C'; | |
385 | $$->a1.p = $1->aux2; | |
2575593e PM |
386 | break; |
387 | default: | |
1183b6b2 | 388 | cf_error("Can not use this class of symbol (%s,%x) as variable.", $1->name, $1->class ); |
2575593e PM |
389 | } |
390 | } | |
4515bdba | 391 | |
6c14255d | 392 | | rtadot FROM { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); } |
36bbfc70 | 393 | |
6c14255d PM |
394 | | rtadot GW { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); } |
395 | | rtadot NET { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_PREFIX; $$->a2.i = 0x12345678; } | |
b1573615 | 396 | | rtadot SOURCE { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); } |
6dc7a0cb | 397 | |
db1326aa | 398 | | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); } |
36bbfc70 | 399 | |
2d496d20 PM |
400 | | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; } |
401 | | term '.' LEN { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_INT; } | |
402 | | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } | |
995e5894 PM |
403 | /* function_call is inlined here */ |
404 | | SYM '(' var_list ')' { | |
405 | struct symbol *sym; | |
406 | struct f_inst *inst = $3; | |
407 | if ($1->class != SYM_FUNCTION) | |
408 | cf_error("You can not call something which is not function. Really."); | |
409 | DBG("You are calling function %s\n", $1->name); | |
410 | $$ = f_new_inst(); | |
411 | $$->code = P('c','a'); | |
412 | $$->a1.p = inst; | |
413 | $$->a2.p = $1->aux2; | |
414 | sym = (void *) $1->aux; | |
415 | while (sym || inst) { | |
416 | if (!sym || !inst) | |
417 | cf_error("wrong number of arguments for function %s.", $1->name); | |
418 | DBG( "You should pass parameter called %s\n", sym->name); | |
419 | inst->a1.p = sym; | |
420 | sym = (void *) sym->aux; | |
421 | inst = inst->next; | |
422 | } | |
423 | } | |
ba921648 PM |
424 | ; |
425 | ||
426 | break_command: | |
427 | QUITBIRD { $$ = F_QUITBIRD } | |
428 | | ACCEPT { $$ = F_ACCEPT } | |
429 | | REJECT { $$ = F_REJECT } | |
430 | | ERROR { $$ = F_ERROR } | |
23b1539b | 431 | | PRINT { $$ = F_NOP } |
d3dd620b | 432 | | PRINTN { $$ = F_NONL } |
ba921648 PM |
433 | ; |
434 | ||
23b1539b | 435 | print_one: |
2db3b288 | 436 | term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; } |
23b1539b PM |
437 | ; |
438 | ||
439 | print_list: /* EMPTY */ { $$ = NULL; } | |
995e5894 PM |
440 | | print_one { $$ = $1; } |
441 | | print_one ',' print_list { | |
23b1539b | 442 | if ($1) { |
995e5894 | 443 | $1->next = $3; |
23b1539b | 444 | $$ = $1; |
995e5894 | 445 | } else $$ = $3; |
23b1539b | 446 | } |
995e5894 | 447 | |
23b1539b PM |
448 | ; |
449 | ||
6dc7a0cb | 450 | var_listn: term { |
d3dd620b PM |
451 | $$ = f_new_inst(); |
452 | $$->code = 's'; | |
453 | $$->a1.p = NULL; | |
454 | $$->a2.p = $1; | |
455 | $$->next = NULL; | |
456 | } | |
6dc7a0cb | 457 | | term ',' var_listn { |
6542ece9 PM |
458 | $$ = f_new_inst(); |
459 | $$->code = 's'; | |
460 | $$->a1.p = NULL; | |
461 | $$->a2.p = $1; | |
462 | $$->next = $3; | |
463 | } | |
464 | ; | |
465 | ||
6dc7a0cb PM |
466 | var_list: /* EMPTY */ { $$ = NULL; } |
467 | | var_listn { $$ = $1; } | |
468 | ; | |
469 | ||
23b1539b | 470 | cmd: |
49955645 MM |
471 | IF term THEN block { |
472 | $$ = f_new_inst(); | |
473 | $$->code = '?'; | |
474 | $$->a1.p = $2; | |
475 | $$->a2.p = $4; | |
23b1539b | 476 | } |
49955645 MM |
477 | | IF term THEN block ELSE block { |
478 | struct f_inst *i = f_new_inst(); | |
479 | i->code = '?'; | |
480 | i->a1.p = $2; | |
481 | i->a2.p = $4; | |
23b1539b PM |
482 | $$ = f_new_inst(); |
483 | $$->code = '?'; | |
49955645 MM |
484 | $$->a1.p = i; |
485 | $$->a2.p = $6; | |
23b1539b | 486 | } |
ba921648 | 487 | | SYM '=' term ';' { |
84c7e194 | 488 | $$ = f_new_inst(); |
d4d75628 | 489 | DBG( "Ook, we'll set value\n" ); |
ba921648 PM |
490 | if (($1->class & ~T_MASK) != SYM_VARIABLE) |
491 | cf_error( "You may only set variables, and this is %x.\n", $1->class ); | |
23b1539b | 492 | $$->code = 's'; |
2db3b288 PM |
493 | $$->a1.p = $1; |
494 | $$->a2.p = $3; | |
b9d70dc8 | 495 | } |
2d496d20 PM |
496 | | RETURN term ';' { |
497 | $$ = f_new_inst(); | |
d4d75628 | 498 | DBG( "Ook, we'll return the value\n" ); |
2d496d20 PM |
499 | $$->code = 'r'; |
500 | $$->a1.p = $2; | |
501 | } | |
db1326aa | 502 | | rtadot dynamic_attr '=' term ';' { |
6c14255d | 503 | $$ = $2; |
2d496d20 | 504 | $$->code = P('e','S'); |
6c14255d | 505 | $$->a1.p = $4; |
f31156ca | 506 | } |
db1326aa | 507 | | UNSET '(' rtadot dynamic_attr ')' ';' { |
6c14255d | 508 | $$ = $4; |
9f4929e7 | 509 | $$->aux = EAF_TYPE_UNDEF | EAF_TEMP; |
2d496d20 | 510 | $$->code = P('e','S'); |
48f9e019 | 511 | $$->a1.p = NULL; |
c7b43f33 | 512 | } |
2d496d20 PM |
513 | | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; } |
514 | | function_call ';' { $$ = $1; } | |
7db7b7db PM |
515 | | CASE term '{' switch_body '}' { |
516 | $$ = f_new_inst(); | |
2d496d20 | 517 | $$->code = P('S','W'); |
7db7b7db | 518 | $$->a1.p = $2; |
41be4444 | 519 | $$->a2.p = build_tree( $4 ); |
7db7b7db | 520 | } |
b9d70dc8 PM |
521 | ; |
522 | ||
523 | CF_END |