]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Case arg { 1: printf "one"; } works. You can not use two commands
authorPavel Machek <pavel@ucw.cz>
Wed, 29 Sep 1999 14:24:58 +0000 (14:24 +0000)
committerPavel Machek <pavel@ucw.cz>
Wed, 29 Sep 1999 14:24:58 +0000 (14:24 +0000)
after one label, yet.

filter/config.Y
filter/filter.c

index 6aa1285f5dd2bd5b626cf03884bded7569c32ccd..7b6a732648c7f2e570cd352e4b46c8ae85be6321 100644 (file)
@@ -21,7 +21,7 @@ CF_DECLS
 CF_KEYWORDS(FUNCTION, PRINT, CONST,
        ACCEPT, REJECT, ERROR, QUITBIRD,
        INT, BOOL, IP, PREFIX, PAIR, SET, STRING,
-       IF, THEN, ELSE,
+       IF, THEN, ELSE, CASE,
        TRUE, FALSE,
        RTA, FROM, GW, NET,
        LEN,
@@ -29,7 +29,7 @@ CF_KEYWORDS(FUNCTION, PRINT, CONST,
        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 <i> type break_command
 %type <e> set_item set_items
@@ -118,6 +118,8 @@ function_def:
 cmds: /* EMPTY */ { $$ = NULL; }
  | cmd cmds {
      if ($1) {
+       if ($1->next)
+        bug("Command has next already set\n");
        $1->next = $2;
        $$ = $1;
      } else $$ = $2;
@@ -160,7 +162,6 @@ constant:
 
 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 = $4; }
  | 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:
    ifthen { 
      $$ = $1;
@@ -272,6 +289,12 @@ cmd:
        inst = inst->next;
      }
    }
+ | CASE term '{' switch_body '}' {
+      $$ = f_new_inst();
+      $$->code = 'sw';
+      $$->a1.p = $2;
+      $$->a2.p = $4;
+   }
  ;
 
 CF_END
index 41499710c98ed74cef29ea1ff7a402cde0cc286b..7939ad01696c74e8d652907cd561927b1804df04 100644 (file)
@@ -53,6 +53,8 @@ struct f_inst *startup_func = NULL;
 int
 val_compare(struct f_val v1, struct f_val v2)
 {
+  if (v1.type != v2.type)
+    return CMP_ERROR;
   switch (v1.type) {
   case T_INT: 
     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
 tree_print(struct f_tree *t)
 {
@@ -98,6 +108,42 @@ val_print(struct f_val v)
 
 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)
 {
@@ -155,11 +201,9 @@ interpret(struct f_inst *what)
   case '~':
     TWOARGS;
     res.type = T_BOOL;
-    if (((v1.type == T_INT) || (v1.type == T_IP)) && (v2.type == T_SET)) {
-      res.val.i = !! find_tree(v2.val.t, v1);
-      break;
-    }
-    runtime( "~ applied on unknown type pair" );
+    res.val.i = val_in_range(v1, v2);
+    if (res.val.i == CMP_ERROR)
+      runtime( "~ applied on unknown type pair" );
     break;
 
   /* Set to consant, a1 = type, a2 = value */
@@ -258,6 +302,10 @@ interpret(struct f_inst *what)
     ONEARG;
     res = interpret(what->a2.p);
     break;
+  case 'sw': /* SWITCH alias CASE */
+    ONEARG;
+    interpret_switch(what->a2.p, v1);
+    break;
   default:
     bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
   }