diff options
author | Pavel Machek <pavel@ucw.cz> | 1999-10-28 23:03:36 +0200 |
---|---|---|
committer | Pavel Machek <pavel@ucw.cz> | 1999-10-28 23:03:36 +0200 |
commit | 41be4444f2f548c5cc135593b2c820180a22ff99 (patch) | |
tree | db23c6c220b8a0304e6e29b07be67ff628099e23 /filter | |
parent | c2250f91c749f563229ad624bbd03053c1d671d0 (diff) | |
download | bird-41be4444f2f548c5cc135593b2c820180a22ff99.tar bird-41be4444f2f548c5cc135593b2c820180a22ff99.zip |
switch() { } done right.
Diffstat (limited to 'filter')
-rw-r--r-- | filter/config.Y | 40 | ||||
-rw-r--r-- | filter/filter.c | 60 | ||||
-rw-r--r-- | filter/tree.c | 2 |
3 files changed, 42 insertions, 60 deletions
diff --git a/filter/config.Y b/filter/config.Y index 9385483..d5a9dca 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -11,7 +11,6 @@ FIXME: whole system of paths, path ~ string, path.prepend(), path.originate FIXME: create community lists FIXME: access to dynamic attributes - FIXME: make case faster */ CF_HDR @@ -37,10 +36,10 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, CONST, FILTER ) -%type <x> term block cmds cmd function_body ifthen constant print_one print_list var_list switch_body +%type <x> term block cmds cmd function_body ifthen constant print_one print_list var_list %type <f> filter filter_body %type <i> type break_command pair -%type <e> set_item set_items +%type <e> set_item set_items switch_body %type <v> set_atom prefix prefix_s ipa %type <s> decls function_params @@ -191,6 +190,20 @@ set_items: | set_items ',' set_item { $$ = $3; $$->left = $1; } ; +/* 2 shift/reduce conflicts here. Curable by replacing cmds with block which breaks syntax */ +switch_body: /* EMPTY */ { $$ = NULL; } + | set_item ':' cmds switch_body { + $$ = $1; + $$->data = $3; + $$->left = $4; + } + | ELSE ':' cmds { + $$ = f_new_tree(); + $$->from.type = T_VOID; + $$->to.type = T_VOID; + $$->data = $3; + } + ; constant: CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->a1.i = T_INT; $$->a2.i = $3; } @@ -286,23 +299,6 @@ var_list: term { } ; -/* 2 shift/reduce conflicts here. Curable by replacing cmds with block which breaks syntax */ -switch_body: /* EMPTY */ { $$ = NULL; } - | term ':' cmds switch_body { - $$ = f_new_inst(); - $$->code = 'of'; - $$->a1.p = $1; - $$->a2.p = $3; - $$->next = $4; - } - | ELSE ':' cmds { - $$ = f_new_inst(); - $$->code = 'el'; - $$->a1.p = NULL; - $$->a2.p = $3; - } - ; - cmd: ifthen { $$ = $1; @@ -346,9 +342,9 @@ cmd: } | CASE term '{' switch_body '}' { $$ = f_new_inst(); - $$->code = 'sw'; + $$->code = 'SW'; $$->a1.p = $2; - $$->a2.p = $4; + $$->a2.p = build_tree( $4 ); } ; diff --git a/filter/filter.c b/filter/filter.c index f6b2d4b..dc8235e 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -54,6 +54,13 @@ struct f_inst *startup_func = NULL; int val_compare(struct f_val v1, struct f_val v2) { + if ((v1.type == T_VOID) && (v2.type == T_VOID)) + return 0; + if (v1.type == T_VOID) /* Hack for else */ + return -1; + if (v2.type == T_VOID) + return 1; + if (v1.type != v2.type) return CMP_ERROR; switch (v1.type) { @@ -64,7 +71,7 @@ val_compare(struct f_val v1, struct f_val v2) return 1; case T_IP: return ipa_compare(v1.val.ip, v2.val.ip); - default: return CMP_ERROR; + default: { printf( "Error comparing\n" ); return CMP_ERROR; } } } @@ -115,40 +122,6 @@ static struct rte **f_rte; static struct f_val interpret(struct f_inst *what); static struct f_val -interpret_switch(struct f_inst *what, struct f_val control) -{ - struct f_val this, res; - int i; - res.type = T_VOID; - - if (!what) - return res; - - switch(what->code) { - case 'el': - return interpret(what->a2.p); - - case 'of': - this = interpret(what->a1.p); - i = val_compare(control, this); - if (!i) - return interpret(what->a2.p); - if (i==CMP_ERROR) { - i = val_in_range(control, this); - if (i==1) - return interpret(what->a2.p); - if (i==CMP_ERROR) - runtime( "incompatible types in case" ); - } - break; - - default: - bug( "This can not happen (%x)\n", what->code ); - } - return interpret_switch(what->next, control); -} - -static struct f_val interpret(struct f_inst *what) { struct symbol *sym; @@ -309,9 +282,22 @@ interpret(struct f_inst *what) ONEARG; res = interpret(what->a2.p); break; - case 'sw': /* SWITCH alias CASE */ + case 'SW': ONEARG; - interpret_switch(what->a2.p, v1); + { + struct f_tree *t = find_tree(what->a2.p, v1); + if (!t) { + v1.type = T_VOID; + t = find_tree(what->a2.p, v1); + if (!t) { + printf( "No else statement?\n "); + break; + } + } + if (!t->data) + die( "Impossible: no code associated!\n" ); + return interpret(t->data); + } break; case 'iM': /* IP.MASK(val) */ TWOARGS_C; diff --git a/filter/tree.c b/filter/tree.c index ea1f18f..43888f0 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -73,7 +73,7 @@ struct f_tree * find_tree(struct f_tree *t, struct f_val val) { if (!t) - return 0; + return NULL; if ((val_compare(t->from, val) != 1) && (val_compare(t->to, val) != -1)) return t; |