]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes several problems in filter syntax.
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 6 May 2011 20:00:54 +0000 (22:00 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 6 May 2011 20:00:54 +0000 (22:00 +0200)
 - Fixes several conflicts in the grammar.
 - Fixes a bug in (a..b, c) pair patterns.
 - Makes pair patterns orthogonal.
 - Allows term expressions in pair patterns without additional ( ).
 - Allows several comma separated values in switch cases.

conf/cf-lex.l
conf/confbase.Y
filter/config.Y
filter/test.conf

index 828dfd25ff13db7cebea49541a4809472196b953..a5f70fff716ca49e9a96b4633b3396e653b105b6 100644 (file)
@@ -172,6 +172,10 @@ else: {
   return CLI_MARKER;
 }
 
+\.\. {
+  return DDOT;
+}
+
 [={}:;,.()+*/%<>~\[\]?!\|-] {
   return yytext[0];
 }
index 68960c2e542d5e40fdb2922452f4acb8c50021a9..499a770e66d7c4651efd5b289b488a811826c022 100644 (file)
@@ -24,6 +24,15 @@ CF_HDR
 
 /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
 
+CF_DEFINES
+
+static void
+check_u16(unsigned val)
+{
+  if (val > 0xFFFF)
+    cf_error("Value %d out of range (0-65535)", val);
+}
+
 CF_DECLS
 
 %union {
@@ -48,7 +57,7 @@ CF_DECLS
   struct timeformat *tf;
 }
 
-%token END CLI_MARKER INVALID_TOKEN ELSECOL
+%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
 %token GEQ LEQ NEQ AND OR
 %token PO PC
 %token <i> NUM ENUM
@@ -96,6 +105,8 @@ expr:
  | SYM { if ($1->class != SYM_NUMBER) cf_error("Number expected"); else $$ = $1->aux; }
  ;
 
+/* expr_u16: expr { check_u16($1); $$ = $1; }; */
+
 CF_ADDTO(conf, definition)
 definition:
    DEFINE SYM '=' expr ';' {
index ebe6f498eba0519d0e65cb26bd8cfec27c1de576..e635f6094e396b6685759b45d9dfc29de44a93eb 100644 (file)
@@ -12,32 +12,67 @@ CF_HDR
 
 CF_DEFINES
 
-#define P(a,b) ((a<<8) | b)
+#define P(a,b) ((a << 8) | b)
 
-static int make_pair(int i1, int i2)
+static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
+static inline u32 pair_a(u32 p) { return p >> 16; }
+static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
+
+
+/*
+ * Sets and their items are during parsing handled as lists, linked
+ * through left ptr. The first item in a list also contains a pointer
+ * to the last item in a list (right ptr). For convenience, even items
+ * are handled as one-item lists. Lists are merged by f_merge_items().
+ */
+
+static inline struct f_tree *
+f_new_item(struct f_val from, struct f_val to)
 {
-  unsigned u1 = i1;
-  unsigned u2 = i2;
+  struct f_tree *t = f_new_tree();
+  t->right = t;
+  t->from = from;
+  t->to = to;
+  return t;
+}
 
-  if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
-    cf_error( "Can't operate with value out of bounds in pair constructor");
+static inline struct f_tree *
+f_merge_items(struct f_tree *a, struct f_tree *b)
+{
+  if (!a) return b;
+  a->right->left = b;
+  a->right = b->right;
+  b->right = NULL;
+  return a;
+}
 
-  return (u1 << 16) | u2;
+static inline struct f_tree *
+f_new_pair_item(int fa, int ta, int fb, int tb)
+{
+  struct f_tree *t = f_new_tree();
+  t->right = t;
+  t->from.type = t->to.type = T_PAIR;
+  t->from.val.i = pair(fa, fb);
+  t->to.val.i = pair(ta, tb);
+  return t;
 }
 
-struct f_tree *f_generate_rev_wcard(int from, int to, int expr)
+static inline struct f_tree *
+f_new_pair_set(int fa, int ta, int fb, int tb)
 {
-       struct f_tree *ret = NULL, *last = NULL;
+  struct f_tree *lst = NULL;
+  int i;
 
-       while (from <= to) {
-               ret = f_new_tree(); 
-               ret->from.type = ret->to.type = T_PAIR;
-               ret->from.val.i = ret->to.val.i = make_pair(from, expr); 
-               ret->left = last;
+  if ((fa == ta) || ((fb == 0) && (tb == 0xFFFF)))
+    return f_new_pair_item(fa, ta, fb, tb);
+  
+  if ((ta < fa) || (tb < fb))
+    cf_error( "From value cannot be higher that To value in pair sets");
 
-               from++; last = ret;
-       }
-       return ret;
+  for (i = fa; i <= ta; i++)
+    lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
+
+  return lst;
 }
 
 CF_DECLS
@@ -60,10 +95,11 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 
 %type <x> term block cmds cmds_int cmd function_body constant print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol dpair bgp_path_expr
 %type <f> filter filter_body where_filter
-%type <i> type break_command
-%type <e> set_item set_items switch_body
+%type <i> type break_command pair_expr
+%type <i32> pair_atom
+%type <e> pair_item set_item switch_item set_items switch_items switch_body
 %type <trie> fprefix_set
-%type <v> set_atom fprefix fprefix_s fipa
+%type <v> set_atom switch_atom fprefix fprefix_s fipa
 %type <s> decls declsn one_decl function_params 
 %type <h> bgp_path bgp_path_tail1 bgp_path_tail2
 
@@ -243,66 +279,71 @@ fipa:
    IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
  ;
 
+
+
+/*
+ * Set constants. They are also used in switch cases. We use separate
+ * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
+ * to elude a collision between symbol (in expr) in set_atom and symbol
+ * as a function call in switch case cmds.
+ */
+
 set_atom:
-   expr  { $$.type = T_INT; $$.val.i = $1; }   /* 'SYM' included in 'expr' creates 3 reduce/shift conflicts */
+   expr  { $$.type = T_INT; $$.val.i = $1; }
  | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
  | fipa  { $$ = $1; }
- | ENUM  { $$.type = $1 >> 16; $$.val.i = $1 & 0xffff; }
- ; 
+ | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
+ ;
 
-set_item:
-   '(' expr ',' expr ')' {
-       $$ = f_new_tree(); 
-       $$->from.type = $$->to.type = T_PAIR;
-       $$->from.val.i = make_pair($2, $4); 
-       $$->to.val.i = make_pair($2, $4);
-   }
- | '(' expr ',' expr '.' '.' expr ')' { 
-       $$ = f_new_tree(); 
-       $$->from.type = $$->to.type = T_PAIR;
-       $$->from.val.i = make_pair($2, $4); 
-       $$->to.val.i = make_pair($2, $7);
-   }
- | '(' expr ',' expr ')' '.' '.' '(' expr ',' expr ')' { 
-       $$ = f_new_tree(); 
-       $$->from.type = $$->to.type = T_PAIR;
-       $$->from.val.i = make_pair($2, $4); 
-       $$->to.val.i = make_pair($9, $11);
-   }
- |  '(' '*' ',' '*' ')' {      /* This is probably useless :-) */
-       $$ = f_new_tree(); 
-       $$->from.type = $$->to.type = T_PAIR;
-       $$->from.val.i = 0;
-       $$->to.val.i = 0xffffffff;
-   }
- |  '(' expr ',' '*' ')' { 
-       $$ = f_new_tree(); 
-       $$->from.type = $$->to.type = T_PAIR;
-       $$->from.val.i = make_pair($2, 0); 
-       $$->to.val.i = make_pair($2, 0xffff);
-   }
- |  '(' '*' ',' expr ')' { 
-       $$ = f_generate_rev_wcard(0, 0xffff, $4);
-   }
- /* This causes 3 reduce/reduce conflicts
- | '(' expr '.' '.' expr ',' expr ')' { 
-       cf_error("Not implemented yet");
-   }*/
- | set_atom { 
-       $$ = f_new_tree(); 
-       $$->from = $1; 
-       $$->to = $1;
+switch_atom:
+   NUM   { $$.type = T_INT; $$.val.i = $1; }
+ | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
+ | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
+ | fipa  { $$ = $1; }
+ | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
+ ;
+
+pair_expr:
+   term { $$ = f_eval_int($1); check_u16($$); }
+
+pair_atom:
+   pair_expr { $$ = pair($1, $1); }
+ | pair_expr DDOT pair_expr { $$ = pair($1, $3); }
+ | '*' { $$ = 0xFFFF; }
+ ;
+
+pair_item:
+   '(' pair_atom ',' pair_atom ')' {
+     $$ = f_new_pair_set(pair_a($2), pair_b($2), pair_a($4), pair_b($4));
    }
- | set_atom '.' '.' set_atom { 
-       $$ = f_new_tree(); 
-       $$->from = $1; 
-       $$->to = $4; 
+ | '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' {
+     /* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */
+     if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4)))
+       cf_error("syntax error");
+     $$ = f_new_pair_item(pair_b($2), pair_b($4), $8, $10); 
    }
  ;
 
+set_item:
+   pair_item
+ | set_atom { $$ = f_new_item($1, $1); }
+ | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
+ ;
+
+switch_item:
+   pair_item
+ | switch_atom { $$ = f_new_item($1, $1); }
+ | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
+ ;
+
 set_items:
-   set_item { $$ = $1; }
- | set_items ',' set_item { $$ = $3; $$->left = $1; }
+   set_item
+ | set_items ',' set_item { $$ = f_merge_items($1, $3); }
+ ;
+
+switch_items:
+   switch_item
+ | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
  ;
 
 fprefix_s:
@@ -328,18 +369,20 @@ fprefix_set:
  ;
 
 switch_body: /* EMPTY */ { $$ = NULL; }
- | switch_body set_item ':' cmds  {
-     $$ = $2;
-     $$->data = $4;
-     $$->left = $1;
-   }
- | switch_body ELSECOL cmds {
-     $$ = f_new_tree(); 
-     $$->from.type = T_VOID; 
-     $$->to.type = T_VOID;
-     $$->data = $3;
-     $$->left = $1;
-   }
+ | switch_body switch_items ':' cmds  {
+     /* Fill data fields */
+     struct f_tree *t;
+     for (t = $2; t; t = t->left)
+       t->data = $4;
+     $$ = f_merge_items($1, $2);
+   }
+ | switch_body ELSECOL cmds { 
+     struct f_tree *t = f_new_tree();
+     t->from.type = t->to.type = T_VOID;
+     t->right = t;
+     t->data = $3;
+     $$ = f_merge_items($1, t);
+ }
  ;
 
 /* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
@@ -374,7 +417,8 @@ dpair:
           { 
             if (($2->aux != T_INT) || ($4->aux != T_INT))
               cf_error( "Can't operate with value of non-integer type in pair constructor" );
-            $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR;  $$->a2.i = make_pair($2->a2.i, $4->a2.i);
+           check_u16($2->a2.i); check_u16($4->a2.i);
+            $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR;  $$->a2.i = pair($2->a2.i, $4->a2.i);
           }
        else
          { $$ = f_new_inst(); $$->code = P('m', 'p'); $$->a1.p = $2; $$->a2.p = $4; }
@@ -399,7 +443,7 @@ constant:
 /*
  *  Maybe there are no dynamic attributes defined by protocols.
  *  For such cases, we force the dynamic_attr list to contain
- *  at least an invalid token, so it's syntantically correct.
+ *  at least an invalid token, so it is syntantically correct.
  */
 CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
 
index b4d3400038d6fe87c225fa561a04531983595f77..dbb3a4ea5752bfe0172dab1a81e80994c822b91d 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  *     This is an example configuration file.
  *     FIXME: add all examples from docs here.
@@ -36,7 +37,7 @@ int i;
        i = arg2;
 
        case arg1 {
-       one: printn "jedna, "; printn "jedna";
+       11, 1, 111: printn "jedna, "; printn "jedna";
        (one+onef(2)): printn "dva, "; printn "jeste jednou dva";
        (2+one) .. 5: if arg2 < 3 then printn "tri az pet";
        else: printn "neco jineho";
@@ -236,8 +237,13 @@ string s;
 
        ps = [(1,(one+one)), (3,4)..(4,8), (5,*), (6,3..6)];
        print "Pair set: ", ps;
-       print "Testing pair set, true:  ", pp ~ ps,  "  ", (3,5) ~ ps, "  ", (4,1) ~ ps, "  ", (5,4) ~ ps, "  ", (5,65535) ~ ps, "  ", (6,4) ~ ps;
-       print "Testing pair set, false: ", (3,3) ~ ps, " ", (4,9) ~ ps, " ", (4,65535) ~ ps, " ", (6,2) ~ ps, " ", (6,(6+one)) ~ ps, " ", ((one+6),2) ~ ps ;
+       print "Testing pair set, true:  ", pp ~ ps,  "  ", (3,5) ~ ps, "  ", (4,1) ~ ps, "  ", (5,4) ~ ps, "  ", (5,65535) ~ ps, "  ", (6,4) ~ ps, "  ", (3, 10000) ~ ps;
+       print "Testing pair set, false: ", (3,3) ~ ps, " ", (4,9) ~ ps, " ", (4,65535) ~ ps, " ", (6,2) ~ ps, " ", (6,6+one) ~ ps, " ", ((one+6),2) ~ ps, " ", (1,1) ~ ps;
+
+       ps = [(20..150, 200..300), (50100..50200, 1000..50000), (*, 5+5)];
+       print "Pair set: .. too long ..";
+       print "Testing pair set, true:  ", (100,200) ~ ps,  "  ", (150,300) ~ ps, "  ", (50180,1200) ~ ps, "  ", (50110,49000) ~ ps, "  ", (0,10) ~ ps, "  ", (64000,10) ~ ps;
+       print "Testing pair set, false: ", (20,199) ~ ps, " ", (151,250) ~ ps, " ", (50050,2000) ~ ps, " ", (50150,50050) ~ ps, " ", (10,9) ~ ps, " ", (65535,11) ~ ps ;
 
        qq = 1.2.3.4;
        print "Testinq quad: 1.2.3.4 = ", qq,