Case arg { 1: printf "one"; } works. You can not use two commands

after one label, yet.
This commit is contained in:
Pavel Machek 1999-09-29 14:24:58 +00:00
parent 4caa2231fc
commit 7db7b7db60
2 changed files with 79 additions and 8 deletions

View file

@ -21,7 +21,7 @@ CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, CONST, CF_KEYWORDS(FUNCTION, PRINT, CONST,
ACCEPT, REJECT, ERROR, QUITBIRD, ACCEPT, REJECT, ERROR, QUITBIRD,
INT, BOOL, IP, PREFIX, PAIR, SET, STRING, INT, BOOL, IP, PREFIX, PAIR, SET, STRING,
IF, THEN, ELSE, IF, THEN, ELSE, CASE,
TRUE, FALSE, TRUE, FALSE,
RTA, FROM, GW, NET, RTA, FROM, GW, NET,
LEN, LEN,
@ -29,7 +29,7 @@ CF_KEYWORDS(FUNCTION, PRINT, CONST,
FILTER FILTER
) )
%type <x> term block cmds cmd function_body ifthen constant print_one print_list var_list %type <x> term block cmds cmd function_body ifthen constant print_one print_list var_list switch_body
%type <f> filter filter_body %type <f> filter filter_body
%type <i> type break_command %type <i> type break_command
%type <e> set_item set_items %type <e> set_item set_items
@ -118,6 +118,8 @@ function_def:
cmds: /* EMPTY */ { $$ = NULL; } cmds: /* EMPTY */ { $$ = NULL; }
| cmd cmds { | cmd cmds {
if ($1) { if ($1) {
if ($1->next)
bug("Command has next already set\n");
$1->next = $2; $1->next = $2;
$$ = $1; $$ = $1;
} else $$ = $2; } else $$ = $2;
@ -160,7 +162,6 @@ constant:
term: term:
term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
| term '=' term { $$ = f_new_inst(); $$->code = '=='; $$->a1.p = $1; $$->a2.p = $3; } | term '=' term { $$ = f_new_inst(); $$->code = '=='; $$->a1.p = $1; $$->a2.p = $3; }
| term '!' '=' term { $$ = f_new_inst(); $$->code = '!='; $$->a1.p = $1; $$->a2.p = $4; } | term '!' '=' term { $$ = f_new_inst(); $$->code = '!='; $$->a1.p = $1; $$->a2.p = $4; }
| term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; } | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
@ -231,6 +232,22 @@ var_list: /* EMPTY */ { $$ = NULL; }
} }
; ;
switch_body: /* EMPTY */ { $$ = NULL; }
| term ':' block switch_body {
$$ = f_new_inst();
$$->code = 'of';
$$->a1.p = $1;
$$->a2.p = $3;
$$->next = $4;
}
| ELSE ':' block {
$$ = f_new_inst();
$$->code = 'el';
$$->a1.p = NULL;
$$->a2.p = $3;
}
;
cmd: cmd:
ifthen { ifthen {
$$ = $1; $$ = $1;
@ -272,6 +289,12 @@ cmd:
inst = inst->next; inst = inst->next;
} }
} }
| CASE term '{' switch_body '}' {
$$ = f_new_inst();
$$->code = 'sw';
$$->a1.p = $2;
$$->a2.p = $4;
}
; ;
CF_END CF_END

View file

@ -53,6 +53,8 @@ struct f_inst *startup_func = NULL;
int int
val_compare(struct f_val v1, struct f_val v2) val_compare(struct f_val v1, struct f_val v2)
{ {
if (v1.type != v2.type)
return CMP_ERROR;
switch (v1.type) { switch (v1.type) {
case T_INT: case T_INT:
if (v1.val.i == v2.val.i) return 0; if (v1.val.i == v2.val.i) return 0;
@ -64,6 +66,14 @@ val_compare(struct f_val v1, struct f_val v2)
} }
} }
int
val_in_range(struct f_val v1, struct f_val v2)
{
if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET))
return !! find_tree(v2.val.t, v1);
return CMP_ERROR;
}
static void static void
tree_print(struct f_tree *t) tree_print(struct f_tree *t)
{ {
@ -98,6 +108,42 @@ val_print(struct f_val v)
static struct rte **f_rte; 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 static struct f_val
interpret(struct f_inst *what) interpret(struct f_inst *what)
{ {
@ -155,11 +201,9 @@ interpret(struct f_inst *what)
case '~': case '~':
TWOARGS; TWOARGS;
res.type = T_BOOL; res.type = T_BOOL;
if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET)) { res.val.i = val_in_range(v1, v2);
res.val.i = !! find_tree(v2.val.t, v1); if (res.val.i == CMP_ERROR)
break; runtime( "~ applied on unknown type pair" );
}
runtime( "~ applied on unknown type pair" );
break; break;
/* Set to consant, a1 = type, a2 = value */ /* Set to consant, a1 = type, a2 = value */
@ -258,6 +302,10 @@ interpret(struct f_inst *what)
ONEARG; ONEARG;
res = interpret(what->a2.p); res = interpret(what->a2.p);
break; break;
case 'sw': /* SWITCH alias CASE */
ONEARG;
interpret_switch(what->a2.p, v1);
break;
default: default:
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
} }