2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 14:05:33 +00:00

[master] Merged trac4233 (new concat string function to classification expression)

This commit is contained in:
Francis Dupont
2016-02-19 17:21:36 +01:00
parent 8e01dbe2fe
commit eec10b436b
14 changed files with 577 additions and 455 deletions

View File

@@ -1,8 +1,13 @@
1080. [func] fdupont
Added a concat function in classification which concatenates two
strings.
(Trac #4233, git ...)
1079. [func] fdupont
Added Not, And and Or logical operators, parentheses around
logical expressions and option[code].exist logical predicate
(to check the presence of an empty option).
(Trac #4231, git xxx)
(Trac #4231, git 8e01dbe2fe2d8c97f89c20f5bb1d03748a2432e0)
1078. [func] tomek
Client classification in DHCPv4 has been enhanced. It is now

View File

@@ -224,6 +224,7 @@ sub-option with code "code" from the Relay Agent Information option
<row><entry>And</entry> <entry>('foo' == 'bar') and ('bar' == 'foo')</entry><entry>Logical and</entry></row>
<row><entry>Or</entry> <entry>('foo' == 'bar') or ('bar' == 'foo')</entry><entry>Logical or</entry></row>
<row><entry>Substring</entry><entry>substring('foobar',0,3)</entry><entry>Return the requested substring</entry></row>
<row><entry>Concat</entry><entry>concat('foo','bar')</entry><entry>Return the concatenation of the strings</entry></row>
</tbody>
</tgroup>
</table>
@@ -261,6 +262,14 @@ sub-option with code "code" from the Relay Agent Information option
substring('foobar', 10, 2) == ''
</screen>
</section>
<section>
<title>Concat</title>
The concat function "concat(string1, string2)" returns the
concatenation of its two arguments. For instance:
<screen>
concat('foo', 'bar') == 'foobar'
</screen>
</section>
</section>
<note>

View File

@@ -460,8 +460,8 @@ static void yy_fatal_error (yyconst char msg[] );
(yy_c_buf_p) = yy_cp;
/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
#define YY_NUM_RULES 25
#define YY_END_OF_BUFFER 26
#define YY_NUM_RULES 26
#define YY_END_OF_BUFFER 27
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@@ -469,33 +469,35 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static yyconst flex_int16_t yy_acclist[119] =
static yyconst flex_int16_t yy_acclist[128] =
{ 0,
26, 24, 25, 1, 24, 25, 2, 25, 24, 25,
19, 24, 25, 20, 24, 25, 23, 24, 25, 24,
25, 18, 24, 25, 5, 24, 25, 5, 24, 25,
24, 25, 24, 25,16390, 21, 24, 25, 22, 24,
25, 24, 25,16390, 24, 25,16390, 24, 25,16390,
24, 25,16390, 24, 25,16390, 24, 25,16390, 24,
25,16390, 24, 25,16390, 1, 2, 3, 5, 7,
16390, 8198,16390,16390,16390,16390,16390,16390, 17,16390,
16390,16390,16390, 4, 14,16390, 16,16390,16390, 10,
16390, 15,16390,16390,16390,16390,16390,16390,16390,16390,
27, 25, 26, 1, 25, 26, 2, 26, 25, 26,
20, 25, 26, 21, 25, 26, 24, 25, 26, 25,
26, 19, 25, 26, 5, 25, 26, 5, 25, 26,
25, 26, 25, 26,16390, 22, 25, 26, 23, 25,
26, 25, 26,16390, 25, 26,16390, 25, 26,16390,
25, 26,16390, 25, 26,16390, 25, 26,16390, 25,
26,16390, 25, 26,16390, 25, 26,16390, 1, 2,
3, 5, 7,16390, 8198,16390,16390,16390,16390,16390,
16390,16390, 18,16390,16390,16390,16390, 4, 14,16390,
17,16390,16390,16390, 10,16390, 16,16390,16390,16390,
16390, 9,16390,16390,16390,16390,16390, 11,16390, 8,
16390, 13,16390,16390,16390,16390, 12,16390
16390,16390,16390,16390,16390,16390,16390, 9,16390,16390,
16390,16390,16390,16390, 15,16390, 11,16390, 8,16390,
12,16390,16390,16390,16390, 13,16390
} ;
static yyconst flex_int16_t yy_accept[76] =
static yyconst flex_int16_t yy_accept[82] =
{ 0,
1, 1, 1, 2, 4, 7, 9, 11, 14, 17,
20, 22, 25, 28, 31, 33, 36, 39, 42, 45,
48, 51, 54, 57, 60, 63, 66, 67, 68, 68,
69, 70, 70, 71, 71, 71, 72, 73, 74, 75,
76, 77, 78, 79, 81, 82, 83, 84, 85, 87,
89, 90, 92, 94, 95, 96, 97, 98, 99, 100,
101, 102, 104, 105, 106, 107, 108, 110, 112, 114,
115, 116, 117, 119, 119
48, 51, 54, 57, 60, 63, 66, 69, 70, 71,
71, 72, 73, 73, 74, 74, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 85, 86, 87, 88,
89, 91, 93, 94, 95, 97, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 110, 111, 112, 113,
114, 115, 117, 119, 121, 123, 124, 125, 126, 128,
128
} ;
static yyconst flex_int32_t yy_ec[256] =
@@ -509,11 +511,11 @@ static yyconst flex_int32_t yy_ec[256] =
13, 1, 1, 1, 14, 14, 14, 14, 14, 14,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 16, 15, 15,
17, 1, 18, 1, 19, 1, 20, 21, 14, 22,
17, 1, 18, 1, 19, 1, 20, 21, 22, 23,
23, 14, 24, 25, 26, 15, 15, 27, 15, 28,
29, 30, 15, 31, 32, 33, 34, 15, 15, 35,
36, 15, 1, 1, 1, 1, 1, 1, 1, 1,
24, 14, 25, 26, 27, 15, 15, 28, 15, 29,
30, 31, 15, 32, 33, 34, 35, 15, 15, 36,
37, 15, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -530,114 +532,118 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1
} ;
static yyconst flex_int32_t yy_meta[37] =
static yyconst flex_int32_t yy_meta[38] =
{ 0,
1, 2, 3, 1, 1, 1, 1, 2, 1, 4,
4, 4, 1, 4, 2, 2, 1, 2, 2, 4,
4, 4, 4, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2
4, 4, 4, 4, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2
} ;
static yyconst flex_int16_t yy_base[78] =
static yyconst flex_int16_t yy_base[84] =
{ 0,
0, 0, 113, 205, 108, 101, 98, 205, 205, 205,
27, 205, 30, 33, 87, 45, 205, 205, 64, 22,
28, 31, 43, 52, 34, 58, 82, 66, 50, 205,
66, 0, 205, 85, 87, 66, 205, 68, 79, 71,
81, 84, 91, 93, 95, 104, 99, 0, 101, 108,
110, 112, 116, 119, 121, 123, 125, 129, 132, 136,
138, 140, 142, 148, 161, 150, 152, 155, 157, 164,
159, 169, 167, 205, 197, 200, 48
0, 0, 202, 219, 167, 155, 138, 219, 219, 219,
28, 219, 31, 34, 94, 46, 219, 219, 66, 22,
27, 29, 31, 44, 42, 51, 53, 103, 80, 74,
219, 77, 0, 219, 88, 90, 68, 219, 70, 81,
72, 84, 86, 92, 95, 74, 88, 104, 99, 0,
102, 108, 112, 110, 116, 118, 121, 131, 124, 127,
134, 136, 138, 143, 145, 147, 149, 153, 156, 175,
160, 162, 165, 167, 169, 172, 177, 182, 180, 219,
211, 214, 58
} ;
static yyconst flex_int16_t yy_def[78] =
static yyconst flex_int16_t yy_def[84] =
{ 0,
74, 1, 74, 74, 74, 74, 75, 74, 74, 74,
74, 74, 74, 74, 74, 76, 74, 74, 76, 19,
19, 19, 19, 19, 19, 19, 74, 74, 75, 74,
74, 77, 74, 74, 19, 19, 74, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 77, 19, 19,
80, 1, 80, 80, 80, 80, 81, 80, 80, 80,
80, 80, 80, 80, 80, 82, 80, 80, 82, 19,
19, 19, 19, 19, 19, 19, 19, 80, 80, 81,
80, 80, 83, 80, 80, 19, 19, 80, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 83,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 0, 74, 74, 74
19, 19, 19, 19, 19, 19, 19, 19, 19, 0,
80, 80, 80
} ;
static yyconst flex_int16_t yy_nxt[242] =
static yyconst flex_int16_t yy_nxt[257] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 14, 15, 16, 16, 16, 17, 18, 4, 19,
16, 16, 20, 16, 21, 16, 16, 22, 23, 16,
24, 25, 26, 16, 16, 16, 31, 31, 31, 31,
31, 31, 31, 31, 31, 32, 34, 34, 36, 36,
41, 48, 35, 30, 36, 36, 40, 36, 36, 42,
36, 36, 37, 35, 32, 34, 34, 46, 28, 36,
36, 35, 43, 44, 45, 31, 31, 31, 36, 36,
47, 37, 35, 27, 36, 36, 34, 34, 74, 74,
38, 39, 36, 36, 49, 36, 51, 36, 36, 33,
16, 20, 16, 21, 16, 22, 16, 16, 23, 24,
16, 25, 26, 27, 16, 16, 16, 32, 32, 32,
32, 32, 32, 32, 32, 32, 33, 35, 35, 37,
37, 41, 43, 36, 37, 37, 37, 37, 37, 37,
44, 50, 42, 38, 36, 47, 33, 35, 35, 37,
37, 37, 37, 36, 45, 46, 49, 31, 37, 37,
37, 37, 29, 38, 36, 48, 32, 32, 32, 35,
35, 80, 80, 39, 40, 37, 37, 51, 37, 37,
50, 30, 37, 28, 74, 36, 36, 36, 36, 27,
36, 36, 74, 36, 36, 52, 53, 36, 36, 36,
36, 55, 36, 54, 56, 36, 36, 36, 36, 74,
36, 36, 74, 57, 36, 36, 36, 36, 36, 36,
60, 58, 36, 36, 59, 36, 36, 36, 36, 36,
36, 36, 36, 74, 61, 36, 36, 62, 36, 36,
64, 63, 36, 36, 36, 36, 36, 36, 36, 36,
66, 65, 69, 67, 36, 68, 36, 36, 36, 36,
70, 36, 36, 36, 36, 36, 72, 36, 36, 71,
36, 36, 73, 36, 36, 36, 36, 29, 29, 74,
53, 37, 37, 52, 28, 38, 34, 80, 37, 37,
54, 37, 37, 37, 37, 58, 37, 37, 37, 37,
37, 55, 37, 37, 59, 56, 37, 37, 57, 37,
37, 37, 37, 61, 60, 37, 37, 37, 37, 37,
37, 31, 62, 37, 37, 37, 37, 63, 37, 37,
64, 37, 37, 67, 37, 37, 65, 29, 37, 37,
66, 37, 37, 37, 37, 37, 37, 69, 28, 68,
37, 37, 37, 37, 37, 37, 37, 37, 71, 70,
37, 37, 72, 37, 74, 73, 75, 37, 37, 37,
37, 76, 37, 37, 37, 37, 37, 37, 77, 37,
29, 36, 36, 36, 3, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74
37, 80, 37, 37, 37, 78, 79, 37, 37, 37,
37, 30, 30, 80, 30, 37, 37, 37, 3, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80
} ;
static yyconst flex_int16_t yy_chk[242] =
static yyconst flex_int16_t yy_chk[257] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 11, 11, 11, 13,
13, 13, 14, 14, 14, 13, 16, 16, 20, 20,
21, 77, 16, 29, 21, 21, 20, 22, 22, 22,
25, 25, 16, 16, 13, 19, 19, 25, 28, 23,
23, 19, 23, 23, 24, 31, 31, 31, 24, 24,
26, 19, 19, 27, 26, 26, 34, 34, 35, 35,
19, 19, 36, 36, 38, 38, 40, 40, 40, 15,
1, 1, 1, 1, 1, 1, 1, 11, 11, 11,
13, 13, 13, 14, 14, 14, 13, 16, 16, 20,
20, 20, 22, 16, 21, 21, 22, 22, 23, 23,
23, 83, 21, 16, 16, 25, 13, 19, 19, 25,
25, 24, 24, 19, 24, 24, 27, 30, 26, 26,
27, 27, 29, 19, 19, 26, 32, 32, 32, 35,
35, 36, 36, 19, 19, 37, 37, 39, 39, 41,
39, 7, 34, 6, 35, 39, 39, 41, 41, 5,
42, 42, 3, 35, 35, 41, 42, 43, 43, 44,
44, 45, 45, 43, 46, 47, 47, 49, 49, 0,
46, 46, 0, 47, 50, 50, 51, 51, 52, 52,
55, 51, 53, 53, 54, 54, 54, 55, 55, 56,
56, 57, 57, 0, 56, 58, 58, 57, 59, 59,
59, 58, 60, 60, 61, 61, 62, 62, 63, 63,
61, 60, 65, 63, 64, 64, 66, 66, 67, 67,
66, 68, 68, 69, 69, 71, 71, 65, 65, 70,
70, 70, 72, 73, 73, 72, 72, 75, 75, 0,
41, 46, 46, 40, 28, 35, 15, 36, 40, 40,
42, 42, 42, 43, 43, 47, 47, 36, 36, 44,
44, 43, 45, 45, 48, 44, 49, 49, 45, 51,
51, 48, 48, 53, 49, 52, 52, 54, 54, 53,
53, 7, 54, 55, 55, 56, 56, 57, 57, 57,
58, 59, 59, 61, 60, 60, 59, 6, 58, 58,
60, 61, 61, 62, 62, 63, 63, 63, 5, 62,
64, 64, 65, 65, 66, 66, 67, 67, 65, 64,
68, 68, 67, 69, 69, 68, 70, 71, 71, 72,
72, 71, 73, 73, 74, 74, 75, 75, 76, 76,
75, 76, 76, 76, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
74
76, 3, 70, 70, 77, 77, 78, 79, 79, 78,
78, 81, 81, 0, 81, 82, 82, 82, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
80, 80, 80, 80, 80, 80
} ;
/* Table of booleans, true if rule could match eol. */
static yyconst flex_int32_t yy_rule_can_match_eol[26] =
static yyconst flex_int32_t yy_rule_can_match_eol[27] =
{ 0,
0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, };
0, 0, 0, 0, 0, 0, 0, };
extern int yy_flex_debug;
int yy_flex_debug = 1;
static yyconst flex_int16_t yy_rule_linenum[25] =
static yyconst flex_int16_t yy_rule_linenum[26] =
{ 0,
78, 82, 88, 98, 104, 118, 125, 126, 127, 128,
129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 143
139, 140, 141, 142, 144
} ;
static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
@@ -714,7 +720,7 @@ static isc::eval::location loc;
// by moving it ahead by yyleng bytes. yyleng specifies the length of the
// currently matched token.
#define YY_USER_ACTION loc.columns(yyleng);
#line 718 "lexer.cc"
#line 724 "lexer.cc"
#define INITIAL 0
@@ -962,7 +968,7 @@ YY_DECL
loc.step();
#line 966 "lexer.cc"
#line 972 "lexer.cc"
if ( !(yy_init) )
{
@@ -1030,14 +1036,14 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 75 )
if ( yy_current_state >= 81 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
*(yy_state_ptr)++ = yy_current_state;
++yy_cp;
}
while ( yy_current_state != 74 );
while ( yy_current_state != 80 );
yy_find_action:
/* %% [10.0] code to find the action number goes here */
@@ -1101,13 +1107,13 @@ do_action: /* This label is used only to access EOF actions. */
{
if ( yy_act == 0 )
fprintf( stderr, "--scanner backing up\n" );
else if ( yy_act < 25 )
else if ( yy_act < 26 )
fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
(long)yy_rule_linenum[yy_act], yytext );
else if ( yy_act == 25 )
else if ( yy_act == 26 )
fprintf( stderr, "--accepting default rule (\"%s\")\n",
yytext );
else if ( yy_act == 26 )
else if ( yy_act == 27 )
fprintf( stderr, "--(end of buffer or a NUL)\n" );
else
fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@ -1212,12 +1218,12 @@ return isc::eval::EvalParser::make_EXISTS(loc);
case 12:
YY_RULE_SETUP
#line 130 "lexer.ll"
return isc::eval::EvalParser::make_SUBSTRING(loc);
return isc::eval::EvalParser::make_RELAY4(loc);
YY_BREAK
case 13:
YY_RULE_SETUP
#line 131 "lexer.ll"
return isc::eval::EvalParser::make_RELAY4(loc);
return isc::eval::EvalParser::make_SUBSTRING(loc);
YY_BREAK
case 14:
YY_RULE_SETUP
@@ -1227,63 +1233,68 @@ return isc::eval::EvalParser::make_ALL(loc);
case 15:
YY_RULE_SETUP
#line 133 "lexer.ll"
return isc::eval::EvalParser::make_NOT(loc);
return isc::eval::EvalParser::make_CONCAT(loc);
YY_BREAK
case 16:
YY_RULE_SETUP
#line 134 "lexer.ll"
return isc::eval::EvalParser::make_AND(loc);
return isc::eval::EvalParser::make_NOT(loc);
YY_BREAK
case 17:
YY_RULE_SETUP
#line 135 "lexer.ll"
return isc::eval::EvalParser::make_OR(loc);
return isc::eval::EvalParser::make_AND(loc);
YY_BREAK
case 18:
YY_RULE_SETUP
#line 136 "lexer.ll"
return isc::eval::EvalParser::make_DOT(loc);
return isc::eval::EvalParser::make_OR(loc);
YY_BREAK
case 19:
YY_RULE_SETUP
#line 137 "lexer.ll"
return isc::eval::EvalParser::make_LPAREN(loc);
return isc::eval::EvalParser::make_DOT(loc);
YY_BREAK
case 20:
YY_RULE_SETUP
#line 138 "lexer.ll"
return isc::eval::EvalParser::make_RPAREN(loc);
return isc::eval::EvalParser::make_LPAREN(loc);
YY_BREAK
case 21:
YY_RULE_SETUP
#line 139 "lexer.ll"
return isc::eval::EvalParser::make_LBRACKET(loc);
return isc::eval::EvalParser::make_RPAREN(loc);
YY_BREAK
case 22:
YY_RULE_SETUP
#line 140 "lexer.ll"
return isc::eval::EvalParser::make_RBRACKET(loc);
return isc::eval::EvalParser::make_LBRACKET(loc);
YY_BREAK
case 23:
YY_RULE_SETUP
#line 141 "lexer.ll"
return isc::eval::EvalParser::make_COMA(loc);
return isc::eval::EvalParser::make_RBRACKET(loc);
YY_BREAK
case 24:
YY_RULE_SETUP
#line 143 "lexer.ll"
driver.error (loc, "Invalid character: " + std::string(yytext));
YY_BREAK
case YY_STATE_EOF(INITIAL):
#line 144 "lexer.ll"
return isc::eval::EvalParser::make_END(loc);
#line 142 "lexer.ll"
return isc::eval::EvalParser::make_COMA(loc);
YY_BREAK
case 25:
YY_RULE_SETUP
#line 144 "lexer.ll"
driver.error (loc, "Invalid character: " + std::string(yytext));
YY_BREAK
case YY_STATE_EOF(INITIAL):
#line 145 "lexer.ll"
return isc::eval::EvalParser::make_END(loc);
YY_BREAK
case 26:
YY_RULE_SETUP
#line 146 "lexer.ll"
ECHO;
YY_BREAK
#line 1287 "lexer.cc"
#line 1298 "lexer.cc"
case YY_END_OF_BUFFER:
{
@@ -1563,7 +1574,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 75 )
if ( yy_current_state >= 81 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1591,11 +1602,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 75 )
if ( yy_current_state >= 81 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 74);
yy_is_jam = (yy_current_state == 80);
if ( ! yy_is_jam )
*(yy_state_ptr)++ = yy_current_state;
@@ -2353,7 +2364,7 @@ void yyfree (void * ptr )
/* %ok-for-header */
#line 145 "lexer.ll"
#line 146 "lexer.ll"

View File

@@ -127,9 +127,10 @@ blank [ \t]
"text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc);
"exists" return isc::eval::EvalParser::make_EXISTS(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"all" return isc::eval::EvalParser::make_ALL(loc);
"concat" return isc::eval::EvalParser::make_CONCAT(loc);
"not" return isc::eval::EvalParser::make_NOT(loc);
"and" return isc::eval::EvalParser::make_AND(loc);
"or" return isc::eval::EvalParser::make_OR(loc);

View File

@@ -1,4 +1,4 @@
// Generated 20160219
// Generated at 20160219
// A Bison parser, made by GNU Bison 3.0.4.
// Locations for Bison parsers in C++

View File

@@ -255,11 +255,10 @@ namespace isc { namespace eval {
value.move< TokenOption::RepresentationType > (that.value);
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
value.move< std::string > (that.value);
break;
@@ -286,11 +285,10 @@ namespace isc { namespace eval {
value.copy< TokenOption::RepresentationType > (that.value);
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
value.copy< std::string > (that.value);
break;
@@ -334,53 +332,46 @@ namespace isc { namespace eval {
<< yysym.location << ": ";
switch (yytype)
{
case 20: // "constant string"
case 21: // "constant string"
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
#line 342 "parser.cc" // lalr1.cc:636
#line 340 "parser.cc" // lalr1.cc:636
break;
case 21: // "integer"
case 22: // "integer"
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
#line 349 "parser.cc" // lalr1.cc:636
#line 347 "parser.cc" // lalr1.cc:636
break;
case 22: // "constant hexstring"
case 23: // "constant hexstring"
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
#line 356 "parser.cc" // lalr1.cc:636
#line 354 "parser.cc" // lalr1.cc:636
break;
case 23: // "option name"
case 24: // "option name"
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
#line 363 "parser.cc" // lalr1.cc:636
break;
case 24: // TOKEN
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); }
#line 370 "parser.cc" // lalr1.cc:636
#line 361 "parser.cc" // lalr1.cc:636
break;
case 29: // option_code
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< uint16_t > (); }
#line 377 "parser.cc" // lalr1.cc:636
#line 368 "parser.cc" // lalr1.cc:636
break;
case 30: // option_repr_type
#line 71 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); }
#line 384 "parser.cc" // lalr1.cc:636
#line 375 "parser.cc" // lalr1.cc:636
break;
@@ -584,11 +575,10 @@ namespace isc { namespace eval {
yylhs.value.build< TokenOption::RepresentationType > ();
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
yylhs.value.build< std::string > ();
break;
@@ -619,7 +609,7 @@ namespace isc { namespace eval {
TokenPtr neg(new TokenNot());
ctx.expression.push_back(neg);
}
#line 623 "parser.cc" // lalr1.cc:859
#line 613 "parser.cc" // lalr1.cc:859
break;
case 5:
@@ -628,7 +618,7 @@ namespace isc { namespace eval {
TokenPtr neg(new TokenAnd());
ctx.expression.push_back(neg);
}
#line 632 "parser.cc" // lalr1.cc:859
#line 622 "parser.cc" // lalr1.cc:859
break;
case 6:
@@ -637,7 +627,7 @@ namespace isc { namespace eval {
TokenPtr neg(new TokenOr());
ctx.expression.push_back(neg);
}
#line 641 "parser.cc" // lalr1.cc:859
#line 631 "parser.cc" // lalr1.cc:859
break;
case 7:
@@ -646,7 +636,7 @@ namespace isc { namespace eval {
TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq);
}
#line 650 "parser.cc" // lalr1.cc:859
#line 640 "parser.cc" // lalr1.cc:859
break;
case 8:
@@ -655,7 +645,7 @@ namespace isc { namespace eval {
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS));
ctx.expression.push_back(opt);
}
#line 659 "parser.cc" // lalr1.cc:859
#line 649 "parser.cc" // lalr1.cc:859
break;
case 9:
@@ -664,7 +654,7 @@ namespace isc { namespace eval {
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 668 "parser.cc" // lalr1.cc:859
#line 658 "parser.cc" // lalr1.cc:859
break;
case 10:
@@ -673,7 +663,7 @@ namespace isc { namespace eval {
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(hex);
}
#line 677 "parser.cc" // lalr1.cc:859
#line 667 "parser.cc" // lalr1.cc:859
break;
case 11:
@@ -682,7 +672,7 @@ namespace isc { namespace eval {
TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ()));
ctx.expression.push_back(opt);
}
#line 686 "parser.cc" // lalr1.cc:859
#line 676 "parser.cc" // lalr1.cc:859
break;
case 12:
@@ -706,7 +696,7 @@ namespace isc { namespace eval {
error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
}
}
#line 710 "parser.cc" // lalr1.cc:859
#line 700 "parser.cc" // lalr1.cc:859
break;
case 13:
@@ -715,70 +705,79 @@ namespace isc { namespace eval {
TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub);
}
#line 719 "parser.cc" // lalr1.cc:859
#line 709 "parser.cc" // lalr1.cc:859
break;
case 14:
#line 152 "parser.yy" // lalr1.cc:859
{
TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc);
}
#line 718 "parser.cc" // lalr1.cc:859
break;
case 15:
#line 156 "parser.yy" // lalr1.cc:859
#line 159 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
}
#line 727 "parser.cc" // lalr1.cc:859
#line 726 "parser.cc" // lalr1.cc:859
break;
case 16:
#line 160 "parser.yy" // lalr1.cc:859
#line 163 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location);
}
#line 735 "parser.cc" // lalr1.cc:859
#line 734 "parser.cc" // lalr1.cc:859
break;
case 17:
#line 166 "parser.yy" // lalr1.cc:859
#line 169 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
}
#line 743 "parser.cc" // lalr1.cc:859
#line 742 "parser.cc" // lalr1.cc:859
break;
case 18:
#line 170 "parser.yy" // lalr1.cc:859
#line 173 "parser.yy" // lalr1.cc:859
{
yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
}
#line 751 "parser.cc" // lalr1.cc:859
#line 750 "parser.cc" // lalr1.cc:859
break;
case 19:
#line 176 "parser.yy" // lalr1.cc:859
#line 179 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 760 "parser.cc" // lalr1.cc:859
#line 759 "parser.cc" // lalr1.cc:859
break;
case 20:
#line 183 "parser.yy" // lalr1.cc:859
#line 186 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 769 "parser.cc" // lalr1.cc:859
#line 768 "parser.cc" // lalr1.cc:859
break;
case 21:
#line 188 "parser.yy" // lalr1.cc:859
#line 191 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString("all"));
ctx.expression.push_back(str);
}
#line 778 "parser.cc" // lalr1.cc:859
#line 777 "parser.cc" // lalr1.cc:859
break;
#line 782 "parser.cc" // lalr1.cc:859
#line 781 "parser.cc" // lalr1.cc:859
default:
break;
}
@@ -1033,75 +1032,77 @@ namespace isc { namespace eval {
}
const signed char EvalParser::yypact_ninf_ = -11;
const signed char EvalParser::yypact_ninf_ = -14;
const signed char EvalParser::yytable_ninf_ = -1;
const signed char
EvalParser::yypact_[] =
{
-4, -8, 9, -4, 12, -4, -11, -11, -11, 29,
7, 37, 16, -1, -11, 16, 0, -11, -4, -4,
-1, -11, -11, 23, 25, 26, 28, -11, -11, 38,
-11, 30, 16, 31, 32, 22, 34, -11, 33, 27,
-11, -11, -11, -11, 35, 11, -11, 27, -11, -11,
39, -11
-2, -12, -4, 3, -2, 14, -2, -14, -14, 39,
33, 40, 16, 6, 6, -14, 16, 17, -14, -2,
-2, 6, -14, -14, 25, 27, 28, 31, 29, -14,
-14, 42, -14, 36, 16, 26, 6, 37, 24, 34,
-14, 41, 35, 18, -14, -14, -14, -14, 43, 0,
-14, -14, 18, -14, -14, 38, -14
};
const unsigned char
EvalParser::yydefact_[] =
{
0, 0, 0, 0, 0, 0, 9, 10, 14, 0,
2, 0, 0, 0, 4, 0, 0, 1, 0, 0,
0, 15, 16, 0, 0, 0, 0, 3, 5, 6,
7, 0, 0, 0, 0, 0, 0, 19, 0, 0,
17, 18, 8, 11, 0, 0, 12, 0, 21, 20,
0, 13
0, 0, 0, 0, 0, 0, 0, 9, 10, 0,
2, 0, 0, 0, 0, 4, 0, 0, 1, 0,
0, 0, 15, 16, 0, 0, 0, 0, 0, 3,
5, 6, 7, 0, 0, 0, 0, 0, 0, 0,
19, 0, 0, 0, 17, 18, 8, 11, 0, 0,
14, 12, 0, 21, 20, 0, 13
};
const signed char
EvalParser::yypgoto_[] =
{
-11, -11, 8, 15, -10, 18, -11, -11
-14, -14, 12, -13, -10, 19, -14, -14
};
const signed char
EvalParser::yydefgoto_[] =
{
-1, 9, 10, 11, 23, 43, 38, 50
-1, 9, 10, 11, 24, 47, 41, 55
};
const unsigned char
EvalParser::yytable_[] =
{
1, 2, 3, 24, 2, 26, 4, 18, 19, 4,
12, 14, 5, 16, 18, 19, 6, 27, 7, 6,
8, 7, 36, 8, 48, 13, 28, 29, 25, 17,
15, 40, 49, 41, 42, 30, 40, 21, 41, 22,
20, 33, 31, 32, 35, 18, 39, 34, 45, 47,
0, 0, 37, 44, 0, 0, 51, 46
26, 27, 1, 2, 3, 4, 28, 12, 32, 5,
25, 2, 3, 13, 53, 6, 15, 5, 17, 7,
14, 8, 54, 42, 39, 19, 20, 7, 44, 8,
45, 30, 31, 16, 44, 29, 45, 46, 22, 18,
23, 19, 20, 21, 35, 33, 34, 36, 40, 37,
19, 38, 43, 50, 48, 0, 56, 49, 52, 0,
0, 0, 51
};
const signed char
EvalParser::yycheck_[] =
{
4, 5, 6, 4, 5, 15, 10, 7, 8, 10,
18, 3, 16, 5, 7, 8, 20, 17, 22, 20,
24, 22, 32, 24, 13, 16, 18, 19, 13, 0,
18, 9, 21, 11, 12, 20, 9, 21, 11, 23,
3, 15, 19, 18, 14, 7, 14, 19, 15, 14,
-1, -1, 21, 19, -1, -1, 17, 39
13, 14, 4, 5, 6, 7, 16, 19, 21, 11,
4, 5, 6, 17, 14, 17, 4, 11, 6, 21,
17, 23, 22, 36, 34, 8, 9, 21, 10, 23,
12, 19, 20, 19, 10, 18, 12, 13, 22, 0,
24, 8, 9, 3, 16, 20, 19, 16, 22, 20,
8, 15, 15, 18, 20, -1, 18, 16, 15, -1,
-1, -1, 43
};
const unsigned char
EvalParser::yystos_[] =
{
0, 4, 5, 6, 10, 16, 20, 22, 24, 26,
27, 28, 18, 16, 27, 18, 27, 0, 7, 8,
3, 21, 23, 29, 4, 28, 29, 17, 27, 27,
28, 19, 18, 15, 19, 14, 29, 21, 31, 14,
9, 11, 12, 30, 19, 15, 30, 14, 13, 21,
32, 17
0, 4, 5, 6, 7, 11, 17, 21, 23, 26,
27, 28, 19, 17, 17, 27, 19, 27, 0, 8,
9, 3, 22, 24, 29, 4, 28, 28, 29, 18,
27, 27, 28, 20, 19, 16, 16, 20, 15, 29,
22, 31, 28, 15, 10, 12, 13, 30, 20, 16,
18, 30, 15, 14, 22, 32, 18
};
const unsigned char
@@ -1116,7 +1117,7 @@ namespace isc { namespace eval {
EvalParser::yyr2_[] =
{
0, 2, 1, 3, 2, 3, 3, 3, 6, 1,
1, 6, 6, 8, 1, 1, 1, 1, 1, 1,
1, 6, 6, 8, 6, 1, 1, 1, 1, 1,
1, 1
};
@@ -1128,10 +1129,10 @@ namespace isc { namespace eval {
const EvalParser::yytname_[] =
{
"\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
"\"substring\"", "\"not\"", "\"and\"", "\"or\"", "\"text\"",
"\"relay4\"", "\"hex\"", "\"exists\"", "\"all\"", "\".\"", "\",\"",
"\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"",
"\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept",
"\"substring\"", "\"concat\"", "\"not\"", "\"and\"", "\"or\"",
"\"text\"", "\"relay4\"", "\"hex\"", "\"exists\"", "\"all\"", "\".\"",
"\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"",
"\"integer\"", "\"constant hexstring\"", "\"option name\"", "$accept",
"expression", "bool_expr", "string_expr", "option_code",
"option_repr_type", "start_expr", "length_expr", YY_NULLPTR
};
@@ -1141,8 +1142,8 @@ namespace isc { namespace eval {
EvalParser::yyrline_[] =
{
0, 80, 80, 83, 84, 89, 94, 99, 104, 111,
116, 121, 126, 146, 151, 155, 159, 165, 169, 175,
182, 187
116, 121, 126, 146, 151, 158, 162, 168, 172, 178,
185, 190
};
// Print the state stack on the debug stream.
@@ -1177,8 +1178,8 @@ namespace isc { namespace eval {
#line 13 "parser.yy" // lalr1.cc:1167
} } // isc::eval
#line 1181 "parser.cc" // lalr1.cc:1167
#line 194 "parser.yy" // lalr1.cc:1168
#line 1182 "parser.cc" // lalr1.cc:1167
#line 197 "parser.yy" // lalr1.cc:1168
void
isc::eval::EvalParser::error(const location_type& loc,

View File

@@ -302,7 +302,6 @@ namespace isc { namespace eval {
// "integer"
// "constant hexstring"
// "option name"
// TOKEN
char dummy2[sizeof(std::string)];
// option_code
@@ -333,25 +332,25 @@ namespace isc { namespace eval {
TOKEN_EQUAL = 258,
TOKEN_OPTION = 259,
TOKEN_SUBSTRING = 260,
TOKEN_NOT = 261,
TOKEN_AND = 262,
TOKEN_OR = 263,
TOKEN_TEXT = 264,
TOKEN_RELAY4 = 265,
TOKEN_HEX = 266,
TOKEN_EXISTS = 267,
TOKEN_ALL = 268,
TOKEN_DOT = 269,
TOKEN_COMA = 270,
TOKEN_LPAREN = 271,
TOKEN_RPAREN = 272,
TOKEN_LBRACKET = 273,
TOKEN_RBRACKET = 274,
TOKEN_STRING = 275,
TOKEN_INTEGER = 276,
TOKEN_HEXSTRING = 277,
TOKEN_OPTION_NAME = 278,
TOKEN_TOKEN = 279
TOKEN_CONCAT = 261,
TOKEN_NOT = 262,
TOKEN_AND = 263,
TOKEN_OR = 264,
TOKEN_TEXT = 265,
TOKEN_RELAY4 = 266,
TOKEN_HEX = 267,
TOKEN_EXISTS = 268,
TOKEN_ALL = 269,
TOKEN_DOT = 270,
TOKEN_COMA = 271,
TOKEN_LPAREN = 272,
TOKEN_RPAREN = 273,
TOKEN_LBRACKET = 274,
TOKEN_RBRACKET = 275,
TOKEN_STRING = 276,
TOKEN_INTEGER = 277,
TOKEN_HEXSTRING = 278,
TOKEN_OPTION_NAME = 279
};
};
@@ -478,6 +477,10 @@ namespace isc { namespace eval {
symbol_type
make_SUBSTRING (const location_type& l);
static inline
symbol_type
make_CONCAT (const location_type& l);
static inline
symbol_type
make_NOT (const location_type& l);
@@ -550,10 +553,6 @@ namespace isc { namespace eval {
symbol_type
make_OPTION_NAME (const std::string& v, const location_type& l);
static inline
symbol_type
make_TOKEN (const std::string& v, const location_type& l);
/// Build a parser object.
EvalParser (EvalContext& ctx_yyarg);
@@ -759,9 +758,9 @@ namespace isc { namespace eval {
enum
{
yyeof_ = 0,
yylast_ = 57, ///< Last index in yytable_.
yylast_ = 62, ///< Last index in yytable_.
yynnts_ = 8, ///< Number of nonterminal symbols.
yyfinal_ = 17, ///< Termination state number.
yyfinal_ = 18, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 25 ///< Number of tokens.
@@ -847,11 +846,10 @@ namespace isc { namespace eval {
value.copy< TokenOption::RepresentationType > (other.value);
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
value.copy< std::string > (other.value);
break;
@@ -880,11 +878,10 @@ namespace isc { namespace eval {
value.copy< TokenOption::RepresentationType > (v);
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
value.copy< std::string > (v);
break;
@@ -958,11 +955,10 @@ namespace isc { namespace eval {
value.template destroy< TokenOption::RepresentationType > ();
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
value.template destroy< std::string > ();
break;
@@ -997,11 +993,10 @@ namespace isc { namespace eval {
value.move< TokenOption::RepresentationType > (s.value);
break;
case 20: // "constant string"
case 21: // "integer"
case 22: // "constant hexstring"
case 23: // "option name"
case 24: // TOKEN
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
value.move< std::string > (s.value);
break;
@@ -1095,6 +1090,12 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_SUBSTRING, l);
}
EvalParser::symbol_type
EvalParser::make_CONCAT (const location_type& l)
{
return symbol_type (token::TOKEN_CONCAT, l);
}
EvalParser::symbol_type
EvalParser::make_NOT (const location_type& l)
{
@@ -1203,16 +1204,10 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_OPTION_NAME, v, l);
}
EvalParser::symbol_type
EvalParser::make_TOKEN (const std::string& v, const location_type& l)
{
return symbol_type (token::TOKEN_TOKEN, v, l);
}
#line 13 "parser.yy" // lalr1.cc:392
} } // isc::eval
#line 1216 "parser.h" // lalr1.cc:392
#line 1211 "parser.h" // lalr1.cc:392

View File

@@ -39,6 +39,7 @@ using namespace isc::eval;
EQUAL "=="
OPTION "option"
SUBSTRING "substring"
CONCAT "concat"
NOT "not"
AND "and"
OR "or"
@@ -59,7 +60,6 @@ using namespace isc::eval;
%token <std::string> INTEGER "integer"
%token <std::string> HEXSTRING "constant hexstring"
%token <std::string> OPTION_NAME "option name"
%token <std::string> TOKEN
%type <uint16_t> option_code
%type <TokenOption::RepresentationType> option_repr_type
@@ -148,8 +148,11 @@ string_expr : STRING
TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub);
}
| TOKEN
// Temporary unused token to avoid explicit but long errors
| CONCAT "(" string_expr "," string_expr ")"
{
TokenPtr conc(new TokenConcat());
ctx.expression.push_back(conc);
}
;
option_code : INTEGER

View File

@@ -1,4 +1,4 @@
// Generated 20160219
// Generated at 20160219
// A Bison parser, made by GNU Bison 3.0.4.
// Positions for Bison parsers in C++

View File

@@ -1,4 +1,4 @@
// Generated 20160219
// Generated at 20160219
// A Bison parser, made by GNU Bison 3.0.4.
// Stack handling for Bison parsers in C++

View File

@@ -81,14 +81,6 @@ public:
EXPECT_EQ(expected_code, opt->getCode());
}
/// @brief checks if the given token is a substring operator
void checkTokenSubstring(const TokenPtr& token) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenSubstring> sub =
boost::dynamic_pointer_cast<TokenSubstring>(token);
EXPECT_TRUE(sub);
}
/// @brief check if the given token is relay4 with the expected code
void checkTokenRelay4(const TokenPtr& token, uint16_t code) {
ASSERT_TRUE(token);
@@ -101,6 +93,22 @@ public:
}
}
/// @brief checks if the given token is a substring operator
void checkTokenSubstring(const TokenPtr& token) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenSubstring> sub =
boost::dynamic_pointer_cast<TokenSubstring>(token);
EXPECT_TRUE(sub);
}
/// @brief checks if the given token is a concat operator
void checkTokenConcat(const TokenPtr& token) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenConcat> conc =
boost::dynamic_pointer_cast<TokenConcat>(token);
EXPECT_TRUE(conc);
}
/// @brief checks if the given expression raises the expected message
/// when it is parsed.
void checkError(const string& expr, const string& msg) {
@@ -275,6 +283,33 @@ TEST_F(EvalContextTest, optionHex) {
checkTokenOption(eval.expression.at(0), 123);
}
// This test checks that the relay[code].hex can be used in expressions.
TEST_F(EvalContextTest, relay4Option) {
EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ =
eval.parseString("relay4[13].hex == 'thirteen'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
TokenPtr tmp1 = eval.expression.at(0);
TokenPtr tmp2 = eval.expression.at(1);
TokenPtr tmp3 = eval.expression.at(2);
checkTokenRelay4(tmp1, 13);
checkTokenString(tmp2, "thirteen");
checkTokenEq(tmp3);
}
// Verify that relay4[13] is not usable in v6
// There will be a separate relay accessor for v6.
TEST_F(EvalContextTest, relay4Error) {
universe_ = Option::V6;
checkError("relay4[13].hex == 'thirteen'",
"<string>:1.1-6: relay4 can only be used in DHCPv4.");
}
// Test parsing of logical operators
TEST_F(EvalContextTest, logicalOps) {
// option.exists
@@ -402,31 +437,23 @@ TEST_F(EvalContextTest, substring) {
checkTokenSubstring(tmp4);
}
// This test checks that the relay[code].hex can be used in expressions.
TEST_F(EvalContextTest, relay4Option) {
// Test the parsing of a concat expression
TEST_F(EvalContextTest, concat) {
EvalContext eval(Option::V4);
EXPECT_NO_THROW(parsed_ =
eval.parseString("relay4[13].hex == 'thirteen'"));
eval.parseString("concat('foo','bar') == 'foobar'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
ASSERT_EQ(5, eval.expression.size());
TokenPtr tmp1 = eval.expression.at(0);
TokenPtr tmp2 = eval.expression.at(1);
TokenPtr tmp3 = eval.expression.at(2);
checkTokenRelay4(tmp1, 13);
checkTokenString(tmp2, "thirteen");
checkTokenEq(tmp3);
}
// Verify that relay4[13] is not usable in v6
// There will be a separate relay accessor for v6.
TEST_F(EvalContextTest, relay4Error) {
universe_ = Option::V6;
checkError("relay4[13].hex == 'thirteen'",
"<string>:1.1-6: relay4 can only be used in DHCPv4.");
checkTokenString(tmp1, "foo");
checkTokenString(tmp2, "bar");
checkTokenConcat(tmp3);
}
// Test some scanner error cases
@@ -439,6 +466,7 @@ TEST_F(EvalContextTest, scanErrors) {
checkError("subtring", "<string>:1.1: Invalid character: s");
checkError("foo", "<string>:1.1: Invalid character: f");
checkError(" bar", "<string>:1.2: Invalid character: b");
checkError("relay[12].hex == 'foo'", "<string>:1.1: Invalid character: r");
}
// Tests some scanner/parser error cases
@@ -546,8 +574,7 @@ TEST_F(EvalContextTest, parseErrors) {
"<string>:1.19-20: syntax error, unexpected ==, "
"expecting end of file");
checkError("substring('foobar') == 'f'",
"<string>:1.19: syntax error, "
"unexpected ), expecting \",\"");
"<string>:1.19: syntax error, unexpected ), expecting \",\"");
checkError("substring('foobar',3) == 'bar'",
"<string>:1.21: syntax error, unexpected ), expecting \",\"");
checkError("substring('foobar','3',3) == 'bar'",
@@ -555,6 +582,10 @@ TEST_F(EvalContextTest, parseErrors) {
"expecting integer");
checkError("substring('foobar',1,a) == 'foo'",
"<string>:1.22: Invalid character: a");
checkError("concat('foobar') == 'f'",
"<string>:1.16: syntax error, unexpected ), expecting \",\"");
checkError("concat('foo','bar','') == 'foobar'",
"<string>:1.19: syntax error, unexpected \",\", expecting )");
}
// Tests some type error cases
@@ -568,6 +599,10 @@ TEST_F(EvalContextTest, typeErrors) {
checkError("substring('foobar',0x32,1) == 'foo'",
"<string>:1.20-23: syntax error, unexpected constant "
"hexstring, expecting integer");
checkError("concat('foo',3) == 'foo3'",
"<string>:1.14: syntax error, unexpected integer");
checkError("concat(3,'foo') == '3foo'",
"<string>:1.8: syntax error, unexpected integer");
checkError("('foo' == 'bar') == 'false'",
"<string>:1.18-19: syntax error, unexpected ==, "
"expecting end of file");

View File

@@ -341,7 +341,7 @@ TEST_F(TokenTest, optionHexString4) {
}
// This test checks if a token representing an option value is able to check
// the existence ofthe option from an IPv4 packet.
// the existence of the option from an IPv4 packet.
TEST_F(TokenTest, optionExistsString4) {
TokenPtr found;
TokenPtr not_found;
@@ -420,7 +420,7 @@ TEST_F(TokenTest, optionHexString6) {
}
// This test checks if a token representing an option value is able to check
// the existence ofthe option from an IPv6 packet.
// the existence of the option from an IPv6 packet.
TEST_F(TokenTest, optionExistsString6) {
TokenPtr found;
TokenPtr not_found;
@@ -441,6 +441,109 @@ TEST_F(TokenTest, optionExistsString6) {
EXPECT_EQ("true", values_.top());
}
// This test checks that the existing relay option can be found.
TEST_F(TokenTest, relayOption) {
// Insert relay option with sub-options 1 and 13
insertRelay4Option();
// Creating the token should be safe.
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
// We should be able to evaluate it.
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// we should have one value on the stack
ASSERT_EQ(1, values_.size());
// The option should be found and relay[13] should evaluate to the
// content of that sub-option, i.e. "thirteen"
EXPECT_EQ("thirteen", values_.top());
}
// This test checks that the code properly handles cases when
// there is a RAI option, but there's no requested sub-option.
TEST_F(TokenTest, relayOptionNoSuboption) {
// Insert relay option with sub-options 1 and 13
insertRelay4Option();
// Creating the token should be safe.
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(15, TokenOption::TEXTUAL)));
// We should be able to evaluate it.
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// we should have one value on the stack
ASSERT_EQ(1, values_.size());
// The option should NOT be found (there is no sub-option 15),
// so the expression should evaluate to ""
EXPECT_EQ("", values_.top());
}
// This test checks that the code properly handles cases when
// there's no RAI option at all.
TEST_F(TokenTest, relayOptionNoRai) {
// We didn't call insertRelay4Option(), so there's no RAI option.
// Creating the token should be safe.
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
// We should be able to evaluate it.
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// we should have one value on the stack
ASSERT_EQ(1, values_.size());
// The option should NOT be found (there is no sub-option 13),
// so the expression should evaluate to ""
EXPECT_EQ("", values_.top());
}
// This test checks that only the RAI is searched for the requested
// sub-option.
TEST_F(TokenTest, relayRAIOnly) {
// Insert relay option with sub-options 1 and 13
insertRelay4Option();
// Add options 13 and 70 to the packet.
OptionPtr opt13(new OptionString(Option::V4, 13, "THIRTEEN"));
OptionPtr opt70(new OptionString(Option::V4, 70, "SEVENTY"));
pkt4_->addOption(opt13);
pkt4_->addOption(opt70);
// The situation is as follows:
// Packet:
// - option 13 (containing "THIRTEEN")
// - option 82 (rai)
// - option 1 (containing "one")
// - option 13 (containing "thirteen")
// Let's try to get option 13. It should get the one from RAI
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
ASSERT_EQ(1, values_.size());
EXPECT_EQ("thirteen", values_.top());
// Try to get option 1. It should get the one from RAI
clearStack();
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(1, TokenOption::TEXTUAL)));
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
ASSERT_EQ(1, values_.size());
EXPECT_EQ("one", values_.top());
// Try to get option 70. It should fail, as there's no such
// sub option in RAI.
clearStack();
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(70, TokenOption::TEXTUAL)));
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
ASSERT_EQ(1, values_.size());
EXPECT_EQ("", values_.top());
}
// This test checks if a token representing an == operator is able to
// compare two values (with incorrectly built stack).
TEST_F(TokenTest, optionEqualInvalid) {
@@ -490,7 +593,7 @@ TEST_F(TokenTest, optionEqualTrue) {
// This test checks if a token representing a not is able to
// negate a boolean value (with incorrectly built stack).
TEST_F(TokenTest, optionNotInvalid) {
TEST_F(TokenTest, operatorNotInvalid) {
ASSERT_NO_THROW(t_.reset(new TokenNot()));
@@ -504,7 +607,7 @@ TEST_F(TokenTest, optionNotInvalid) {
// This test checks if a token representing a not operator is able to
// negate a boolean value.
TEST_F(TokenTest, optionNot) {
TEST_F(TokenTest, operatorNot) {
ASSERT_NO_THROW(t_.reset(new TokenNot()));
@@ -523,7 +626,7 @@ TEST_F(TokenTest, optionNot) {
// This test checks if a token representing an and is able to
// conjugate two values (with incorrectly built stack).
TEST_F(TokenTest, optionAndInvalid) {
TEST_F(TokenTest, operatorAndInvalid) {
ASSERT_NO_THROW(t_.reset(new TokenAnd()));
@@ -547,7 +650,7 @@ TEST_F(TokenTest, optionAndInvalid) {
// This test checks if a token representing an and operator is able to
// conjugate false with another logical
TEST_F(TokenTest, optionAndFalse) {
TEST_F(TokenTest, operatorAndFalse) {
ASSERT_NO_THROW(t_.reset(new TokenAnd()));
@@ -574,7 +677,7 @@ TEST_F(TokenTest, optionAndFalse) {
// This test checks if a token representing an and is able to
// conjugate two true values.
TEST_F(TokenTest, optionAndTrue) {
TEST_F(TokenTest, operatorAndTrue) {
ASSERT_NO_THROW(t_.reset(new TokenAnd()));
@@ -589,7 +692,7 @@ TEST_F(TokenTest, optionAndTrue) {
// This test checks if a token representing an or is able to
// combinate two values (with incorrectly built stack).
TEST_F(TokenTest, optionOrInvalid) {
TEST_F(TokenTest, operatorOrInvalid) {
ASSERT_NO_THROW(t_.reset(new TokenOr()));
@@ -613,7 +716,7 @@ TEST_F(TokenTest, optionOrInvalid) {
// This test checks if a token representing an or is able to
// conjugate two false values.
TEST_F(TokenTest, optionOrFalse) {
TEST_F(TokenTest, operatorOrFalse) {
ASSERT_NO_THROW(t_.reset(new TokenOr()));
@@ -628,7 +731,7 @@ TEST_F(TokenTest, optionOrFalse) {
// This test checks if a token representing an == operator is able to
// conjugate true with another logical
TEST_F(TokenTest, optionOrTrue) {
TEST_F(TokenTest, operatorOrTrue) {
ASSERT_NO_THROW(t_.reset(new TokenOr()));
@@ -655,7 +758,7 @@ TEST_F(TokenTest, optionOrTrue) {
};
// This test checks if an a token representing a substring request
// This test checks if a token representing a substring request
// throws an exception if there aren't enough values on the stack.
// The stack from the top is: length, start, string.
// The actual packet is not used.
@@ -663,7 +766,7 @@ TEST_F(TokenTest, substringNotEnoughValues) {
ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
// Subsring requires three values on the stack, try
// with 0, 1 and 2 all should thorw an exception
// with 0, 1 and 2 all should throw an exception
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
values_.push("");
@@ -790,7 +893,7 @@ TEST_F(TokenTest, substringEquals) {
// The substring values
// Subsring requires three values on the stack, try
// with 0, 1 and 2 all should thorw an exception
// with 0, 1 and 2 all should throw an exception
values_.push("foobar");
values_.push("1");
values_.push("4");
@@ -813,7 +916,7 @@ TEST_F(TokenTest, substringEquals) {
// The substring values
// Subsring requires three values on the stack, try
// with 0, 1 and 2 all should thorw an exception
// with 0, 1 and 2 all should throw an exception
values_.push("foobar");
values_.push("1");
values_.push("4");
@@ -829,105 +932,24 @@ TEST_F(TokenTest, substringEquals) {
}
// This test checks that the existing relay option can be found.
TEST_F(TokenTest, relayOption) {
// This test checks if a token representing a concat request
// throws an exception if there aren't enough values on the stack.
// The actual packet is not used.
TEST_F(TokenTest, concat) {
ASSERT_NO_THROW(t_.reset(new TokenConcat()));
// Insert relay option with sub-options 1 and 13
insertRelay4Option();
// Concat requires two values on the stack, try
// with 0 and 1 both should throw an exception
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
// Creating the token should be safe.
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
values_.push("foo");
EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
// We should be able to evaluate it.
// Two should work
values_.push("bar");
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// we should have one value on the stack
// Check the result
ASSERT_EQ(1, values_.size());
// The option should be found and relay[13] should evaluate to the
// content of that sub-option, i.e. "thirteen"
EXPECT_EQ("thirteen", values_.top());
}
// This test checks that the code properly handles cases when
// there is a RAI option, but there's no requested sub-option.
TEST_F(TokenTest, relayOptionNoSuboption) {
// Insert relay option with sub-options 1 and 13
insertRelay4Option();
// Creating the token should be safe.
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(15, TokenOption::TEXTUAL)));
// We should be able to evaluate it.
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// we should have one value on the stack
ASSERT_EQ(1, values_.size());
// The option should NOT be found (there is no sub-option 15),
// so the expression should evaluate to ""
EXPECT_EQ("", values_.top());
}
// This test checks that the code properly handles cases when
// there's no RAI option at all.
TEST_F(TokenTest, relayOptionNoRai) {
// We didn't call insertRelay4Option(), so there's no RAI option.
// Creating the token should be safe.
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
// We should be able to evaluate it.
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
// we should have one value on the stack
ASSERT_EQ(1, values_.size());
// The option should NOT be found (there is no sub-option 13),
// so the expression should evaluate to ""
EXPECT_EQ("", values_.top());
}
// This test checks that only the RAI is searched for the requested
// sub-option.
TEST_F(TokenTest, relayRAIOnly) {
// Insert relay option with sub-options 1 and 13
insertRelay4Option();
// Add options 13 and 70 to the packet.
OptionPtr opt13(new OptionString(Option::V4, 13, "THIRTEEN"));
OptionPtr opt70(new OptionString(Option::V4, 70, "SEVENTY"));
pkt4_->addOption(opt13);
pkt4_->addOption(opt70);
// The situation is as follows:
// Packet:
// - option 13 (containing "THIRTEEN")
// - option 82 (rai)
// - option 1 (containing "one")
// - option 13 (containing "thirteen")
// Let's try to get option 13. It should get the one from RAI
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
ASSERT_EQ(1, values_.size());
EXPECT_EQ("thirteen", values_.top());
// Try to get option 1. It should get the one from RAI
clearStack();
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(1, TokenOption::TEXTUAL)));
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
ASSERT_EQ(1, values_.size());
EXPECT_EQ("one", values_.top());
// Try to get option 70. It should fail, as there's no such
// sub option in RAI.
clearStack();
ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(70, TokenOption::TEXTUAL)));
EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
ASSERT_EQ(1, values_.size());
EXPECT_EQ("", values_.top());
EXPECT_EQ("foobar", values_.top());
}

View File

@@ -84,6 +84,23 @@ TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
values.push(opt_str);
}
TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
const RepresentationType& rep_type)
:TokenOption(option_code, rep_type) {
}
OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
// Check if there is Relay Agent Option.
OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
if (!rai) {
return (OptionPtr());
}
// If there is, try to return its suboption
return (rai->getOption(option_code_));
}
void
TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
@@ -178,21 +195,21 @@ TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
values.push(string_str.substr(start_pos, length));
}
TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
const RepresentationType& rep_type)
:TokenOption(option_code, rep_type) {
}
void
TokenConcat::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
// Check if there is Relay Agent Option.
OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
if (!rai) {
return (OptionPtr());
if (values.size() < 2) {
isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
"2 values for concat, got " << values.size());
}
// If there is, try to return its suboption
return (rai->getOption(option_code_));
string op1 = values.top();
values.pop();
string op2 = values.top();
values.pop(); // Dammit, std::stack interface is awkward.
// The top of the stack was evaluated last so this is the right order
values.push(op2 + op1);
}
void

View File

@@ -219,6 +219,34 @@ protected:
RepresentationType representation_type_; ///< Representation type.
};
/// @brief Represents a sub-option inserted by the DHCPv4 relay.
///
/// DHCPv4 relays insert sub-options in option 82. This token attempts to extract
/// such sub-options. Note in DHCPv6 it is radically different (possibly
/// many encapsulation levels), thus there are separate classes for v4 and v6.
///
/// This token can represent the following expressions:
/// relay[13].text - Textual representation of sub-option 13 in RAI (option 82)
/// relay[13].hex - Binary representation of sub-option 13 in RAI (option 82)
/// relay[vendor-class].text - Text representation of sub-option X in RAI (option 82)
/// relay[vendor-class].hex - Binary representation of sub-option X in RAI (option 82)
class TokenRelay4Option : public TokenOption {
public:
/// @brief Constructor for extracting sub-option from RAI (option 82)
///
/// @param option_code code of the requested sub-option
/// @param rep_type code representation (currently .hex and .text are supported)
TokenRelay4Option(const uint16_t option_code,
const RepresentationType& rep_type);
protected:
/// @brief Attempts to obtain specified sub-option of option 82 from the packet
/// @param pkt DHCPv4 packet (that hopefully contains option 82)
/// @return found sub-option from option 82
virtual OptionPtr getOption(const Pkt& pkt);
};
/// @brief Token that represents equality operator (compares two other tokens)
///
/// For example in the expression option[vendor-class].text == "MSFT"
@@ -300,32 +328,27 @@ public:
void evaluate(const Pkt& pkt, ValueStack& values);
};
/// @brief Represents a sub-option inserted by the DHCPv4 relay.
/// @brief Token that represents concat operator (concatenates two other tokens)
///
/// DHCPv4 relays insert sub-options in option 82. This token attempts to extract
/// such sub-options. Note in DHCPv6 it is radically different (possibly
/// many encapsulation levels), thus there are separate classes for v4 and v6.
///
/// This token can represent the following expressions:
/// relay[13].text - Textual representation of sub-option 13 in RAI (option 82)
/// relay[13].hex - Binary representation of sub-option 13 in RAI (option 82)
/// relay[vendor-class].text - Text representation of sub-option X in RAI (option 82)
/// relay[vendor-class].hex - Binary representation of sub-option X in RAI (option 82)
class TokenRelay4Option : public TokenOption {
/// For example in the sub-expression "concat('foo','bar')" the result
/// of the evaluation is "foobar"
class TokenConcat : public Token {
public:
/// @brief Constructor (does nothing)
TokenConcat() {}
/// @brief Constructor for extracting sub-option from RAI (option 82)
/// @brief Concatenate two values.
///
/// @param option_code code of the requested sub-option
/// @param rep_type code representation (currently .hex and .text are supported)
TokenRelay4Option(const uint16_t option_code,
const RepresentationType& rep_type);
protected:
/// @brief Attempts to obtain specified sub-option of option 82 from the packet
/// @param pkt DHCPv4 packet (that hopefully contains option 82)
/// @return found sub-option from option 82
virtual OptionPtr getOption(const Pkt& pkt);
/// Evaluation does not use packet information, but rather consumes the last
/// two parameters. It does a simple string concatenation. It requires
/// at least two parameters to be present on stack.
///
/// @throw EvalBadStack if there are less than 2 values on stack
///
/// @param pkt (unused)
/// @param values - stack of values (2 arguments will be popped, 1 result
/// will be pushed)
void evaluate(const Pkt& pkt, ValueStack& values);
};
/// @brief Token that represents logical negation operator