From ce332093aaef9bf2e29d9f47c309728d8478360e Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Wed, 9 Dec 2015 13:41:28 +0100 Subject: [PATCH 1/9] [4231] Added ( bool_expr ) --- src/lib/eval/lexer.cc | 80 +++++++++--------- src/lib/eval/lexer.ll | 2 +- src/lib/eval/parser.cc | 108 +++++++++++++------------ src/lib/eval/parser.h | 4 +- src/lib/eval/parser.yy | 3 +- src/lib/eval/tests/context_unittest.cc | 9 +++ 6 files changed, 109 insertions(+), 97 deletions(-) diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc index 2122b1d39a..245922c83b 100644 --- a/src/lib/eval/lexer.cc +++ b/src/lib/eval/lexer.cc @@ -18,7 +18,7 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 +#define YY_FLEX_SUBMINOR_VERSION 39 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -72,7 +72,6 @@ typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; -typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; @@ -80,7 +79,6 @@ typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -111,6 +109,8 @@ typedef unsigned int flex_uint32_t; #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ /* %endif */ @@ -225,11 +225,18 @@ extern FILE *yyin, *yyout; */ #define YY_LESS_LINENO(n) \ do { \ - yy_size_t yyl;\ + int yyl;\ for ( yyl = n; yyl < yyleng; ++yyl )\ if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ @@ -420,7 +427,7 @@ void yyfree (void * ); /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ /* Begin user sect3 */ -#define yywrap(n) 1 +#define yywrap() 1 #define YY_SKIP_YYWRAP #define FLEX_DEBUG @@ -438,6 +445,8 @@ int yylineno = 1; extern char *yytext; #define yytext_ptr yytext +/* %% [1.5] DFA */ + /* %if-c-only Standard (non-C++) definition */ static yy_state_type yy_get_previous_state (void ); @@ -453,7 +462,7 @@ static void yy_fatal_error (yyconst char msg[] ); #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ - yyleng = (yy_size_t) (yy_cp - yy_bp); \ + yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ @@ -691,7 +700,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 695 "lexer.cc" +#line 704 "lexer.cc" #define INITIAL 0 @@ -809,7 +818,7 @@ static int input (void ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) /* %endif */ /* %if-c++-only C++ definition */ /* %endif */ @@ -824,7 +833,7 @@ static int input (void ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - yy_size_t n; \ + size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -930,17 +939,6 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -/* %% [7.0] user's declarations go here */ -#line 79 "lexer.ll" - - - - // Code run each time yylex is called. - loc.step(); - - -#line 943 "lexer.cc" - if ( !(yy_init) ) { (yy_init) = 1; @@ -981,6 +979,18 @@ YY_DECL yy_load_buffer_state( ); } + { +/* %% [7.0] user's declarations go here */ +#line 79 "lexer.ll" + + + + // Code run each time yylex is called. + loc.step(); + + +#line 993 "lexer.cc" + while ( 1 ) /* loops until end-of-file is reached */ { /* %% [8.0] yymore()-related code goes here */ @@ -1003,7 +1013,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; @@ -1020,7 +1030,6 @@ yy_find_action: /* %% [10.0] code to find the action number goes here */ yy_current_state = *--(yy_state_ptr); (yy_lp) = yy_accept[yy_current_state]; -goto find_rule; /* Shut up GCC warning -Wall */ find_rule: /* we branch to this label when backing up */ for ( ; ; ) /* until we find what rule we matched */ { @@ -1235,7 +1244,7 @@ YY_RULE_SETUP #line 148 "lexer.ll" ECHO; YY_BREAK -#line 1239 "lexer.cc" +#line 1248 "lexer.cc" case YY_END_OF_BUFFER: { @@ -1365,6 +1374,7 @@ ECHO; "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ + } /* end of user's declarations */ } /* end of yylex */ /* %ok-for-header */ @@ -1551,7 +1561,7 @@ static int yy_get_next_buffer (void) if ( ! yy_is_jam ) *(yy_state_ptr)++ = yy_current_state; - return yy_is_jam ? 0 : yy_current_state; + return yy_is_jam ? 0 : yy_current_state; } /* %if-c-only */ @@ -1610,7 +1620,7 @@ static int yy_get_next_buffer (void) case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) - return 0; + return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; @@ -1774,17 +1784,6 @@ static void yy_load_buffer_state (void) yyfree((void *) b ); } -/* %if-c-only */ - -#ifndef __cplusplus -extern int isatty (int ); -#endif /* __cplusplus */ - -/* %endif */ - -/* %if-c++-only */ -/* %endif */ - /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. @@ -2025,8 +2024,8 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) /* %if-c-only */ /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ @@ -2034,7 +2033,8 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len { YY_BUFFER_STATE b; char *buf; - yy_size_t n, i; + yy_size_t n; + yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; @@ -2320,7 +2320,7 @@ EvalContext::scanStringBegin() buffer = yy_scan_bytes(string_.c_str(),string_.size()); if (!buffer) { fatal("cannot scan string"); - // fatal() throws an exception so this can't be reached + // fatal() throws an exception so this can't be reached } } diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index f8297139fa..61207ef2e0 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -158,7 +158,7 @@ EvalContext::scanStringBegin() buffer = yy_scan_bytes(string_.c_str(), string_.size()); if (!buffer) { fatal("cannot scan string"); - // fatal() throws an exception so this can't be reached + // fatal() throws an exception so this can't be reached } } diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc index 34bd22a8e2..ff2cdc1d6f 100644 --- a/src/lib/eval/parser.cc +++ b/src/lib/eval/parser.cc @@ -613,8 +613,8 @@ namespace isc { namespace eval { { switch (yyn) { - case 3: -#line 83 "parser.yy" // lalr1.cc:859 + case 4: +#line 84 "parser.yy" // lalr1.cc:859 { TokenPtr eq(new TokenEqual()); ctx.expression.push_back(eq); @@ -622,8 +622,8 @@ namespace isc { namespace eval { #line 623 "parser.cc" // lalr1.cc:859 break; - case 4: -#line 90 "parser.yy" // lalr1.cc:859 + case 5: +#line 91 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); @@ -631,8 +631,8 @@ namespace isc { namespace eval { #line 632 "parser.cc" // lalr1.cc:859 break; - case 5: -#line 95 "parser.yy" // lalr1.cc:859 + case 6: +#line 96 "parser.yy" // lalr1.cc:859 { TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(hex); @@ -640,8 +640,8 @@ namespace isc { namespace eval { #line 641 "parser.cc" // lalr1.cc:859 break; - case 6: -#line 100 "parser.yy" // lalr1.cc:859 + case 7: +#line 101 "parser.yy" // lalr1.cc:859 { TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); ctx.expression.push_back(opt); @@ -649,8 +649,8 @@ namespace isc { namespace eval { #line 650 "parser.cc" // lalr1.cc:859 break; - case 7: -#line 105 "parser.yy" // lalr1.cc:859 + case 8: +#line 106 "parser.yy" // lalr1.cc:859 { TokenPtr sub(new TokenSubstring()); ctx.expression.push_back(sub); @@ -658,40 +658,40 @@ namespace isc { namespace eval { #line 659 "parser.cc" // lalr1.cc:859 break; - case 9: -#line 114 "parser.yy" // lalr1.cc:859 + case 10: +#line 115 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); } #line 667 "parser.cc" // lalr1.cc:859 break; - case 10: -#line 118 "parser.yy" // lalr1.cc:859 + case 11: +#line 119 "parser.yy" // lalr1.cc:859 { yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); } #line 675 "parser.cc" // lalr1.cc:859 break; - case 11: -#line 124 "parser.yy" // lalr1.cc:859 + case 12: +#line 125 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; } #line 683 "parser.cc" // lalr1.cc:859 break; - case 12: -#line 128 "parser.yy" // lalr1.cc:859 + case 13: +#line 129 "parser.yy" // lalr1.cc:859 { yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; } #line 691 "parser.cc" // lalr1.cc:859 break; - case 13: -#line 134 "parser.yy" // lalr1.cc:859 + case 14: +#line 135 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); @@ -699,8 +699,8 @@ namespace isc { namespace eval { #line 700 "parser.cc" // lalr1.cc:859 break; - case 14: -#line 141 "parser.yy" // lalr1.cc:859 + case 15: +#line 142 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); @@ -708,8 +708,8 @@ namespace isc { namespace eval { #line 709 "parser.cc" // lalr1.cc:859 break; - case 15: -#line 146 "parser.yy" // lalr1.cc:859 + case 16: +#line 147 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString("all")); ctx.expression.push_back(str); @@ -973,77 +973,79 @@ namespace isc { namespace eval { } - const signed char EvalParser::yypact_ninf_ = -14; + const signed char EvalParser::yypact_ninf_ = -9; const signed char EvalParser::yytable_ninf_ = -1; const signed char EvalParser::yypact_[] = { - -4, -9, -5, -14, -14, -14, 8, -14, 9, -13, - -4, -14, -4, -14, -14, 0, 11, -14, 13, 2, - 10, -14, 14, -14, -14, -14, -6, -14, -14, 7, - -14 + -4, -8, -3, -4, -9, -9, -9, 12, -9, 19, + 1, -1, 11, -9, -1, -9, -9, 10, 15, -9, + -9, 17, 13, 14, -9, 18, -9, -9, -9, -6, + -9, -9, 20, -9 }; const unsigned char EvalParser::yydefact_[] = { - 0, 0, 0, 4, 5, 8, 0, 2, 0, 0, - 0, 1, 0, 9, 10, 0, 0, 3, 0, 0, - 0, 13, 0, 11, 12, 6, 0, 15, 14, 0, - 7 + 0, 0, 0, 0, 5, 6, 9, 0, 2, 0, + 0, 0, 0, 1, 0, 10, 11, 0, 0, 3, + 4, 0, 0, 0, 14, 0, 12, 13, 7, 0, + 16, 15, 0, 8 }; const signed char EvalParser::yypgoto_[] = { - -14, -14, -14, -3, -14, -14, -14, -14 + -9, -9, 24, -5, -9, -9, -9, -9 }; const signed char EvalParser::yydefgoto_[] = { - -1, 6, 7, 8, 15, 25, 22, 29 + -1, 7, 8, 9, 17, 28, 25, 32 }; const unsigned char EvalParser::yytable_[] = { - 1, 2, 27, 13, 9, 14, 10, 16, 11, 17, - 28, 3, 12, 4, 18, 5, 23, 24, 21, 30, - 0, 19, 20, 0, 26 + 1, 2, 30, 1, 2, 10, 18, 3, 11, 20, + 31, 4, 13, 5, 4, 6, 5, 15, 6, 16, + 26, 27, 14, 19, 21, 22, 23, 12, 29, 24, + 0, 0, 33 }; const signed char EvalParser::yycheck_[] = { - 4, 5, 8, 16, 13, 18, 11, 10, 0, 12, - 16, 15, 3, 17, 14, 19, 6, 7, 16, 12, - -1, 10, 9, -1, 10 + 4, 5, 8, 4, 5, 13, 11, 11, 11, 14, + 16, 15, 0, 17, 15, 19, 17, 16, 19, 18, + 6, 7, 3, 12, 14, 10, 9, 3, 10, 16, + -1, -1, 12 }; const unsigned char EvalParser::yystos_[] = { - 0, 4, 5, 15, 17, 19, 21, 22, 23, 13, - 11, 0, 3, 16, 18, 24, 23, 23, 14, 10, - 9, 16, 26, 6, 7, 25, 10, 8, 16, 27, - 12 + 0, 4, 5, 11, 15, 17, 19, 21, 22, 23, + 13, 11, 22, 0, 3, 16, 18, 24, 23, 12, + 23, 14, 10, 9, 16, 26, 6, 7, 25, 10, + 8, 16, 27, 12 }; const unsigned char EvalParser::yyr1_[] = { - 0, 20, 21, 22, 23, 23, 23, 23, 23, 24, - 24, 25, 25, 26, 27, 27 + 0, 20, 21, 22, 22, 23, 23, 23, 23, 23, + 24, 24, 25, 25, 26, 27, 27 }; const unsigned char EvalParser::yyr2_[] = { - 0, 2, 1, 3, 1, 1, 6, 8, 1, 1, - 1, 1, 1, 1, 1, 1 + 0, 2, 1, 3, 3, 1, 1, 6, 8, 1, + 1, 1, 1, 1, 1, 1, 1 }; @@ -1065,8 +1067,8 @@ namespace isc { namespace eval { const unsigned char EvalParser::yyrline_[] = { - 0, 79, 79, 82, 89, 94, 99, 104, 109, 113, - 117, 123, 127, 133, 140, 145 + 0, 79, 79, 82, 83, 90, 95, 100, 105, 110, + 114, 118, 124, 128, 134, 141, 146 }; // Print the state stack on the debug stream. @@ -1101,8 +1103,8 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:1167 } } // isc::eval -#line 1105 "parser.cc" // lalr1.cc:1167 -#line 152 "parser.yy" // lalr1.cc:1168 +#line 1107 "parser.cc" // lalr1.cc:1167 +#line 153 "parser.yy" // lalr1.cc:1168 void isc::eval::EvalParser::error(const location_type& loc, diff --git a/src/lib/eval/parser.h b/src/lib/eval/parser.h index 85718716cf..b5a1d9d0cc 100644 --- a/src/lib/eval/parser.h +++ b/src/lib/eval/parser.h @@ -734,9 +734,9 @@ namespace isc { namespace eval { enum { yyeof_ = 0, - yylast_ = 24, ///< Last index in yytable_. + yylast_ = 32, ///< Last index in yytable_. yynnts_ = 8, ///< Number of nonterminal symbols. - yyfinal_ = 11, ///< Termination state number. + yyfinal_ = 13, ///< Termination state number. yyterror_ = 1, yyerrcode_ = 256, yyntokens_ = 20 ///< Number of tokens. diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index de4a96136c..961889929e 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -79,7 +79,8 @@ using namespace isc::eval; expression : bool_expr ; -bool_expr : string_expr EQUAL string_expr +bool_expr : "(" bool_expr ")" + | string_expr EQUAL string_expr { TokenPtr eq(new TokenEqual()); ctx.expression.push_back(eq); diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index 25985b3c08..030cacbff6 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -341,6 +341,12 @@ TEST_F(EvalContextTest, parseErrors) { checkError("== 'ab'", ":1.1-2: syntax error, unexpected =="); checkError("'foo' ==", ":1.9: syntax error, unexpected end of file"); + checkError("('foo' == 'bar'", + ":1.16: syntax error, unexpected end of file, " + "expecting )"); + checkError("('foo' == 'bar') ''", + ":1.18-19: syntax error, unexpected constant string, " + "expecting end of file"); checkError("option 'ab'", ":1.8-11: syntax error, unexpected " "constant string, expecting ["); @@ -382,6 +388,9 @@ TEST_F(EvalContextTest, typeErrors) { checkError("substring('foobar',0x32,1) == 'foo'", ":1.20-23: syntax error, unexpected constant " "hexstring, expecting integer"); + checkError("('foo' == 'bar') == 'false'", + ":1.18-19: syntax error, unexpected ==, " + "expecting end of file"); } }; From a557a43b391b0fa65f03131d41471e49c6990bcd Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Wed, 9 Dec 2015 14:27:37 +0100 Subject: [PATCH 2/9] [4231] Added not operator --- src/lib/eval/lexer.cc | 185 ++++++++++---------- src/lib/eval/lexer.ll | 1 + src/lib/eval/parser.cc | 229 +++++++++++++------------ src/lib/eval/parser.h | 106 +++++++----- src/lib/eval/parser.yy | 6 + src/lib/eval/tests/context_unittest.cc | 8 + src/lib/eval/tests/token_unittest.cc | 33 ++++ src/lib/eval/token.cc | 20 +++ src/lib/eval/token.h | 25 +++ 9 files changed, 368 insertions(+), 245 deletions(-) diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc index 245922c83b..ed5f9f46e8 100644 --- a/src/lib/eval/lexer.cc +++ b/src/lib/eval/lexer.cc @@ -469,8 +469,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 20 -#define YY_END_OF_BUFFER 21 +#define YY_NUM_RULES 21 +#define YY_END_OF_BUFFER 22 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -478,27 +478,29 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_acclist[90] = +static yyconst flex_int16_t yy_acclist[96] = { 0, - 21, 19, 20, 1, 19, 20, 2, 20, 19, 20, - 14, 19, 20, 15, 19, 20, 18, 19, 20, 19, - 20, 13, 19, 20, 5, 19, 20, 5, 19, 20, - 19, 20, 19, 20,16390, 16, 19, 20, 17, 19, - 20, 19, 20,16390, 19, 20,16390, 19, 20,16390, - 19, 20,16390, 19, 20,16390, 1, 2, 3, 5, - 7,16390, 8198,16390,16390,16390,16390,16390, 4, 12, - 16390, 10,16390,16390,16390,16390,16390,16390, 9,16390, - 16390,16390, 8,16390,16390,16390,16390, 11,16390 + 22, 20, 21, 1, 20, 21, 2, 21, 20, 21, + 15, 20, 21, 16, 20, 21, 19, 20, 21, 20, + 21, 14, 20, 21, 5, 20, 21, 5, 20, 21, + 20, 21, 20, 21,16390, 17, 20, 21, 18, 20, + 21, 20, 21,16390, 20, 21,16390, 20, 21,16390, + 20, 21,16390, 20, 21,16390, 20, 21,16390, 1, + 2, 3, 5, 7,16390, 8198,16390,16390,16390,16390, + 16390,16390, 4, 13,16390, 10,16390, 12,16390,16390, + 16390,16390,16390,16390, 9,16390,16390,16390, 8,16390, + 16390,16390,16390, 11,16390 + } ; -static yyconst flex_int16_t yy_accept[58] = +static yyconst flex_int16_t yy_accept[61] = { 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, 58, 59, 59, 60, 61, 61, - 62, 62, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 72, 74, 75, 76, 77, 78, 79, 81, 82, - 83, 85, 86, 87, 88, 90, 90 + 48, 51, 54, 57, 60, 61, 62, 62, 63, 64, + 64, 65, 65, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 76, 78, 80, 81, 82, 83, 84, + 85, 87, 88, 89, 91, 92, 93, 94, 96, 96 } ; static yyconst flex_int32_t yy_ec[256] = @@ -541,81 +543,83 @@ static yyconst flex_int32_t yy_meta[34] = 2, 2, 2 } ; -static yyconst flex_int16_t yy_base[60] = +static yyconst flex_int16_t yy_base[63] = { 0, - 0, 0, 119, 120, 116, 114, 112, 120, 120, 120, - 24, 120, 26, 28, 103, 58, 120, 120, 75, 19, - 17, 18, 26, 112, 110, 108, 120, 38, 0, 120, - 50, 54, 86, 120, 85, 21, 33, 43, 37, 0, - 80, 76, 48, 44, 55, 57, 56, 66, 63, 65, - 60, 71, 72, 77, 40, 120, 102, 105, 51 + 0, 0, 124, 125, 121, 119, 117, 125, 125, 125, + 24, 125, 26, 28, 108, 58, 125, 125, 75, 19, + 18, 21, 22, 27, 117, 115, 113, 125, 40, 0, + 125, 53, 55, 91, 125, 86, 38, 37, 42, 44, + 49, 0, 82, 81, 74, 60, 56, 63, 62, 65, + 54, 72, 66, 40, 77, 78, 83, 28, 125, 108, + 111, 38 } ; -static yyconst flex_int16_t yy_def[60] = +static yyconst flex_int16_t yy_def[63] = { 0, - 56, 1, 56, 56, 56, 56, 57, 56, 56, 56, - 56, 56, 56, 56, 56, 58, 56, 56, 58, 19, - 19, 19, 19, 56, 56, 57, 56, 56, 59, 56, - 56, 19, 19, 56, 19, 19, 19, 19, 19, 59, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 0, 56, 56, 56 + 59, 1, 59, 59, 59, 59, 60, 59, 59, 59, + 59, 59, 59, 59, 59, 61, 59, 59, 61, 19, + 19, 19, 19, 19, 59, 59, 60, 59, 59, 62, + 59, 59, 19, 19, 59, 19, 19, 19, 19, 19, + 19, 62, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 0, 59, + 59, 59 } ; -static yyconst flex_int16_t yy_nxt[154] = +static yyconst flex_int16_t yy_nxt[159] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 17, 18, 4, 19, 16, - 16, 16, 20, 16, 16, 16, 21, 16, 16, 22, - 23, 16, 16, 28, 28, 28, 28, 28, 28, 36, - 29, 33, 33, 33, 37, 33, 39, 28, 28, 38, - 33, 31, 31, 42, 40, 56, 56, 33, 29, 31, - 31, 33, 44, 43, 33, 32, 34, 33, 33, 45, - 56, 46, 33, 47, 34, 32, 31, 31, 33, 33, - 33, 33, 32, 49, 33, 48, 50, 33, 51, 33, - 33, 34, 32, 52, 53, 33, 33, 54, 55, 35, + 16, 16, 20, 16, 16, 21, 22, 16, 16, 23, + 24, 16, 16, 29, 29, 29, 29, 29, 29, 37, + 30, 42, 34, 34, 38, 34, 34, 41, 39, 29, + 29, 34, 34, 40, 32, 32, 59, 59, 30, 32, + 32, 34, 34, 47, 34, 33, 34, 45, 34, 35, + 44, 59, 46, 34, 35, 33, 32, 32, 34, 34, + 34, 48, 33, 49, 34, 50, 34, 34, 52, 34, + 34, 35, 33, 51, 55, 53, 34, 54, 34, 36, - 33, 33, 26, 26, 33, 26, 33, 33, 33, 41, - 33, 27, 25, 24, 30, 27, 25, 24, 56, 3, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56 + 56, 34, 34, 57, 58, 34, 34, 34, 27, 27, + 43, 27, 34, 34, 34, 34, 28, 26, 25, 31, + 28, 26, 25, 59, 3, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59 } ; -static yyconst flex_int16_t yy_chk[154] = +static yyconst flex_int16_t yy_chk[159] = { 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, 11, 11, 13, 13, 14, 14, 20, - 13, 21, 22, 20, 21, 36, 23, 28, 28, 22, - 23, 31, 31, 36, 59, 32, 32, 37, 13, 16, - 16, 39, 38, 37, 55, 16, 31, 38, 44, 39, - 32, 43, 43, 44, 16, 16, 19, 19, 32, 45, - 47, 46, 19, 46, 51, 45, 47, 49, 49, 50, - 48, 19, 19, 50, 52, 52, 53, 53, 54, 19, + 13, 62, 21, 20, 21, 22, 23, 24, 22, 29, + 29, 24, 58, 23, 32, 32, 33, 33, 13, 16, + 16, 38, 37, 40, 54, 16, 39, 38, 40, 32, + 37, 33, 39, 41, 16, 16, 19, 19, 51, 33, + 47, 41, 19, 46, 46, 47, 49, 48, 49, 50, + 53, 19, 19, 48, 53, 50, 52, 52, 45, 19, - 42, 54, 57, 57, 41, 57, 58, 58, 58, 35, - 33, 26, 25, 24, 15, 7, 6, 5, 3, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56 + 55, 55, 56, 56, 57, 44, 43, 57, 60, 60, + 36, 60, 61, 61, 61, 34, 27, 26, 25, 15, + 7, 6, 5, 3, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[21] = +static yyconst flex_int32_t yy_rule_can_match_eol[22] = { 0, 0, 1, 0, 0, 0, 1, 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[20] = +static yyconst flex_int16_t yy_rule_linenum[21] = { 0, 86, 90, 96, 106, 112, 126, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 146 + 137, 138, 139, 140, 141, 142, 143, 144, 145, 147 } ; static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; @@ -700,7 +704,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 704 "lexer.cc" +#line 708 "lexer.cc" #define INITIAL 0 @@ -989,7 +993,7 @@ YY_DECL loc.step(); -#line 993 "lexer.cc" +#line 997 "lexer.cc" while ( 1 ) /* loops until end-of-file is reached */ { @@ -1017,14 +1021,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 >= 57 ) + if ( yy_current_state >= 60 ) 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 != 56 ); + while ( yy_current_state != 59 ); yy_find_action: /* %% [10.0] code to find the action number goes here */ @@ -1087,13 +1091,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 < 20 ) + else if ( yy_act < 21 ) fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", (long)yy_rule_linenum[yy_act], yytext ); - else if ( yy_act == 20 ) + else if ( yy_act == 21 ) fprintf( stderr, "--accepting default rule (\"%s\")\n", yytext ); - else if ( yy_act == 21 ) + else if ( yy_act == 22 ) fprintf( stderr, "--(end of buffer or a NUL)\n" ); else fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); @@ -1198,53 +1202,58 @@ return isc::eval::EvalParser::make_SUBSTRING(loc); case 12: YY_RULE_SETUP #line 138 "lexer.ll" -return isc::eval::EvalParser::make_ALL(loc); +return isc::eval::EvalParser::make_NOT(loc); YY_BREAK case 13: YY_RULE_SETUP #line 139 "lexer.ll" -return isc::eval::EvalParser::make_DOT(loc); +return isc::eval::EvalParser::make_ALL(loc); YY_BREAK case 14: YY_RULE_SETUP #line 140 "lexer.ll" -return isc::eval::EvalParser::make_LPAREN(loc); +return isc::eval::EvalParser::make_DOT(loc); YY_BREAK case 15: YY_RULE_SETUP #line 141 "lexer.ll" -return isc::eval::EvalParser::make_RPAREN(loc); +return isc::eval::EvalParser::make_LPAREN(loc); YY_BREAK case 16: YY_RULE_SETUP #line 142 "lexer.ll" -return isc::eval::EvalParser::make_LBRACKET(loc); +return isc::eval::EvalParser::make_RPAREN(loc); YY_BREAK case 17: YY_RULE_SETUP #line 143 "lexer.ll" -return isc::eval::EvalParser::make_RBRACKET(loc); +return isc::eval::EvalParser::make_LBRACKET(loc); YY_BREAK case 18: YY_RULE_SETUP #line 144 "lexer.ll" -return isc::eval::EvalParser::make_COMA(loc); +return isc::eval::EvalParser::make_RBRACKET(loc); YY_BREAK case 19: YY_RULE_SETUP -#line 146 "lexer.ll" -driver.error (loc, "Invalid character: " + std::string(yytext)); - YY_BREAK -case YY_STATE_EOF(INITIAL): -#line 147 "lexer.ll" -return isc::eval::EvalParser::make_END(loc); +#line 145 "lexer.ll" +return isc::eval::EvalParser::make_COMA(loc); YY_BREAK case 20: YY_RULE_SETUP +#line 147 "lexer.ll" +driver.error (loc, "Invalid character: " + std::string(yytext)); + YY_BREAK +case YY_STATE_EOF(INITIAL): #line 148 "lexer.ll" +return isc::eval::EvalParser::make_END(loc); + YY_BREAK +case 21: +YY_RULE_SETUP +#line 149 "lexer.ll" ECHO; YY_BREAK -#line 1248 "lexer.cc" +#line 1257 "lexer.cc" case YY_END_OF_BUFFER: { @@ -1525,7 +1534,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 >= 57 ) + if ( yy_current_state >= 60 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1553,11 +1562,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 >= 57 ) + if ( yy_current_state >= 60 ) 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 == 56); + yy_is_jam = (yy_current_state == 59); if ( ! yy_is_jam ) *(yy_state_ptr)++ = yy_current_state; @@ -2305,7 +2314,7 @@ void yyfree (void * ptr ) /* %ok-for-header */ -#line 148 "lexer.ll" +#line 149 "lexer.ll" diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index 61207ef2e0..a77e7593df 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -135,6 +135,7 @@ blank [ \t] "text" return isc::eval::EvalParser::make_TEXT(loc); "hex" return isc::eval::EvalParser::make_HEX(loc); "substring" return isc::eval::EvalParser::make_SUBSTRING(loc); +"not" return isc::eval::EvalParser::make_NOT(loc); "all" return isc::eval::EvalParser::make_ALL(loc); "." return isc::eval::EvalParser::make_DOT(loc); "(" return isc::eval::EvalParser::make_LPAREN(loc); diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc index ff2cdc1d6f..d743ac5672 100644 --- a/src/lib/eval/parser.cc +++ b/src/lib/eval/parser.cc @@ -251,19 +251,19 @@ namespace isc { namespace eval { { switch (that.type_get ()) { - case 25: // option_repr_type + case 26: // option_repr_type value.move< TokenOption::RepresentationType > (that.value); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN value.move< std::string > (that.value); break; - case 24: // option_code + case 25: // option_code value.move< uint16_t > (that.value); break; @@ -282,19 +282,19 @@ namespace isc { namespace eval { state = that.state; switch (that.type_get ()) { - case 25: // option_repr_type + case 26: // option_repr_type value.copy< TokenOption::RepresentationType > (that.value); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN value.copy< std::string > (that.value); break; - case 24: // option_code + case 25: // option_code value.copy< uint16_t > (that.value); break; @@ -334,51 +334,51 @@ namespace isc { namespace eval { << yysym.location << ": "; switch (yytype) { - case 15: // "constant string" + case 16: // "constant string" -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 342 "parser.cc" // lalr1.cc:636 break; - case 16: // "integer" + case 17: // "integer" -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 349 "parser.cc" // lalr1.cc:636 break; - case 17: // "constant hexstring" + case 18: // "constant hexstring" -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 356 "parser.cc" // lalr1.cc:636 break; - case 18: // "option name" + case 19: // "option name" -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 363 "parser.cc" // lalr1.cc:636 break; - case 19: // TOKEN + case 20: // TOKEN -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 370 "parser.cc" // lalr1.cc:636 break; - case 24: // option_code + case 25: // option_code -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< uint16_t > (); } #line 377 "parser.cc" // lalr1.cc:636 break; - case 25: // option_repr_type + case 26: // option_repr_type -#line 70 "parser.yy" // lalr1.cc:636 +#line 71 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); } #line 384 "parser.cc" // lalr1.cc:636 break; @@ -580,19 +580,19 @@ namespace isc { namespace eval { when using variants. */ switch (yyr1_[yyn]) { - case 25: // option_repr_type + case 26: // option_repr_type yylhs.value.build< TokenOption::RepresentationType > (); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN yylhs.value.build< std::string > (); break; - case 24: // option_code + case 25: // option_code yylhs.value.build< uint16_t > (); break; @@ -614,111 +614,120 @@ namespace isc { namespace eval { switch (yyn) { case 4: -#line 84 "parser.yy" // lalr1.cc:859 +#line 85 "parser.yy" // lalr1.cc:859 { - TokenPtr eq(new TokenEqual()); - ctx.expression.push_back(eq); + TokenPtr neg(new TokenNot()); + ctx.expression.push_back(neg); } #line 623 "parser.cc" // lalr1.cc:859 break; case 5: -#line 91 "parser.yy" // lalr1.cc:859 +#line 90 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + TokenPtr eq(new TokenEqual()); + ctx.expression.push_back(eq); + } #line 632 "parser.cc" // lalr1.cc:859 break; case 6: -#line 96 "parser.yy" // lalr1.cc:859 +#line 97 "parser.yy" // lalr1.cc:859 { - TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(hex); + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); } #line 641 "parser.cc" // lalr1.cc:859 break; case 7: -#line 101 "parser.yy" // lalr1.cc:859 +#line 102 "parser.yy" // lalr1.cc:859 { - TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); - ctx.expression.push_back(opt); + TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(hex); } #line 650 "parser.cc" // lalr1.cc:859 break; case 8: -#line 106 "parser.yy" // lalr1.cc:859 +#line 107 "parser.yy" // lalr1.cc:859 { - TokenPtr sub(new TokenSubstring()); - ctx.expression.push_back(sub); + TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); + ctx.expression.push_back(opt); } #line 659 "parser.cc" // lalr1.cc:859 break; - case 10: -#line 115 "parser.yy" // lalr1.cc:859 + case 9: +#line 112 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); - } -#line 667 "parser.cc" // lalr1.cc:859 + TokenPtr sub(new TokenSubstring()); + ctx.expression.push_back(sub); + } +#line 668 "parser.cc" // lalr1.cc:859 break; case 11: -#line 119 "parser.yy" // lalr1.cc:859 +#line 121 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); + yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); } -#line 675 "parser.cc" // lalr1.cc:859 +#line 676 "parser.cc" // lalr1.cc:859 break; case 12: #line 125 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; - } -#line 683 "parser.cc" // lalr1.cc:859 + yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); + } +#line 684 "parser.cc" // lalr1.cc:859 break; case 13: -#line 129 "parser.yy" // lalr1.cc:859 +#line 131 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; } -#line 691 "parser.cc" // lalr1.cc:859 +#line 692 "parser.cc" // lalr1.cc:859 break; case 14: #line 135 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; + } #line 700 "parser.cc" // lalr1.cc:859 break; case 15: -#line 142 "parser.yy" // lalr1.cc:859 +#line 141 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); + } #line 709 "parser.cc" // lalr1.cc:859 break; case 16: -#line 147 "parser.yy" // lalr1.cc:859 +#line 148 "parser.yy" // lalr1.cc:859 + { + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); + } +#line 718 "parser.cc" // lalr1.cc:859 + break; + + case 17: +#line 153 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString("all")); ctx.expression.push_back(str); } -#line 718 "parser.cc" // lalr1.cc:859 +#line 727 "parser.cc" // lalr1.cc:859 break; -#line 722 "parser.cc" // lalr1.cc:859 +#line 731 "parser.cc" // lalr1.cc:859 default: break; } @@ -973,79 +982,79 @@ namespace isc { namespace eval { } - const signed char EvalParser::yypact_ninf_ = -9; + const signed char EvalParser::yypact_ninf_ = -10; const signed char EvalParser::yytable_ninf_ = -1; const signed char EvalParser::yypact_[] = { - -4, -8, -3, -4, -9, -9, -9, 12, -9, 19, - 1, -1, 11, -9, -1, -9, -9, 10, 15, -9, - -9, 17, 13, 14, -9, 18, -9, -9, -9, -6, - -9, -9, 20, -9 + -4, -1, 3, -4, -4, -10, -10, -10, 18, -10, + 17, -8, 1, -10, 13, -10, 1, -10, -10, 12, + 19, -10, -10, 22, 11, 16, -10, 20, -10, -10, + -10, -7, -10, -10, 23, -10 }; const unsigned char EvalParser::yydefact_[] = { - 0, 0, 0, 0, 5, 6, 9, 0, 2, 0, - 0, 0, 0, 1, 0, 10, 11, 0, 0, 3, - 4, 0, 0, 0, 14, 0, 12, 13, 7, 0, - 16, 15, 0, 8 + 0, 0, 0, 0, 0, 6, 7, 10, 0, 2, + 0, 0, 0, 4, 0, 1, 0, 11, 12, 0, + 0, 3, 5, 0, 0, 0, 15, 0, 13, 14, + 8, 0, 17, 16, 0, 9 }; const signed char EvalParser::yypgoto_[] = { - -9, -9, 24, -5, -9, -9, -9, -9 + -10, -10, 21, -9, -10, -10, -10, -10 }; const signed char EvalParser::yydefgoto_[] = { - -1, 7, 8, 9, 17, 28, 25, 32 + -1, 8, 9, 10, 19, 30, 27, 34 }; const unsigned char EvalParser::yytable_[] = { - 1, 2, 30, 1, 2, 10, 18, 3, 11, 20, - 31, 4, 13, 5, 4, 6, 5, 15, 6, 16, - 26, 27, 14, 19, 21, 22, 23, 12, 29, 24, - 0, 0, 33 + 1, 2, 32, 20, 3, 1, 2, 22, 4, 17, + 33, 18, 5, 11, 6, 12, 7, 5, 15, 6, + 16, 7, 28, 29, 13, 14, 21, 23, 26, 0, + 24, 31, 25, 0, 0, 0, 35 }; const signed char EvalParser::yycheck_[] = { - 4, 5, 8, 4, 5, 13, 11, 11, 11, 14, - 16, 15, 0, 17, 15, 19, 17, 16, 19, 18, - 6, 7, 3, 12, 14, 10, 9, 3, 10, 16, - -1, -1, 12 + 4, 5, 9, 12, 8, 4, 5, 16, 12, 17, + 17, 19, 16, 14, 18, 12, 20, 16, 0, 18, + 3, 20, 6, 7, 3, 4, 13, 15, 17, -1, + 11, 11, 10, -1, -1, -1, 13 }; const unsigned char EvalParser::yystos_[] = { - 0, 4, 5, 11, 15, 17, 19, 21, 22, 23, - 13, 11, 22, 0, 3, 16, 18, 24, 23, 12, - 23, 14, 10, 9, 16, 26, 6, 7, 25, 10, - 8, 16, 27, 12 + 0, 4, 5, 8, 12, 16, 18, 20, 22, 23, + 24, 14, 12, 23, 23, 0, 3, 17, 19, 25, + 24, 13, 24, 15, 11, 10, 17, 27, 6, 7, + 26, 11, 9, 17, 28, 13 }; const unsigned char EvalParser::yyr1_[] = { - 0, 20, 21, 22, 22, 23, 23, 23, 23, 23, - 24, 24, 25, 25, 26, 27, 27 + 0, 21, 22, 23, 23, 23, 24, 24, 24, 24, + 24, 25, 25, 26, 26, 27, 28, 28 }; const unsigned char EvalParser::yyr2_[] = { - 0, 2, 1, 3, 3, 1, 1, 6, 8, 1, - 1, 1, 1, 1, 1, 1, 1 + 0, 2, 1, 3, 2, 3, 1, 1, 6, 8, + 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -1056,10 +1065,10 @@ namespace isc { namespace eval { const EvalParser::yytname_[] = { "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"", - "\"substring\"", "\"text\"", "\"hex\"", "\"all\"", "\".\"", "\",\"", - "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"", - "\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept", - "expression", "bool_expr", "string_expr", "option_code", + "\"substring\"", "\"text\"", "\"hex\"", "\"not\"", "\"all\"", "\".\"", + "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", + "\"integer\"", "\"constant hexstring\"", "\"option name\"", "TOKEN", + "$accept", "expression", "bool_expr", "string_expr", "option_code", "option_repr_type", "start_expr", "length_expr", YY_NULLPTR }; @@ -1067,8 +1076,8 @@ namespace isc { namespace eval { const unsigned char EvalParser::yyrline_[] = { - 0, 79, 79, 82, 83, 90, 95, 100, 105, 110, - 114, 118, 124, 128, 134, 141, 146 + 0, 80, 80, 83, 84, 89, 96, 101, 106, 111, + 116, 120, 124, 130, 134, 140, 147, 152 }; // Print the state stack on the debug stream. @@ -1103,8 +1112,8 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:1167 } } // isc::eval -#line 1107 "parser.cc" // lalr1.cc:1167 -#line 153 "parser.yy" // lalr1.cc:1168 +#line 1116 "parser.cc" // lalr1.cc:1167 +#line 159 "parser.yy" // lalr1.cc:1168 void isc::eval::EvalParser::error(const location_type& loc, diff --git a/src/lib/eval/parser.h b/src/lib/eval/parser.h index b5a1d9d0cc..3aa107e905 100644 --- a/src/lib/eval/parser.h +++ b/src/lib/eval/parser.h @@ -335,18 +335,19 @@ namespace isc { namespace eval { TOKEN_SUBSTRING = 260, TOKEN_TEXT = 261, TOKEN_HEX = 262, - TOKEN_ALL = 263, - TOKEN_DOT = 264, - TOKEN_COMA = 265, - TOKEN_LPAREN = 266, - TOKEN_RPAREN = 267, - TOKEN_LBRACKET = 268, - TOKEN_RBRACKET = 269, - TOKEN_STRING = 270, - TOKEN_INTEGER = 271, - TOKEN_HEXSTRING = 272, - TOKEN_OPTION_NAME = 273, - TOKEN_TOKEN = 274 + TOKEN_NOT = 263, + TOKEN_ALL = 264, + TOKEN_DOT = 265, + TOKEN_COMA = 266, + TOKEN_LPAREN = 267, + TOKEN_RPAREN = 268, + TOKEN_LBRACKET = 269, + TOKEN_RBRACKET = 270, + TOKEN_STRING = 271, + TOKEN_INTEGER = 272, + TOKEN_HEXSTRING = 273, + TOKEN_OPTION_NAME = 274, + TOKEN_TOKEN = 275 }; }; @@ -481,6 +482,10 @@ namespace isc { namespace eval { symbol_type make_HEX (const location_type& l); + static inline + symbol_type + make_NOT (const location_type& l); + static inline symbol_type make_ALL (const location_type& l); @@ -734,12 +739,12 @@ namespace isc { namespace eval { enum { yyeof_ = 0, - yylast_ = 32, ///< Last index in yytable_. + yylast_ = 36, ///< Last index in yytable_. yynnts_ = 8, ///< Number of nonterminal symbols. - yyfinal_ = 13, ///< Termination state number. + yyfinal_ = 15, ///< Termination state number. yyterror_ = 1, yyerrcode_ = 256, - yyntokens_ = 20 ///< Number of tokens. + yyntokens_ = 21 ///< Number of tokens. }; @@ -783,9 +788,9 @@ namespace isc { namespace eval { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19 + 15, 16, 17, 18, 19, 20 }; - const unsigned int user_token_number_max_ = 274; + const unsigned int user_token_number_max_ = 275; const token_number_type undef_token_ = 2; if (static_cast(t) <= yyeof_) @@ -818,19 +823,19 @@ namespace isc { namespace eval { { switch (other.type_get ()) { - case 25: // option_repr_type + case 26: // option_repr_type value.copy< TokenOption::RepresentationType > (other.value); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN value.copy< std::string > (other.value); break; - case 24: // option_code + case 25: // option_code value.copy< uint16_t > (other.value); break; @@ -851,19 +856,19 @@ namespace isc { namespace eval { (void) v; switch (this->type_get ()) { - case 25: // option_repr_type + case 26: // option_repr_type value.copy< TokenOption::RepresentationType > (v); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN value.copy< std::string > (v); break; - case 24: // option_code + case 25: // option_code value.copy< uint16_t > (v); break; @@ -929,19 +934,19 @@ namespace isc { namespace eval { // Type destructor. switch (yytype) { - case 25: // option_repr_type + case 26: // option_repr_type value.template destroy< TokenOption::RepresentationType > (); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN value.template destroy< std::string > (); break; - case 24: // option_code + case 25: // option_code value.template destroy< uint16_t > (); break; @@ -968,19 +973,19 @@ namespace isc { namespace eval { super_type::move(s); switch (this->type_get ()) { - case 25: // option_repr_type + case 26: // option_repr_type value.move< TokenOption::RepresentationType > (s.value); break; - case 15: // "constant string" - case 16: // "integer" - case 17: // "constant hexstring" - case 18: // "option name" - case 19: // TOKEN + case 16: // "constant string" + case 17: // "integer" + case 18: // "constant hexstring" + case 19: // "option name" + case 20: // TOKEN value.move< std::string > (s.value); break; - case 24: // option_code + case 25: // option_code value.move< uint16_t > (s.value); break; @@ -1040,7 +1045,8 @@ namespace isc { namespace eval { yytoken_number_[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274 + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275 }; return static_cast (yytoken_number_[type]); } @@ -1081,6 +1087,12 @@ namespace isc { namespace eval { return symbol_type (token::TOKEN_HEX, l); } + EvalParser::symbol_type + EvalParser::make_NOT (const location_type& l) + { + return symbol_type (token::TOKEN_NOT, l); + } + EvalParser::symbol_type EvalParser::make_ALL (const location_type& l) { @@ -1156,7 +1168,7 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:392 } } // isc::eval -#line 1160 "parser.h" // lalr1.cc:392 +#line 1172 "parser.h" // lalr1.cc:392 diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 961889929e..9087ab3a6c 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -49,6 +49,7 @@ using namespace isc::eval; SUBSTRING "substring" TEXT "text" HEX "hex" + NOT "not" ALL "all" DOT "." COMA "," @@ -80,6 +81,11 @@ expression : bool_expr ; bool_expr : "(" bool_expr ")" + | NOT bool_expr + { + TokenPtr neg(new TokenNot()); + ctx.expression.push_back(neg); + } | string_expr EQUAL string_expr { TokenPtr eq(new TokenEqual()); diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index 030cacbff6..eed1043b02 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -341,6 +341,14 @@ TEST_F(EvalContextTest, parseErrors) { checkError("== 'ab'", ":1.1-2: syntax error, unexpected =="); checkError("'foo' ==", ":1.9: syntax error, unexpected end of file"); + checkError("not 'foo'", + ":1.10: syntax error, unexpected end of file, " + "expecting =="); + checkError("not()", + ":1.5: syntax error, unexpected )"); + checkError("(not('foo' 'bar')", + ":1.12-16: syntax error, unexpected constant string, " + "expecting =="); checkError("('foo' == 'bar'", ":1.16: syntax error, unexpected end of file, " "expecting )"); diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index e93d558f88..307b0034a9 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -407,6 +407,39 @@ TEST_F(TokenTest, optionEqualTrue) { EXPECT_EQ("true", values_.top()); } +// This test checks if a token representing a not is able to +// negate a boolean value (with incorrectly built stack). +TEST_F(TokenTest, optionNotInvalid) { + + ASSERT_NO_THROW(t_.reset(new TokenNot())); + + // CASE 1: The stack is empty. + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack); + + // CASE 2: The top value is not a boolean + values_.push("foo"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError); +} + +// This test checks if a token representing a not operator is able to +// negate a boolean value. +TEST_F(TokenTest, optionNot) { + + ASSERT_NO_THROW(t_.reset(new TokenNot())); + + values_.push("true"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + + // After evaluation there should be the negation of the value. + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("false", values_.top()); + + // Double negation is identity. + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("true", values_.top()); +} + }; // This test checks if an a token representing a substring request diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index 59df54ce22..ea693276b7 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -176,3 +176,23 @@ TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) { // and finally get the substring values.push(string_str.substr(start_pos, length)); } + +void +TokenNot::evaluate(const Pkt& /*pkt*/, ValueStack& values) { + + if (values.size() == 0) { + isc_throw(EvalBadStack, "Incorrect empty stack."); + } + + string op = values.top(); + values.pop(); + + if (op == "true") { + values.push("false"); + } else if (op == "false") { + values.push("true"); + } else { + isc_throw(EvalTypeError, "Expected a logical value at top of stack. " + << "Got '" << op << "'."); + } +} diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index a476948adc..ca45078bb7 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -277,6 +277,31 @@ public: void evaluate(const Pkt& pkt, ValueStack& values); }; +/// @brief Token that represents logical negation operator +/// +/// For example in the expression "not(option[vendor-class].text == 'MSF')" +/// this token represents the leading "not" +class TokenNot : public Token { +public: + /// @brief Constructor (does nothing) + TokenNot() {} + + /// @brief Logical negation. + /// + /// Evaluation does not use packet information, but rather consumes the last + /// result. It does a simple string comparison and sets the value to + /// either "true" or "false". It requires at least one value to be + /// present on stack and to be either "true" or "false". + /// + /// @throw EvalBadStack if there are less than 1 value on stack + /// @throw EvalTypeError if the top value on the stack is not either + /// "true" or "false" + /// + /// @param pkt (unused) + /// @param values - stack of values (logical top value negated) + void evaluate(const Pkt& pkt, ValueStack& values); +}; + }; // end of isc::dhcp namespace }; // end of isc namespace From 8f6bc1575e3290fc933a7a7f4d824df95597afbe Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Wed, 9 Dec 2015 14:54:00 +0100 Subject: [PATCH 3/9] [4231] Added .exists to option --- src/lib/eval/lexer.cc | 194 +++++++++---------- src/lib/eval/lexer.ll | 3 +- src/lib/eval/parser.cc | 235 +++++++++++++----------- src/lib/eval/parser.h | 115 ++++++------ src/lib/eval/parser.yy | 8 +- src/lib/eval/tests/context_unittest.cc | 13 ++ src/lib/eval/tests/evaluate_unittest.cc | 26 +++ src/lib/eval/tests/token_unittest.cc | 44 +++++ src/lib/eval/token.cc | 6 +- src/lib/eval/token.h | 8 +- 10 files changed, 392 insertions(+), 260 deletions(-) diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc index ed5f9f46e8..109d8c241b 100644 --- a/src/lib/eval/lexer.cc +++ b/src/lib/eval/lexer.cc @@ -469,8 +469,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 21 -#define YY_END_OF_BUFFER 22 +#define YY_NUM_RULES 22 +#define YY_END_OF_BUFFER 23 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -478,29 +478,31 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_acclist[96] = +static yyconst flex_int16_t yy_acclist[105] = { 0, - 22, 20, 21, 1, 20, 21, 2, 21, 20, 21, - 15, 20, 21, 16, 20, 21, 19, 20, 21, 20, - 21, 14, 20, 21, 5, 20, 21, 5, 20, 21, - 20, 21, 20, 21,16390, 17, 20, 21, 18, 20, - 21, 20, 21,16390, 20, 21,16390, 20, 21,16390, - 20, 21,16390, 20, 21,16390, 20, 21,16390, 1, - 2, 3, 5, 7,16390, 8198,16390,16390,16390,16390, - 16390,16390, 4, 13,16390, 10,16390, 12,16390,16390, - 16390,16390,16390,16390, 9,16390,16390,16390, 8,16390, - 16390,16390,16390, 11,16390 + 23, 21, 22, 1, 21, 22, 2, 22, 21, 22, + 16, 21, 22, 17, 21, 22, 20, 21, 22, 21, + 22, 15, 21, 22, 5, 21, 22, 5, 21, 22, + 21, 22, 21, 22,16390, 18, 21, 22, 19, 21, + 22, 21, 22,16390, 21, 22,16390, 21, 22,16390, + 21, 22,16390, 21, 22,16390, 21, 22,16390, 21, + 22,16390, 1, 2, 3, 5, 7,16390, 8198,16390, + 16390,16390,16390,16390,16390,16390, 4, 13,16390,16390, + 10,16390, 14,16390,16390,16390,16390,16390,16390,16390, + 9,16390,16390,16390,16390, 11,16390, 8,16390,16390, + 16390,16390, 12,16390 } ; -static yyconst flex_int16_t yy_accept[61] = +static yyconst flex_int16_t yy_accept[67] = { 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, 61, 62, 62, 63, 64, - 64, 65, 65, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 76, 78, 80, 81, 82, 83, 84, - 85, 87, 88, 89, 91, 92, 93, 94, 96, 96 + 48, 51, 54, 57, 60, 63, 64, 65, 65, 66, + 67, 67, 68, 68, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 80, 81, 83, 85, 86, + 87, 88, 89, 90, 91, 93, 94, 95, 96, 98, + 100, 101, 102, 103, 105, 105 } ; static yyconst flex_int32_t yy_ec[256] = @@ -543,83 +545,86 @@ static yyconst flex_int32_t yy_meta[34] = 2, 2, 2 } ; -static yyconst flex_int16_t yy_base[63] = +static yyconst flex_int16_t yy_base[69] = { 0, - 0, 0, 124, 125, 121, 119, 117, 125, 125, 125, - 24, 125, 26, 28, 108, 58, 125, 125, 75, 19, - 18, 21, 22, 27, 117, 115, 113, 125, 40, 0, - 125, 53, 55, 91, 125, 86, 38, 37, 42, 44, - 49, 0, 82, 81, 74, 60, 56, 63, 62, 65, - 54, 72, 66, 40, 77, 78, 83, 28, 125, 108, - 111, 38 + 0, 0, 135, 136, 132, 130, 128, 136, 136, 136, + 24, 136, 26, 28, 119, 58, 136, 136, 75, 15, + 21, 18, 19, 24, 29, 128, 126, 124, 136, 41, + 0, 136, 55, 62, 102, 136, 101, 38, 48, 43, + 55, 64, 57, 0, 100, 66, 99, 98, 45, 69, + 70, 72, 28, 73, 97, 77, 80, 42, 96, 95, + 84, 85, 63, 94, 136, 111, 114, 110 } ; -static yyconst flex_int16_t yy_def[63] = +static yyconst flex_int16_t yy_def[69] = { 0, - 59, 1, 59, 59, 59, 59, 60, 59, 59, 59, - 59, 59, 59, 59, 59, 61, 59, 59, 61, 19, - 19, 19, 19, 19, 59, 59, 60, 59, 59, 62, - 59, 59, 19, 19, 59, 19, 19, 19, 19, 19, - 19, 62, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 0, 59, - 59, 59 + 65, 1, 65, 65, 65, 65, 66, 65, 65, 65, + 65, 65, 65, 65, 65, 67, 65, 65, 67, 19, + 19, 19, 19, 19, 19, 65, 65, 66, 65, 65, + 68, 65, 65, 19, 19, 65, 19, 19, 19, 19, + 19, 19, 19, 68, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 65, 65, 65 } ; -static yyconst flex_int16_t yy_nxt[159] = +static yyconst flex_int16_t yy_nxt[170] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 17, 18, 4, 19, 16, - 16, 16, 20, 16, 16, 21, 22, 16, 16, 23, - 24, 16, 16, 29, 29, 29, 29, 29, 29, 37, - 30, 42, 34, 34, 38, 34, 34, 41, 39, 29, - 29, 34, 34, 40, 32, 32, 59, 59, 30, 32, - 32, 34, 34, 47, 34, 33, 34, 45, 34, 35, - 44, 59, 46, 34, 35, 33, 32, 32, 34, 34, - 34, 48, 33, 49, 34, 50, 34, 34, 52, 34, - 34, 35, 33, 51, 55, 53, 34, 54, 34, 36, + 20, 16, 21, 16, 16, 22, 23, 16, 16, 24, + 25, 16, 16, 30, 30, 30, 30, 30, 30, 35, + 31, 39, 35, 35, 40, 35, 41, 38, 35, 43, + 30, 30, 35, 35, 57, 42, 33, 33, 31, 33, + 33, 46, 35, 65, 65, 34, 35, 35, 53, 35, + 61, 36, 35, 48, 36, 34, 33, 33, 65, 35, + 47, 35, 34, 50, 64, 49, 35, 35, 35, 51, + 35, 36, 34, 35, 35, 52, 35, 35, 54, 37, - 56, 34, 34, 57, 58, 34, 34, 34, 27, 27, - 43, 27, 34, 34, 34, 34, 28, 26, 25, 31, - 28, 26, 25, 59, 3, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59 + 55, 35, 56, 58, 35, 60, 59, 62, 35, 35, + 63, 28, 28, 44, 28, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 45, 35, 29, 27, 26, + 32, 29, 27, 26, 65, 3, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65 } ; -static yyconst flex_int16_t yy_chk[159] = +static yyconst flex_int16_t yy_chk[170] = { 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, 11, 11, 13, 13, 14, 14, 20, - 13, 62, 21, 20, 21, 22, 23, 24, 22, 29, - 29, 24, 58, 23, 32, 32, 33, 33, 13, 16, - 16, 38, 37, 40, 54, 16, 39, 38, 40, 32, - 37, 33, 39, 41, 16, 16, 19, 19, 51, 33, - 47, 41, 19, 46, 46, 47, 49, 48, 49, 50, - 53, 19, 19, 48, 53, 50, 52, 52, 45, 19, + 13, 21, 22, 23, 22, 21, 23, 20, 24, 25, + 30, 30, 53, 25, 53, 24, 33, 33, 13, 16, + 16, 38, 38, 34, 34, 16, 58, 40, 49, 49, + 58, 33, 39, 40, 16, 16, 19, 19, 34, 41, + 39, 43, 19, 42, 63, 41, 34, 63, 42, 43, + 46, 19, 19, 50, 51, 46, 52, 54, 50, 19, - 55, 55, 56, 56, 57, 44, 43, 57, 60, 60, - 36, 60, 61, 61, 61, 34, 27, 26, 25, 15, - 7, 6, 5, 3, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59 + 51, 56, 52, 54, 57, 57, 56, 61, 61, 62, + 62, 66, 66, 68, 66, 67, 67, 67, 64, 60, + 59, 55, 48, 47, 45, 37, 35, 28, 27, 26, + 15, 7, 6, 5, 3, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[22] = +static yyconst flex_int32_t yy_rule_can_match_eol[23] = { 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, }; extern int yy_flex_debug; int yy_flex_debug = 1; -static yyconst flex_int16_t yy_rule_linenum[21] = +static yyconst flex_int16_t yy_rule_linenum[22] = { 0, 86, 90, 96, 106, 112, 126, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 147 + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 148 } ; static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; @@ -704,7 +709,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 708 "lexer.cc" +#line 713 "lexer.cc" #define INITIAL 0 @@ -993,7 +998,7 @@ YY_DECL loc.step(); -#line 997 "lexer.cc" +#line 1002 "lexer.cc" while ( 1 ) /* loops until end-of-file is reached */ { @@ -1021,14 +1026,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 >= 60 ) + if ( yy_current_state >= 66 ) 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 != 59 ); + while ( yy_current_state != 65 ); yy_find_action: /* %% [10.0] code to find the action number goes here */ @@ -1091,13 +1096,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 < 21 ) + else if ( yy_act < 22 ) fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", (long)yy_rule_linenum[yy_act], yytext ); - else if ( yy_act == 21 ) + else if ( yy_act == 22 ) fprintf( stderr, "--accepting default rule (\"%s\")\n", yytext ); - else if ( yy_act == 22 ) + else if ( yy_act == 23 ) fprintf( stderr, "--(end of buffer or a NUL)\n" ); else fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); @@ -1197,12 +1202,12 @@ return isc::eval::EvalParser::make_HEX(loc); case 11: YY_RULE_SETUP #line 137 "lexer.ll" -return isc::eval::EvalParser::make_SUBSTRING(loc); +return isc::eval::EvalParser::make_EXISTS(loc); YY_BREAK case 12: YY_RULE_SETUP #line 138 "lexer.ll" -return isc::eval::EvalParser::make_NOT(loc); +return isc::eval::EvalParser::make_SUBSTRING(loc); YY_BREAK case 13: YY_RULE_SETUP @@ -1212,48 +1217,53 @@ return isc::eval::EvalParser::make_ALL(loc); case 14: YY_RULE_SETUP #line 140 "lexer.ll" -return isc::eval::EvalParser::make_DOT(loc); +return isc::eval::EvalParser::make_NOT(loc); YY_BREAK case 15: YY_RULE_SETUP #line 141 "lexer.ll" -return isc::eval::EvalParser::make_LPAREN(loc); +return isc::eval::EvalParser::make_DOT(loc); YY_BREAK case 16: YY_RULE_SETUP #line 142 "lexer.ll" -return isc::eval::EvalParser::make_RPAREN(loc); +return isc::eval::EvalParser::make_LPAREN(loc); YY_BREAK case 17: YY_RULE_SETUP #line 143 "lexer.ll" -return isc::eval::EvalParser::make_LBRACKET(loc); +return isc::eval::EvalParser::make_RPAREN(loc); YY_BREAK case 18: YY_RULE_SETUP #line 144 "lexer.ll" -return isc::eval::EvalParser::make_RBRACKET(loc); +return isc::eval::EvalParser::make_LBRACKET(loc); YY_BREAK case 19: YY_RULE_SETUP #line 145 "lexer.ll" -return isc::eval::EvalParser::make_COMA(loc); +return isc::eval::EvalParser::make_RBRACKET(loc); YY_BREAK case 20: YY_RULE_SETUP -#line 147 "lexer.ll" -driver.error (loc, "Invalid character: " + std::string(yytext)); - YY_BREAK -case YY_STATE_EOF(INITIAL): -#line 148 "lexer.ll" -return isc::eval::EvalParser::make_END(loc); +#line 146 "lexer.ll" +return isc::eval::EvalParser::make_COMA(loc); YY_BREAK case 21: YY_RULE_SETUP +#line 148 "lexer.ll" +driver.error (loc, "Invalid character: " + std::string(yytext)); + YY_BREAK +case YY_STATE_EOF(INITIAL): #line 149 "lexer.ll" +return isc::eval::EvalParser::make_END(loc); + YY_BREAK +case 22: +YY_RULE_SETUP +#line 150 "lexer.ll" ECHO; YY_BREAK -#line 1257 "lexer.cc" +#line 1267 "lexer.cc" case YY_END_OF_BUFFER: { @@ -1534,7 +1544,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 >= 60 ) + if ( yy_current_state >= 66 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1562,11 +1572,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 >= 60 ) + if ( yy_current_state >= 66 ) 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 == 59); + yy_is_jam = (yy_current_state == 65); if ( ! yy_is_jam ) *(yy_state_ptr)++ = yy_current_state; @@ -2314,7 +2324,7 @@ void yyfree (void * ptr ) /* %ok-for-header */ -#line 149 "lexer.ll" +#line 150 "lexer.ll" diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index a77e7593df..1112b58c31 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -134,9 +134,10 @@ blank [ \t] "option" return isc::eval::EvalParser::make_OPTION(loc); "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); -"not" return isc::eval::EvalParser::make_NOT(loc); "all" return isc::eval::EvalParser::make_ALL(loc); +"not" return isc::eval::EvalParser::make_NOT(loc); "." return isc::eval::EvalParser::make_DOT(loc); "(" return isc::eval::EvalParser::make_LPAREN(loc); ")" return isc::eval::EvalParser::make_RPAREN(loc); diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc index d743ac5672..304b2cc48e 100644 --- a/src/lib/eval/parser.cc +++ b/src/lib/eval/parser.cc @@ -251,19 +251,19 @@ namespace isc { namespace eval { { switch (that.type_get ()) { - case 26: // option_repr_type + case 27: // option_repr_type value.move< TokenOption::RepresentationType > (that.value); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN value.move< std::string > (that.value); break; - case 25: // option_code + case 26: // option_code value.move< uint16_t > (that.value); break; @@ -282,19 +282,19 @@ namespace isc { namespace eval { state = that.state; switch (that.type_get ()) { - case 26: // option_repr_type + case 27: // option_repr_type value.copy< TokenOption::RepresentationType > (that.value); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN value.copy< std::string > (that.value); break; - case 25: // option_code + case 26: // option_code value.copy< uint16_t > (that.value); break; @@ -334,51 +334,51 @@ namespace isc { namespace eval { << yysym.location << ": "; switch (yytype) { - case 16: // "constant string" + case 17: // "constant string" -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 342 "parser.cc" // lalr1.cc:636 break; - case 17: // "integer" + case 18: // "integer" -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 349 "parser.cc" // lalr1.cc:636 break; - case 18: // "constant hexstring" + case 19: // "constant hexstring" -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 356 "parser.cc" // lalr1.cc:636 break; - case 19: // "option name" + case 20: // "option name" -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 363 "parser.cc" // lalr1.cc:636 break; - case 20: // TOKEN + case 21: // TOKEN -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 370 "parser.cc" // lalr1.cc:636 break; - case 25: // option_code + case 26: // option_code -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< uint16_t > (); } #line 377 "parser.cc" // lalr1.cc:636 break; - case 26: // option_repr_type + case 27: // option_repr_type -#line 71 "parser.yy" // lalr1.cc:636 +#line 72 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); } #line 384 "parser.cc" // lalr1.cc:636 break; @@ -580,19 +580,19 @@ namespace isc { namespace eval { when using variants. */ switch (yyr1_[yyn]) { - case 26: // option_repr_type + case 27: // option_repr_type yylhs.value.build< TokenOption::RepresentationType > (); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN yylhs.value.build< std::string > (); break; - case 25: // option_code + case 26: // option_code yylhs.value.build< uint16_t > (); break; @@ -614,7 +614,7 @@ namespace isc { namespace eval { switch (yyn) { case 4: -#line 85 "parser.yy" // lalr1.cc:859 +#line 86 "parser.yy" // lalr1.cc:859 { TokenPtr neg(new TokenNot()); ctx.expression.push_back(neg); @@ -623,7 +623,7 @@ namespace isc { namespace eval { break; case 5: -#line 90 "parser.yy" // lalr1.cc:859 +#line 91 "parser.yy" // lalr1.cc:859 { TokenPtr eq(new TokenEqual()); ctx.expression.push_back(eq); @@ -632,102 +632,111 @@ namespace isc { namespace eval { break; case 6: -#line 97 "parser.yy" // lalr1.cc:859 +#line 96 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS)); + ctx.expression.push_back(opt); + } #line 641 "parser.cc" // lalr1.cc:859 break; case 7: -#line 102 "parser.yy" // lalr1.cc:859 +#line 103 "parser.yy" // lalr1.cc:859 { - TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(hex); + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); } #line 650 "parser.cc" // lalr1.cc:859 break; case 8: -#line 107 "parser.yy" // lalr1.cc:859 +#line 108 "parser.yy" // lalr1.cc:859 { - TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); - ctx.expression.push_back(opt); + TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(hex); } #line 659 "parser.cc" // lalr1.cc:859 break; case 9: -#line 112 "parser.yy" // lalr1.cc:859 +#line 113 "parser.yy" // lalr1.cc:859 { - TokenPtr sub(new TokenSubstring()); - ctx.expression.push_back(sub); + TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); + ctx.expression.push_back(opt); } #line 668 "parser.cc" // lalr1.cc:859 break; - case 11: -#line 121 "parser.yy" // lalr1.cc:859 + case 10: +#line 118 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); - } -#line 676 "parser.cc" // lalr1.cc:859 + TokenPtr sub(new TokenSubstring()); + ctx.expression.push_back(sub); + } +#line 677 "parser.cc" // lalr1.cc:859 break; case 12: -#line 125 "parser.yy" // lalr1.cc:859 +#line 127 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); + yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); } -#line 684 "parser.cc" // lalr1.cc:859 +#line 685 "parser.cc" // lalr1.cc:859 break; case 13: #line 131 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; - } -#line 692 "parser.cc" // lalr1.cc:859 + yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); + } +#line 693 "parser.cc" // lalr1.cc:859 break; case 14: -#line 135 "parser.yy" // lalr1.cc:859 +#line 137 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; } -#line 700 "parser.cc" // lalr1.cc:859 +#line 701 "parser.cc" // lalr1.cc:859 break; case 15: #line 141 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; + } #line 709 "parser.cc" // lalr1.cc:859 break; case 16: -#line 148 "parser.yy" // lalr1.cc:859 +#line 147 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); + } #line 718 "parser.cc" // lalr1.cc:859 break; case 17: -#line 153 "parser.yy" // lalr1.cc:859 +#line 154 "parser.yy" // lalr1.cc:859 + { + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); + } +#line 727 "parser.cc" // lalr1.cc:859 + break; + + case 18: +#line 159 "parser.yy" // lalr1.cc:859 { TokenPtr str(new TokenString("all")); ctx.expression.push_back(str); } -#line 727 "parser.cc" // lalr1.cc:859 +#line 736 "parser.cc" // lalr1.cc:859 break; -#line 731 "parser.cc" // lalr1.cc:859 +#line 740 "parser.cc" // lalr1.cc:859 default: break; } @@ -982,79 +991,84 @@ namespace isc { namespace eval { } - const signed char EvalParser::yypact_ninf_ = -10; + const signed char EvalParser::yypact_ninf_ = -14; const signed char EvalParser::yytable_ninf_ = -1; const signed char EvalParser::yypact_[] = { - -4, -1, 3, -4, -4, -10, -10, -10, 18, -10, - 17, -8, 1, -10, 13, -10, 1, -10, -10, 12, - 19, -10, -10, 22, 11, 16, -10, 20, -10, -10, - -10, -7, -10, -10, 23, -10 + -4, -7, 15, -4, -4, -14, -14, -14, 12, -14, + 11, -13, -1, -14, 16, -14, -1, -14, -14, 13, + 18, 19, -14, -14, 21, -13, 20, 14, 24, -14, + 22, -14, -14, -14, -14, 25, 1, 17, -14, -14, + 27, -14 }; const unsigned char EvalParser::yydefact_[] = { - 0, 0, 0, 0, 0, 6, 7, 10, 0, 2, - 0, 0, 0, 4, 0, 1, 0, 11, 12, 0, - 0, 3, 5, 0, 0, 0, 15, 0, 13, 14, - 8, 0, 17, 16, 0, 9 + 0, 0, 0, 0, 0, 7, 8, 11, 0, 2, + 0, 0, 0, 4, 0, 1, 0, 12, 13, 0, + 0, 0, 3, 5, 0, 0, 0, 0, 0, 16, + 0, 14, 15, 6, 9, 0, 0, 0, 18, 17, + 0, 10 }; const signed char EvalParser::yypgoto_[] = { - -10, -10, 21, -9, -10, -10, -10, -10 + -14, -14, 23, -6, 10, -14, -14, -14 }; const signed char EvalParser::yydefgoto_[] = { - -1, 8, 9, 10, 19, 30, 27, 34 + -1, 8, 9, 10, 19, 34, 30, 40 }; const unsigned char EvalParser::yytable_[] = { - 1, 2, 32, 20, 3, 1, 2, 22, 4, 17, - 33, 18, 5, 11, 6, 12, 7, 5, 15, 6, - 16, 7, 28, 29, 13, 14, 21, 23, 26, 0, - 24, 31, 25, 0, 0, 0, 35 + 1, 2, 3, 20, 2, 17, 21, 18, 11, 4, + 23, 38, 15, 5, 16, 6, 5, 7, 6, 39, + 7, 31, 32, 33, 31, 32, 13, 14, 12, 24, + 22, 26, 27, 25, 36, 28, 37, 0, 29, 0, + 35, 41 }; const signed char EvalParser::yycheck_[] = { - 4, 5, 9, 12, 8, 4, 5, 16, 12, 17, - 17, 19, 16, 14, 18, 12, 20, 16, 0, 18, - 3, 20, 6, 7, 3, 4, 13, 15, 17, -1, - 11, 11, 10, -1, -1, -1, 13 + 4, 5, 6, 4, 5, 18, 12, 20, 15, 13, + 16, 10, 0, 17, 3, 19, 17, 21, 19, 18, + 21, 7, 8, 9, 7, 8, 3, 4, 13, 16, + 14, 12, 11, 15, 12, 25, 11, -1, 18, -1, + 16, 14 }; const unsigned char EvalParser::yystos_[] = { - 0, 4, 5, 8, 12, 16, 18, 20, 22, 23, - 24, 14, 12, 23, 23, 0, 3, 17, 19, 25, - 24, 13, 24, 15, 11, 10, 17, 27, 6, 7, - 26, 11, 9, 17, 28, 13 + 0, 4, 5, 6, 13, 17, 19, 21, 23, 24, + 25, 15, 13, 24, 24, 0, 3, 18, 20, 26, + 4, 25, 14, 25, 16, 15, 12, 11, 26, 18, + 28, 7, 8, 9, 27, 16, 12, 11, 10, 18, + 29, 14 }; const unsigned char EvalParser::yyr1_[] = { - 0, 21, 22, 23, 23, 23, 24, 24, 24, 24, - 24, 25, 25, 26, 26, 27, 28, 28 + 0, 22, 23, 24, 24, 24, 24, 25, 25, 25, + 25, 25, 26, 26, 27, 27, 28, 29, 29 }; const unsigned char EvalParser::yyr2_[] = { - 0, 2, 1, 3, 2, 3, 1, 1, 6, 8, - 1, 1, 1, 1, 1, 1, 1, 1 + 0, 2, 1, 3, 2, 3, 6, 1, 1, 6, + 8, 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -1065,19 +1079,20 @@ namespace isc { namespace eval { const EvalParser::yytname_[] = { "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"", - "\"substring\"", "\"text\"", "\"hex\"", "\"not\"", "\"all\"", "\".\"", - "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", - "\"integer\"", "\"constant hexstring\"", "\"option name\"", "TOKEN", - "$accept", "expression", "bool_expr", "string_expr", "option_code", - "option_repr_type", "start_expr", "length_expr", YY_NULLPTR + "\"substring\"", "\"not\"", "\"text\"", "\"hex\"", "\"exists\"", + "\"all\"", "\".\"", "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", + "\"constant string\"", "\"integer\"", "\"constant hexstring\"", + "\"option name\"", "TOKEN", "$accept", "expression", "bool_expr", + "string_expr", "option_code", "option_repr_type", "start_expr", + "length_expr", YY_NULLPTR }; #if YYDEBUG const unsigned char EvalParser::yyrline_[] = { - 0, 80, 80, 83, 84, 89, 96, 101, 106, 111, - 116, 120, 124, 130, 134, 140, 147, 152 + 0, 81, 81, 84, 85, 90, 95, 102, 107, 112, + 117, 122, 126, 130, 136, 140, 146, 153, 158 }; // Print the state stack on the debug stream. @@ -1112,8 +1127,8 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:1167 } } // isc::eval -#line 1116 "parser.cc" // lalr1.cc:1167 -#line 159 "parser.yy" // lalr1.cc:1168 +#line 1131 "parser.cc" // lalr1.cc:1167 +#line 165 "parser.yy" // lalr1.cc:1168 void isc::eval::EvalParser::error(const location_type& loc, diff --git a/src/lib/eval/parser.h b/src/lib/eval/parser.h index 3aa107e905..1d2bd0a10c 100644 --- a/src/lib/eval/parser.h +++ b/src/lib/eval/parser.h @@ -333,21 +333,22 @@ namespace isc { namespace eval { TOKEN_EQUAL = 258, TOKEN_OPTION = 259, TOKEN_SUBSTRING = 260, - TOKEN_TEXT = 261, - TOKEN_HEX = 262, - TOKEN_NOT = 263, - TOKEN_ALL = 264, - TOKEN_DOT = 265, - TOKEN_COMA = 266, - TOKEN_LPAREN = 267, - TOKEN_RPAREN = 268, - TOKEN_LBRACKET = 269, - TOKEN_RBRACKET = 270, - TOKEN_STRING = 271, - TOKEN_INTEGER = 272, - TOKEN_HEXSTRING = 273, - TOKEN_OPTION_NAME = 274, - TOKEN_TOKEN = 275 + TOKEN_NOT = 261, + TOKEN_TEXT = 262, + TOKEN_HEX = 263, + TOKEN_EXISTS = 264, + TOKEN_ALL = 265, + TOKEN_DOT = 266, + TOKEN_COMA = 267, + TOKEN_LPAREN = 268, + TOKEN_RPAREN = 269, + TOKEN_LBRACKET = 270, + TOKEN_RBRACKET = 271, + TOKEN_STRING = 272, + TOKEN_INTEGER = 273, + TOKEN_HEXSTRING = 274, + TOKEN_OPTION_NAME = 275, + TOKEN_TOKEN = 276 }; }; @@ -474,6 +475,10 @@ namespace isc { namespace eval { symbol_type make_SUBSTRING (const location_type& l); + static inline + symbol_type + make_NOT (const location_type& l); + static inline symbol_type make_TEXT (const location_type& l); @@ -484,7 +489,7 @@ namespace isc { namespace eval { static inline symbol_type - make_NOT (const location_type& l); + make_EXISTS (const location_type& l); static inline symbol_type @@ -739,12 +744,12 @@ namespace isc { namespace eval { enum { yyeof_ = 0, - yylast_ = 36, ///< Last index in yytable_. + yylast_ = 41, ///< Last index in yytable_. yynnts_ = 8, ///< Number of nonterminal symbols. yyfinal_ = 15, ///< Termination state number. yyterror_ = 1, yyerrcode_ = 256, - yyntokens_ = 21 ///< Number of tokens. + yyntokens_ = 22 ///< Number of tokens. }; @@ -788,9 +793,9 @@ namespace isc { namespace eval { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20 + 15, 16, 17, 18, 19, 20, 21 }; - const unsigned int user_token_number_max_ = 275; + const unsigned int user_token_number_max_ = 276; const token_number_type undef_token_ = 2; if (static_cast(t) <= yyeof_) @@ -823,19 +828,19 @@ namespace isc { namespace eval { { switch (other.type_get ()) { - case 26: // option_repr_type + case 27: // option_repr_type value.copy< TokenOption::RepresentationType > (other.value); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN value.copy< std::string > (other.value); break; - case 25: // option_code + case 26: // option_code value.copy< uint16_t > (other.value); break; @@ -856,19 +861,19 @@ namespace isc { namespace eval { (void) v; switch (this->type_get ()) { - case 26: // option_repr_type + case 27: // option_repr_type value.copy< TokenOption::RepresentationType > (v); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN value.copy< std::string > (v); break; - case 25: // option_code + case 26: // option_code value.copy< uint16_t > (v); break; @@ -934,19 +939,19 @@ namespace isc { namespace eval { // Type destructor. switch (yytype) { - case 26: // option_repr_type + case 27: // option_repr_type value.template destroy< TokenOption::RepresentationType > (); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN value.template destroy< std::string > (); break; - case 25: // option_code + case 26: // option_code value.template destroy< uint16_t > (); break; @@ -973,19 +978,19 @@ namespace isc { namespace eval { super_type::move(s); switch (this->type_get ()) { - case 26: // option_repr_type + case 27: // option_repr_type value.move< TokenOption::RepresentationType > (s.value); break; - case 16: // "constant string" - case 17: // "integer" - case 18: // "constant hexstring" - case 19: // "option name" - case 20: // TOKEN + case 17: // "constant string" + case 18: // "integer" + case 19: // "constant hexstring" + case 20: // "option name" + case 21: // TOKEN value.move< std::string > (s.value); break; - case 25: // option_code + case 26: // option_code value.move< uint16_t > (s.value); break; @@ -1046,7 +1051,7 @@ namespace isc { namespace eval { { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275 + 275, 276 }; return static_cast (yytoken_number_[type]); } @@ -1075,6 +1080,12 @@ namespace isc { namespace eval { return symbol_type (token::TOKEN_SUBSTRING, l); } + EvalParser::symbol_type + EvalParser::make_NOT (const location_type& l) + { + return symbol_type (token::TOKEN_NOT, l); + } + EvalParser::symbol_type EvalParser::make_TEXT (const location_type& l) { @@ -1088,9 +1099,9 @@ namespace isc { namespace eval { } EvalParser::symbol_type - EvalParser::make_NOT (const location_type& l) + EvalParser::make_EXISTS (const location_type& l) { - return symbol_type (token::TOKEN_NOT, l); + return symbol_type (token::TOKEN_EXISTS, l); } EvalParser::symbol_type @@ -1168,7 +1179,7 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:392 } } // isc::eval -#line 1172 "parser.h" // lalr1.cc:392 +#line 1183 "parser.h" // lalr1.cc:392 diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 9087ab3a6c..fda62bab5e 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -47,9 +47,10 @@ using namespace isc::eval; EQUAL "==" OPTION "option" SUBSTRING "substring" + NOT "not" TEXT "text" HEX "hex" - NOT "not" + EXISTS "exists" ALL "all" DOT "." COMA "," @@ -91,6 +92,11 @@ bool_expr : "(" bool_expr ")" TokenPtr eq(new TokenEqual()); ctx.expression.push_back(eq); } + | OPTION "[" option_code "]" "." EXISTS + { + TokenPtr opt(new TokenOption($3, TokenOption::EXISTS)); + ctx.expression.push_back(opt); + } ; string_expr : STRING diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index eed1043b02..bded550b07 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -228,6 +228,16 @@ TEST_F(EvalContextTest, optionWithName) { checkTokenOption(eval.expression.at(0), 12); } +// Test parsing of an option existence +TEST_F(EvalContextTest, optionExists) { + EvalContext eval(Option::V4); + + EXPECT_NO_THROW(parsed_ = eval.parseString("option[100].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(1, eval.expression.size()); + checkTokenOption(eval.expression.at(0), 100); +} + // Test checking that whitespace can surround option name. TEST_F(EvalContextTest, optionWithNameAndWhitespace) { EvalContext eval(Option::V4); @@ -373,6 +383,9 @@ TEST_F(EvalContextTest, parseErrors) { "expecting integer or option name"); checkError("option[10].bin", ":1.12: Invalid character: b"); checkError("option[boot-size].bin", ":1.19: Invalid character: b"); + checkError("option[10].exists == 'foo'", + ":1.19-20: syntax error, unexpected ==, " + "expecting end of file"); checkError("substring('foobar') == 'f'", ":1.19: syntax error, " "unexpected ), expecting \",\""); diff --git a/src/lib/eval/tests/evaluate_unittest.cc b/src/lib/eval/tests/evaluate_unittest.cc index d404b12830..0fde9bce82 100644 --- a/src/lib/eval/tests/evaluate_unittest.cc +++ b/src/lib/eval/tests/evaluate_unittest.cc @@ -190,6 +190,32 @@ TEST_F(EvaluateTest, compare6) { EXPECT_FALSE(result_); } +// A test using option existence +TEST_F(EvaluateTest, exists) { + TokenPtr toption; + + ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::EXISTS))); + e_.push_back(toption); + + ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_)); + EXPECT_TRUE(result_); + ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_)); + EXPECT_TRUE(result_); +} + +// A test using option non-existence +TEST_F(EvaluateTest, dontExists) { + TokenPtr toption; + + ASSERT_NO_THROW(toption.reset(new TokenOption(101, TokenOption::EXISTS))); + e_.push_back(toption); + + ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_)); + EXPECT_FALSE(result_); + ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_)); + EXPECT_FALSE(result_); +} + // A test using packets. TEST_F(EvaluateTest, packet) { TokenPtr toption; diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index 307b0034a9..3652a97ea8 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -303,6 +303,28 @@ TEST_F(TokenTest, optionHexString4) { EXPECT_EQ("hundred4", values_.top()); } +// This test checks if a token representing an option value is able to check +// the existence ofthe option from an IPv4 packet. +TEST_F(TokenTest, optionExistsString4) { + TokenPtr found; + TokenPtr not_found; + + // The packets we use have option 100 with a string in them. + ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::EXISTS))); + ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::EXISTS))); + + ASSERT_NO_THROW(found->evaluate(*pkt4_, values_)); + ASSERT_NO_THROW(not_found->evaluate(*pkt4_, values_)); + + // There should be 2 values evaluated. + ASSERT_EQ(2, values_.size()); + + // This is a stack, so the pop order is inversed. + EXPECT_EQ("false", values_.top()); + values_.pop(); + EXPECT_EQ("true", values_.top()); +} + // This test checks if a token representing an option value is able to extract // the option from an IPv6 packet and properly store the option's value. TEST_F(TokenTest, optionString6) { @@ -360,6 +382,28 @@ TEST_F(TokenTest, optionHexString6) { EXPECT_EQ("hundred6", values_.top()); } +// This test checks if a token representing an option value is able to check +// the existence ofthe option from an IPv6 packet. +TEST_F(TokenTest, optionExistsString6) { + TokenPtr found; + TokenPtr not_found; + + // The packets we use have option 100 with a string in them. + ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::EXISTS))); + ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::EXISTS))); + + ASSERT_NO_THROW(found->evaluate(*pkt6_, values_)); + ASSERT_NO_THROW(not_found->evaluate(*pkt6_, values_)); + + // There should be 2 values evaluated. + ASSERT_EQ(2, values_.size()); + + // This is a stack, so the pop order is inversed. + EXPECT_EQ("false", values_.top()); + values_.pop(); + EXPECT_EQ("true", 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) { diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index ea693276b7..f528c50d71 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -69,13 +69,17 @@ TokenOption::evaluate(const Pkt& pkt, ValueStack& values) { if (opt) { if (representation_type_ == TEXTUAL) { opt_str = opt->toString(); - } else { + } else if (representation_type_ == HEXADECIMAL) { std::vector binary = opt->toBinary(); opt_str.resize(binary.size()); if (!binary.empty()) { memmove(&opt_str[0], &binary[0], binary.size()); } + } else { + opt_str = "true"; } + } else if (representation_type_ == EXISTS) { + opt_str = "false"; } // Push value of the option or empty string if there was no such option diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index ca45078bb7..e06ad43b6f 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -144,20 +144,22 @@ protected: /// option[vendor-class].text /// /// During the evaluation it tries to extract the value of the specified -/// option. If the option is not found, an empty string ("") is returned. +/// option. If the option is not found, an empty string ("") is returned +/// (or "false" when the representation is EXISTS). class TokenOption : public Token { public: /// @brief Token representation type. /// /// There are many possible ways in which option can be presented. - /// Currently the textual and hexadecimal representations are + /// Currently the textual, hexadecimal and exists representations are /// supported. The type of representation is specified in the /// constructor and it affects the value generated by the /// @c TokenOption::evaluate function. enum RepresentationType { TEXTUAL, - HEXADECIMAL + HEXADECIMAL, + EXISTS }; /// @brief Constructor that takes an option code as a parameter From d0ee0b0811cee581a322450a3af7bce4e377ae5d Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Wed, 9 Dec 2015 16:00:46 +0100 Subject: [PATCH 4/9] [4231] Added and & or operators --- src/lib/eval/lexer.cc | 220 +++++++++++--------- src/lib/eval/lexer.ll | 2 + src/lib/eval/location.hh | 2 +- src/lib/eval/parser.cc | 271 +++++++++++++------------ src/lib/eval/parser.h | 122 ++++++----- src/lib/eval/parser.yy | 18 +- src/lib/eval/position.hh | 2 +- src/lib/eval/stack.hh | 2 +- src/lib/eval/tests/context_unittest.cc | 43 +++- src/lib/eval/tests/token_unittest.cc | 132 ++++++++++++ src/lib/eval/token.cc | 71 +++++++ src/lib/eval/token.h | 50 +++++ 12 files changed, 651 insertions(+), 284 deletions(-) diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc index 109d8c241b..99843f2814 100644 --- a/src/lib/eval/lexer.cc +++ b/src/lib/eval/lexer.cc @@ -469,8 +469,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 22 -#define YY_END_OF_BUFFER 23 +#define YY_NUM_RULES 24 +#define YY_END_OF_BUFFER 25 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -478,31 +478,31 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_acclist[105] = +static yyconst flex_int16_t yy_acclist[110] = { 0, - 23, 21, 22, 1, 21, 22, 2, 22, 21, 22, - 16, 21, 22, 17, 21, 22, 20, 21, 22, 21, - 22, 15, 21, 22, 5, 21, 22, 5, 21, 22, - 21, 22, 21, 22,16390, 18, 21, 22, 19, 21, - 22, 21, 22,16390, 21, 22,16390, 21, 22,16390, - 21, 22,16390, 21, 22,16390, 21, 22,16390, 21, - 22,16390, 1, 2, 3, 5, 7,16390, 8198,16390, - 16390,16390,16390,16390,16390,16390, 4, 13,16390,16390, - 10,16390, 14,16390,16390,16390,16390,16390,16390,16390, - 9,16390,16390,16390,16390, 11,16390, 8,16390,16390, + 25, 23, 24, 1, 23, 24, 2, 24, 23, 24, + 18, 23, 24, 19, 23, 24, 22, 23, 24, 23, + 24, 17, 23, 24, 5, 23, 24, 5, 23, 24, + 23, 24, 23, 24,16390, 20, 23, 24, 21, 23, + 24, 23, 24,16390, 23, 24,16390, 23, 24,16390, + 23, 24,16390, 23, 24,16390, 23, 24,16390, 23, + 24,16390, 1, 2, 3, 5, 7,16390, 8198,16390, + 16390,16390,16390,16390,16390, 16,16390,16390,16390, 4, + 13,16390, 15,16390,16390, 10,16390, 14,16390,16390, + 16390,16390,16390,16390,16390, 9,16390,16390,16390,16390, - 16390,16390, 12,16390 + 11,16390, 8,16390,16390,16390,16390, 12,16390 } ; -static yyconst flex_int16_t yy_accept[67] = +static yyconst flex_int16_t yy_accept[70] = { 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, 64, 65, 65, 66, 67, 67, 68, 68, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 80, 81, 83, 85, 86, - 87, 88, 89, 90, 91, 93, 94, 95, 96, 98, - 100, 101, 102, 103, 105, 105 + 74, 75, 76, 78, 79, 80, 81, 83, 85, 86, + 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, + 100, 101, 103, 105, 106, 107, 108, 110, 110 } ; static yyconst flex_int32_t yy_ec[256] = @@ -516,10 +516,10 @@ static yyconst flex_int32_t yy_ec[256] = 12, 1, 1, 1, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, - 16, 1, 17, 1, 18, 1, 19, 20, 13, 13, + 16, 1, 17, 1, 18, 1, 19, 20, 13, 21, - 21, 13, 22, 23, 24, 14, 14, 25, 14, 26, - 27, 28, 14, 29, 30, 31, 32, 14, 14, 33, + 22, 13, 23, 24, 25, 14, 14, 26, 14, 27, + 28, 29, 14, 30, 31, 32, 33, 14, 14, 34, 14, 14, 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, @@ -537,94 +537,108 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[34] = +static yyconst flex_int32_t yy_meta[35] = { 0, 1, 2, 3, 1, 1, 1, 1, 2, 1, 4, 4, 1, 4, 2, 2, 1, 2, 2, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2 + 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2 } ; -static yyconst flex_int16_t yy_base[69] = +static yyconst flex_int16_t yy_base[72] = { 0, - 0, 0, 135, 136, 132, 130, 128, 136, 136, 136, - 24, 136, 26, 28, 119, 58, 136, 136, 75, 15, - 21, 18, 19, 24, 29, 128, 126, 124, 136, 41, - 0, 136, 55, 62, 102, 136, 101, 38, 48, 43, - 55, 64, 57, 0, 100, 66, 99, 98, 45, 69, - 70, 72, 28, 73, 97, 77, 80, 42, 96, 95, - 84, 85, 63, 94, 136, 111, 114, 110 + 0, 0, 95, 184, 83, 73, 70, 184, 184, 184, + 25, 184, 27, 29, 48, 41, 184, 184, 60, 19, + 25, 28, 40, 38, 53, 55, 47, 44, 184, 62, + 0, 184, 79, 81, 62, 184, 64, 73, 76, 78, + 83, 87, 66, 91, 94, 0, 96, 98, 100, 103, + 106, 109, 111, 113, 117, 120, 124, 126, 128, 131, + 134, 136, 139, 142, 144, 149, 147, 184, 176, 179, + 37 } ; -static yyconst flex_int16_t yy_def[69] = +static yyconst flex_int16_t yy_def[72] = { 0, - 65, 1, 65, 65, 65, 65, 66, 65, 65, 65, - 65, 65, 65, 65, 65, 67, 65, 65, 67, 19, - 19, 19, 19, 19, 19, 65, 65, 66, 65, 65, - 68, 65, 65, 19, 19, 65, 19, 19, 19, 19, - 19, 19, 19, 68, 19, 19, 19, 19, 19, 19, + 68, 1, 68, 68, 68, 68, 69, 68, 68, 68, + 68, 68, 68, 68, 68, 70, 68, 68, 70, 19, + 19, 19, 19, 19, 19, 68, 68, 69, 68, 68, + 71, 68, 68, 19, 19, 68, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 71, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 0, 65, 65, 65 + 19, 19, 19, 19, 19, 19, 19, 0, 68, 68, + 68 } ; -static yyconst flex_int16_t yy_nxt[170] = +static yyconst flex_int16_t yy_nxt[219] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 17, 18, 4, 19, 16, - 20, 16, 21, 16, 16, 22, 23, 16, 16, 24, - 25, 16, 16, 30, 30, 30, 30, 30, 30, 35, - 31, 39, 35, 35, 40, 35, 41, 38, 35, 43, - 30, 30, 35, 35, 57, 42, 33, 33, 31, 33, - 33, 46, 35, 65, 65, 34, 35, 35, 53, 35, - 61, 36, 35, 48, 36, 34, 33, 33, 65, 35, - 47, 35, 34, 50, 64, 49, 35, 35, 35, 51, - 35, 36, 34, 35, 35, 52, 35, 35, 54, 37, + 16, 20, 16, 21, 16, 16, 22, 23, 16, 16, + 24, 25, 16, 16, 30, 30, 30, 30, 30, 30, + 46, 31, 33, 33, 35, 35, 40, 29, 34, 27, + 35, 35, 39, 35, 35, 41, 26, 36, 34, 32, + 31, 33, 33, 35, 35, 35, 35, 34, 42, 43, + 44, 30, 30, 29, 45, 27, 36, 34, 35, 35, + 33, 33, 68, 68, 26, 37, 38, 35, 35, 47, + 35, 35, 35, 48, 68, 36, 68, 68, 35, 35, - 55, 35, 56, 58, 35, 60, 59, 62, 35, 35, - 63, 28, 28, 44, 28, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 45, 35, 29, 27, 26, - 32, 29, 27, 26, 65, 3, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65 + 49, 35, 35, 35, 35, 68, 35, 35, 35, 35, + 53, 50, 35, 35, 51, 68, 35, 35, 52, 35, + 35, 35, 35, 35, 35, 35, 35, 54, 35, 35, + 55, 35, 35, 56, 35, 35, 35, 35, 35, 35, + 68, 57, 35, 35, 58, 35, 35, 60, 59, 35, + 35, 35, 35, 35, 35, 61, 35, 63, 62, 35, + 35, 35, 35, 64, 35, 35, 65, 35, 35, 35, + 66, 67, 35, 35, 35, 35, 28, 28, 68, 28, + 35, 35, 35, 3, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 } ; -static yyconst flex_int16_t yy_chk[170] = +static yyconst flex_int16_t yy_chk[219] = { 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, 11, 11, 13, 13, 14, 14, 20, - 13, 21, 22, 23, 22, 21, 23, 20, 24, 25, - 30, 30, 53, 25, 53, 24, 33, 33, 13, 16, - 16, 38, 38, 34, 34, 16, 58, 40, 49, 49, - 58, 33, 39, 40, 16, 16, 19, 19, 34, 41, - 39, 43, 19, 42, 63, 41, 34, 63, 42, 43, - 46, 19, 19, 50, 51, 46, 52, 54, 50, 19, + 1, 1, 1, 1, 11, 11, 13, 13, 14, 14, + 71, 13, 16, 16, 20, 20, 21, 28, 16, 27, + 21, 21, 20, 22, 22, 22, 26, 16, 16, 15, + 13, 19, 19, 24, 24, 23, 23, 19, 23, 23, + 24, 30, 30, 7, 25, 6, 19, 19, 25, 25, + 33, 33, 34, 34, 5, 19, 19, 35, 35, 37, + 37, 43, 43, 38, 3, 33, 0, 34, 38, 38, - 51, 56, 52, 54, 57, 57, 56, 61, 61, 62, - 62, 66, 66, 68, 66, 67, 67, 67, 64, 60, - 59, 55, 48, 47, 45, 37, 35, 28, 27, 26, - 15, 7, 6, 5, 3, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65 + 39, 39, 39, 40, 40, 0, 34, 34, 41, 41, + 44, 40, 42, 42, 41, 0, 44, 44, 42, 45, + 45, 47, 47, 48, 48, 49, 49, 45, 50, 50, + 49, 51, 51, 52, 52, 52, 53, 53, 54, 54, + 0, 53, 55, 55, 54, 56, 56, 56, 55, 57, + 57, 58, 58, 59, 59, 57, 60, 60, 59, 61, + 61, 62, 62, 61, 63, 63, 64, 64, 64, 65, + 65, 66, 67, 67, 66, 66, 69, 69, 0, 69, + 70, 70, 70, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 } ; /* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[23] = +static yyconst flex_int32_t yy_rule_can_match_eol[25] = { 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, }; extern int yy_flex_debug; int yy_flex_debug = 1; -static yyconst flex_int16_t yy_rule_linenum[22] = +static yyconst flex_int16_t yy_rule_linenum[24] = { 0, 86, 90, 96, 106, 112, 126, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 148 + 147, 148, 150 } ; static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; @@ -709,7 +723,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 713 "lexer.cc" +#line 727 "lexer.cc" #define INITIAL 0 @@ -998,7 +1012,7 @@ YY_DECL loc.step(); -#line 1002 "lexer.cc" +#line 1016 "lexer.cc" while ( 1 ) /* loops until end-of-file is reached */ { @@ -1026,14 +1040,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 >= 66 ) + if ( yy_current_state >= 69 ) 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 != 65 ); + while ( yy_current_state != 68 ); yy_find_action: /* %% [10.0] code to find the action number goes here */ @@ -1096,13 +1110,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 < 22 ) + else if ( yy_act < 24 ) fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", (long)yy_rule_linenum[yy_act], yytext ); - else if ( yy_act == 22 ) + else if ( yy_act == 24 ) fprintf( stderr, "--accepting default rule (\"%s\")\n", yytext ); - else if ( yy_act == 23 ) + else if ( yy_act == 25 ) fprintf( stderr, "--(end of buffer or a NUL)\n" ); else fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); @@ -1222,48 +1236,58 @@ return isc::eval::EvalParser::make_NOT(loc); case 15: YY_RULE_SETUP #line 141 "lexer.ll" -return isc::eval::EvalParser::make_DOT(loc); +return isc::eval::EvalParser::make_AND(loc); YY_BREAK case 16: YY_RULE_SETUP #line 142 "lexer.ll" -return isc::eval::EvalParser::make_LPAREN(loc); +return isc::eval::EvalParser::make_OR(loc); YY_BREAK case 17: YY_RULE_SETUP #line 143 "lexer.ll" -return isc::eval::EvalParser::make_RPAREN(loc); +return isc::eval::EvalParser::make_DOT(loc); YY_BREAK case 18: YY_RULE_SETUP #line 144 "lexer.ll" -return isc::eval::EvalParser::make_LBRACKET(loc); +return isc::eval::EvalParser::make_LPAREN(loc); YY_BREAK case 19: YY_RULE_SETUP #line 145 "lexer.ll" -return isc::eval::EvalParser::make_RBRACKET(loc); +return isc::eval::EvalParser::make_RPAREN(loc); YY_BREAK case 20: YY_RULE_SETUP #line 146 "lexer.ll" -return isc::eval::EvalParser::make_COMA(loc); +return isc::eval::EvalParser::make_LBRACKET(loc); YY_BREAK case 21: YY_RULE_SETUP -#line 148 "lexer.ll" -driver.error (loc, "Invalid character: " + std::string(yytext)); - YY_BREAK -case YY_STATE_EOF(INITIAL): -#line 149 "lexer.ll" -return isc::eval::EvalParser::make_END(loc); +#line 147 "lexer.ll" +return isc::eval::EvalParser::make_RBRACKET(loc); YY_BREAK case 22: YY_RULE_SETUP +#line 148 "lexer.ll" +return isc::eval::EvalParser::make_COMA(loc); + YY_BREAK +case 23: +YY_RULE_SETUP #line 150 "lexer.ll" +driver.error (loc, "Invalid character: " + std::string(yytext)); + YY_BREAK +case YY_STATE_EOF(INITIAL): +#line 151 "lexer.ll" +return isc::eval::EvalParser::make_END(loc); + YY_BREAK +case 24: +YY_RULE_SETUP +#line 152 "lexer.ll" ECHO; YY_BREAK -#line 1267 "lexer.cc" +#line 1291 "lexer.cc" case YY_END_OF_BUFFER: { @@ -1544,7 +1568,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 >= 66 ) + if ( yy_current_state >= 69 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1572,11 +1596,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 >= 66 ) + if ( yy_current_state >= 69 ) 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 == 65); + yy_is_jam = (yy_current_state == 68); if ( ! yy_is_jam ) *(yy_state_ptr)++ = yy_current_state; @@ -2324,7 +2348,7 @@ void yyfree (void * ptr ) /* %ok-for-header */ -#line 150 "lexer.ll" +#line 152 "lexer.ll" diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index 1112b58c31..ff458cc0c6 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -138,6 +138,8 @@ blank [ \t] "substring" return isc::eval::EvalParser::make_SUBSTRING(loc); "all" return isc::eval::EvalParser::make_ALL(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); "." return isc::eval::EvalParser::make_DOT(loc); "(" return isc::eval::EvalParser::make_LPAREN(loc); ")" return isc::eval::EvalParser::make_RPAREN(loc); diff --git a/src/lib/eval/location.hh b/src/lib/eval/location.hh index 3f828a7ee5..2f28d52763 100644 --- a/src/lib/eval/location.hh +++ b/src/lib/eval/location.hh @@ -1,4 +1,4 @@ -// Generated 20151207 +// Generated 20151209 // A Bison parser, made by GNU Bison 3.0.4. // Locations for Bison parsers in C++ diff --git a/src/lib/eval/parser.cc b/src/lib/eval/parser.cc index 304b2cc48e..9bbef776dc 100644 --- a/src/lib/eval/parser.cc +++ b/src/lib/eval/parser.cc @@ -251,19 +251,19 @@ namespace isc { namespace eval { { switch (that.type_get ()) { - case 27: // option_repr_type + case 29: // option_repr_type value.move< TokenOption::RepresentationType > (that.value); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN value.move< std::string > (that.value); break; - case 26: // option_code + case 28: // option_code value.move< uint16_t > (that.value); break; @@ -282,19 +282,19 @@ namespace isc { namespace eval { state = that.state; switch (that.type_get ()) { - case 27: // option_repr_type + case 29: // option_repr_type value.copy< TokenOption::RepresentationType > (that.value); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN value.copy< std::string > (that.value); break; - case 26: // option_code + case 28: // option_code value.copy< uint16_t > (that.value); break; @@ -334,51 +334,51 @@ namespace isc { namespace eval { << yysym.location << ": "; switch (yytype) { - case 17: // "constant string" + case 19: // "constant string" -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 342 "parser.cc" // lalr1.cc:636 break; - case 18: // "integer" + case 20: // "integer" -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 349 "parser.cc" // lalr1.cc:636 break; - case 19: // "constant hexstring" + case 21: // "constant hexstring" -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 356 "parser.cc" // lalr1.cc:636 break; - case 20: // "option name" + case 22: // "option name" -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 363 "parser.cc" // lalr1.cc:636 break; - case 21: // TOKEN + case 23: // TOKEN -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< std::string > (); } #line 370 "parser.cc" // lalr1.cc:636 break; - case 26: // option_code + case 28: // option_code -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< uint16_t > (); } #line 377 "parser.cc" // lalr1.cc:636 break; - case 27: // option_repr_type + case 29: // option_repr_type -#line 72 "parser.yy" // lalr1.cc:636 +#line 78 "parser.yy" // lalr1.cc:636 { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); } #line 384 "parser.cc" // lalr1.cc:636 break; @@ -580,19 +580,19 @@ namespace isc { namespace eval { when using variants. */ switch (yyr1_[yyn]) { - case 27: // option_repr_type + case 29: // option_repr_type yylhs.value.build< TokenOption::RepresentationType > (); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN yylhs.value.build< std::string > (); break; - case 26: // option_code + case 28: // option_code yylhs.value.build< uint16_t > (); break; @@ -614,7 +614,7 @@ namespace isc { namespace eval { switch (yyn) { case 4: -#line 86 "parser.yy" // lalr1.cc:859 +#line 92 "parser.yy" // lalr1.cc:859 { TokenPtr neg(new TokenNot()); ctx.expression.push_back(neg); @@ -623,120 +623,138 @@ namespace isc { namespace eval { break; case 5: -#line 91 "parser.yy" // lalr1.cc:859 +#line 97 "parser.yy" // lalr1.cc:859 { - TokenPtr eq(new TokenEqual()); - ctx.expression.push_back(eq); + TokenPtr neg(new TokenAnd()); + ctx.expression.push_back(neg); } #line 632 "parser.cc" // lalr1.cc:859 break; case 6: -#line 96 "parser.yy" // lalr1.cc:859 +#line 102 "parser.yy" // lalr1.cc:859 { - TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS)); - ctx.expression.push_back(opt); + TokenPtr neg(new TokenOr()); + ctx.expression.push_back(neg); } #line 641 "parser.cc" // lalr1.cc:859 break; case 7: -#line 103 "parser.yy" // lalr1.cc:859 +#line 107 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + TokenPtr eq(new TokenEqual()); + ctx.expression.push_back(eq); + } #line 650 "parser.cc" // lalr1.cc:859 break; case 8: -#line 108 "parser.yy" // lalr1.cc:859 +#line 112 "parser.yy" // lalr1.cc:859 { - TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(hex); - } + TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), TokenOption::EXISTS)); + ctx.expression.push_back(opt); + } #line 659 "parser.cc" // lalr1.cc:859 break; case 9: -#line 113 "parser.yy" // lalr1.cc:859 +#line 119 "parser.yy" // lalr1.cc:859 { - TokenPtr opt(new TokenOption(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ())); - ctx.expression.push_back(opt); + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); } #line 668 "parser.cc" // lalr1.cc:859 break; case 10: -#line 118 "parser.yy" // lalr1.cc:859 +#line 124 "parser.yy" // lalr1.cc:859 { - TokenPtr sub(new TokenSubstring()); - ctx.expression.push_back(sub); + TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(hex); } #line 677 "parser.cc" // lalr1.cc:859 break; - case 12: -#line 127 "parser.yy" // lalr1.cc:859 + case 11: +#line 129 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); - } -#line 685 "parser.cc" // lalr1.cc:859 + 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 break; - case 13: -#line 131 "parser.yy" // lalr1.cc:859 + case 12: +#line 134 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); - } -#line 693 "parser.cc" // lalr1.cc:859 + TokenPtr sub(new TokenSubstring()); + ctx.expression.push_back(sub); + } +#line 695 "parser.cc" // lalr1.cc:859 break; case 14: -#line 137 "parser.yy" // lalr1.cc:859 +#line 143 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; - } -#line 701 "parser.cc" // lalr1.cc:859 + yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location); + } +#line 703 "parser.cc" // lalr1.cc:859 break; case 15: -#line 141 "parser.yy" // lalr1.cc:859 +#line 147 "parser.yy" // lalr1.cc:859 { - yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; - } -#line 709 "parser.cc" // lalr1.cc:859 + yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location); + } +#line 711 "parser.cc" // lalr1.cc:859 break; case 16: -#line 147 "parser.yy" // lalr1.cc:859 +#line 153 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } -#line 718 "parser.cc" // lalr1.cc:859 + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL; + } +#line 719 "parser.cc" // lalr1.cc:859 break; case 17: -#line 154 "parser.yy" // lalr1.cc:859 +#line 157 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); - ctx.expression.push_back(str); - } + yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL; + } #line 727 "parser.cc" // lalr1.cc:859 break; case 18: -#line 159 "parser.yy" // lalr1.cc:859 +#line 163 "parser.yy" // lalr1.cc:859 { - TokenPtr str(new TokenString("all")); + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); ctx.expression.push_back(str); } #line 736 "parser.cc" // lalr1.cc:859 break; + case 19: +#line 170 "parser.yy" // lalr1.cc:859 + { + TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); + ctx.expression.push_back(str); + } +#line 745 "parser.cc" // lalr1.cc:859 + break; -#line 740 "parser.cc" // lalr1.cc:859 + case 20: +#line 175 "parser.yy" // lalr1.cc:859 + { + TokenPtr str(new TokenString("all")); + ctx.expression.push_back(str); + } +#line 754 "parser.cc" // lalr1.cc:859 + break; + + +#line 758 "parser.cc" // lalr1.cc:859 default: break; } @@ -998,77 +1016,79 @@ namespace isc { namespace eval { const signed char EvalParser::yypact_[] = { - -4, -7, 15, -4, -4, -14, -14, -14, 12, -14, - 11, -13, -1, -14, 16, -14, -1, -14, -14, 13, - 18, 19, -14, -14, 21, -13, 20, 14, 24, -14, - 22, -14, -14, -14, -14, 25, 1, 17, -14, -14, - 27, -14 + -4, -9, -5, -4, -4, -14, -14, -14, 35, 20, + 18, -13, -1, -14, -2, -14, -4, -4, -1, -14, + -14, 19, 22, 26, -14, -14, 29, -14, 25, -13, + 23, 21, 27, -14, 28, -14, -14, -14, -14, 31, + 4, 24, -14, -14, 30, -14 }; const unsigned char EvalParser::yydefact_[] = { - 0, 0, 0, 0, 0, 7, 8, 11, 0, 2, - 0, 0, 0, 4, 0, 1, 0, 12, 13, 0, - 0, 0, 3, 5, 0, 0, 0, 0, 0, 16, - 0, 14, 15, 6, 9, 0, 0, 0, 18, 17, - 0, 10 + 0, 0, 0, 0, 0, 9, 10, 13, 0, 2, + 0, 0, 0, 4, 0, 1, 0, 0, 0, 14, + 15, 0, 0, 0, 3, 5, 6, 7, 0, 0, + 0, 0, 0, 18, 0, 16, 17, 8, 11, 0, + 0, 0, 20, 19, 0, 12 }; const signed char EvalParser::yypgoto_[] = { - -14, -14, 23, -6, 10, -14, -14, -14 + -14, -14, 9, 11, 12, -14, -14, -14 }; const signed char EvalParser::yydefgoto_[] = { - -1, 8, 9, 10, 19, 34, 30, 40 + -1, 8, 9, 10, 21, 38, 34, 44 }; const unsigned char EvalParser::yytable_[] = { - 1, 2, 3, 20, 2, 17, 21, 18, 11, 4, - 23, 38, 15, 5, 16, 6, 5, 7, 6, 39, - 7, 31, 32, 33, 31, 32, 13, 14, 12, 24, - 22, 26, 27, 25, 36, 28, 37, 0, 29, 0, - 35, 41 + 1, 2, 3, 22, 2, 16, 17, 19, 11, 20, + 12, 4, 13, 14, 24, 5, 42, 6, 5, 7, + 6, 18, 7, 23, 43, 25, 26, 16, 17, 27, + 35, 36, 37, 35, 36, 15, 16, 28, 31, 29, + 30, 32, 40, 33, 41, 39, 45 }; - const signed char + const unsigned char EvalParser::yycheck_[] = { - 4, 5, 6, 4, 5, 18, 12, 20, 15, 13, - 16, 10, 0, 17, 3, 19, 17, 21, 19, 18, - 21, 7, 8, 9, 7, 8, 3, 4, 13, 16, - 14, 12, 11, 15, 12, 25, 11, -1, 18, -1, - 16, 14 + 4, 5, 6, 4, 5, 7, 8, 20, 17, 22, + 15, 15, 3, 4, 16, 19, 12, 21, 19, 23, + 21, 3, 23, 12, 20, 16, 17, 7, 8, 18, + 9, 10, 11, 9, 10, 0, 7, 18, 13, 17, + 14, 29, 14, 20, 13, 18, 16 }; const unsigned char EvalParser::yystos_[] = { - 0, 4, 5, 6, 13, 17, 19, 21, 23, 24, - 25, 15, 13, 24, 24, 0, 3, 18, 20, 26, - 4, 25, 14, 25, 16, 15, 12, 11, 26, 18, - 28, 7, 8, 9, 27, 16, 12, 11, 10, 18, - 29, 14 + 0, 4, 5, 6, 15, 19, 21, 23, 25, 26, + 27, 17, 15, 26, 26, 0, 7, 8, 3, 20, + 22, 28, 4, 27, 16, 26, 26, 27, 18, 17, + 14, 13, 28, 20, 30, 9, 10, 11, 29, 18, + 14, 13, 12, 20, 31, 16 }; const unsigned char EvalParser::yyr1_[] = { - 0, 22, 23, 24, 24, 24, 24, 25, 25, 25, - 25, 25, 26, 26, 27, 27, 28, 29, 29 + 0, 24, 25, 26, 26, 26, 26, 26, 26, 27, + 27, 27, 27, 27, 28, 28, 29, 29, 30, 31, + 31 }; const unsigned char EvalParser::yyr2_[] = { - 0, 2, 1, 3, 2, 3, 6, 1, 1, 6, - 8, 1, 1, 1, 1, 1, 1, 1, 1 + 0, 2, 1, 3, 2, 3, 3, 3, 6, 1, + 1, 6, 8, 1, 1, 1, 1, 1, 1, 1, + 1 }; @@ -1079,9 +1099,9 @@ namespace isc { namespace eval { const EvalParser::yytname_[] = { "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"", - "\"substring\"", "\"not\"", "\"text\"", "\"hex\"", "\"exists\"", - "\"all\"", "\".\"", "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", - "\"constant string\"", "\"integer\"", "\"constant hexstring\"", + "\"substring\"", "\"not\"", "\"and\"", "\"or\"", "\"text\"", "\"hex\"", + "\"exists\"", "\"all\"", "\".\"", "\",\"", "\"(\"", "\")\"", "\"[\"", + "\"]\"", "\"constant string\"", "\"integer\"", "\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept", "expression", "bool_expr", "string_expr", "option_code", "option_repr_type", "start_expr", "length_expr", YY_NULLPTR @@ -1091,8 +1111,9 @@ namespace isc { namespace eval { const unsigned char EvalParser::yyrline_[] = { - 0, 81, 81, 84, 85, 90, 95, 102, 107, 112, - 117, 122, 126, 130, 136, 140, 146, 153, 158 + 0, 87, 87, 90, 91, 96, 101, 106, 111, 118, + 123, 128, 133, 138, 142, 146, 152, 156, 162, 169, + 174 }; // Print the state stack on the debug stream. @@ -1127,8 +1148,8 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:1167 } } // isc::eval -#line 1131 "parser.cc" // lalr1.cc:1167 -#line 165 "parser.yy" // lalr1.cc:1168 +#line 1152 "parser.cc" // lalr1.cc:1167 +#line 181 "parser.yy" // lalr1.cc:1168 void isc::eval::EvalParser::error(const location_type& loc, diff --git a/src/lib/eval/parser.h b/src/lib/eval/parser.h index 1d2bd0a10c..9f76e82eae 100644 --- a/src/lib/eval/parser.h +++ b/src/lib/eval/parser.h @@ -334,21 +334,23 @@ namespace isc { namespace eval { TOKEN_OPTION = 259, TOKEN_SUBSTRING = 260, TOKEN_NOT = 261, - TOKEN_TEXT = 262, - TOKEN_HEX = 263, - TOKEN_EXISTS = 264, - TOKEN_ALL = 265, - TOKEN_DOT = 266, - TOKEN_COMA = 267, - TOKEN_LPAREN = 268, - TOKEN_RPAREN = 269, - TOKEN_LBRACKET = 270, - TOKEN_RBRACKET = 271, - TOKEN_STRING = 272, - TOKEN_INTEGER = 273, - TOKEN_HEXSTRING = 274, - TOKEN_OPTION_NAME = 275, - TOKEN_TOKEN = 276 + TOKEN_AND = 262, + TOKEN_OR = 263, + TOKEN_TEXT = 264, + TOKEN_HEX = 265, + TOKEN_EXISTS = 266, + TOKEN_ALL = 267, + TOKEN_DOT = 268, + TOKEN_COMA = 269, + TOKEN_LPAREN = 270, + TOKEN_RPAREN = 271, + TOKEN_LBRACKET = 272, + TOKEN_RBRACKET = 273, + TOKEN_STRING = 274, + TOKEN_INTEGER = 275, + TOKEN_HEXSTRING = 276, + TOKEN_OPTION_NAME = 277, + TOKEN_TOKEN = 278 }; }; @@ -479,6 +481,14 @@ namespace isc { namespace eval { symbol_type make_NOT (const location_type& l); + static inline + symbol_type + make_AND (const location_type& l); + + static inline + symbol_type + make_OR (const location_type& l); + static inline symbol_type make_TEXT (const location_type& l); @@ -624,7 +634,7 @@ namespace isc { namespace eval { // number is the opposite. If YYTABLE_NINF, syntax error. static const unsigned char yytable_[]; - static const signed char yycheck_[]; + static const unsigned char yycheck_[]; // YYSTOS[STATE-NUM] -- The (internal number of the) accessing // symbol of state STATE-NUM. @@ -744,12 +754,12 @@ namespace isc { namespace eval { enum { yyeof_ = 0, - yylast_ = 41, ///< Last index in yytable_. + yylast_ = 46, ///< Last index in yytable_. yynnts_ = 8, ///< Number of nonterminal symbols. yyfinal_ = 15, ///< Termination state number. yyterror_ = 1, yyerrcode_ = 256, - yyntokens_ = 22 ///< Number of tokens. + yyntokens_ = 24 ///< Number of tokens. }; @@ -793,9 +803,9 @@ namespace isc { namespace eval { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21 + 15, 16, 17, 18, 19, 20, 21, 22, 23 }; - const unsigned int user_token_number_max_ = 276; + const unsigned int user_token_number_max_ = 278; const token_number_type undef_token_ = 2; if (static_cast(t) <= yyeof_) @@ -828,19 +838,19 @@ namespace isc { namespace eval { { switch (other.type_get ()) { - case 27: // option_repr_type + case 29: // option_repr_type value.copy< TokenOption::RepresentationType > (other.value); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN value.copy< std::string > (other.value); break; - case 26: // option_code + case 28: // option_code value.copy< uint16_t > (other.value); break; @@ -861,19 +871,19 @@ namespace isc { namespace eval { (void) v; switch (this->type_get ()) { - case 27: // option_repr_type + case 29: // option_repr_type value.copy< TokenOption::RepresentationType > (v); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN value.copy< std::string > (v); break; - case 26: // option_code + case 28: // option_code value.copy< uint16_t > (v); break; @@ -939,19 +949,19 @@ namespace isc { namespace eval { // Type destructor. switch (yytype) { - case 27: // option_repr_type + case 29: // option_repr_type value.template destroy< TokenOption::RepresentationType > (); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN value.template destroy< std::string > (); break; - case 26: // option_code + case 28: // option_code value.template destroy< uint16_t > (); break; @@ -978,19 +988,19 @@ namespace isc { namespace eval { super_type::move(s); switch (this->type_get ()) { - case 27: // option_repr_type + case 29: // option_repr_type value.move< TokenOption::RepresentationType > (s.value); break; - case 17: // "constant string" - case 18: // "integer" - case 19: // "constant hexstring" - case 20: // "option name" - case 21: // TOKEN + case 19: // "constant string" + case 20: // "integer" + case 21: // "constant hexstring" + case 22: // "option name" + case 23: // TOKEN value.move< std::string > (s.value); break; - case 26: // option_code + case 28: // option_code value.move< uint16_t > (s.value); break; @@ -1051,7 +1061,7 @@ namespace isc { namespace eval { { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276 + 275, 276, 277, 278 }; return static_cast (yytoken_number_[type]); } @@ -1086,6 +1096,18 @@ namespace isc { namespace eval { return symbol_type (token::TOKEN_NOT, l); } + EvalParser::symbol_type + EvalParser::make_AND (const location_type& l) + { + return symbol_type (token::TOKEN_AND, l); + } + + EvalParser::symbol_type + EvalParser::make_OR (const location_type& l) + { + return symbol_type (token::TOKEN_OR, l); + } + EvalParser::symbol_type EvalParser::make_TEXT (const location_type& l) { @@ -1179,7 +1201,7 @@ namespace isc { namespace eval { #line 21 "parser.yy" // lalr1.cc:392 } } // isc::eval -#line 1183 "parser.h" // lalr1.cc:392 +#line 1205 "parser.h" // lalr1.cc:392 diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index fda62bab5e..7ddedfe1a2 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -48,6 +48,8 @@ using namespace isc::eval; OPTION "option" SUBSTRING "substring" NOT "not" + AND "and" + OR "or" TEXT "text" HEX "hex" EXISTS "exists" @@ -69,6 +71,10 @@ using namespace isc::eval; %type option_code %type option_repr_type +%left OR +%left AND +%precedence NOT + %printer { yyoutput << $$; } <*>; %% @@ -87,6 +93,16 @@ bool_expr : "(" bool_expr ")" TokenPtr neg(new TokenNot()); ctx.expression.push_back(neg); } + | bool_expr AND bool_expr + { + TokenPtr neg(new TokenAnd()); + ctx.expression.push_back(neg); + } + | bool_expr OR bool_expr + { + TokenPtr neg(new TokenOr()); + ctx.expression.push_back(neg); + } | string_expr EQUAL string_expr { TokenPtr eq(new TokenEqual()); @@ -120,7 +136,7 @@ string_expr : STRING ctx.expression.push_back(sub); } | TOKEN - // Temporary unused token to avoid explict but long errors + // Temporary unused token to avoid explicit but long errors ; option_code : INTEGER diff --git a/src/lib/eval/position.hh b/src/lib/eval/position.hh index 28ec48963a..d314a8426c 100644 --- a/src/lib/eval/position.hh +++ b/src/lib/eval/position.hh @@ -1,4 +1,4 @@ -// Generated 20151207 +// Generated 20151209 // A Bison parser, made by GNU Bison 3.0.4. // Positions for Bison parsers in C++ diff --git a/src/lib/eval/stack.hh b/src/lib/eval/stack.hh index 39dfd940f5..14b0aeb4dd 100644 --- a/src/lib/eval/stack.hh +++ b/src/lib/eval/stack.hh @@ -1,4 +1,4 @@ -// Generated 20151207 +// Generated 20151209 // A Bison parser, made by GNU Bison 3.0.4. // Stack handling for Bison parsers in C++ diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index bded550b07..fbb5e3f508 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -348,9 +348,19 @@ TEST_F(EvalContextTest, parseErrors) { checkError("'foo''bar'", ":1.6-10: syntax error, unexpected constant string, " "expecting =="); + checkError("'foo' (", + ":1.7: syntax error, unexpected (, expecting =="); checkError("== 'ab'", ":1.1-2: syntax error, unexpected =="); checkError("'foo' ==", ":1.9: syntax error, unexpected end of file"); + checkError("('foo' == 'bar'", + ":1.16: syntax error, unexpected end of file, " + "expecting and or or or )"); + checkError("('foo' == 'bar') ''", + ":1.18-19: syntax error, unexpected constant string, " + "expecting end of file"); + checkError("not", + ":1.4: syntax error, unexpected end of file"); checkError("not 'foo'", ":1.10: syntax error, unexpected end of file, " "expecting =="); @@ -359,12 +369,24 @@ TEST_F(EvalContextTest, parseErrors) { checkError("(not('foo' 'bar')", ":1.12-16: syntax error, unexpected constant string, " "expecting =="); - checkError("('foo' == 'bar'", - ":1.16: syntax error, unexpected end of file, " - "expecting )"); - checkError("('foo' == 'bar') ''", - ":1.18-19: syntax error, unexpected constant string, " - "expecting end of file"); + checkError("and", + ":1.1-3: syntax error, unexpected and"); + checkError("'foo' and", + ":1.7-9: syntax error, unexpected and, expecting =="); + checkError("'foo' == 'bar' and", + ":1.19: syntax error, unexpected end of file"); + checkError("'foo' == 'bar' and ''", + ":1.22: syntax error, unexpected end of file, " + "expecting =="); + checkError("or", + ":1.1-2: syntax error, unexpected or"); + checkError("'foo' or", + ":1.7-8: syntax error, unexpected or, expecting =="); + checkError("'foo' == 'bar' or", + ":1.18: syntax error, unexpected end of file"); + checkError("'foo' == 'bar' or ''", + ":1.21: syntax error, unexpected end of file, " + "expecting =="); checkError("option 'ab'", ":1.8-11: syntax error, unexpected " "constant string, expecting ["); @@ -398,7 +420,7 @@ TEST_F(EvalContextTest, parseErrors) { ":1.22: Invalid character: a"); } -// Tests some type error cases (caught only by the strongly typed parser) +// Tests some type error cases TEST_F(EvalContextTest, typeErrors) { checkError("'foobar'", ":1.9: syntax error, unexpected end of file, " @@ -412,6 +434,13 @@ TEST_F(EvalContextTest, typeErrors) { checkError("('foo' == 'bar') == 'false'", ":1.18-19: syntax error, unexpected ==, " "expecting end of file"); + checkError("not 'true'", + ":1.11: syntax error, unexpected end of file, " + "expecting =="); + checkError("'true' and 'false'", + ":1.8-10: syntax error, unexpected and, expecting =="); + checkError("'true' or 'false'", + ":1.8-9: syntax error, unexpected or, expecting =="); } }; diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index 3652a97ea8..0fcf98f3fc 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -484,6 +484,138 @@ TEST_F(TokenTest, optionNot) { EXPECT_EQ("true", values_.top()); } +// This test checks if a token representing an and is able to +// conjugate two values (with incorrectly built stack). +TEST_F(TokenTest, optionAndInvalid) { + + ASSERT_NO_THROW(t_.reset(new TokenAnd())); + + // CASE 1: There's not enough values on the stack. and is an operator that + // takes two parameters. There are 0 on the stack. + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack); + + // CASE 2: One value is still not enough. + values_.push("foo"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack); + + // CASE 3: The two values must be logical + values_.push("true"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError); + + // Swap the 2 values + values_.push("true"); + values_.push("foo"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError); +} + +// This test checks if a token representing an and operator is able to +// conjugate false with another logical +TEST_F(TokenTest, optionAndFalse) { + + ASSERT_NO_THROW(t_.reset(new TokenAnd())); + + values_.push("true"); + values_.push("false"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + + // After evaluation there should be a single "false" value + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("false", values_.top()); + + // After true and false, checks false and true + values_.push("true"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("false", values_.top()); + + // And false and false + values_.push("false"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("false", values_.top()); +} + +// This test checks if a token representing an and is able to +// conjugate two true values. +TEST_F(TokenTest, optionAndTrue) { + + ASSERT_NO_THROW(t_.reset(new TokenAnd())); + + values_.push("true"); + values_.push("true"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + + // After evaluation there should be a single "true" value + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("true", values_.top()); +} + +// This test checks if a token representing an or is able to +// combinate two values (with incorrectly built stack). +TEST_F(TokenTest, optionOrInvalid) { + + ASSERT_NO_THROW(t_.reset(new TokenOr())); + + // CASE 1: There's not enough values on the stack. or is an operator that + // takes two parameters. There are 0 on the stack. + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack); + + // CASE 2: One value is still not enough. + values_.push("foo"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack); + + // CASE 3: The two values must be logical + values_.push("true"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError); + + // Swap the 2 values + values_.push("true"); + values_.push("foo"); + EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError); +} + +// This test checks if a token representing an or is able to +// conjugate two false values. +TEST_F(TokenTest, optionOrFalse) { + + ASSERT_NO_THROW(t_.reset(new TokenOr())); + + values_.push("false"); + values_.push("false"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + + // After evaluation there should be a single "false" value + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("false", values_.top()); +} + +// This test checks if a token representing an == operator is able to +// conjugate true with another logical +TEST_F(TokenTest, optionOrTrue) { + + ASSERT_NO_THROW(t_.reset(new TokenOr())); + + values_.push("false"); + values_.push("true"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + + // After evaluation there should be a single "true" value + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("true", values_.top()); + + // After false or true, checks true or false + values_.push("false"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("true", values_.top()); + + // And true or true + values_.push("true"); + EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_)); + ASSERT_EQ(1, values_.size()); + EXPECT_EQ("true", values_.top()); +} + }; // This test checks if an a token representing a substring request diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index f528c50d71..289caa03d6 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -200,3 +200,74 @@ TokenNot::evaluate(const Pkt& /*pkt*/, ValueStack& values) { << "Got '" << op << "'."); } } + +void +TokenAnd::evaluate(const Pkt& /*pkt*/, ValueStack& values) { + + if (values.size() < 2) { + isc_throw(EvalBadStack, "Incorrect stack order. Expected at least " + "2 values for and operator, got " << values.size()); + } + + string op1 = values.top(); + values.pop(); + string op2 = values.top(); + values.pop(); // Dammit, std::stack interface is awkward. + + if (op1 == "true") { + if (op2 == "true") { + values.push("true"); + } else if (op2 == "false") { + values.push("false"); + } else { + isc_throw(EvalTypeError, "Expected logical values at " + << "top of stack. Got 'true' and '" << op2 << "'"); + } + } else if (op1 == "false") { + if ((op2 == "true") || (op2 == "false")) { + values.push("false"); + } else { + isc_throw(EvalTypeError, "Expected logical values at " + << "top of stack. Got 'false' and '" << op2 << "'"); + } + } else { + isc_throw(EvalTypeError, "Expected logical values at top of stack. " + << "Got '" << op1 << "' and '" << op2 << "'"); + } +} + +void +TokenOr::evaluate(const Pkt& /*pkt*/, ValueStack& values) { + + if (values.size() < 2) { + isc_throw(EvalBadStack, "Incorrect stack order. Expected at least " + "2 values for or operator, got " << values.size()); + } + + string op1 = values.top(); + values.pop(); + string op2 = values.top(); + values.pop(); // Dammit, std::stack interface is awkward. + + if (op1 == "true") { + if ((op2 == "true") || (op2 == "false")) { + values.push("true"); + } else { + isc_throw(EvalTypeError, "Expected logical values at " + << "top of stack. Got 'true' and '" << op2 << "'"); + } + } else if (op1 == "false") { + if (op2 == "true") { + values.push("true"); + } else if (op2 == "false") { + values.push("false"); + } else { + isc_throw(EvalTypeError, "Expected logical values at " + << "top of stack. Got 'false' and '" << op2 << "'"); + } + } else { + isc_throw(EvalTypeError, "Expected logical values at top of stack. " + << "Got '" << op1 << "' and '" << op2 << "'"); + } +} + diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index e06ad43b6f..eacf51f905 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -304,6 +304,56 @@ public: void evaluate(const Pkt& pkt, ValueStack& values); }; +/// @brief Token that represents logical and operator +/// +/// For example "option[10].exists and option[11].exists" +class TokenAnd : public Token { +public: + /// @brief Constructor (does nothing) + TokenAnd() {} + + /// @brief Logical and. + /// + /// Evaluation does not use packet information, but rather consumes the last + /// two parameters. It returns "true" if and only if both are "true". + /// It requires at least two logical (i.e., "true" or "false') values + /// present on stack. + /// + /// @throw EvalBadStack if there are less than 2 values on stack + /// @throw EvalTypeError if one of the 2 values on stack is not + /// "true" or "false" + /// + /// @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 or operator +/// +/// For example "option[10].exists or option[11].exists" +class TokenOr : public Token { +public: + /// @brief Constructor (does nothing) + TokenOr() {} + + /// @brief Logical or. + /// + /// Evaluation does not use packet information, but rather consumes the last + /// two parameters. It returns "false" if and only if both are "false". + /// It requires at least two logical (i.e., "true" or "false') values + /// present on stack. + /// + /// @throw EvalBadStack if there are less than 2 values on stack + /// @throw EvalTypeError if one of the 2 values on stack is not + /// "true" or "false" + /// + /// @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); +}; + }; // end of isc::dhcp namespace }; // end of isc namespace From 723117cf2887b7f8a23b4e596a21dc8122936bf3 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Thu, 10 Dec 2015 00:11:47 +0100 Subject: [PATCH 5/9] [4231] more parsing unit tests --- src/lib/eval/tests/context_unittest.cc | 77 ++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index fbb5e3f508..d6f2f42659 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -271,6 +271,83 @@ TEST_F(EvalContextTest, optionHex) { checkTokenOption(eval.expression.at(0), 123); } +// Test parsing of logical operators +TEST_F(EvalContextTest, logicalOps) { + // option.exists + EvalContext eval0(Option::V4); + EXPECT_NO_THROW(parsed_ = eval0.parseString("option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(1, eval0.expression.size()); + TokenPtr token = eval0.expression.at(0); + ASSERT_TRUE(token); + boost::shared_ptr opt = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(opt); + + // not + EvalContext evaln(Option::V4); + EXPECT_NO_THROW(parsed_ = evaln.parseString("not option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(2, evaln.expression.size()); + token = evaln.expression.at(1); + ASSERT_TRUE(token); + boost::shared_ptr tnot = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tnot); + + // and + EvalContext evala(Option::V4); + EXPECT_NO_THROW(parsed_ = + evala.parseString("option[123].exists and option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(3, evala.expression.size()); + token = evala.expression.at(2); + ASSERT_TRUE(token); + boost::shared_ptr tand = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tand); + + // or + EvalContext evalo(Option::V4); + EXPECT_NO_THROW(parsed_ = + evalo.parseString("option[123].exists or option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(3, evalo.expression.size()); + token = evalo.expression.at(2); + ASSERT_TRUE(token); + boost::shared_ptr tor = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tor); +} + +// Test parsing of logical operators with precedence +TEST_F(EvalContextTest, logicalPrecedence) { + // not precedence > and precedence + EvalContext evalna(Option::V4); + EXPECT_NO_THROW(parsed_ = + evalna.parseString("not option[123].exists and option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(4, evalna.expression.size()); + TokenPtr token = evalna.expression.at(3); + ASSERT_TRUE(token); + boost::shared_ptr tand = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tand); + + // and precedence > or precedence + EvalContext evaloa(Option::V4); + EXPECT_NO_THROW(parsed_ = + evaloa.parseString("option[123].exists or option[123].exists " + "and option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(5, evaloa.expression.size()); + token = evaloa.expression.at(4); + ASSERT_TRUE(token); + boost::shared_ptr tor = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tor); +} + // Test the parsing of a substring expression TEST_F(EvalContextTest, substring) { EvalContext eval(Option::V4); From 732af87d48ee1b4cb81f6abfadd7cfa3567e50bb Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Mon, 15 Feb 2016 16:47:27 +0100 Subject: [PATCH 6/9] [4231] Addressed code comments --- src/lib/eval/evaluate.cc | 11 +--- src/lib/eval/lexer.cc | 2 +- src/lib/eval/lexer.ll | 2 +- src/lib/eval/parser.yy | 2 +- src/lib/eval/tests/Makefile.am | 3 +- src/lib/eval/tests/boolean_unittest.cc | 72 +++++++++++++++++++++++++ src/lib/eval/tests/context_unittest.cc | 2 +- src/lib/eval/tests/evaluate_unittest.cc | 2 +- src/lib/eval/tests/token_unittest.cc | 20 ++++++- src/lib/eval/token.cc | 59 ++++++-------------- src/lib/eval/token.h | 20 ++++++- 11 files changed, 134 insertions(+), 61 deletions(-) create mode 100644 src/lib/eval/tests/boolean_unittest.cc diff --git a/src/lib/eval/evaluate.cc b/src/lib/eval/evaluate.cc index a70ee2c6ed..dd5e0af68d 100644 --- a/src/lib/eval/evaluate.cc +++ b/src/lib/eval/evaluate.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -27,14 +27,7 @@ bool evaluate(const Expression& expr, const Pkt& pkt) { isc_throw(EvalBadStack, "Incorrect stack order. Expected exactly " "1 value at the end of evaluatuion, got " << values.size()); } - if (values.top() == "false") { - return (false); - } else if (values.top() == "true") { - return (true); - } else { - isc_throw(EvalTypeError, "Incorrect evaluation type. Expected " - "\"false\" or \"true\", got \"" << values.top() << "\""); - } + return (Token::toBool(values.top())); } }; // end of isc::dhcp namespace diff --git a/src/lib/eval/lexer.cc b/src/lib/eval/lexer.cc index 99843f2814..b9fbae02b5 100644 --- a/src/lib/eval/lexer.cc +++ b/src/lib/eval/lexer.cc @@ -665,7 +665,7 @@ goto find_rule; \ #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "lexer.ll" -/* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +/* Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index ff458cc0c6..238c131356 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +/* Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 7ddedfe1a2..786a22546b 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +/* Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/src/lib/eval/tests/Makefile.am b/src/lib/eval/tests/Makefile.am index 77d0ad2bf1..b284fb01e5 100644 --- a/src/lib/eval/tests/Makefile.am +++ b/src/lib/eval/tests/Makefile.am @@ -26,7 +26,8 @@ if HAVE_GTEST TESTS += libeval_unittests -libeval_unittests_SOURCES = context_unittest.cc +libeval_unittests_SOURCES = boolean_unittest.cc +libeval_unittests_SOURCES += context_unittest.cc libeval_unittests_SOURCES += evaluate_unittest.cc libeval_unittests_SOURCES += token_unittest.cc libeval_unittests_SOURCES += run_unittests.cc diff --git a/src/lib/eval/tests/boolean_unittest.cc b/src/lib/eval/tests/boolean_unittest.cc new file mode 100644 index 0000000000..5e478ea0fb --- /dev/null +++ b/src/lib/eval/tests/boolean_unittest.cc @@ -0,0 +1,72 @@ +// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace isc::dhcp; + +namespace { + +/// @brief Test fixture for testing booleans. +class BooleanTest : public ::testing::Test { +public: + void check(const string& expr, bool expected) { + EvalContext eval(Option::V4); + ASSERT_TRUE(eval.parseString(expr)); + Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 12345)); + if (expected) { + EXPECT_TRUE(evaluate(eval.expression, *pkt4)); + } else { + EXPECT_FALSE(evaluate(eval.expression, *pkt4)); + } + } +}; + +// A group of tests +TEST_F(BooleanTest, tests) { + // true and (false or false) + check("('a' == 'a') and (('a' == 'b') or ('b' == 'a'))", false); + // (true and false) or false + check("(('a' == 'a') and ('a' == 'b')) or ('b' == 'a')", false); + // not true + check("not ('a' == 'a')", false); + // not false + check("not ('a' == 'b')", true); + // true and true and true and false + check("('a' == 'a') and ('b' == 'b') and ('c' == 'c') and ('a' == 'c')", + false); + // false or false or false or true + check("('a' == 'b') or ('a' == 'c') or ('b' == 'c') or ('b' == 'b')", + true); + // true or false or false or false + check("('a' == 'a') or ('a' == 'b') or ('a' == 'c') or ('b' == 'c')", + true); + // not (true or false) + check("not (('a' == 'a') or ('a' == 'b'))", false); + // not (true and false) + check("not (('a' == 'a') and ('a' == 'b'))", true); + // (not true) and false + check("(not ('a' == 'a')) and ('a' == 'b')",false); +} + +}; diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index d6f2f42659..f7164a85bd 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above diff --git a/src/lib/eval/tests/evaluate_unittest.cc b/src/lib/eval/tests/evaluate_unittest.cc index 0fde9bce82..0b575cad64 100644 --- a/src/lib/eval/tests/evaluate_unittest.cc +++ b/src/lib/eval/tests/evaluate_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc index 0fcf98f3fc..46d0471ed2 100644 --- a/src/lib/eval/tests/token_unittest.cc +++ b/src/lib/eval/tests/token_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -106,6 +106,24 @@ public: /// @todo: Add more option types here }; +// This tests the toBool() conversions +TEST_F(TokenTest, toBool) { + + ASSERT_NO_THROW(Token::toBool("true")); + EXPECT_TRUE(Token::toBool("true")); + ASSERT_NO_THROW(Token::toBool("false")); + EXPECT_FALSE(Token::toBool("false")); + + // Token::toBool() is case-sensitive + EXPECT_THROW(Token::toBool("True"), EvalTypeError); + EXPECT_THROW(Token::toBool("TRUE"), EvalTypeError); + + // Proposed aliases + EXPECT_THROW(Token::toBool("1"), EvalTypeError); + EXPECT_THROW(Token::toBool("0"), EvalTypeError); + EXPECT_THROW(Token::toBool(""), EvalTypeError); +} + // This simple test checks that a TokenString, representing a constant string, // can be used in Pkt4 evaluation. (The actual packet is not used) TEST_F(TokenTest, string4) { diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc index 289caa03d6..f14ebe6428 100644 --- a/src/lib/eval/token.cc +++ b/src/lib/eval/token.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -190,14 +190,12 @@ TokenNot::evaluate(const Pkt& /*pkt*/, ValueStack& values) { string op = values.top(); values.pop(); + bool val = toBool(op); - if (op == "true") { - values.push("false"); - } else if (op == "false") { - values.push("true"); + if (val) { + values.push("false"); } else { - isc_throw(EvalTypeError, "Expected a logical value at top of stack. " - << "Got '" << op << "'."); + values.push("true"); } } @@ -211,28 +209,15 @@ TokenAnd::evaluate(const Pkt& /*pkt*/, ValueStack& values) { string op1 = values.top(); values.pop(); + bool val1 = toBool(op1); string op2 = values.top(); values.pop(); // Dammit, std::stack interface is awkward. + bool val2 = toBool(op2); - if (op1 == "true") { - if (op2 == "true") { - values.push("true"); - } else if (op2 == "false") { - values.push("false"); - } else { - isc_throw(EvalTypeError, "Expected logical values at " - << "top of stack. Got 'true' and '" << op2 << "'"); - } - } else if (op1 == "false") { - if ((op2 == "true") || (op2 == "false")) { - values.push("false"); - } else { - isc_throw(EvalTypeError, "Expected logical values at " - << "top of stack. Got 'false' and '" << op2 << "'"); - } + if (val1 && val2) { + values.push("true"); } else { - isc_throw(EvalTypeError, "Expected logical values at top of stack. " - << "Got '" << op1 << "' and '" << op2 << "'"); + values.push("false"); } } @@ -246,28 +231,14 @@ TokenOr::evaluate(const Pkt& /*pkt*/, ValueStack& values) { string op1 = values.top(); values.pop(); + bool val1 = toBool(op1); string op2 = values.top(); values.pop(); // Dammit, std::stack interface is awkward. + bool val2 = toBool(op2); - if (op1 == "true") { - if ((op2 == "true") || (op2 == "false")) { - values.push("true"); - } else { - isc_throw(EvalTypeError, "Expected logical values at " - << "top of stack. Got 'true' and '" << op2 << "'"); - } - } else if (op1 == "false") { - if (op2 == "true") { - values.push("true"); - } else if (op2 == "false") { - values.push("false"); - } else { - isc_throw(EvalTypeError, "Expected logical values at " - << "top of stack. Got 'false' and '" << op2 << "'"); - } + if (val1 || val2) { + values.push("true"); } else { - isc_throw(EvalTypeError, "Expected logical values at top of stack. " - << "Got '" << op1 << "' and '" << op2 << "'"); + values.push("false"); } } - diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h index eacf51f905..073c4a40c9 100644 --- a/src/lib/eval/token.h +++ b/src/lib/eval/token.h @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -87,6 +87,24 @@ public: /// @brief Virtual destructor virtual ~Token() {} + + /// @brief Coverts a (string) value to a boolean + /// + /// Only "true" and "false" are expected. + /// + /// @param the (string) value + /// @return the boolean represented by the value + /// @throw EvalTypeError when the value is not either "true" or "false". + static inline bool toBool(std::string value) { + if (value == "true") { + return (true); + } else if (value == "false") { + return (false); + } else { + isc_throw(EvalTypeError, "Incorrect boolean. Expected exactly " + "\"false\" or \"true\", got \"" << value << "\""); + } + } }; /// @brief Token representing a constant string From 2cc2e7e0ebebb8acc8037038d4095d8d67ac5363 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Mon, 15 Feb 2016 17:10:09 +0100 Subject: [PATCH 7/9] [4231] Added doc --- doc/guide/classify.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index 2fd21bb206..b9eb042686 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -164,6 +164,7 @@ Option Textoption[code].textThe value of the option with code "code" from the packet as text --> Option Hexoption[code].hexThe value of the option with code "code" from the packet as hex +Option Existoption[code].existIf the option with code "code" is present in the packet "true" else "false" @@ -184,6 +185,11 @@ the option payload without the type code or length fields. + + "option[code].exist" checks if an option with the given code is present + in the incoming packet. It can be used with empty options. + + List of Classification Expressions @@ -200,12 +206,24 @@ Equal 'foo' == 'bar'Compare the two values and return "true" or "false" +Not not ('foo' == 'bar')Logical negation +And ('foo' == 'bar') and ('bar' == 'foo')Logical and +Or ('foo' == 'bar') or ('bar' == 'foo')Logical orSubstringsubstring('foobar',0,3)Return the requested substring
+
+ Logical operators + The Not, And and Or logical operators are the common operators. Not + has the highest precedence, Or the lowest. And and Or are (left) + associative, parentheses around a logical expression can be used + to enforce a specific grouping, for instance in "A and (B or C)" + ("A and B or C" means "(A and B) or C"). +
+
Substring The substring operator "substring(value, start, length)" accepts both positive and @@ -362,7 +380,7 @@ - The following example shows restricting access to a DHCPv6 subnet. This + The following example shows restricting access to a DHCPv6 subnet. This configuration will restrict use of the addresses 2001:db8:1::1 to 2001:db8:1::FFFF to members of the "Client_enterprise" class. From 0c554b2287a10d49f8144ad83c7725c5893573d2 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Tue, 16 Feb 2016 09:44:14 +0100 Subject: [PATCH 8/9] [4231] Improved parenthesis doc --- doc/guide/classify.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml index b9eb042686..0aea48ee18 100644 --- a/doc/guide/classify.xml +++ b/doc/guide/classify.xml @@ -221,7 +221,7 @@ has the highest precedence, Or the lowest. And and Or are (left) associative, parentheses around a logical expression can be used to enforce a specific grouping, for instance in "A and (B or C)" - ("A and B or C" means "(A and B) or C"). + (without parentheses "A and B or C" means "(A and B) or C").
From 09233722f695ccaade8f51bed305786972e34640 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Thu, 18 Feb 2016 22:57:39 +0100 Subject: [PATCH 9/9] [4231] Added logicalParentheses as a complement of logicalPrecedence unit tests --- src/lib/eval/tests/context_unittest.cc | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index f7164a85bd..4377e84330 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -348,6 +348,35 @@ TEST_F(EvalContextTest, logicalPrecedence) { EXPECT_TRUE(tor); } +// Test parsing of logical operators with parentheses (same than +// with precedence but using parentheses to overwrite precedence) +TEST_F(EvalContextTest, logicalParentheses) { + // not precedence > and precedence + EvalContext evalna(Option::V4); + EXPECT_NO_THROW(parsed_ = + evalna.parseString("not (option[123].exists and option[123].exists)")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(4, evalna.expression.size()); + TokenPtr token = evalna.expression.at(3); + ASSERT_TRUE(token); + boost::shared_ptr tnot = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tnot); + + // and precedence > or precedence + EvalContext evaloa(Option::V4); + EXPECT_NO_THROW(parsed_ = + evaloa.parseString("(option[123].exists or option[123].exists) " + "and option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(5, evaloa.expression.size()); + token = evaloa.expression.at(4); + ASSERT_TRUE(token); + boost::shared_ptr tand = + boost::dynamic_pointer_cast(token); + EXPECT_TRUE(tand); +} + // Test the parsing of a substring expression TEST_F(EvalContextTest, substring) { EvalContext eval(Option::V4);