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:
parent
409e8a6e21
commit
b8cc390e7e
4 changed files with 155 additions and 90 deletions
|
@ -172,6 +172,10 @@ else: {
|
||||||
return CLI_MARKER;
|
return CLI_MARKER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
\.\. {
|
||||||
|
return DDOT;
|
||||||
|
}
|
||||||
|
|
||||||
[={}:;,.()+*/%<>~\[\]?!\|-] {
|
[={}:;,.()+*/%<>~\[\]?!\|-] {
|
||||||
return yytext[0];
|
return yytext[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,15 @@ CF_HDR
|
||||||
|
|
||||||
/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
|
/* 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
|
CF_DECLS
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
|
@ -48,7 +57,7 @@ CF_DECLS
|
||||||
struct timeformat *tf;
|
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 GEQ LEQ NEQ AND OR
|
||||||
%token PO PC
|
%token PO PC
|
||||||
%token <i> NUM ENUM
|
%token <i> NUM ENUM
|
||||||
|
@ -96,6 +105,8 @@ expr:
|
||||||
| SYM { if ($1->class != SYM_NUMBER) cf_error("Number expected"); else $$ = $1->aux; }
|
| SYM { if ($1->class != SYM_NUMBER) cf_error("Number expected"); else $$ = $1->aux; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* expr_u16: expr { check_u16($1); $$ = $1; }; */
|
||||||
|
|
||||||
CF_ADDTO(conf, definition)
|
CF_ADDTO(conf, definition)
|
||||||
definition:
|
definition:
|
||||||
DEFINE SYM '=' expr ';' {
|
DEFINE SYM '=' expr ';' {
|
||||||
|
|
216
filter/config.Y
216
filter/config.Y
|
@ -12,32 +12,67 @@ CF_HDR
|
||||||
|
|
||||||
CF_DEFINES
|
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;
|
struct f_tree *t = f_new_tree();
|
||||||
unsigned u2 = i2;
|
t->right = t;
|
||||||
|
t->from = from;
|
||||||
if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
|
t->to = to;
|
||||||
cf_error( "Can't operate with value out of bounds in pair constructor");
|
return t;
|
||||||
|
|
||||||
return (u1 << 16) | u2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
static inline struct f_tree *
|
||||||
ret = f_new_tree();
|
f_new_pair_item(int fa, int ta, int fb, int tb)
|
||||||
ret->from.type = ret->to.type = T_PAIR;
|
{
|
||||||
ret->from.val.i = ret->to.val.i = make_pair(from, expr);
|
struct f_tree *t = f_new_tree();
|
||||||
ret->left = last;
|
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;
|
static inline struct f_tree *
|
||||||
}
|
f_new_pair_set(int fa, int ta, int fb, int tb)
|
||||||
return ret;
|
{
|
||||||
|
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
|
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 <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 <f> filter filter_body where_filter
|
||||||
%type <i> type break_command
|
%type <i> type break_command pair_expr
|
||||||
%type <e> set_item set_items switch_body
|
%type <i32> pair_atom
|
||||||
|
%type <e> pair_item set_item switch_item set_items switch_items switch_body
|
||||||
%type <trie> fprefix_set
|
%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 <s> decls declsn one_decl function_params
|
||||||
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
|
%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; }
|
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:
|
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; }
|
| RTRID { $$.type = T_QUAD; $$.val.i = $1; }
|
||||||
| fipa { $$ = $1; }
|
| fipa { $$ = $1; }
|
||||||
| ENUM { $$.type = $1 >> 16; $$.val.i = $1 & 0xffff; }
|
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
set_item:
|
switch_atom:
|
||||||
'(' expr ',' expr ')' {
|
NUM { $$.type = T_INT; $$.val.i = $1; }
|
||||||
$$ = f_new_tree();
|
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
|
||||||
$$->from.type = $$->to.type = T_PAIR;
|
| RTRID { $$.type = T_QUAD; $$.val.i = $1; }
|
||||||
$$->from.val.i = make_pair($2, $4);
|
| fipa { $$ = $1; }
|
||||||
$$->to.val.i = make_pair($2, $4);
|
| 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));
|
||||||
}
|
}
|
||||||
| '(' expr ',' expr '.' '.' expr ')' {
|
| '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' {
|
||||||
$$ = f_new_tree();
|
/* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */
|
||||||
$$->from.type = $$->to.type = T_PAIR;
|
if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4)))
|
||||||
$$->from.val.i = make_pair($2, $4);
|
cf_error("syntax error");
|
||||||
$$->to.val.i = make_pair($2, $7);
|
$$ = f_new_pair_item(pair_b($2), pair_b($4), $8, $10);
|
||||||
}
|
|
||||||
| '(' 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;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
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_items:
|
||||||
set_item { $$ = $1; }
|
set_item
|
||||||
| set_items ',' set_item { $$ = $3; $$->left = $1; }
|
| set_items ',' set_item { $$ = f_merge_items($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
switch_items:
|
||||||
|
switch_item
|
||||||
|
| switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
fprefix_s:
|
fprefix_s:
|
||||||
|
@ -328,18 +369,20 @@ fprefix_set:
|
||||||
;
|
;
|
||||||
|
|
||||||
switch_body: /* EMPTY */ { $$ = NULL; }
|
switch_body: /* EMPTY */ { $$ = NULL; }
|
||||||
| switch_body set_item ':' cmds {
|
| switch_body switch_items ':' cmds {
|
||||||
$$ = $2;
|
/* Fill data fields */
|
||||||
$$->data = $4;
|
struct f_tree *t;
|
||||||
$$->left = $1;
|
for (t = $2; t; t = t->left)
|
||||||
}
|
t->data = $4;
|
||||||
| switch_body ELSECOL cmds {
|
$$ = f_merge_items($1, $2);
|
||||||
$$ = f_new_tree();
|
|
||||||
$$->from.type = T_VOID;
|
|
||||||
$$->to.type = T_VOID;
|
|
||||||
$$->data = $3;
|
|
||||||
$$->left = $1;
|
|
||||||
}
|
}
|
||||||
|
| 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; } */
|
/* 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))
|
if (($2->aux != T_INT) || ($4->aux != T_INT))
|
||||||
cf_error( "Can't operate with value of non-integer type in pair constructor" );
|
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
|
else
|
||||||
{ $$ = f_new_inst(); $$->code = P('m', 'p'); $$->a1.p = $2; $$->a2.p = $4; }
|
{ $$ = 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.
|
* Maybe there are no dynamic attributes defined by protocols.
|
||||||
* For such cases, we force the dynamic_attr list to contain
|
* 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; })
|
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is an example configuration file.
|
* This is an example configuration file.
|
||||||
* FIXME: add all examples from docs here.
|
* FIXME: add all examples from docs here.
|
||||||
|
@ -36,7 +37,7 @@ int i;
|
||||||
i = arg2;
|
i = arg2;
|
||||||
|
|
||||||
case arg1 {
|
case arg1 {
|
||||||
one: printn "jedna, "; printn "jedna";
|
11, 1, 111: printn "jedna, "; printn "jedna";
|
||||||
(one+onef(2)): printn "dva, "; printn "jeste jednou dva";
|
(one+onef(2)): printn "dva, "; printn "jeste jednou dva";
|
||||||
(2+one) .. 5: if arg2 < 3 then printn "tri az pet";
|
(2+one) .. 5: if arg2 < 3 then printn "tri az pet";
|
||||||
else: printn "neco jineho";
|
else: printn "neco jineho";
|
||||||
|
@ -236,8 +237,13 @@ string s;
|
||||||
|
|
||||||
ps = [(1,(one+one)), (3,4)..(4,8), (5,*), (6,3..6)];
|
ps = [(1,(one+one)), (3,4)..(4,8), (5,*), (6,3..6)];
|
||||||
print "Pair set: ", ps;
|
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, 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 ;
|
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;
|
qq = 1.2.3.4;
|
||||||
print "Testinq quad: 1.2.3.4 = ", qq,
|
print "Testinq quad: 1.2.3.4 = ", qq,
|
||||||
|
|
Loading…
Reference in a new issue