Fixes several problems in filter syntax.

- 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.
This commit is contained in:
Ondrej Zajicek 2011-05-06 22:00:54 +02:00
parent 409e8a6e21
commit b8cc390e7e
4 changed files with 155 additions and 90 deletions

View file

@ -172,6 +172,10 @@ else: {
return CLI_MARKER;
}
\.\. {
return DDOT;
}
[={}:;,.()+*/%<>~\[\]?!\|-] {
return yytext[0];
}

View 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 ';' {

View 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;
if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
cf_error( "Can't operate with value out of bounds in pair constructor");
return (u1 << 16) | u2;
struct f_tree *t = f_new_tree();
t->right = t;
t->from = from;
t->to = to;
return t;
}
struct f_tree *f_generate_rev_wcard(int from, int to, int expr)
static inline struct f_tree *
f_merge_items(struct f_tree *a, struct f_tree *b)
{
struct f_tree *ret = NULL, *last = NULL;
if (!a) return b;
a->right->left = b;
a->right = b->right;
b->right = NULL;
return a;
}
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;
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;
}
from++; last = ret;
}
return ret;
static inline struct f_tree *
f_new_pair_set(int fa, int ta, int fb, int tb)
{
struct f_tree *lst = NULL;
int i;
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");
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); }
;
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));
}
| '(' 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:
'(' 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;
}
| set_atom '.' '.' set_atom {
$$ = f_new_tree();
$$->from = $1;
$$->to = $4;
}
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,17 +369,19 @@ fprefix_set:
;
switch_body: /* EMPTY */ { $$ = NULL; }
| switch_body set_item ':' cmds {
$$ = $2;
$$->data = $4;
$$->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 {
$$ = f_new_tree();
$$->from.type = T_VOID;
$$->to.type = T_VOID;
$$->data = $3;
$$->left = $1;
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);
}
;
@ -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; })

View 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,