]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[master] Finished merge of trac4231 (new boolean operators)
authorFrancis Dupont <fdupont@isc.org>
Fri, 19 Feb 2016 15:53:05 +0000 (16:53 +0100)
committerFrancis Dupont <fdupont@isc.org>
Fri, 19 Feb 2016 15:53:05 +0000 (16:53 +0100)
16 files changed:
1  2 
ChangeLog
doc/guide/classify.xml
src/lib/eval/evaluate.cc
src/lib/eval/lexer.cc
src/lib/eval/lexer.ll
src/lib/eval/location.hh
src/lib/eval/parser.cc
src/lib/eval/parser.h
src/lib/eval/parser.yy
src/lib/eval/position.hh
src/lib/eval/stack.hh
src/lib/eval/tests/context_unittest.cc
src/lib/eval/tests/evaluate_unittest.cc
src/lib/eval/tests/token_unittest.cc
src/lib/eval/token.cc
src/lib/eval/token.h

diff --cc ChangeLog
index 4fc769b90e7c7b207d8ec8963bec8d5c496cafc4,5d6a08cb79b8a01644cb35aa29ec080b1efe2fae..c81bc84a9757e49fd7da9c46254b4e9bf1ba1dc5
+++ b/ChangeLog
@@@ -1,86 -1,3 +1,92 @@@
++1079. [func]          fdupont
++      Added Not, And and Or logical operators, parentheses around
++      logical expressions and option[code].exist logical predicate
++      (to check the presence of an empty option).
++      (Trac #4231, git xxx)
++
 +1078. [func]          tomek
 +      Client classification in DHCPv4 has been enhanced. It is now
 +      possible to access relay sub-options using the expression
 +      relay[123].hex.
 +      (Trac #4264, git c13791e916ceae9a73ca44005581e0e39385a572)
 +
 +1077. [func]          marcin
 +      perfdhcp now accepts -f option for DHCPv4 server testing, which
 +      enables lease renewals at the specified rate.
 +      (Trac #4254, git 8c5630b9ce6d3fba224f0643a7c69e4f7aaefca7)
 +
 +1076. [bug]           jpopelka
 +      Fixed compilation issue in MySQL host data source: the
 +      dhcp_identifer_length is now unsigned long. This addresses
 +      a compilation problem on Fedora.
 +      (Github #17, git 8548d1b589df98cc956b4d80d2cb8819ef576717)
 +
 +1075. [bug]           fdupont
 +      Removed warnings emitted during generation of Doxygen documentation.
 +      (Trac #4234, git b67910a3893bc79eb77a48bae6c31214a317bd40)
 +
 +1074. [bug]           marcin
 +      Addressed regression in distcheck after merge of #4224.
 +      Before the changes one of the lease files produced by
 +      'kea-lfc' was not removed after tests running lease file
 +      cleanup. As a result, the distcheck failed discovering
 +      this file being left after distclean.
 +      (Trac #4249, git 04aa9b95bf8c4dd8b555dd78cc8cd57126473800)
 +
 +1073. [bug]           tmark
 +      This change bumps the MySQL schema version from 4.0 to 4.1 and includes
 +      the following changes: added explicit use of InnoDB engine to all MySQL
 +      table create statements,  MySQL lease dump output is now sorted by lease
 +      address in ascending order, and the MySQL lease_hwaddr_source table now
 +      contains an entry for HWADDR_SOURCE_UNKNOWN (i.e. source = 0). Our thanks
 +      to Sebastien Couture at Ubity Inc. for reporting the InnoDB engine issue
 +      and submitting a fix for it.
 +      (Github #16, Trac #4237,#4238, git f0fb9f35a394785215573a591c2bcc68ab481436)
 +
 +1075. [doc]           marcin
 +      Changed Kea license from ISC to Mozilla Public License,
 +      v. 2.0.
 +      (Trac #4236, git a0574cdab4deb31e3244fc4e237753a1ad361d96)
 +
 +1074. [bug]           marcin
 +      PID files created by Kea processes are used in shell based
 +      tests to determine if the given process is running. This
 +      solves the problem whereby some unrelated processes could
 +      be reported as running Kea processes in those tests, causing
 +      the tests to fail.
 +      (Trac #4224, git 94edccc50cb374ec4db35f653b869c9f06d356ea)
 +
 +1073. [doc]           tomek
 +      Developer's Guide updated with client classification text
 +      and several clean-ups.
 +      (Trac #4102, git ac33ebf7428ba5935d3302d000bed317716fabfe)
 +
 +1072. [bug]           tmark
 +      The lease6 hardware address source value is now being properly populated.
 +      Prior to this the value stored with each IPv6 lease was always zero.
 +      (Trac #4247, git 27886dadcf9051dc622ee6fde586c27f3d431f8b)
 +
 +1071. [func]          tmark
 +      Assigned unique log message IDs to log messages issued from
 +      MySQL hosts storage operations, eliminating resuse of
 +      lease database message IDs.
 +      (Trac #4216, git f0e37cd6d45537971a730c68187011dce41217cc)
 +
 +1070. [doc]           sar
 +      Correct v6 classification examples to use client-id (1) instead
 +      of server-id (2).
 +      (Trac #4222, git 69dd98d03861d9de72c2ef75c17c8154b0c5088b)
 +
 +1069. [bug]           tomek
 +      Improved handling of incoming packets with invalid client-id
 +      and DUID.
 +      (Trac #4206, git 2c94f80e30abe53ae5b677762fc69e888c92e03f)
 +
 +1068. [func]          marcin
 +      Renamed log message compiler binary from 'message' to
 +      'kea-msg-compiler'.
 +      (Trac #4228, git bbeb5c776c39b9f4132f7f614720db75590ccef9)
 +
  Kea 1.0.0-beta released on December 8, 2015
  
  1067. [doc]           sar
index e261281637cb691ec82d30cad33ec4347f6042da,0aea48ee18a994e7d4aaaa10c40bbe84db3658d9..f24c712acc4e82eecce84a4b8cdbd4bd20b0dbcf
  <row><entry>Option Text</entry><entry>option[code].text</entry><entry>The value of the option with code "code" from the packet as text</entry></row>
  -->
  <row><entry>Option Hex</entry><entry>option[code].hex</entry><entry>The value of the option with code "code" from the packet as hex</entry></row>
+ <row><entry>Option Exist</entry><entry>option[code].exist</entry><entry>If the option with code "code" is present in the packet "true" else "false"</entry></row>
 +<row><entry>DHCPv4 Relay Agent
 +sub-option</entry><entry>relay[code].hex</entry><entry>The value of
 +sub-option with code "code" from the Relay Agent Information option
 +(option 82)</entry></row>
            </tbody>
            </tgroup>
          </table>
        the option payload without the type code or length fields.
        </para>
  
+       <para>
+       "option[code].exist" checks if an option with the given code is present
+       in the incoming packet. It can be used with empty options.
+       </para>
 +      <para>
 +        "relay[code].hex" attempts to extract the value of the sub-option
 +        "code" from the option inserted as the Relay Agent Information
 +        (82) option. If the packet doesn't contain a RAI option, or the RAI
 +        option doesn't contain the requested sub-option, the expression returns
 +        an empty string. The string is presented as a byte string of the
 +        option payload without the type code or length fields. This
 +        expression is allowed in DHCPv4 only.
 +      </para>
 +
        <para>
          <table frame="all" id="classification-expressions-list">
            <title>List of Classification Expressions</title>
index aba0e1fb4d3e77da8128b423de35152b726888be,dd5e0af68de766d1b967268136765918eb1c5660..630b2273109d90ae13f531c0dd9c102ab02e454c
@@@ -1,8 -1,16 +1,8 @@@
- // 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
 -// 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.
 +// This Source Code Form is subject to the terms of the Mozilla Public
 +// License, v. 2.0. If a copy of the MPL was not distributed with this
 +// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  
  #include <eval/evaluate.h>
  
index 33e5c55d5e2ff0399fc45fe73daaeb120c9fd3e6,b9fbae02b50af59dc7b71a93ac2d61a59c0bc98f..438b5fdf08f07feb2f968da85420d811c9849075
@@@ -18,7 -18,7 +18,7 @@@
  #define FLEX_SCANNER
  #define YY_FLEX_MAJOR_VERSION 2
  #define YY_FLEX_MINOR_VERSION 5
--#define YY_FLEX_SUBMINOR_VERSION 39
++#define YY_FLEX_SUBMINOR_VERSION 35
  #if YY_FLEX_SUBMINOR_VERSION > 0
  #define FLEX_BETA
  #endif
@@@ -72,6 -72,6 +72,7 @@@ 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;
@@@ -79,6 -79,6 +80,7 @@@ 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
  #define UINT32_MAX             (4294967295U)
  #endif
  
--#endif /* ! C99 */
--
  #endif /* ! FLEXINT_H */
  
  /* %endif */
@@@ -233,18 -225,18 +225,11 @@@ extern FILE *yyin, *yyout
       */
      #define  YY_LESS_LINENO(n) \
              do { \
--                int yyl;\
++                yy_size_t 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) \
@@@ -435,7 -427,7 +420,7 @@@ void yyfree (void *  )
  /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
  /* Begin user sect3 */
  
--#define yywrap() 1
++#define yywrap(n) 1
  #define YY_SKIP_YYWRAP
  
  #define FLEX_DEBUG
@@@ -453,8 -445,8 +438,6 @@@ 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 );
@@@ -470,15 -462,15 +453,15 @@@ static void yy_fatal_error (yyconst cha
  #define YY_DO_BEFORE_ACTION \
        (yytext_ptr) = yy_bp; \
  /* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
--      yyleng = (size_t) (yy_cp - yy_bp); \
++      yyleng = (yy_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 \ */\
        (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 24
 -#define YY_END_OF_BUFFER 25
++#define YY_NUM_RULES 25
++#define YY_END_OF_BUFFER 26
  /* This struct is not used in this scanner,
     but its presence is necessary. */
  struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
- static yyconst flex_int16_t yy_acclist[99] =
 -static yyconst flex_int16_t yy_acclist[110] =
++static yyconst flex_int16_t yy_acclist[119] =
      {   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,16390,16390,16390,
-     16390,16390,16390,16390,    9,16390,16390,16390,16390,    8,
-     16390,   12,16390,16390,16390,16390,   11,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,
--
 -       11,16390,    8,16390,16390,16390,16390,   12,16390
++       26,   24,   25,    1,   24,   25,    2,   25,   24,   25,
++       19,   24,   25,   20,   24,   25,   23,   24,   25,   24,
++       25,   18,   24,   25,    5,   24,   25,    5,   24,   25,
++       24,   25,   24,   25,16390,   21,   24,   25,   22,   24,
++       25,   24,   25,16390,   24,   25,16390,   24,   25,16390,
++       24,   25,16390,   24,   25,16390,   24,   25,16390,   24,
++       25,16390,   24,   25,16390,    1,    2,    3,    5,    7,
++    16390, 8198,16390,16390,16390,16390,16390,16390,   17,16390,
++    16390,16390,16390,    4,   14,16390,   16,16390,16390,   10,
++    16390,   15,16390,16390,16390,16390,16390,16390,16390,16390,
++
++    16390,    9,16390,16390,16390,16390,16390,   11,16390,    8,
++    16390,   13,16390,16390,16390,16390,   12,16390
      } ;
  
- static yyconst flex_int16_t yy_accept[64] =
 -static yyconst flex_int16_t yy_accept[70] =
++static yyconst flex_int16_t yy_accept[76] =
      {   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,   79,   80,   81,   82,   83,
-        84,   85,   87,   88,   89,   90,   92,   94,   95,   96,
-        97,   99,   99
 -       48,   51,   54,   57,   60,   63,   64,   65,   65,   66,
 -       67,   67,   68,   68,   68,   69,   70,   71,   72,   73,
 -       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
++       48,   51,   54,   57,   60,   63,   66,   67,   68,   68,
++       69,   70,   70,   71,   71,   71,   72,   73,   74,   75,
++       76,   77,   78,   79,   81,   82,   83,   84,   85,   87,
++       89,   90,   92,   94,   95,   96,   97,   98,   99,  100,
++      101,  102,  104,  105,  106,  107,  108,  110,  112,  114,
++      115,  116,  117,  119,  119
      } ;
  
  static yyconst flex_int32_t yy_ec[256] =
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    2,    1,    1,    1,    1,    1,    1,    4,    5,
          6,    1,    1,    7,    8,    9,    1,   10,   11,   11,
 -       11,   11,   11,   11,   11,   11,   11,    1,    1,    1,
 -       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,   21,
 -
 -       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,
 +       11,   12,   11,   11,   11,   11,   11,    1,    1,    1,
 +       13,    1,    1,    1,   14,   14,   14,   14,   14,   14,
 +       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
 +       15,   15,   15,   15,   15,   15,   15,   16,   15,   15,
-        17,    1,   18,    1,   19,    1,   20,   21,   14,   14,
++       17,    1,   18,    1,   19,    1,   20,   21,   14,   22,
 +
-        22,   14,   23,   24,   25,   15,   15,   26,   15,   27,
-        28,   29,   15,   30,   31,   32,   33,   15,   15,   34,
-        35,   15,    1,    1,    1,    1,    1,    1,    1,    1,
++       23,   14,   24,   25,   26,   15,   15,   27,   15,   28,
++       29,   30,   15,   31,   32,   33,   34,   15,   15,   35,
++       36,   15,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    1,    1,    1,    1
      } ;
  
- static yyconst flex_int32_t yy_meta[36] =
 -static yyconst flex_int32_t yy_meta[35] =
++static yyconst flex_int32_t yy_meta[37] =
      {   0,
          1,    2,    3,    1,    1,    1,    1,    2,    1,    4,
 -        4,    1,    4,    2,    2,    1,    2,    2,    4,    4,
 -        4,    4,    2,    2,    2,    2,    2,    2,    2,    2,
 -        2,    2,    2,    2
 +        4,    4,    1,    4,    2,    2,    1,    2,    2,    4,
-         4,    4,    2,    2,    2,    2,    2,    2,    2,    2,
-         2,    2,    2,    2,    2
++        4,    4,    4,    2,    2,    2,    2,    2,    2,    2,
++        2,    2,    2,    2,    2,    2
      } ;
  
- static yyconst flex_int16_t yy_base[66] =
 -static yyconst flex_int16_t yy_base[72] =
++static yyconst flex_int16_t yy_base[78] =
      {   0,
-         0,    0,  135,  136,  132,  130,  128,  136,  136,  136,
-        26,  136,   29,   32,  118,   46,  136,  136,   64,   24,
-        26,   25,   27,   35,  128,  126,  124,  136,   58,    0,
-       136,   56,   73,  101,  136,  100,   45,   30,   99,   52,
-        51,    0,   98,   97,   55,   66,   58,   61,   68,   62,
-        69,   96,   76,   86,   74,   95,   90,   80,   81,   87,
-        85,  136,  113,  116,  105
 -        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
++        0,    0,  113,  205,  108,  101,   98,  205,  205,  205,
++       27,  205,   30,   33,   87,   45,  205,  205,   64,   22,
++       28,   31,   43,   52,   34,   58,   82,   66,   50,  205,
++       66,    0,  205,   85,   87,   66,  205,   68,   79,   71,
++       81,   84,   91,   93,   95,  104,   99,    0,  101,  108,
++      110,  112,  116,  119,  121,  123,  125,  129,  132,  136,
++      138,  140,  142,  148,  161,  150,  152,  155,  157,  164,
++      159,  169,  167,  205,  197,  200,   48
      } ;
  
- static yyconst flex_int16_t yy_def[66] =
 -static yyconst flex_int16_t yy_def[72] =
++static yyconst flex_int16_t yy_def[78] =
      {   0,
-        62,    1,   62,   62,   62,   62,   63,   62,   62,   62,
-        62,   62,   62,   62,   62,   64,   62,   62,   64,   19,
-        19,   19,   19,   19,   62,   62,   63,   62,   62,   65,
-        62,   62,   19,   19,   62,   19,   19,   19,   19,   19,
-        19,   65,   19,   19,   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,
++       74,    1,   74,   74,   74,   74,   75,   74,   74,   74,
++       74,   74,   74,   74,   74,   76,   74,   74,   76,   19,
++       19,   19,   19,   19,   19,   19,   74,   74,   75,   74,
++       74,   77,   74,   74,   19,   19,   74,   19,   19,   19,
++       19,   19,   19,   19,   19,   19,   19,   77,   19,   19,
+        19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
 -       19,   19,   19,   19,   19,   19,   19,    0,   68,   68,
 -       68
 +       19,   19,   19,   19,   19,   19,   19,   19,   19,   19,
-        19,    0,   62,   62,   62
++       19,   19,   19,    0,   74,   74,   74
      } ;
  
- static yyconst flex_int16_t yy_nxt[172] =
 -static yyconst flex_int16_t yy_nxt[219] =
++static yyconst flex_int16_t yy_nxt[242] =
      {   0,
          4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
 -       14,   15,   16,   16,   16,   17,   18,    4,   19,   16,
 -       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,
 -
 -       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
 +       14,   14,   15,   16,   16,   16,   17,   18,    4,   19,
-        16,   16,   16,   20,   16,   16,   16,   21,   16,   22,
-        23,   24,   16,   16,   16,   29,   29,   29,   29,   29,
-        29,   29,   29,   29,   30,   37,   39,   32,   32,   34,
-        34,   34,   34,   33,   38,   34,   41,   32,   32,   40,
-        34,   45,   30,   35,   33,   32,   32,   29,   29,   29,
-        34,   33,   47,   35,   62,   62,   34,   34,   44,   49,
-        34,   35,   33,   34,   48,   50,   34,   34,   51,   36,
-        62,   34,   52,   34,   34,   53,   54,   57,   34,   34,
-        55,   34,   56,   58,   59,   34,   34,   60,   42,   61,
-        34,   34,   34,   27,   27,   34,   27,   34,   34,   34,
-        34,   34,   34,   34,   46,   43,   34,   28,   26,   25,
-        31,   28,   26,   25,   62,    3,   62,   62,   62,   62,
-        62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-        62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-        62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-        62
++       16,   16,   20,   16,   21,   16,   16,   22,   23,   16,
++       24,   25,   26,   16,   16,   16,   31,   31,   31,   31,
++       31,   31,   31,   31,   31,   32,   34,   34,   36,   36,
++       41,   48,   35,   30,   36,   36,   40,   36,   36,   42,
++       36,   36,   37,   35,   32,   34,   34,   46,   28,   36,
++       36,   35,   43,   44,   45,   31,   31,   31,   36,   36,
++       47,   37,   35,   27,   36,   36,   34,   34,   74,   74,
++       38,   39,   36,   36,   49,   36,   51,   36,   36,   33,
++
++       50,   30,   37,   28,   74,   36,   36,   36,   36,   27,
++       36,   36,   74,   36,   36,   52,   53,   36,   36,   36,
++       36,   55,   36,   54,   56,   36,   36,   36,   36,   74,
++       36,   36,   74,   57,   36,   36,   36,   36,   36,   36,
++       60,   58,   36,   36,   59,   36,   36,   36,   36,   36,
++       36,   36,   36,   74,   61,   36,   36,   62,   36,   36,
++       64,   63,   36,   36,   36,   36,   36,   36,   36,   36,
++       66,   65,   69,   67,   36,   68,   36,   36,   36,   36,
++       70,   36,   36,   36,   36,   36,   72,   36,   36,   71,
++       36,   36,   73,   36,   36,   36,   36,   29,   29,   74,
++
++       29,   36,   36,   36,    3,   74,   74,   74,   74,   74,
++       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
++       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
++       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
++       74
      } ;
  
- static yyconst flex_int16_t yy_chk[172] =
 -static yyconst flex_int16_t yy_chk[219] =
++static yyconst flex_int16_t yy_chk[242] =
      {   0,
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-         1,    1,    1,    1,    1,   11,   11,   11,   13,   13,
-        13,   14,   14,   14,   13,   20,   22,   16,   16,   20,
-        22,   21,   23,   16,   21,   38,   24,   32,   32,   23,
-        24,   38,   13,   16,   16,   19,   19,   29,   29,   29,
-        37,   19,   40,   32,   33,   33,   41,   40,   37,   45,
-        45,   19,   19,   47,   41,   46,   48,   50,   47,   19,
-        33,   46,   48,   49,   51,   49,   50,   54,   33,   55,
 -        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,   53,   53,   55,   58,   58,   59,   59,   65,   60,
-        61,   54,   60,   63,   63,   57,   63,   64,   64,   64,
-        56,   52,   44,   43,   39,   36,   34,   27,   26,   25,
-        15,    7,    6,    5,    3,   62,   62,   62,   62,   62,
-        62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-        62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-        62,   62,   62,   62,   62,   62,   62,   62,   62,   62,
-        62
 -       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
++        1,    1,    1,    1,    1,    1,   11,   11,   11,   13,
++       13,   13,   14,   14,   14,   13,   16,   16,   20,   20,
++       21,   77,   16,   29,   21,   21,   20,   22,   22,   22,
++       25,   25,   16,   16,   13,   19,   19,   25,   28,   23,
++       23,   19,   23,   23,   24,   31,   31,   31,   24,   24,
++       26,   19,   19,   27,   26,   26,   34,   34,   35,   35,
++       19,   19,   36,   36,   38,   38,   40,   40,   40,   15,
++
++       39,    7,   34,    6,   35,   39,   39,   41,   41,    5,
++       42,   42,    3,   35,   35,   41,   42,   43,   43,   44,
++       44,   45,   45,   43,   46,   47,   47,   49,   49,    0,
++       46,   46,    0,   47,   50,   50,   51,   51,   52,   52,
++       55,   51,   53,   53,   54,   54,   54,   55,   55,   56,
++       56,   57,   57,    0,   56,   58,   58,   57,   59,   59,
++       59,   58,   60,   60,   61,   61,   62,   62,   63,   63,
++       61,   60,   65,   63,   64,   64,   66,   66,   67,   67,
++       66,   68,   68,   69,   69,   71,   71,   65,   65,   70,
++       70,   70,   72,   73,   73,   72,   72,   75,   75,    0,
++
++       75,   76,   76,   76,   74,   74,   74,   74,   74,   74,
++       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
++       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
++       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
++       74
      } ;
  
  /* 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[25] =
++static yyconst flex_int32_t yy_rule_can_match_eol[26] =
      {   0,
  0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
-     0, 0,     };
 -    0, 0, 0, 0, 0,     };
++    0, 0, 0, 0, 0, 0,     };
  
  extern int yy_flex_debug;
  int yy_flex_debug = 1;
  
- static yyconst flex_int16_t yy_rule_linenum[21] =
 -static yyconst flex_int16_t yy_rule_linenum[24] =
++static yyconst flex_int16_t yy_rule_linenum[25] =
      {   0,
 -       86,   90,   96,  106,  112,  126,  133,  134,  135,  136,
 -      137,  138,  139,  140,  141,  142,  143,  144,  145,  146,
 -      147,  148,  150
 +       78,   82,   88,   98,  104,  118,  125,  126,  127,  128,
-       129,  130,  131,  132,  133,  134,  135,  136,  137,  139
++      129,  130,  131,  132,  133,  134,  135,  136,  137,  138,
++      139,  140,  141,  143
      } ;
  
  static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
@@@ -709,7 -723,7 +714,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"
++#line 718 "lexer.cc"
  
  #define INITIAL 0
  
@@@ -832,7 -841,7 +832,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 do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
++#define ECHO fwrite( yytext, yyleng, 1, yyout )
  /* %endif */
  /* %if-c++-only C++ definition */
  /* %endif */
        if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
                { \
                int c = '*'; \
--              size_t n; \
++              yy_size_t n; \
                for ( n = 0; n < max_size && \
                             (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
                        buf[n] = (char) c; \
@@@ -953,6 -962,6 +953,17 @@@ YY_DEC
        register char *yy_cp, *yy_bp;
        register int yy_act;
      
++/* %% [7.0] user's declarations go here */
++#line 71 "lexer.ll"
++
++
++
++    // Code run each time yylex is called.
++    loc.step();
++
++
++#line 966 "lexer.cc"
++
        if ( !(yy_init) )
                {
                (yy_init) = 1;
                yy_load_buffer_state( );
                }
  
--      {
--/* %% [7.0] user's declarations go here */
- #line 71 "lexer.ll"
 -#line 79 "lexer.ll"
--
--
--
--    // Code run each time yylex is called.
--    loc.step();
--
--
- #line 1007 "lexer.cc"
 -#line 1016 "lexer.cc"
--
        while ( 1 )             /* loops until end-of-file is reached */
                {
  /* %% [8.0] yymore()-related code goes here */
  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];
-                               if ( yy_current_state >= 63 )
 -                              if ( yy_current_state >= 69 )
++                              if ( yy_current_state >= 75 )
                                        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 != 62 );
 -              while ( yy_current_state != 68 );
++              while ( yy_current_state != 74 );
  
  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 */
                        {
@@@ -1101,13 -1110,13 +1101,13 @@@ do_action:   /* This label is used only t
                        {
                        if ( yy_act == 0 )
                                fprintf( stderr, "--scanner backing up\n" );
-                       else if ( yy_act < 21 )
 -                      else if ( yy_act < 24 )
++                      else if ( yy_act < 25 )
                                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 == 24 )
++                      else if ( yy_act == 25 )
                                fprintf( stderr, "--accepting default rule (\"%s\")\n",
                                         yytext );
-                       else if ( yy_act == 22 )
 -                      else if ( yy_act == 25 )
++                      else if ( yy_act == 26 )
                                fprintf( stderr, "--(end of buffer or a NUL)\n" );
                        else
                                fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@@ -1206,64 -1215,79 +1206,84 @@@ return isc::eval::EvalParser::make_HEX(
        YY_BREAK
  case 11:
  YY_RULE_SETUP
 -#line 137 "lexer.ll"
 +#line 129 "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"
 +#line 130 "lexer.ll"
- return isc::eval::EvalParser::make_RELAY4(loc);
+ return isc::eval::EvalParser::make_SUBSTRING(loc);
        YY_BREAK
  case 13:
  YY_RULE_SETUP
 -#line 139 "lexer.ll"
 -return isc::eval::EvalParser::make_ALL(loc);
 +#line 131 "lexer.ll"
- return isc::eval::EvalParser::make_ALL(loc);
++return isc::eval::EvalParser::make_RELAY4(loc);
        YY_BREAK
  case 14:
  YY_RULE_SETUP
 -#line 140 "lexer.ll"
 -return isc::eval::EvalParser::make_NOT(loc);
 +#line 132 "lexer.ll"
- return isc::eval::EvalParser::make_DOT(loc);
++return isc::eval::EvalParser::make_ALL(loc);
        YY_BREAK
  case 15:
  YY_RULE_SETUP
 -#line 141 "lexer.ll"
 -return isc::eval::EvalParser::make_AND(loc);
 +#line 133 "lexer.ll"
- return isc::eval::EvalParser::make_LPAREN(loc);
++return isc::eval::EvalParser::make_NOT(loc);
        YY_BREAK
  case 16:
  YY_RULE_SETUP
 -#line 142 "lexer.ll"
 -return isc::eval::EvalParser::make_OR(loc);
 +#line 134 "lexer.ll"
- return isc::eval::EvalParser::make_RPAREN(loc);
++return isc::eval::EvalParser::make_AND(loc);
        YY_BREAK
  case 17:
  YY_RULE_SETUP
 -#line 143 "lexer.ll"
 -return isc::eval::EvalParser::make_DOT(loc);
 +#line 135 "lexer.ll"
- return isc::eval::EvalParser::make_LBRACKET(loc);
++return isc::eval::EvalParser::make_OR(loc);
        YY_BREAK
  case 18:
  YY_RULE_SETUP
 -#line 144 "lexer.ll"
 -return isc::eval::EvalParser::make_LPAREN(loc);
 +#line 136 "lexer.ll"
- return isc::eval::EvalParser::make_RBRACKET(loc);
++return isc::eval::EvalParser::make_DOT(loc);
        YY_BREAK
  case 19:
  YY_RULE_SETUP
 -#line 145 "lexer.ll"
 -return isc::eval::EvalParser::make_RPAREN(loc);
 +#line 137 "lexer.ll"
- return isc::eval::EvalParser::make_COMA(loc);
++return isc::eval::EvalParser::make_LPAREN(loc);
        YY_BREAK
  case 20:
  YY_RULE_SETUP
 -#line 146 "lexer.ll"
 -return isc::eval::EvalParser::make_LBRACKET(loc);
++#line 138 "lexer.ll"
++return isc::eval::EvalParser::make_RPAREN(loc);
+       YY_BREAK
+ case 21:
+ YY_RULE_SETUP
 -#line 147 "lexer.ll"
 -return isc::eval::EvalParser::make_RBRACKET(loc);
 +#line 139 "lexer.ll"
++return isc::eval::EvalParser::make_LBRACKET(loc);
+       YY_BREAK
+ case 22:
+ YY_RULE_SETUP
 -#line 148 "lexer.ll"
 -return isc::eval::EvalParser::make_COMA(loc);
++#line 140 "lexer.ll"
++return isc::eval::EvalParser::make_RBRACKET(loc);
+       YY_BREAK
+ case 23:
+ YY_RULE_SETUP
 -#line 150 "lexer.ll"
++#line 141 "lexer.ll"
++return isc::eval::EvalParser::make_COMA(loc);
++      YY_BREAK
++case 24:
++YY_RULE_SETUP
++#line 143 "lexer.ll"
  driver.error (loc, "Invalid character: " + std::string(yytext));
        YY_BREAK
  case YY_STATE_EOF(INITIAL):
- #line 140 "lexer.ll"
 -#line 151 "lexer.ll"
++#line 144 "lexer.ll"
  return isc::eval::EvalParser::make_END(loc);
        YY_BREAK
- case 21:
 -case 24:
++case 25:
  YY_RULE_SETUP
- #line 141 "lexer.ll"
 -#line 152 "lexer.ll"
++#line 145 "lexer.ll"
  ECHO;
        YY_BREAK
- #line 1267 "lexer.cc"
 -#line 1291 "lexer.cc"
++#line 1287 "lexer.cc"
  
        case YY_END_OF_BUFFER:
                {
                        "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 */
  
@@@ -1544,7 -1568,7 +1563,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 >= 63 )
 -                      if ( yy_current_state >= 69 )
++                      if ( yy_current_state >= 75 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
        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 >= 63 )
 -              if ( yy_current_state >= 69 )
++              if ( yy_current_state >= 75 )
                        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 == 62);
 -      yy_is_jam = (yy_current_state == 68);
++      yy_is_jam = (yy_current_state == 74);
        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 */
                                case EOB_ACT_END_OF_FILE:
                                        {
                                        if ( yywrap( ) )
--                                              return EOF;
++                                              return 0;
  
                                        if ( ! (yy_did_buffer_switch_on_eof) )
                                                YY_NEW_FILE;
@@@ -1803,6 -1827,6 +1822,17 @@@ 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.
@@@ -2043,8 -2067,8 +2073,8 @@@ YY_BUFFER_STATE yy_scan_string (yycons
  /* %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 yybytes the byte buffer to scan
-- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
++ * @param bytes the byte buffer to scan
++ * @param len the number of bytes in the buffer pointed to by @a bytes.
   * 
   * @return the newly allocated buffer state object.
   */
@@@ -2052,8 -2076,8 +2082,7 @@@ YY_BUFFER_STATE yy_scan_bytes  (yycons
  {
        YY_BUFFER_STATE b;
        char *buf;
--      yy_size_t n;
--      yy_size_t i;
++      yy_size_t n, i;
      
        /* Get memory for full buffer, including space for trailing EOB's. */
        n = _yybytes_len + 2;
@@@ -2324,7 -2348,7 +2353,7 @@@ void yyfree (void * ptr 
  
  /* %ok-for-header */
  
- #line 140 "lexer.ll"
 -#line 152 "lexer.ll"
++#line 145 "lexer.ll"
  
  
  
index 6911a3a2bc21c6a1ba1cc31b58dcbc4159b69a4c,238c131356a208a15db0bd94b2c16178225b7f9b..34aab5df0c427c924dce2e1c1d84000b8d894740
@@@ -126,9 -134,12 +126,13 @@@ 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);
 +"relay4"    return isc::eval::EvalParser::make_RELAY4(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);
index c01735e7bd5f0a39d782cd265976ec7b9b2ddad5,2f28d5276381ab4aa9889bcf8eea926c8651818c..82d489124053e84e6cf2b84d5ba562d2aaee8a8e
@@@ -1,4 -1,5 +1,5 @@@
- // A Bison parser, made by GNU Bison 3.0.2.
 -// Generated 20151209
++// Generated 20160219
+ // A Bison parser, made by GNU Bison 3.0.4.
  
  // Locations for Bison parsers in C++
  
index 9289f5364c3300bde5b7cae4de1a5d249f7aef45,9bbef776dc70a7429c40eeaf54772445f8570b1b..ab19e2f68a8c69ece198532c8b61c8991f4ac589
@@@ -47,9 -47,9 +47,9 @@@
  
  // User implementation prologue.
  
- #line 51 "parser.cc" // lalr1.cc:407
+ #line 51 "parser.cc" // lalr1.cc:412
  // Unqualified %code blocks.
- #line 32 "parser.yy" // lalr1.cc:408
 -#line 40 "parser.yy" // lalr1.cc:413
++#line 32 "parser.yy" // lalr1.cc:413
  
  # include "eval_context.h"
  
  #define YYERROR         goto yyerrorlab
  #define YYRECOVERING()  (!!yyerrstatus_)
  
- #line 13 "parser.yy" // lalr1.cc:474
 -#line 21 "parser.yy" // lalr1.cc:479
++#line 13 "parser.yy" // lalr1.cc:479
  namespace isc { namespace eval {
- #line 143 "parser.cc" // lalr1.cc:474
+ #line 143 "parser.cc" // lalr1.cc:479
  
    /* Return YYSTR after stripping away unnecessary quotes and
       backslashes, so that it's suitable for yyerror.  The heuristic is
    {
        switch (that.type_get ())
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          value.move< std::string > (that.value);
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          value.move< uint16_t > (that.value);
          break;
  
      state = that.state;
        switch (that.type_get ())
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          value.copy< std::string > (that.value);
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          value.copy< uint16_t > (that.value);
          break;
  
          << yysym.location << ": ";
      switch (yytype)
      {
-             case 16: // "constant string"
 -            case 19: // "constant string"
++            case 20: // "constant string"
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "parser.yy" // lalr1.cc:636
++#line 71 "parser.yy" // lalr1.cc:636
          { yyoutput << yysym.value.template as< std::string > (); }
- #line 328 "parser.cc" // lalr1.cc:617
+ #line 342 "parser.cc" // lalr1.cc:636
          break;
  
-       case 17: // "integer"
 -      case 20: // "integer"
++      case 21: // "integer"
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "parser.yy" // lalr1.cc:636
++#line 71 "parser.yy" // lalr1.cc:636
          { yyoutput << yysym.value.template as< std::string > (); }
- #line 335 "parser.cc" // lalr1.cc:617
+ #line 349 "parser.cc" // lalr1.cc:636
          break;
  
-       case 18: // "constant hexstring"
 -      case 21: // "constant hexstring"
++      case 22: // "constant hexstring"
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "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:617
+ #line 356 "parser.cc" // lalr1.cc:636
          break;
  
-       case 19: // "option name"
 -      case 22: // "option name"
++      case 23: // "option name"
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "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:617
+ #line 363 "parser.cc" // lalr1.cc:636
          break;
  
-       case 20: // TOKEN
 -      case 23: // TOKEN
++      case 24: // TOKEN
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "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:617
+ #line 370 "parser.cc" // lalr1.cc:636
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "parser.yy" // lalr1.cc:636
++#line 71 "parser.yy" // lalr1.cc:636
          { yyoutput << yysym.value.template as< uint16_t > (); }
- #line 363 "parser.cc" // lalr1.cc:617
+ #line 377 "parser.cc" // lalr1.cc:636
          break;
  
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // option_repr_type
  
- #line 63 "parser.yy" // lalr1.cc:617
 -#line 78 "parser.yy" // lalr1.cc:636
++#line 71 "parser.yy" // lalr1.cc:636
          { yyoutput << yysym.value.template as< TokenOption::RepresentationType > (); }
- #line 370 "parser.cc" // lalr1.cc:617
+ #line 384 "parser.cc" // lalr1.cc:636
          break;
  
  
           when using variants.  */
          switch (yyr1_[yyn])
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          yylhs.value.build< std::string > ();
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          yylhs.value.build< uint16_t > ();
          break;
  
          {
            switch (yyn)
              {
-   case 3:
- #line 76 "parser.yy" // lalr1.cc:847
+   case 4:
 -#line 92 "parser.yy" // lalr1.cc:859
++#line 85 "parser.yy" // lalr1.cc:859
+     {
+                     TokenPtr neg(new TokenNot());
+                     ctx.expression.push_back(neg);
+                 }
+ #line 623 "parser.cc" // lalr1.cc:859
+     break;
+   case 5:
 -#line 97 "parser.yy" // lalr1.cc:859
++#line 90 "parser.yy" // lalr1.cc:859
+     {
+                     TokenPtr neg(new TokenAnd());
+                     ctx.expression.push_back(neg);
+                 }
+ #line 632 "parser.cc" // lalr1.cc:859
+     break;
+   case 6:
 -#line 102 "parser.yy" // lalr1.cc:859
++#line 95 "parser.yy" // lalr1.cc:859
+     {
+                     TokenPtr neg(new TokenOr());
+                     ctx.expression.push_back(neg);
+                 }
+ #line 641 "parser.cc" // lalr1.cc:859
+     break;
+   case 7:
 -#line 107 "parser.yy" // lalr1.cc:859
++#line 100 "parser.yy" // lalr1.cc:859
      {
                      TokenPtr eq(new TokenEqual());
                      ctx.expression.push_back(eq);
                  }
- #line 616 "parser.cc" // lalr1.cc:847
+ #line 650 "parser.cc" // lalr1.cc:859
      break;
  
-   case 4:
- #line 83 "parser.yy" // lalr1.cc:847
+   case 8:
 -#line 112 "parser.yy" // lalr1.cc:859
++#line 105 "parser.yy" // lalr1.cc:859
+     {
+                     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 119 "parser.yy" // lalr1.cc:859
++#line 112 "parser.yy" // lalr1.cc:859
      {
                        TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
                        ctx.expression.push_back(str);
                    }
- #line 625 "parser.cc" // lalr1.cc:847
+ #line 668 "parser.cc" // lalr1.cc:859
      break;
  
-   case 5:
- #line 88 "parser.yy" // lalr1.cc:847
+   case 10:
 -#line 124 "parser.yy" // lalr1.cc:859
++#line 117 "parser.yy" // lalr1.cc:859
      {
                        TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
                        ctx.expression.push_back(hex);
                    }
- #line 634 "parser.cc" // lalr1.cc:847
+ #line 677 "parser.cc" // lalr1.cc:859
      break;
  
-   case 6:
- #line 93 "parser.yy" // lalr1.cc:847
+   case 11:
 -#line 129 "parser.yy" // lalr1.cc:859
++#line 122 "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 643 "parser.cc" // lalr1.cc:847
+ #line 686 "parser.cc" // lalr1.cc:859
      break;
  
-   case 7:
- #line 98 "parser.yy" // lalr1.cc:847
+   case 12:
 -#line 134 "parser.yy" // lalr1.cc:859
++#line 127 "parser.yy" // lalr1.cc:859
 +    {
 +                     switch (ctx.getUniverse()) {
 +                     case Option::V4:
 +                     {
 +                         TokenPtr opt(new TokenRelay4Option(yystack_[3].value.as< uint16_t > (), yystack_[0].value.as< TokenOption::RepresentationType > ()));
 +                         ctx.expression.push_back(opt);
 +                         break;
 +                     }
 +                     case Option::V6:
 +                         // We will have relay6[123] for the DHCPv6.
 +                         // In a very distant future we'll possibly be able
 +                         // to mix both if we have DHCPv4-over-DHCPv6, so it
 +                         // has some sense to make it explicit whether we
 +                         // talk about DHCPv4 relay or DHCPv6 relay. However,
 +                         // for the time being relay4 can be used in DHCPv4
 +                         // only.
 +                         error(yystack_[5].location, "relay4 can only be used in DHCPv4.");
 +                     }
 +                  }
- #line 667 "parser.cc" // lalr1.cc:847
++#line 710 "parser.cc" // lalr1.cc:859
 +    break;
 +
-   case 8:
- #line 118 "parser.yy" // lalr1.cc:847
++  case 13:
++#line 147 "parser.yy" // lalr1.cc:859
      {
                        TokenPtr sub(new TokenSubstring());
                        ctx.expression.push_back(sub);
                    }
- #line 676 "parser.cc" // lalr1.cc:847
 -#line 695 "parser.cc" // lalr1.cc:859
++#line 719 "parser.cc" // lalr1.cc:859
      break;
  
-   case 10:
- #line 127 "parser.yy" // lalr1.cc:847
 -  case 14:
 -#line 143 "parser.yy" // lalr1.cc:859
++  case 15:
++#line 156 "parser.yy" // lalr1.cc:859
      {
                       yylhs.value.as< uint16_t > () = ctx.convertOptionCode(yystack_[0].value.as< std::string > (), yystack_[0].location);
                   }
- #line 684 "parser.cc" // lalr1.cc:847
 -#line 703 "parser.cc" // lalr1.cc:859
++#line 727 "parser.cc" // lalr1.cc:859
      break;
  
-   case 11:
- #line 131 "parser.yy" // lalr1.cc:847
 -  case 15:
 -#line 147 "parser.yy" // lalr1.cc:859
++  case 16:
++#line 160 "parser.yy" // lalr1.cc:859
      {
                       yylhs.value.as< uint16_t > () = ctx.convertOptionName(yystack_[0].value.as< std::string > (), yystack_[0].location);
                   }
- #line 692 "parser.cc" // lalr1.cc:847
 -#line 711 "parser.cc" // lalr1.cc:859
++#line 735 "parser.cc" // lalr1.cc:859
      break;
  
-   case 12:
- #line 137 "parser.yy" // lalr1.cc:847
 -  case 16:
 -#line 153 "parser.yy" // lalr1.cc:859
++  case 17:
++#line 166 "parser.yy" // lalr1.cc:859
      {
                            yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::TEXTUAL;
                        }
- #line 700 "parser.cc" // lalr1.cc:847
 -#line 719 "parser.cc" // lalr1.cc:859
++#line 743 "parser.cc" // lalr1.cc:859
      break;
  
-   case 13:
- #line 141 "parser.yy" // lalr1.cc:847
 -  case 17:
 -#line 157 "parser.yy" // lalr1.cc:859
++  case 18:
++#line 170 "parser.yy" // lalr1.cc:859
      {
                            yylhs.value.as< TokenOption::RepresentationType > () = TokenOption::HEXADECIMAL;
                        }
- #line 708 "parser.cc" // lalr1.cc:847
 -#line 727 "parser.cc" // lalr1.cc:859
++#line 751 "parser.cc" // lalr1.cc:859
      break;
  
-   case 14:
- #line 147 "parser.yy" // lalr1.cc:847
 -  case 18:
 -#line 163 "parser.yy" // lalr1.cc:859
++  case 19:
++#line 176 "parser.yy" // lalr1.cc:859
      {
                       TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
                       ctx.expression.push_back(str);
                   }
- #line 717 "parser.cc" // lalr1.cc:847
 -#line 736 "parser.cc" // lalr1.cc:859
++#line 760 "parser.cc" // lalr1.cc:859
      break;
  
-   case 15:
- #line 154 "parser.yy" // lalr1.cc:847
 -  case 19:
 -#line 170 "parser.yy" // lalr1.cc:859
++  case 20:
++#line 183 "parser.yy" // lalr1.cc:859
      {
                        TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
                        ctx.expression.push_back(str);
                    }
- #line 726 "parser.cc" // lalr1.cc:847
 -#line 745 "parser.cc" // lalr1.cc:859
++#line 769 "parser.cc" // lalr1.cc:859
      break;
  
-   case 16:
- #line 159 "parser.yy" // lalr1.cc:847
 -  case 20:
 -#line 175 "parser.yy" // lalr1.cc:859
++  case 21:
++#line 188 "parser.yy" // lalr1.cc:859
      {
                       TokenPtr str(new TokenString("all"));
                       ctx.expression.push_back(str);
                   }
- #line 735 "parser.cc" // lalr1.cc:847
 -#line 754 "parser.cc" // lalr1.cc:859
++#line 778 "parser.cc" // lalr1.cc:859
      break;
  
  
- #line 739 "parser.cc" // lalr1.cc:847
 -#line 758 "parser.cc" // lalr1.cc:859
++#line 782 "parser.cc" // lalr1.cc:859
              default:
                break;
              }
    }
  
  
--  const signed char EvalParser::yypact_ninf_ = -14;
++  const signed char EvalParser::yypact_ninf_ = -11;
  
    const signed char EvalParser::yytable_ninf_ = -1;
  
    const signed char
    EvalParser::yypact_[] =
    {
-       -4,    -3,     3,    -1,   -14,   -14,   -14,    17,   -14,    15,
-      -13,    -4,   -13,   -14,    -4,   -14,   -14,     4,     9,     6,
-      -14,    12,     7,    13,     1,   -14,    14,     1,   -14,   -14,
-      -14,    -7,   -14,   -14,   -14,    16,   -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
++      -4,    -8,     9,    -4,    12,    -4,   -11,   -11,   -11,    29,
++       7,    37,    16,    -1,   -11,    16,     0,   -11,    -4,    -4,
++      -1,   -11,   -11,    23,    25,    26,    28,   -11,   -11,    38,
++     -11,    30,    16,    31,    32,    22,    34,   -11,    33,    27,
++     -11,   -11,   -11,   -11,    35,    11,   -11,    27,   -11,   -11,
++      39,   -11
    };
  
    const unsigned char
    EvalParser::yydefact_[] =
    {
-        0,     0,     0,     0,     4,     5,     9,     0,     2,     0,
-        0,     0,     0,     1,     0,    10,    11,     0,     0,     0,
-        3,     0,     0,     0,     0,    14,     0,     0,    12,    13,
-        6,     0,     7,    16,    15,     0,     8
 -       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
++       0,     0,     0,     0,     0,     0,     9,    10,    14,     0,
++       2,     0,     0,     0,     4,     0,     0,     1,     0,     0,
++       0,    15,    16,     0,     0,     0,     0,     3,     5,     6,
++       7,     0,     0,     0,     0,     0,     0,    19,     0,     0,
++      17,    18,     8,    11,     0,     0,    12,     0,    21,    20,
++       0,    13
    };
  
    const signed char
    EvalParser::yypgoto_[] =
    {
-      -14,   -14,   -14,    -6,    18,     0,   -14,   -14
 -     -14,   -14,     9,    11,    12,   -14,   -14,   -14
++     -11,   -11,     8,    15,   -10,    18,   -11,   -11
    };
  
    const signed char
    EvalParser::yydefgoto_[] =
    {
-       -1,     7,     8,     9,    17,    30,    26,    35
 -      -1,     8,     9,    10,    21,    38,    34,    44
++      -1,     9,    10,    11,    23,    43,    38,    50
    };
  
    const unsigned char
    EvalParser::yytable_[] =
    {
-        1,     2,    33,     3,    15,    18,    16,    28,    20,    29,
-       34,    10,     4,    12,     5,    11,     6,    13,    14,    21,
-       22,    23,    24,    27,    25,    31,     0,    32,     0,    36,
-       19
 -       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
++       1,     2,     3,    24,     2,    26,     4,    18,    19,     4,
++      12,    14,     5,    16,    18,    19,     6,    27,     7,     6,
++       8,     7,    36,     8,    48,    13,    28,    29,    25,    17,
++      15,    40,    49,    41,    42,    30,    40,    21,    41,    22,
++      20,    33,    31,    32,    35,    18,    39,    34,    45,    47,
++       0,     0,    37,    44,     0,     0,    51,    46
    };
  
 -  const unsigned char
 +  const signed char
    EvalParser::yycheck_[] =
    {
-        4,     5,     9,     7,    17,    11,    19,     6,    14,     8,
-       17,    14,    16,    14,    18,    12,    20,     0,     3,    15,
-       11,    15,    10,    10,    17,    11,    -1,    27,    -1,    13,
-       12
 -       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
++       4,     5,     6,     4,     5,    15,    10,     7,     8,    10,
++      18,     3,    16,     5,     7,     8,    20,    17,    22,    20,
++      24,    22,    32,    24,    13,    16,    18,    19,    13,     0,
++      18,     9,    21,    11,    12,    20,     9,    21,    11,    23,
++       3,    15,    19,    18,    14,     7,    14,    19,    15,    14,
++      -1,    -1,    21,    19,    -1,    -1,    17,    39
    };
  
    const unsigned char
    EvalParser::yystos_[] =
    {
-        0,     4,     5,     7,    16,    18,    20,    22,    23,    24,
-       14,    12,    14,     0,     3,    17,    19,    25,    24,    25,
-       24,    15,    11,    15,    10,    17,    27,    10,     6,     8,
-       26,    11,    26,     9,    17,    28,    13
 -       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
++       0,     4,     5,     6,    10,    16,    20,    22,    24,    26,
++      27,    28,    18,    16,    27,    18,    27,     0,     7,     8,
++       3,    21,    23,    29,     4,    28,    29,    17,    27,    27,
++      28,    19,    18,    15,    19,    14,    29,    21,    31,    14,
++       9,    11,    12,    30,    19,    15,    30,    14,    13,    21,
++      32,    17
    };
  
    const unsigned char
    EvalParser::yyr1_[] =
    {
-        0,    21,    22,    23,    24,    24,    24,    24,    24,    24,
-       25,    25,    26,    26,    27,    28,    28
 -       0,    24,    25,    26,    26,    26,    26,    26,    26,    27,
 -      27,    27,    27,    27,    28,    28,    29,    29,    30,    31,
 -      31
++       0,    25,    26,    27,    27,    27,    27,    27,    27,    28,
++      28,    28,    28,    28,    28,    29,    29,    30,    30,    31,
++      32,    32
    };
  
    const unsigned char
    EvalParser::yyr2_[] =
    {
-        0,     2,     1,     3,     1,     1,     6,     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
++       1,     6,     6,     8,     1,     1,     1,     1,     1,     1,
++       1,     1
    };
  
  
    const EvalParser::yytname_[] =
    {
    "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
-   "\"substring\"", "\"text\"", "\"relay4\"", "\"hex\"", "\"all\"", "\".\"",
-   "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"",
-   "\"integer\"", "\"constant hexstring\"", "\"option name\"", "TOKEN",
-   "$accept", "expression", "bool_expr", "string_expr", "option_code",
 -  "\"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
++  "\"substring\"", "\"not\"", "\"and\"", "\"or\"", "\"text\"",
++  "\"relay4\"", "\"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,    72,    72,    75,    82,    87,    92,    97,   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
++       0,    80,    80,    83,    84,    89,    94,    99,   104,   111,
++     116,   121,   126,   146,   151,   155,   159,   165,   169,   175,
++     182,   187
    };
  
    // Print the state stack on the debug stream.
  #endif // YYDEBUG
  
  
- #line 13 "parser.yy" // lalr1.cc:1155
 -#line 21 "parser.yy" // lalr1.cc:1167
++#line 13 "parser.yy" // lalr1.cc:1167
  } } // isc::eval
- #line 1124 "parser.cc" // lalr1.cc:1155
- #line 165 "parser.yy" // lalr1.cc:1156
 -#line 1152 "parser.cc" // lalr1.cc:1167
 -#line 181 "parser.yy" // lalr1.cc:1168
++#line 1181 "parser.cc" // lalr1.cc:1167
++#line 194 "parser.yy" // lalr1.cc:1168
  
  void
  isc::eval::EvalParser::error(const location_type& loc,
index 388cb5fbb41e98a82a55a11f2e85cf8756999412,9f76e82eae4d1abf153f9f340cc13df20fdb072d..93bc8cf8ce165ae40c14f75e680672a603d24d57
@@@ -40,7 -40,7 +40,7 @@@
  #ifndef YY_YY_PARSER_H_INCLUDED
  # define YY_YY_PARSER_H_INCLUDED
  // //                    "%code requires" blocks.
- #line 16 "parser.yy" // lalr1.cc:372
 -#line 24 "parser.yy" // lalr1.cc:392
++#line 16 "parser.yy" // lalr1.cc:392
  
  #include <string>
  #include <eval/token.h>
@@@ -125,9 -126,9 +126,9 @@@ using namespace isc::eval
  # define YYDEBUG 1
  #endif
  
- #line 13 "parser.yy" // lalr1.cc:372
 -#line 21 "parser.yy" // lalr1.cc:392
++#line 13 "parser.yy" // lalr1.cc:392
  namespace isc { namespace eval {
- #line 131 "parser.h" // lalr1.cc:372
+ #line 132 "parser.h" // lalr1.cc:392
  
  
  
          TOKEN_EQUAL = 258,
          TOKEN_OPTION = 259,
          TOKEN_SUBSTRING = 260,
-         TOKEN_TEXT = 261,
-         TOKEN_RELAY4 = 262,
-         TOKEN_HEX = 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_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
++        TOKEN_RELAY4 = 265,
++        TOKEN_HEX = 266,
++        TOKEN_EXISTS = 267,
++        TOKEN_ALL = 268,
++        TOKEN_DOT = 269,
++        TOKEN_COMA = 270,
++        TOKEN_LPAREN = 271,
++        TOKEN_RPAREN = 272,
++        TOKEN_LBRACKET = 273,
++        TOKEN_RBRACKET = 274,
++        TOKEN_STRING = 275,
++        TOKEN_INTEGER = 276,
++        TOKEN_HEXSTRING = 277,
++        TOKEN_OPTION_NAME = 278,
++        TOKEN_TOKEN = 279
        };
      };
  
      enum
      {
        yyeof_ = 0,
-       yylast_ = 30,     ///< Last index in yytable_.
 -      yylast_ = 46,     ///< Last index in yytable_.
++      yylast_ = 57,     ///< Last index in yytable_.
        yynnts_ = 8,  ///< Number of nonterminal symbols.
-       yyempty_ = -2,
-       yyfinal_ = 13, ///< Termination state number.
 -      yyfinal_ = 15, ///< Termination state number.
++      yyfinal_ = 17, ///< Termination state number.
        yyterror_ = 1,
        yyerrcode_ = 256,
-       yyntokens_ = 21  ///< Number of tokens.
 -      yyntokens_ = 24  ///< Number of tokens.
++      yyntokens_ = 25  ///< Number of tokens.
      };
  
  
         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,    22,    23
++      15,    16,    17,    18,    19,    20,    21,    22,    23,    24
      };
-     const unsigned int user_token_number_max_ = 275;
 -    const unsigned int user_token_number_max_ = 278;
++    const unsigned int user_token_number_max_ = 279;
      const token_number_type undef_token_ = 2;
  
      if (static_cast<int>(t) <= yyeof_)
    {
        switch (other.type_get ())
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          value.copy< std::string > (other.value);
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          value.copy< uint16_t > (other.value);
          break;
  
      (void) v;
        switch (this->type_get ())
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          value.copy< std::string > (v);
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          value.copy< uint16_t > (v);
          break;
  
      // Type destructor.
      switch (yytype)
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          value.template destroy< std::string > ();
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          value.template destroy< uint16_t > ();
          break;
  
      super_type::move(s);
        switch (this->type_get ())
      {
-       case 26: // option_repr_type
 -      case 29: // option_repr_type
++      case 30: // 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 19: // "constant string"
 -      case 20: // "integer"
 -      case 21: // "constant hexstring"
 -      case 22: // "option name"
 -      case 23: // TOKEN
++      case 20: // "constant string"
++      case 21: // "integer"
++      case 22: // "constant hexstring"
++      case 23: // "option name"
++      case 24: // TOKEN
          value.move< std::string > (s.value);
          break;
  
-       case 25: // option_code
 -      case 28: // option_code
++      case 29: // option_code
          value.move< uint16_t > (s.value);
          break;
  
      {
         0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
       265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-      275
 -     275,   276,   277,   278
++     275,   276,   277,   278,   279
      };
      return static_cast<token_type> (yytoken_number_[type]);
    }
    }
  
  
- #line 13 "parser.yy" // lalr1.cc:372
 -#line 21 "parser.yy" // lalr1.cc:392
++#line 13 "parser.yy" // lalr1.cc:392
  } } // isc::eval
- #line 1129 "parser.h" // lalr1.cc:372
 -#line 1205 "parser.h" // lalr1.cc:392
++#line 1216 "parser.h" // lalr1.cc:392
  
  
  
index b127442ae30d9cfc5f16f65c69786f5771bfeb66,786a22546be7a59f98b5f7677bef201ef7aa51c6..c8b0f3700bed947350de84b9e882805de5166a1a
@@@ -39,9 -47,12 +39,13 @@@ using namespace isc::eval
    EQUAL "=="
    OPTION "option"
    SUBSTRING "substring"
+   NOT "not"
+   AND "and"
+   OR "or"
    TEXT "text"
 +  RELAY4 "relay4"
    HEX "hex"
+   EXISTS "exists"
    ALL "all"
    DOT "."
    COMA ","
index ba6f7174611b3669608e7a8f458201a8b53ba4d2,d314a8426cd9f106ad7ff21e2b09a3119bf735e5..59f4b295f593a422a6fff754a92504cc6f2dad47
@@@ -1,4 -1,5 +1,5 @@@
- // A Bison parser, made by GNU Bison 3.0.2.
 -// Generated 20151209
++// Generated 20160219
+ // A Bison parser, made by GNU Bison 3.0.4.
  
  // Positions for Bison parsers in C++
  
index 246a2cdd1abdaa0e1842f627bc07ac7f9fd4e4a3,14b0aeb4ddb67b676df664ea6249ba597e055890..0ad2aa53703ec1585705b76c92f11f3b77ab93aa
@@@ -1,4 -1,5 +1,5 @@@
- // A Bison parser, made by GNU Bison 3.0.2.
 -// Generated 20151209
++// Generated 20160219
+ // A Bison parser, made by GNU Bison 3.0.4.
  
  // Stack handling for Bison parsers in C++
  
index 9c25f229f8a5c5eb6b1c6a7caf16ab226c459509,0b575cad641edbbe445b4abacd73173d3f721afe..e08204a58b154d166e5d5f9c5fc734a5672fede7
@@@ -1,8 -1,16 +1,8 @@@
- // 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
 -// 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.
 +// This Source Code Form is subject to the terms of the Mozilla Public
 +// License, v. 2.0. If a copy of the MPL was not distributed with this
 +// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  
  #include <config.h>
  #include <eval/evaluate.h>
Simple merge
index 78e080d24c80c21bf2482c0052e00fcd047294fd,f14ebe6428ff6f28c4428ade1eaf0d977169c77d..72e73e91fb457dacce71d5e4c64a16be102c3beb
@@@ -174,19 -181,64 +178,81 @@@ TokenSubstring::evaluate(const Pkt& /*p
      values.push(string_str.substr(start_pos, length));
  }
  
 -    if (val) {
 -      values.push("false");
 -    } else {
 +TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
 +                                     const RepresentationType& rep_type)
 +    :TokenOption(option_code, rep_type) {
 +}
 +
 +OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
 +
 +    // Check if there is Relay Agent Option.
 +    OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
 +    if (!rai) {
 +        return (OptionPtr());
 +    }
 +
 +    // If there is, try to return its suboption
 +    return (rai->getOption(option_code_));
 +}
++
+ void
+ TokenNot::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
+     if (values.size() == 0) {
+         isc_throw(EvalBadStack, "Incorrect empty stack.");
+     }
+     string op = values.top();
+     values.pop();
+     bool val = toBool(op);
++    if (!val) {
+       values.push("true");
++    } else {
++      values.push("false");
+     }
+ }
+ 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();
+     bool val1 = toBool(op1);
+     string op2 = values.top();
+     values.pop(); // Dammit, std::stack interface is awkward.
+     bool val2 = toBool(op2);
+     if (val1 && val2) {
+       values.push("true");
+     } else {
+       values.push("false");
+     }
+ }
+ 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();
+     bool val1 = toBool(op1);
+     string op2 = values.top();
+     values.pop(); // Dammit, std::stack interface is awkward.
+     bool val2 = toBool(op2);
+     if (val1 || val2) {
+       values.push("true");
+     } else {
+       values.push("false");
+     }
+ }
index 6b512175a284a2c3a9fc8d16a3898ad660b464aa,073c4a40c9f2ee966654716fdf542a666eb34edf..7dd7a022eb1c233e5c6d41100b8757a901d5f696
@@@ -280,34 -297,80 +300,108 @@@ public
      void evaluate(const Pkt& pkt, ValueStack& values);
  };
  
 +/// @brief Represents a sub-option inserted by the DHCPv4 relay.
 +///
 +/// DHCPv4 relays insert sub-options in option 82. This token attempts to extract
 +/// such sub-options. Note in DHCPv6 it is radically different (possibly
 +/// many encapsulation levels), thus there are separate classes for v4 and v6.
 +///
 +/// This token can represent the following expressions:
 +/// relay[13].text - Textual representation of sub-option 13 in RAI (option 82)
 +/// relay[13].hex  - Binary representation of sub-option 13 in RAI (option 82)
 +/// relay[vendor-class].text - Text representation of sub-option X in RAI (option 82)
 +/// relay[vendor-class].hex - Binary representation of sub-option X in RAI (option 82)
 +class TokenRelay4Option : public TokenOption {
 +public:
 +
 +    /// @brief Constructor for extracting sub-option from RAI (option 82)
 +    ///
 +    /// @param option_code code of the requested sub-option
 +    /// @param rep_type code representation (currently .hex and .text are supported)
 +    TokenRelay4Option(const uint16_t option_code,
 +                      const RepresentationType& rep_type);
 +
 +protected:
 +    /// @brief Attempts to obtain specified sub-option of option 82 from the packet
 +    /// @param pkt DHCPv4 packet (that hopefully contains option 82)
 +    /// @return found sub-option from option 82
 +    virtual OptionPtr getOption(const Pkt& pkt);
 +};
 +
+ /// @brief Token that represents 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);
+ };
+ /// @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