Browse Source

[4231] Added not operator

Francis Dupont 9 years ago
parent
commit
a557a43b39

+ 97 - 88
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,
-
-       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
+       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,
+
+       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,
-
-       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
+       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,
+
+       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"
+#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 147 "lexer.ll"
+#line 148 "lexer.ll"
 return isc::eval::EvalParser::make_END(loc);
 	YY_BREAK
-case 20:
+case 21:
 YY_RULE_SETUP
-#line 148 "lexer.ll"
+#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"
 
 
 

+ 1 - 0
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);

+ 115 - 106
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 eq(new TokenEqual());
+                    ctx.expression.push_back(eq);
+                }
+#line 632 "parser.cc" // lalr1.cc:859
+    break;
+
+  case 6:
+#line 97 "parser.yy" // lalr1.cc:859
     {
                       TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
                       ctx.expression.push_back(str);
                   }
-#line 632 "parser.cc" // lalr1.cc:859
+#line 641 "parser.cc" // lalr1.cc:859
     break;
 
-  case 6:
-#line 96 "parser.yy" // lalr1.cc:859
+  case 7:
+#line 102 "parser.yy" // lalr1.cc:859
     {
                       TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
                       ctx.expression.push_back(hex);
                   }
-#line 641 "parser.cc" // lalr1.cc:859
+#line 650 "parser.cc" // lalr1.cc:859
     break;
 
-  case 7:
-#line 101 "parser.yy" // lalr1.cc:859
+  case 8:
+#line 107 "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);
                   }
-#line 650 "parser.cc" // lalr1.cc:859
+#line 659 "parser.cc" // lalr1.cc:859
     break;
 
-  case 8:
-#line 106 "parser.yy" // lalr1.cc:859
+  case 9:
+#line 112 "parser.yy" // lalr1.cc:859
     {
                       TokenPtr sub(new TokenSubstring());
                       ctx.expression.push_back(sub);
                   }
-#line 659 "parser.cc" // lalr1.cc:859
+#line 668 "parser.cc" // lalr1.cc:859
     break;
 
-  case 10:
-#line 115 "parser.yy" // lalr1.cc:859
+  case 11:
+#line 121 "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
+#line 676 "parser.cc" // lalr1.cc:859
     break;
 
-  case 11:
-#line 119 "parser.yy" // lalr1.cc:859
+  case 12:
+#line 125 "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
+#line 684 "parser.cc" // lalr1.cc:859
     break;
 
-  case 12:
-#line 125 "parser.yy" // lalr1.cc:859
+  case 13:
+#line 131 "parser.yy" // lalr1.cc:859
     {
                           yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
                       }
-#line 683 "parser.cc" // lalr1.cc:859
+#line 692 "parser.cc" // lalr1.cc:859
     break;
 
-  case 13:
-#line 129 "parser.yy" // lalr1.cc:859
+  case 14:
+#line 135 "parser.yy" // lalr1.cc:859
     {
                           yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
                       }
-#line 691 "parser.cc" // lalr1.cc:859
+#line 700 "parser.cc" // lalr1.cc:859
     break;
 
-  case 14:
-#line 135 "parser.yy" // lalr1.cc:859
+  case 15:
+#line 141 "parser.yy" // lalr1.cc:859
     {
                      TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
                      ctx.expression.push_back(str);
                  }
-#line 700 "parser.cc" // lalr1.cc:859
+#line 709 "parser.cc" // lalr1.cc:859
     break;
 
-  case 15:
-#line 142 "parser.yy" // lalr1.cc:859
+  case 16:
+#line 148 "parser.yy" // lalr1.cc:859
     {
                       TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
                       ctx.expression.push_back(str);
                   }
-#line 709 "parser.cc" // lalr1.cc:859
+#line 718 "parser.cc" // lalr1.cc:859
     break;
 
-  case 16:
-#line 147 "parser.yy" // lalr1.cc:859
+  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,

+ 59 - 47
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
       };
     };
 
@@ -483,6 +484,10 @@ namespace isc { namespace eval {
 
     static inline
     symbol_type
+    make_NOT (const location_type& l);
+
+    static inline
+    symbol_type
     make_ALL (const location_type& l);
 
     static inline
@@ -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<int>(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<token_type> (yytoken_number_[type]);
   }
@@ -1082,6 +1088,12 @@ namespace isc { namespace eval {
   }
 
   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)
   {
     return symbol_type (token::TOKEN_ALL, 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
 
 
 

+ 6 - 0
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());

+ 8 - 0
src/lib/eval/tests/context_unittest.cc

@@ -341,6 +341,14 @@ TEST_F(EvalContextTest, parseErrors) {
     checkError("== 'ab'", "<string>:1.1-2: syntax error, unexpected ==");
     checkError("'foo' ==",
                "<string>:1.9: syntax error, unexpected end of file");
+    checkError("not 'foo'",
+               "<string>:1.10: syntax error, unexpected end of file, "
+               "expecting ==");
+    checkError("not()",
+               "<string>:1.5: syntax error, unexpected )");
+    checkError("(not('foo' 'bar')",
+               "<string>:1.12-16: syntax error, unexpected constant string, "
+               "expecting ==");
     checkError("('foo' == 'bar'",
                "<string>:1.16: syntax error, unexpected end of file, "
                "expecting )");

+ 33 - 0
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

+ 20 - 0
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 << "'.");
+    }
+}

+ 25 - 0
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