2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-01 22:45:18 +00:00

[4097a] Merged #4093

This commit is contained in:
Francis Dupont
2015-11-23 14:56:49 +01:00
parent 09df1b387a
commit fd12a6d69f
21 changed files with 608 additions and 293 deletions

View File

@@ -1,3 +1,8 @@
1052. [func] marcin
libeval: expressions involving options can now use textual or
hexadecimal format of the options.
(Trac #4093 git 4cdf0fff1067b3dde6570dc6831e8b1343bc50fe)
1051. [func] [tmark] 1051. [func] [tmark]
kea-dhcp4 and kea-dhcp6 configuration parsing now supports kea-dhcp4 and kea-dhcp6 configuration parsing now supports
the "client-classes" element for defining client classes. the "client-classes" element for defining client classes.

View File

@@ -1696,7 +1696,7 @@ TEST_F(Dhcpv4SrvTest, matchClassification) {
" \"option-data\": [" " \"option-data\": ["
" { \"name\": \"ip-forwarding\", " " { \"name\": \"ip-forwarding\", "
" \"data\": \"true\" } ], " " \"data\": \"true\" } ], "
" \"test\": \"option[12] == 'foo'\" } ] }"; " \"test\": \"option[12].text == 'foo'\" } ] }";
ElementPtr json = Element::fromJSON(config); ElementPtr json = Element::fromJSON(config);
ConstElementPtr status; ConstElementPtr status;
@@ -1792,7 +1792,7 @@ TEST_F(Dhcpv4SrvTest, subnetClassPriority) {
" \"option-data\": [" " \"option-data\": ["
" { \"name\": \"ip-forwarding\", " " { \"name\": \"ip-forwarding\", "
" \"data\": \"true\" } ], " " \"data\": \"true\" } ], "
" \"test\": \"option[12] == 'foo'\" } ] }"; " \"test\": \"option[12].text == 'foo'\" } ] }";
ElementPtr json = Element::fromJSON(config); ElementPtr json = Element::fromJSON(config);
ConstElementPtr status; ConstElementPtr status;
@@ -1869,7 +1869,7 @@ TEST_F(Dhcpv4SrvTest, classGlobalPriority) {
" \"option-data\": [" " \"option-data\": ["
" { \"name\": \"ip-forwarding\", " " { \"name\": \"ip-forwarding\", "
" \"data\": \"true\" } ], " " \"data\": \"true\" } ], "
" \"test\": \"option[12] == 'foo'\" } ] }"; " \"test\": \"option[12].text == 'foo'\" } ] }";
ElementPtr json = Element::fromJSON(config); ElementPtr json = Element::fromJSON(config);
ConstElementPtr status; ConstElementPtr status;

View File

@@ -1866,7 +1866,7 @@ TEST_F(Dhcpv6SrvTest, matchClassification) {
" \"option-data\": [" " \"option-data\": ["
" { \"name\": \"ipv6-forwarding\", " " { \"name\": \"ipv6-forwarding\", "
" \"data\": \"true\" } ], " " \"data\": \"true\" } ], "
" \"test\": \"option[1234] == 'foo'\" } ] }"; " \"test\": \"option[1234].text == 'foo'\" } ] }";
ASSERT_NO_THROW(configure(config)); ASSERT_NO_THROW(configure(config));
// Create packets with enough to select the subnet // Create packets with enough to select the subnet
@@ -1962,7 +1962,7 @@ TEST_F(Dhcpv6SrvTest, subnetClassPriority) {
" \"option-data\": [" " \"option-data\": ["
" { \"name\": \"ipv6-forwarding\", " " { \"name\": \"ipv6-forwarding\", "
" \"data\": \"true\" } ], " " \"data\": \"true\" } ], "
" \"test\": \"option[1234] == 'foo'\" } ] }"; " \"test\": \"option[1234].text == 'foo'\" } ] }";
ASSERT_NO_THROW(configure(config)); ASSERT_NO_THROW(configure(config));
// Create a packet with enough to select the subnet and go through // Create a packet with enough to select the subnet and go through
@@ -2037,7 +2037,7 @@ TEST_F(Dhcpv6SrvTest, classGlobalPriority) {
" \"option-data\": [" " \"option-data\": ["
" { \"name\": \"ipv6-forwarding\", " " { \"name\": \"ipv6-forwarding\", "
" \"data\": \"true\" } ], " " \"data\": \"true\" } ], "
" \"test\": \"option[1234] == 'foo'\" } ] }"; " \"test\": \"option[1234].text == 'foo'\" } ] }";
ASSERT_NO_THROW(configure(config)); ASSERT_NO_THROW(configure(config));
// Create a packet with enough to select the subnet and go through // Create a packet with enough to select the subnet and go through

View File

@@ -16,6 +16,7 @@
#include <dhcp/libdhcp++.h> #include <dhcp/libdhcp++.h>
#include <dhcp/option.h> #include <dhcp/option.h>
#include <exceptions/exceptions.h> #include <exceptions/exceptions.h>
#include <util/encode/hex.h>
#include <util/io_utilities.h> #include <util/io_utilities.h>
#include <iomanip> #include <iomanip>
@@ -219,6 +220,34 @@ Option::toString() {
return (toText(0)); return (toText(0));
} }
std::string
Option::toHexString(const bool include_header) {
OutputBuffer buf(len());
try {
// If the option is too long, exception will be thrown. We allow
// for this exception to propagate to not mask this error.
pack(buf);
} catch (const std::exception &ex) {
isc_throw(OutOfRange, "unable to obtain hexadecimal representation"
" of option " << getType() << ": " << ex.what());
}
const uint8_t* option_data = static_cast<const uint8_t*>(buf.getData());
std::vector<uint8_t> option_vec;
// Assign option data to a vector, with or without option header depending
// on the value of "include_header" flag.
option_vec.assign(option_data + (include_header ? 0 : getHeaderLen()),
option_data + buf.getLength());
// Return hexadecimal representation prepended with 0x or empty string
// if option has no payload and the header fields are excluded.
std::ostringstream s;
if (!option_vec.empty()) {
s << "0x" << encode::encodeHex(option_vec);
}
return (s.str());
}
std::string std::string
Option::headerToText(const int indent, const std::string& type_name) { Option::headerToText(const int indent, const std::string& type_name) {

View File

@@ -216,6 +216,15 @@ public:
/// @return string that represents the value of the option. /// @return string that represents the value of the option.
virtual std::string toString(); virtual std::string toString();
/// @brief Returns string containing hexadecimal representation of option.
///
/// @param include_header Boolean flag which indicates if the output should
/// also contain header fields. The default is that it shouldn't include
/// header fields.
///
/// @return String containing hexadecimal representation of the option.
virtual std::string toHexString(const bool include_header = false);
/// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6) /// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
/// ///
/// @return option type /// @return option type

View File

@@ -236,6 +236,38 @@ TEST_F(OptionTest, v4_toText) {
EXPECT_EQ("type=253, len=003: 00:0f:ff", opt.toText()); EXPECT_EQ("type=253, len=003: 00:0f:ff", opt.toText());
} }
// Test converting option to the hexadecimal representation.
TEST_F(OptionTest, v4_toHexString) {
std::vector<uint8_t> payload;
for (unsigned int i = 0; i < 16; ++i) {
payload.push_back(static_cast<uint8_t>(i));
}
Option opt(Option::V4, 122, payload);
EXPECT_EQ("0x000102030405060708090A0B0C0D0E0F", opt.toHexString());
EXPECT_EQ("0x7A10000102030405060708090A0B0C0D0E0F",
opt.toHexString(true));
// Test empty option.
Option opt_empty(Option::V4, 65, std::vector<uint8_t>());
EXPECT_TRUE(opt_empty.toHexString().empty());
EXPECT_EQ("0x4100", opt_empty.toHexString(true));
// Test too long option. We can't simply create such option by
// providing a long payload, because class constructor would not
// accept it. Instead we'll add two long sub options after we
// create an option instance.
Option opt_too_long(Option::V4, 33);
// Both suboptions have payloads of 150 bytes.
std::vector<uint8_t> long_payload(150, 1);
OptionPtr sub1(new Option(Option::V4, 100, long_payload));
OptionPtr sub2(new Option(Option::V4, 101, long_payload));
opt_too_long.addOption(sub1);
opt_too_long.addOption(sub2);
// The toHexString() should throw exception.
EXPECT_THROW(opt_too_long.toHexString(), isc::OutOfRange);
}
// Tests simple constructor // Tests simple constructor
TEST_F(OptionTest, v6_basic) { TEST_F(OptionTest, v6_basic) {
@@ -446,6 +478,22 @@ TEST_F(OptionTest, v6_toText) {
EXPECT_EQ("type=00258, len=00003: 00:0f:ff", opt->toText()); EXPECT_EQ("type=00258, len=00003: 00:0f:ff", opt->toText());
} }
// Test converting option to the hexadecimal representation.
TEST_F(OptionTest, v6_toHexString) {
std::vector<uint8_t> payload;
for (unsigned int i = 0; i < 16; ++i) {
payload.push_back(static_cast<uint8_t>(i));
}
Option opt(Option::V6, 12202, payload);
EXPECT_EQ("0x000102030405060708090A0B0C0D0E0F", opt.toHexString());
EXPECT_EQ("0x2FAA0010000102030405060708090A0B0C0D0E0F",
opt.toHexString(true));
// Test empty option.
Option opt_empty(Option::V6, 65000, std::vector<uint8_t>());
EXPECT_TRUE(opt_empty.toHexString().empty());
EXPECT_EQ("0xFDE80000", opt_empty.toHexString(true));
}
TEST_F(OptionTest, getUintX) { TEST_F(OptionTest, getUintX) {

View File

@@ -119,7 +119,7 @@ TEST(ExpressionParserTest, validExpression4) {
ExpressionPtr parsed_expr; ExpressionPtr parsed_expr;
// Turn config into elements. This may emit exceptions. // Turn config into elements. This may emit exceptions.
std::string cfg_txt = "\"option[100] == 'hundred4'\""; std::string cfg_txt = "\"option[100].text == 'hundred4'\"";
ElementPtr config_element = Element::fromJSON(cfg_txt); ElementPtr config_element = Element::fromJSON(cfg_txt);
// Create the parser. // Create the parser.
@@ -150,7 +150,7 @@ TEST(ExpressionParserTest, validExpression6) {
ExpressionPtr parsed_expr; ExpressionPtr parsed_expr;
// Turn config into elements. This may emit exceptions. // Turn config into elements. This may emit exceptions.
std::string cfg_txt = "\"option[100] == 'hundred6'\""; std::string cfg_txt = "\"option[100].text == 'hundred6'\"";
ElementPtr config_element = Element::fromJSON(cfg_txt); ElementPtr config_element = Element::fromJSON(cfg_txt);
// Create the parser. // Create the parser.
@@ -249,7 +249,7 @@ TEST_F(ClientClassDefParserTest, nameAndExpressionClass) {
std::string cfg_text = std::string cfg_text =
"{ \n" "{ \n"
" \"name\": \"class_one\", \n" " \"name\": \"class_one\", \n"
" \"test\": \"option[100] == 'works right'\" \n" " \"test\": \"option[100].text == 'works right'\" \n"
"} \n"; "} \n";
ClientClassDefPtr cclass; ClientClassDefPtr cclass;
@@ -325,7 +325,7 @@ TEST_F(ClientClassDefParserTest, basicValidClass) {
std::string cfg_text = std::string cfg_text =
"{ \n" "{ \n"
" \"name\": \"MICROSOFT\", \n" " \"name\": \"MICROSOFT\", \n"
" \"test\": \"option[100] == 'booya'\", \n" " \"test\": \"option[100].text == 'booya'\", \n"
" \"option-data\": [ \n" " \"option-data\": [ \n"
" { \n" " { \n"
" \"name\": \"domain-name-servers\", \n" " \"name\": \"domain-name-servers\", \n"
@@ -368,7 +368,7 @@ TEST_F(ClientClassDefParserTest, noClassName) {
std::string cfg_text = std::string cfg_text =
"{ \n" "{ \n"
" \"test\": \"option[123] == 'abc'\", \n" " \"test\": \"option[123].text == 'abc'\", \n"
" \"option-data\": [ \n" " \"option-data\": [ \n"
" { \n" " { \n"
" \"name\": \"domain-name-servers\", \n" " \"name\": \"domain-name-servers\", \n"
@@ -391,7 +391,7 @@ TEST_F(ClientClassDefParserTest, blankClassName) {
std::string cfg_text = std::string cfg_text =
"{ \n" "{ \n"
" \"name\": \"\", \n" " \"name\": \"\", \n"
" \"test\": \"option[123] == 'abc'\", \n" " \"test\": \"option[123].text == 'abc'\", \n"
" \"option-data\": [ \n" " \"option-data\": [ \n"
" { \n" " { \n"
" \"name\": \"domain-name-servers\", \n" " \"name\": \"domain-name-servers\", \n"

View File

@@ -18,8 +18,9 @@
@section dhcpEvalIntroduction Introduction @section dhcpEvalIntroduction Introduction
The core of the libeval library is a parser that is able to parse an The core of the libeval library is a parser that is able to parse an
expression (e.g. option[123] == 'APC'). This is currently used for client expression (e.g. option[123].text == 'APC'). This is currently used for
classification, but in the future may be also used for other applications. client classification, but in the future may be also used for other
applications.
The external interface to the library is the @ref isc::eval::EvalContext The external interface to the library is the @ref isc::eval::EvalContext
class. Once instantiated, it offers a major method: class. Once instantiated, it offers a major method:
@@ -79,12 +80,17 @@
14. TokenPtr hex(new TokenHexString($1)); 14. TokenPtr hex(new TokenHexString($1));
15. ctx.expression.push_back(hex); 15. ctx.expression.push_back(hex);
16. } 16. }
17. | OPTION '[' INTEGER ']' 17. | OPTION '[' INTEGER ']' DOT TEXT
18. { 18. {
19. TokenPtr opt(new TokenOption($3)); 19. TokenPtr opt(new TokenOption($3, TokenOption::TEXTUAL));
20. ctx.expression.push_back(opt); 20. ctx.expression.push_back(opt);
21. } 21. }
22. ; 22. | OPTION '[' INTEGER ']' DOT HEX
23. {
24. TokenPtr opt(new TokenOption($3, TokenOption::HEXADECIMAL));
25. ctx.expression.push_back(opt);
26. }
27. ;
@endcode @endcode
This code determines that the grammar starts from expression (line 1). This code determines that the grammar starts from expression (line 1).
@@ -92,7 +98,8 @@ The actual definition of expression (lines 3-5) may either be a
single token or an expression "token == token" (EQUAL has been defined as single token or an expression "token == token" (EQUAL has been defined as
"==" elsewhere). Token is further "==" elsewhere). Token is further
defined in lines 7-22: it may either be a string (lines 7-11), defined in lines 7-22: it may either be a string (lines 7-11),
a hex string (lines 12-16) or option (lines 17-21). a hex string (lines 12-16), option in the textual format (lines 17-21)
or option in a hexadecimal format (lines 22-26).
When the actual case is determined, the respective C++ action When the actual case is determined, the respective C++ action
is executed. For example, if the token is a string, the TokenString class is is executed. For example, if the token is a string, the TokenString class is
instantiated with the appropriate value and put onto the expression vector. instantiated with the appropriate value and put onto the expression vector.

View File

@@ -18,7 +18,7 @@
#define FLEX_SCANNER #define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 39 #define YY_FLEX_SUBMINOR_VERSION 35
#if YY_FLEX_SUBMINOR_VERSION > 0 #if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA #define FLEX_BETA
#endif #endif
@@ -72,6 +72,7 @@ typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t; typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t; typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t; typedef uint32_t flex_uint32_t;
typedef uint64_t flex_uint64_t;
#else #else
typedef signed char flex_int8_t; typedef signed char flex_int8_t;
typedef short int flex_int16_t; typedef short int flex_int16_t;
@@ -79,6 +80,7 @@ typedef int flex_int32_t;
typedef unsigned char flex_uint8_t; typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t; typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t; typedef unsigned int flex_uint32_t;
#endif /* ! C99 */
/* Limits of integral types. */ /* Limits of integral types. */
#ifndef INT8_MIN #ifndef INT8_MIN
@@ -109,8 +111,6 @@ typedef unsigned int flex_uint32_t;
#define UINT32_MAX (4294967295U) #define UINT32_MAX (4294967295U)
#endif #endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */ #endif /* ! FLEXINT_H */
/* %endif */ /* %endif */
@@ -225,18 +225,11 @@ extern FILE *yyin, *yyout;
*/ */
#define YY_LESS_LINENO(n) \ #define YY_LESS_LINENO(n) \
do { \ do { \
int yyl;\ yy_size_t yyl;\
for ( yyl = n; yyl < yyleng; ++yyl )\ for ( yyl = n; yyl < yyleng; ++yyl )\
if ( yytext[yyl] == '\n' )\ if ( yytext[yyl] == '\n' )\
--yylineno;\ --yylineno;\
}while(0) }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. */ /* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \ #define yyless(n) \
@@ -427,7 +420,7 @@ void yyfree (void * );
/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ /* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
/* Begin user sect3 */ /* Begin user sect3 */
#define yywrap() 1 #define yywrap(n) 1
#define YY_SKIP_YYWRAP #define YY_SKIP_YYWRAP
#define FLEX_DEBUG #define FLEX_DEBUG
@@ -445,8 +438,6 @@ int yylineno = 1;
extern char *yytext; extern char *yytext;
#define yytext_ptr yytext #define yytext_ptr yytext
/* %% [1.5] DFA */
/* %if-c-only Standard (non-C++) definition */ /* %if-c-only Standard (non-C++) definition */
static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_get_previous_state (void );
@@ -462,15 +453,15 @@ static void yy_fatal_error (yyconst char msg[] );
#define YY_DO_BEFORE_ACTION \ #define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \ (yytext_ptr) = yy_bp; \
/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ /* %% [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_hold_char) = *yy_cp; \
*yy_cp = '\0'; \ *yy_cp = '\0'; \
/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ /* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
(yy_c_buf_p) = yy_cp; (yy_c_buf_p) = yy_cp;
/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ /* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
#define YY_NUM_RULES 16 #define YY_NUM_RULES 19
#define YY_END_OF_BUFFER 17 #define YY_END_OF_BUFFER 20
/* This struct is not used in this scanner, /* This struct is not used in this scanner,
but its presence is necessary. */ but its presence is necessary. */
struct yy_trans_info struct yy_trans_info
@@ -478,13 +469,14 @@ struct yy_trans_info
flex_int32_t yy_verify; flex_int32_t yy_verify;
flex_int32_t yy_nxt; flex_int32_t yy_nxt;
}; };
static yyconst flex_int16_t yy_accept[44] = static yyconst flex_int16_t yy_accept[52] =
{ 0, { 0,
0, 0, 17, 15, 1, 2, 15, 10, 11, 14, 0, 0, 20, 18, 1, 2, 18, 13, 14, 17,
15, 5, 5, 15, 12, 13, 15, 15, 15, 1, 18, 12, 5, 5, 18, 15, 16, 18, 18, 18,
2, 0, 3, 5, 0, 6, 0, 0, 0, 4, 18, 18, 1, 2, 0, 3, 5, 0, 6, 0,
9, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 4, 11, 9, 0, 0, 0,
0, 8, 0 0, 0, 8, 0, 0, 7, 0, 0, 0, 10,
0
} ; } ;
static yyconst flex_int32_t yy_ec[256] = static yyconst flex_int32_t yy_ec[256] =
@@ -493,15 +485,15 @@ static yyconst flex_int32_t yy_ec[256] =
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, 2, 1, 1, 1, 1, 1, 1, 4, 5, 1, 2, 1, 1, 1, 1, 1, 1, 4, 5,
6, 1, 1, 7, 8, 1, 1, 9, 10, 10, 6, 1, 1, 7, 8, 9, 1, 10, 11, 11,
10, 10, 10, 10, 10, 10, 10, 1, 1, 1, 11, 11, 11, 11, 11, 11, 11, 1, 1, 1,
11, 1, 1, 1, 12, 12, 12, 12, 12, 12, 12, 1, 1, 1, 13, 13, 13, 13, 13, 13,
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, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1,
14, 1, 15, 1, 1, 1, 16, 17, 12, 12, 15, 1, 16, 1, 1, 1, 17, 18, 13, 13,
12, 12, 18, 1, 19, 1, 1, 20, 1, 21, 19, 13, 20, 21, 22, 1, 1, 23, 1, 24,
22, 23, 1, 24, 25, 26, 27, 1, 1, 13, 25, 26, 1, 27, 28, 29, 30, 1, 1, 31,
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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -519,61 +511,71 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1 1, 1, 1, 1, 1
} ; } ;
static yyconst flex_int32_t yy_meta[28] = static yyconst flex_int32_t yy_meta[32] =
{ 0, { 0,
1, 1, 2, 1, 1, 1, 1, 1, 3, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3,
1, 3, 1, 1, 1, 3, 3, 1, 1, 1, 3, 1, 3, 1, 1, 1, 3, 3, 3, 1,
1, 1, 1, 1, 1, 1, 1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1
} ; } ;
static yyconst flex_int16_t yy_base[46] = static yyconst flex_int16_t yy_base[54] =
{ 0, { 0,
0, 0, 62, 63, 59, 57, 55, 63, 63, 63, 0, 0, 72, 73, 69, 67, 65, 73, 73, 73,
19, 21, 23, 47, 63, 63, 37, 33, 28, 52, 22, 73, 24, 26, 56, 73, 73, 44, 47, 39,
50, 48, 63, 26, 0, 63, 31, 24, 32, 0, 34, 44, 60, 58, 56, 73, 29, 0, 73, 36,
63, 29, 22, 24, 19, 23, 19, 63, 23, 20, 26, 25, 35, 21, 0, 73, 73, 29, 22, 20,
22, 63, 63, 36, 35 23, 18, 73, 22, 18, 73, 22, 19, 22, 73,
73, 55, 38
} ; } ;
static yyconst flex_int16_t yy_def[46] = static yyconst flex_int16_t yy_def[54] =
{ 0, { 0,
43, 1, 43, 43, 43, 43, 44, 43, 43, 43, 51, 1, 51, 51, 51, 51, 52, 51, 51, 51,
43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
43, 44, 43, 43, 45, 43, 43, 43, 43, 45, 51, 51, 51, 51, 52, 51, 51, 53, 51, 51,
43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 51, 51, 51, 51, 53, 51, 51, 51, 51, 51,
43, 43, 0, 43, 43 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
0, 51, 51
} ; } ;
static yyconst flex_int16_t yy_nxt[91] = static yyconst flex_int16_t yy_nxt[105] =
{ 0, { 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 4, 4, 15, 16, 17, 4, 4, 4, 4, 14, 15, 4, 4, 16, 17, 18, 4, 4, 4,
4, 18, 4, 4, 19, 4, 4, 24, 24, 24, 19, 4, 4, 4, 20, 4, 4, 21, 22, 4,
24, 24, 24, 25, 24, 24, 22, 30, 22, 42, 4, 27, 27, 27, 27, 27, 27, 28, 27, 27,
41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 35, 50, 49, 48, 47, 46, 45, 44, 43, 42,
31, 23, 21, 20, 29, 28, 27, 26, 23, 21, 41, 40, 39, 38, 28, 25, 37, 25, 36, 26,
20, 43, 3, 43, 43, 43, 43, 43, 43, 43, 24, 23, 34, 33, 32, 31, 30, 29, 26, 24,
43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 23, 51, 3, 51, 51, 51, 51, 51, 51, 51,
43, 43, 43, 43, 43, 43, 43, 43, 43, 43 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51
} ; } ;
static yyconst flex_int16_t yy_chk[91] = static yyconst flex_int16_t yy_chk[105] =
{ 0, { 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 11, 11, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
12, 13, 13, 12, 24, 24, 44, 45, 44, 41, 1, 11, 11, 13, 13, 14, 14, 13, 27, 27,
40, 39, 37, 36, 35, 34, 33, 32, 29, 28, 53, 49, 48, 47, 45, 44, 42, 41, 40, 39,
27, 22, 21, 20, 19, 18, 17, 14, 7, 6, 38, 34, 33, 32, 13, 52, 31, 52, 30, 25,
5, 3, 43, 43, 43, 43, 43, 43, 43, 43, 24, 23, 22, 21, 20, 19, 18, 15, 7, 6,
43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 3, 51, 51, 51, 51, 51, 51, 51, 51,
43, 43, 43, 43, 43, 43, 43, 43, 43, 43 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
51, 51, 51, 51
} ; } ;
/* Table of booleans, true if rule could match eol. */ /* Table of booleans, true if rule could match eol. */
static yyconst flex_int32_t yy_rule_can_match_eol[17] = static yyconst flex_int32_t yy_rule_can_match_eol[20] =
{ 0, { 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static yy_state_type yy_last_accepting_state; static yy_state_type yy_last_accepting_state;
static char *yy_last_accepting_cpos; static char *yy_last_accepting_cpos;
@@ -581,10 +583,10 @@ static char *yy_last_accepting_cpos;
extern int yy_flex_debug; extern int yy_flex_debug;
int yy_flex_debug = 1; int yy_flex_debug = 1;
static yyconst flex_int16_t yy_rule_linenum[16] = static yyconst flex_int16_t yy_rule_linenum[19] =
{ 0, { 0,
83, 87, 93, 103, 109, 123, 124, 125, 126, 127, 83, 87, 93, 103, 109, 123, 124, 125, 126, 127,
128, 129, 130, 131, 133 128, 129, 130, 131, 132, 133, 134, 136
} ; } ;
/* The intent behind this definition is that it'll catch /* The intent behind this definition is that it'll catch
@@ -651,7 +653,7 @@ static isc::eval::location loc;
// by moving it ahead by yyleng bytes. yyleng specifies the length of the // by moving it ahead by yyleng bytes. yyleng specifies the length of the
// currently matched token. // currently matched token.
#define YY_USER_ACTION loc.columns(yyleng); #define YY_USER_ACTION loc.columns(yyleng);
#line 655 "lexer.cc" #line 657 "lexer.cc"
#define INITIAL 0 #define INITIAL 0
@@ -769,7 +771,7 @@ static int input (void );
/* This used to be an fputs(), but since the string might contain NUL's, /* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite(). * we now use fwrite().
*/ */
#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #define ECHO fwrite( yytext, yyleng, 1, yyout )
/* %endif */ /* %endif */
/* %if-c++-only C++ definition */ /* %if-c++-only C++ definition */
/* %endif */ /* %endif */
@@ -784,7 +786,7 @@ static int input (void );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \ { \
int c = '*'; \ int c = '*'; \
size_t n; \ yy_size_t n; \
for ( n = 0; n < max_size && \ for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \ buf[n] = (char) c; \
@@ -890,6 +892,17 @@ YY_DECL
register char *yy_cp, *yy_bp; register char *yy_cp, *yy_bp;
register int yy_act; register int yy_act;
/* %% [7.0] user's declarations go here */
#line 76 "lexer.ll"
// Code run each time yylex is called.
loc.step();
#line 905 "lexer.cc"
if ( !(yy_init) ) if ( !(yy_init) )
{ {
(yy_init) = 1; (yy_init) = 1;
@@ -924,18 +937,6 @@ YY_DECL
yy_load_buffer_state( ); yy_load_buffer_state( );
} }
{
/* %% [7.0] user's declarations go here */
#line 76 "lexer.ll"
// Code run each time yylex is called.
loc.step();
#line 938 "lexer.cc"
while ( 1 ) /* loops until end-of-file is reached */ while ( 1 ) /* loops until end-of-file is reached */
{ {
/* %% [8.0] yymore()-related code goes here */ /* %% [8.0] yymore()-related code goes here */
@@ -963,13 +964,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{ {
yy_current_state = (int) yy_def[yy_current_state]; yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 44 ) if ( yy_current_state >= 52 )
yy_c = yy_meta[(unsigned int) yy_c]; yy_c = yy_meta[(unsigned int) yy_c];
} }
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp; ++yy_cp;
} }
while ( yy_current_state != 43 ); while ( yy_current_state != 51 );
yy_cp = (yy_last_accepting_cpos); yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state); yy_current_state = (yy_last_accepting_state);
@@ -998,13 +999,13 @@ do_action: /* This label is used only to access EOF actions. */
{ {
if ( yy_act == 0 ) if ( yy_act == 0 )
fprintf( stderr, "--scanner backing up\n" ); fprintf( stderr, "--scanner backing up\n" );
else if ( yy_act < 16 ) else if ( yy_act < 19 )
fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
(long)yy_rule_linenum[yy_act], yytext ); (long)yy_rule_linenum[yy_act], yytext );
else if ( yy_act == 16 ) else if ( yy_act == 19 )
fprintf( stderr, "--accepting default rule (\"%s\")\n", fprintf( stderr, "--accepting default rule (\"%s\")\n",
yytext ); yytext );
else if ( yy_act == 17 ) else if ( yy_act == 20 )
fprintf( stderr, "--(end of buffer or a NUL)\n" ); fprintf( stderr, "--(end of buffer or a NUL)\n" );
else else
fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
@@ -1090,53 +1091,68 @@ return isc::eval::EvalParser::make_OPTION(loc);
case 8: case 8:
YY_RULE_SETUP YY_RULE_SETUP
#line 125 "lexer.ll" #line 125 "lexer.ll"
return isc::eval::EvalParser::make_SUBSTRING(loc); return isc::eval::EvalParser::make_TEXT(loc);
YY_BREAK YY_BREAK
case 9: case 9:
YY_RULE_SETUP YY_RULE_SETUP
#line 126 "lexer.ll" #line 126 "lexer.ll"
return isc::eval::EvalParser::make_ALL(loc); return isc::eval::EvalParser::make_HEX(loc);
YY_BREAK YY_BREAK
case 10: case 10:
YY_RULE_SETUP YY_RULE_SETUP
#line 127 "lexer.ll" #line 127 "lexer.ll"
return isc::eval::EvalParser::make_LPAREN(loc); return isc::eval::EvalParser::make_SUBSTRING(loc);
YY_BREAK YY_BREAK
case 11: case 11:
YY_RULE_SETUP YY_RULE_SETUP
#line 128 "lexer.ll" #line 128 "lexer.ll"
return isc::eval::EvalParser::make_RPAREN(loc); return isc::eval::EvalParser::make_ALL(loc);
YY_BREAK YY_BREAK
case 12: case 12:
YY_RULE_SETUP YY_RULE_SETUP
#line 129 "lexer.ll" #line 129 "lexer.ll"
return isc::eval::EvalParser::make_LBRACKET(loc); return isc::eval::EvalParser::make_DOT(loc);
YY_BREAK YY_BREAK
case 13: case 13:
YY_RULE_SETUP YY_RULE_SETUP
#line 130 "lexer.ll" #line 130 "lexer.ll"
return isc::eval::EvalParser::make_RBRACKET(loc); return isc::eval::EvalParser::make_LPAREN(loc);
YY_BREAK YY_BREAK
case 14: case 14:
YY_RULE_SETUP YY_RULE_SETUP
#line 131 "lexer.ll" #line 131 "lexer.ll"
return isc::eval::EvalParser::make_COMA(loc); return isc::eval::EvalParser::make_RPAREN(loc);
YY_BREAK YY_BREAK
case 15: case 15:
YY_RULE_SETUP YY_RULE_SETUP
#line 133 "lexer.ll" #line 132 "lexer.ll"
driver.error (loc, "Invalid character: " + std::string(yytext)); return isc::eval::EvalParser::make_LBRACKET(loc);
YY_BREAK
case YY_STATE_EOF(INITIAL):
#line 134 "lexer.ll"
return isc::eval::EvalParser::make_END(loc);
YY_BREAK YY_BREAK
case 16: case 16:
YY_RULE_SETUP YY_RULE_SETUP
#line 135 "lexer.ll" #line 133 "lexer.ll"
return isc::eval::EvalParser::make_RBRACKET(loc);
YY_BREAK
case 17:
YY_RULE_SETUP
#line 134 "lexer.ll"
return isc::eval::EvalParser::make_COMA(loc);
YY_BREAK
case 18:
YY_RULE_SETUP
#line 136 "lexer.ll"
driver.error (loc, "Invalid character: " + std::string(yytext));
YY_BREAK
case YY_STATE_EOF(INITIAL):
#line 137 "lexer.ll"
return isc::eval::EvalParser::make_END(loc);
YY_BREAK
case 19:
YY_RULE_SETUP
#line 138 "lexer.ll"
ECHO; ECHO;
YY_BREAK YY_BREAK
#line 1140 "lexer.cc" #line 1156 "lexer.cc"
case YY_END_OF_BUFFER: case YY_END_OF_BUFFER:
{ {
@@ -1267,7 +1283,6 @@ ECHO;
"fatal flex scanner internal error--no action found" ); "fatal flex scanner internal error--no action found" );
} /* end of action switch */ } /* end of action switch */
} /* end of scanning one token */ } /* end of scanning one token */
} /* end of user's declarations */
} /* end of yylex */ } /* end of yylex */
/* %ok-for-header */ /* %ok-for-header */
@@ -1342,7 +1357,7 @@ static int yy_get_next_buffer (void)
{ /* Not enough room in the buffer - grow it. */ { /* Not enough room in the buffer - grow it. */
/* just a shorter name for the current buffer */ /* just a shorter name for the current buffer */
YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
int yy_c_buf_p_offset = int yy_c_buf_p_offset =
(int) ((yy_c_buf_p) - b->yy_ch_buf); (int) ((yy_c_buf_p) - b->yy_ch_buf);
@@ -1449,7 +1464,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{ {
yy_current_state = (int) yy_def[yy_current_state]; yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 44 ) if ( yy_current_state >= 52 )
yy_c = yy_meta[(unsigned int) yy_c]; yy_c = yy_meta[(unsigned int) yy_c];
} }
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1482,11 +1497,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{ {
yy_current_state = (int) yy_def[yy_current_state]; yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 44 ) if ( yy_current_state >= 52 )
yy_c = yy_meta[(unsigned int) yy_c]; yy_c = yy_meta[(unsigned int) yy_c];
} }
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 43); yy_is_jam = (yy_current_state == 51);
return yy_is_jam ? 0 : yy_current_state; return yy_is_jam ? 0 : yy_current_state;
} }
@@ -1547,7 +1562,7 @@ static int yy_get_next_buffer (void)
case EOB_ACT_END_OF_FILE: case EOB_ACT_END_OF_FILE:
{ {
if ( yywrap( ) ) if ( yywrap( ) )
return EOF; return 0;
if ( ! (yy_did_buffer_switch_on_eof) ) if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE; YY_NEW_FILE;
@@ -1711,6 +1726,17 @@ static void yy_load_buffer_state (void)
yyfree((void *) b ); yyfree((void *) b );
} }
/* %if-c-only */
#ifndef __cplusplus
extern int isatty (int );
#endif /* __cplusplus */
/* %endif */
/* %if-c++-only */
/* %endif */
/* Initializes or reinitializes a buffer. /* Initializes or reinitializes a buffer.
* This function is sometimes called more than once on the same buffer, * This function is sometimes called more than once on the same buffer,
* such as during a yyrestart() or at EOF. * such as during a yyrestart() or at EOF.
@@ -1951,8 +1977,8 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
/* %if-c-only */ /* %if-c-only */
/** Setup the input buffer state to scan the given bytes. The next call to yylex() will /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
* scan from a @e copy of @a bytes. * scan from a @e copy of @a bytes.
* @param yybytes the byte buffer to scan * @param bytes the byte buffer to scan
* @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param len the number of bytes in the buffer pointed to by @a bytes.
* *
* @return the newly allocated buffer state object. * @return the newly allocated buffer state object.
*/ */
@@ -1960,8 +1986,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len
{ {
YY_BUFFER_STATE b; YY_BUFFER_STATE b;
char *buf; char *buf;
yy_size_t n; yy_size_t n, i;
yy_size_t i;
/* Get memory for full buffer, including space for trailing EOB's. */ /* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2; n = _yybytes_len + 2;
@@ -2224,7 +2249,7 @@ void yyfree (void * ptr )
/* %ok-for-header */ /* %ok-for-header */
#line 135 "lexer.ll" #line 138 "lexer.ll"

View File

@@ -122,8 +122,11 @@ blank [ \t]
"==" return isc::eval::EvalParser::make_EQUAL(loc); "==" return isc::eval::EvalParser::make_EQUAL(loc);
"option" return isc::eval::EvalParser::make_OPTION(loc); "option" return isc::eval::EvalParser::make_OPTION(loc);
"text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc); "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
"all" return isc::eval::EvalParser::make_ALL(loc); "all" return isc::eval::EvalParser::make_ALL(loc);
"." return isc::eval::EvalParser::make_DOT(loc);
"(" return isc::eval::EvalParser::make_LPAREN(loc); "(" return isc::eval::EvalParser::make_LPAREN(loc);
")" return isc::eval::EvalParser::make_RPAREN(loc); ")" return isc::eval::EvalParser::make_RPAREN(loc);
"[" return isc::eval::EvalParser::make_LBRACKET(loc); "[" return isc::eval::EvalParser::make_LBRACKET(loc);

View File

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

View File

@@ -52,8 +52,34 @@
#line 39 "parser.yy" // lalr1.cc:413 #line 39 "parser.yy" // lalr1.cc:413
# include "eval_context.h" # include "eval_context.h"
#line 67 "parser.yy" // lalr1.cc:413
#line 57 "parser.cc" // lalr1.cc:413 namespace {
/* Convert option code specified as string to an 16 bit unsigned
representation. If the option code is not within the range of
0..65535 an error is reported. */
uint16_t
convert_option_code(const std::string& option_code,
const isc::eval::EvalParser::location_type& loc,
EvalContext& ctx) {
int n = 0;
try {
n = boost::lexical_cast<int>(option_code);
} catch (const boost::bad_lexical_cast &) {
// This can't happen...
ctx.error(loc, "Option code has invalid value in " + option_code);
}
if (n < 0 || n > 65535) {
ctx.error(loc, "Option code has invalid value in "
+ option_code + ". Allowed range: 0..65535");
}
return (static_cast<uint16_t>(n));
}
}
#line 83 "parser.cc" // lalr1.cc:413
#ifndef YY_ #ifndef YY_
@@ -139,7 +165,7 @@
#line 21 "parser.yy" // lalr1.cc:479 #line 21 "parser.yy" // lalr1.cc:479
namespace isc { namespace eval { namespace isc { namespace eval {
#line 143 "parser.cc" // lalr1.cc:479 #line 169 "parser.cc" // lalr1.cc:479
/* Return YYSTR after stripping away unnecessary quotes and /* Return YYSTR after stripping away unnecessary quotes and
backslashes, so that it's suitable for yyerror. The heuristic is backslashes, so that it's suitable for yyerror. The heuristic is
@@ -251,10 +277,10 @@ namespace isc { namespace eval {
{ {
switch (that.type_get ()) switch (that.type_get ())
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
value.move< std::string > (that.value); value.move< std::string > (that.value);
break; break;
@@ -273,10 +299,10 @@ namespace isc { namespace eval {
state = that.state; state = that.state;
switch (that.type_get ()) switch (that.type_get ())
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
value.copy< std::string > (that.value); value.copy< std::string > (that.value);
break; break;
@@ -316,32 +342,32 @@ namespace isc { namespace eval {
<< yysym.location << ": "; << yysym.location << ": ";
switch (yytype) switch (yytype)
{ {
case 12: // "constant string" case 15: // "constant string"
#line 61 "parser.yy" // lalr1.cc:636 #line 64 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 324 "parser.cc" // lalr1.cc:636 #line 350 "parser.cc" // lalr1.cc:636
break; break;
case 13: // "integer" case 16: // "integer"
#line 61 "parser.yy" // lalr1.cc:636 #line 64 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 331 "parser.cc" // lalr1.cc:636 #line 357 "parser.cc" // lalr1.cc:636
break; break;
case 14: // "constant hexstring" case 17: // "constant hexstring"
#line 61 "parser.yy" // lalr1.cc:636 #line 64 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 338 "parser.cc" // lalr1.cc:636 #line 364 "parser.cc" // lalr1.cc:636
break; break;
case 15: // TOKEN case 18: // TOKEN
#line 61 "parser.yy" // lalr1.cc:636 #line 64 "parser.yy" // lalr1.cc:636
{ yyoutput << yysym.value.template as< std::string > (); } { yyoutput << yysym.value.template as< std::string > (); }
#line 345 "parser.cc" // lalr1.cc:636 #line 371 "parser.cc" // lalr1.cc:636
break; break;
@@ -541,10 +567,10 @@ namespace isc { namespace eval {
when using variants. */ when using variants. */
switch (yyr1_[yyn]) switch (yyr1_[yyn])
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
yylhs.value.build< std::string > (); yylhs.value.build< std::string > ();
break; break;
@@ -566,92 +592,90 @@ namespace isc { namespace eval {
switch (yyn) switch (yyn)
{ {
case 3: case 3:
#line 73 "parser.yy" // lalr1.cc:859 #line 105 "parser.yy" // lalr1.cc:859
{ {
TokenPtr eq(new TokenEqual()); TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq); ctx.expression.push_back(eq);
} }
#line 575 "parser.cc" // lalr1.cc:859 #line 601 "parser.cc" // lalr1.cc:859
break; break;
case 4: case 4:
#line 80 "parser.yy" // lalr1.cc:859 #line 112 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str); ctx.expression.push_back(str);
} }
#line 584 "parser.cc" // lalr1.cc:859 #line 610 "parser.cc" // lalr1.cc:859
break; break;
case 5: case 5:
#line 85 "parser.yy" // lalr1.cc:859 #line 117 "parser.yy" // lalr1.cc:859
{ {
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ())); TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(hex); ctx.expression.push_back(hex);
} }
#line 593 "parser.cc" // lalr1.cc:859 #line 619 "parser.cc" // lalr1.cc:859
break; break;
case 6: case 6:
#line 90 "parser.yy" // lalr1.cc:859 #line 122 "parser.yy" // lalr1.cc:859
{ {
int n = 0; uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
try { TokenPtr opt(new TokenOption(numeric_code, TokenOption::TEXTUAL));
n = boost::lexical_cast<int>(yystack_[1].value.as< std::string > ());
} catch (const boost::bad_lexical_cast &) {
// This can't happen...
ctx.error(yystack_[1].location,
"Option code has invalid value in " + yystack_[1].value.as< std::string > ());
}
if (n < 0 || n > 65535) {
ctx.error(yystack_[1].location,
"Option code has invalid value in "
+ yystack_[1].value.as< std::string > () + ". Allowed range: 0..65535");
}
TokenPtr opt(new TokenOption(static_cast<uint16_t>(n)));
ctx.expression.push_back(opt); ctx.expression.push_back(opt);
} }
#line 615 "parser.cc" // lalr1.cc:859 #line 629 "parser.cc" // lalr1.cc:859
break; break;
case 7: case 7:
#line 108 "parser.yy" // lalr1.cc:859 #line 128 "parser.yy" // lalr1.cc:859
{
uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
ctx.expression.push_back(opt);
}
#line 639 "parser.cc" // lalr1.cc:859
break;
case 8:
#line 134 "parser.yy" // lalr1.cc:859
{ {
TokenPtr sub(new TokenSubstring()); TokenPtr sub(new TokenSubstring());
ctx.expression.push_back(sub); ctx.expression.push_back(sub);
} }
#line 624 "parser.cc" // lalr1.cc:859 #line 648 "parser.cc" // lalr1.cc:859
break;
case 9:
#line 117 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 633 "parser.cc" // lalr1.cc:859
break; break;
case 10: case 10:
#line 124 "parser.yy" // lalr1.cc:859 #line 143 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ())); TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str); ctx.expression.push_back(str);
} }
#line 642 "parser.cc" // lalr1.cc:859 #line 657 "parser.cc" // lalr1.cc:859
break; break;
case 11: case 11:
#line 129 "parser.yy" // lalr1.cc:859 #line 150 "parser.yy" // lalr1.cc:859
{
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
ctx.expression.push_back(str);
}
#line 666 "parser.cc" // lalr1.cc:859
break;
case 12:
#line 155 "parser.yy" // lalr1.cc:859
{ {
TokenPtr str(new TokenString("all")); TokenPtr str(new TokenString("all"));
ctx.expression.push_back(str); ctx.expression.push_back(str);
} }
#line 651 "parser.cc" // lalr1.cc:859 #line 675 "parser.cc" // lalr1.cc:859
break; break;
#line 655 "parser.cc" // lalr1.cc:859 #line 679 "parser.cc" // lalr1.cc:859
default: default:
break; break;
} }
@@ -906,72 +930,74 @@ 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::yytable_ninf_ = -1;
const signed char const signed char
EvalParser::yypact_[] = EvalParser::yypact_[] =
{ {
-4, -7, -2, -9, -9, -9, 7, -9, 6, 0, -4, -9, -3, -10, -10, -10, 9, -10, 12, 1,
-4, -9, -4, 3, 8, -9, -9, 4, -9, 9, -4, -10, -4, -2, 6, -10, 10, 2, 0, -10,
-1, -9, -9, 10, -9 11, -10, -10, -6, -10, -10, 8, -10
}; };
const unsigned char const unsigned char
EvalParser::yydefact_[] = EvalParser::yydefact_[] =
{ {
0, 0, 0, 4, 5, 8, 0, 2, 0, 0, 0, 0, 0, 4, 5, 9, 0, 2, 0, 0,
0, 1, 0, 0, 0, 3, 6, 0, 9, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 10,
0, 11, 10, 0, 7 0, 6, 7, 0, 12, 11, 0, 8
}; };
const signed char const signed char
EvalParser::yypgoto_[] = EvalParser::yypgoto_[] =
{ {
-9, -9, -9, -8, -9, -9 -10, -10, -10, -7, -10, -10
}; };
const signed char const signed char
EvalParser::yydefgoto_[] = EvalParser::yydefgoto_[] =
{ {
-1, 6, 7, 8, 19, 23 -1, 6, 7, 8, 20, 26
}; };
const unsigned char const unsigned char
EvalParser::yytable_[] = EvalParser::yytable_[] =
{ {
1, 2, 14, 9, 15, 21, 10, 11, 3, 12, 1, 2, 24, 14, 9, 15, 21, 22, 10, 11,
4, 5, 22, 13, 16, 17, 20, 18, 0, 24 25, 3, 16, 4, 5, 12, 17, 13, 19, 18,
27, 23
}; };
const signed char const unsigned char
EvalParser::yycheck_[] = EvalParser::yycheck_[] =
{ {
4, 5, 10, 10, 12, 6, 8, 0, 12, 3, 4, 5, 8, 10, 13, 12, 6, 7, 11, 0,
14, 15, 13, 13, 11, 7, 7, 13, -1, 9 16, 15, 14, 17, 18, 3, 10, 16, 16, 9,
12, 10
}; };
const unsigned char const unsigned char
EvalParser::yystos_[] = EvalParser::yystos_[] =
{ {
0, 4, 5, 12, 14, 15, 17, 18, 19, 10, 0, 4, 5, 15, 17, 18, 20, 21, 22, 13,
8, 0, 3, 13, 19, 19, 11, 7, 13, 20, 11, 0, 3, 16, 22, 22, 14, 10, 9, 16,
7, 6, 13, 21, 9 23, 6, 7, 10, 8, 16, 24, 12
}; };
const unsigned char const unsigned char
EvalParser::yyr1_[] = EvalParser::yyr1_[] =
{ {
0, 16, 17, 18, 19, 19, 19, 19, 19, 20, 0, 19, 20, 21, 22, 22, 22, 22, 22, 22,
21, 21 23, 24, 24
}; };
const unsigned char const unsigned char
EvalParser::yyr2_[] = EvalParser::yyr2_[] =
{ {
0, 2, 1, 3, 1, 1, 4, 8, 1, 1, 0, 2, 1, 3, 1, 1, 6, 6, 8, 1,
1, 1 1, 1, 1
}; };
@@ -982,18 +1008,18 @@ namespace isc { namespace eval {
const EvalParser::yytname_[] = const EvalParser::yytname_[] =
{ {
"\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"", "\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
"\"substring\"", "\"all\"", "\",\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"substring\"", "\"text\"", "\"hex\"", "\"all\"", "\".\"", "\",\"",
"\"constant string\"", "\"integer\"", "\"constant hexstring\"", "TOKEN", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"",
"$accept", "expression", "bool_expr", "string_expr", "start_expr", "\"constant hexstring\"", "TOKEN", "$accept", "expression", "bool_expr",
"length_expr", YY_NULLPTR "string_expr", "start_expr", "length_expr", YY_NULLPTR
}; };
#if YYDEBUG #if YYDEBUG
const unsigned char const unsigned char
EvalParser::yyrline_[] = EvalParser::yyrline_[] =
{ {
0, 69, 69, 72, 79, 84, 89, 107, 112, 116, 0, 101, 101, 104, 111, 116, 121, 127, 133, 138,
123, 128 142, 149, 154
}; };
// Print the state stack on the debug stream. // Print the state stack on the debug stream.
@@ -1028,8 +1054,8 @@ namespace isc { namespace eval {
#line 21 "parser.yy" // lalr1.cc:1167 #line 21 "parser.yy" // lalr1.cc:1167
} } // isc::eval } } // isc::eval
#line 1032 "parser.cc" // lalr1.cc:1167 #line 1058 "parser.cc" // lalr1.cc:1167
#line 135 "parser.yy" // lalr1.cc:1168 #line 161 "parser.yy" // lalr1.cc:1168
void void
isc::eval::EvalParser::error(const location_type& loc, isc::eval::EvalParser::error(const location_type& loc,

View File

@@ -325,16 +325,19 @@ namespace isc { namespace eval {
TOKEN_EQUAL = 258, TOKEN_EQUAL = 258,
TOKEN_OPTION = 259, TOKEN_OPTION = 259,
TOKEN_SUBSTRING = 260, TOKEN_SUBSTRING = 260,
TOKEN_ALL = 261, TOKEN_TEXT = 261,
TOKEN_COMA = 262, TOKEN_HEX = 262,
TOKEN_LPAREN = 263, TOKEN_ALL = 263,
TOKEN_RPAREN = 264, TOKEN_DOT = 264,
TOKEN_LBRACKET = 265, TOKEN_COMA = 265,
TOKEN_RBRACKET = 266, TOKEN_LPAREN = 266,
TOKEN_STRING = 267, TOKEN_RPAREN = 267,
TOKEN_INTEGER = 268, TOKEN_LBRACKET = 268,
TOKEN_HEXSTRING = 269, TOKEN_RBRACKET = 269,
TOKEN_TOKEN = 270 TOKEN_STRING = 270,
TOKEN_INTEGER = 271,
TOKEN_HEXSTRING = 272,
TOKEN_TOKEN = 273
}; };
}; };
@@ -457,10 +460,22 @@ namespace isc { namespace eval {
symbol_type symbol_type
make_SUBSTRING (const location_type& l); make_SUBSTRING (const location_type& l);
static inline
symbol_type
make_TEXT (const location_type& l);
static inline
symbol_type
make_HEX (const location_type& l);
static inline static inline
symbol_type symbol_type
make_ALL (const location_type& l); make_ALL (const location_type& l);
static inline
symbol_type
make_DOT (const location_type& l);
static inline static inline
symbol_type symbol_type
make_COMA (const location_type& l); make_COMA (const location_type& l);
@@ -582,7 +597,7 @@ namespace isc { namespace eval {
// number is the opposite. If YYTABLE_NINF, syntax error. // number is the opposite. If YYTABLE_NINF, syntax error.
static const unsigned char yytable_[]; static const unsigned char yytable_[];
static const signed char yycheck_[]; static const unsigned char yycheck_[];
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing // YYSTOS[STATE-NUM] -- The (internal number of the) accessing
// symbol of state STATE-NUM. // symbol of state STATE-NUM.
@@ -702,12 +717,12 @@ namespace isc { namespace eval {
enum enum
{ {
yyeof_ = 0, yyeof_ = 0,
yylast_ = 19, ///< Last index in yytable_. yylast_ = 21, ///< Last index in yytable_.
yynnts_ = 6, ///< Number of nonterminal symbols. yynnts_ = 6, ///< Number of nonterminal symbols.
yyfinal_ = 11, ///< Termination state number. yyfinal_ = 11, ///< Termination state number.
yyterror_ = 1, yyterror_ = 1,
yyerrcode_ = 256, yyerrcode_ = 256,
yyntokens_ = 16 ///< Number of tokens. yyntokens_ = 19 ///< Number of tokens.
}; };
@@ -751,9 +766,9 @@ namespace isc { namespace eval {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15 15, 16, 17, 18
}; };
const unsigned int user_token_number_max_ = 270; const unsigned int user_token_number_max_ = 273;
const token_number_type undef_token_ = 2; const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_) if (static_cast<int>(t) <= yyeof_)
@@ -786,10 +801,10 @@ namespace isc { namespace eval {
{ {
switch (other.type_get ()) switch (other.type_get ())
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
value.copy< std::string > (other.value); value.copy< std::string > (other.value);
break; break;
@@ -810,10 +825,10 @@ namespace isc { namespace eval {
(void) v; (void) v;
switch (this->type_get ()) switch (this->type_get ())
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
value.copy< std::string > (v); value.copy< std::string > (v);
break; break;
@@ -865,10 +880,10 @@ namespace isc { namespace eval {
// Type destructor. // Type destructor.
switch (yytype) switch (yytype)
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
value.template destroy< std::string > (); value.template destroy< std::string > ();
break; break;
@@ -895,10 +910,10 @@ namespace isc { namespace eval {
super_type::move(s); super_type::move(s);
switch (this->type_get ()) switch (this->type_get ())
{ {
case 12: // "constant string" case 15: // "constant string"
case 13: // "integer" case 16: // "integer"
case 14: // "constant hexstring" case 17: // "constant hexstring"
case 15: // TOKEN case 18: // TOKEN
value.move< std::string > (s.value); value.move< std::string > (s.value);
break; break;
@@ -958,7 +973,7 @@ namespace isc { namespace eval {
yytoken_number_[] = yytoken_number_[] =
{ {
0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270 265, 266, 267, 268, 269, 270, 271, 272, 273
}; };
return static_cast<token_type> (yytoken_number_[type]); return static_cast<token_type> (yytoken_number_[type]);
} }
@@ -987,12 +1002,30 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_SUBSTRING, l); return symbol_type (token::TOKEN_SUBSTRING, l);
} }
EvalParser::symbol_type
EvalParser::make_TEXT (const location_type& l)
{
return symbol_type (token::TOKEN_TEXT, l);
}
EvalParser::symbol_type
EvalParser::make_HEX (const location_type& l)
{
return symbol_type (token::TOKEN_HEX, l);
}
EvalParser::symbol_type EvalParser::symbol_type
EvalParser::make_ALL (const location_type& l) EvalParser::make_ALL (const location_type& l)
{ {
return symbol_type (token::TOKEN_ALL, l); return symbol_type (token::TOKEN_ALL, l);
} }
EvalParser::symbol_type
EvalParser::make_DOT (const location_type& l)
{
return symbol_type (token::TOKEN_DOT, l);
}
EvalParser::symbol_type EvalParser::symbol_type
EvalParser::make_COMA (const location_type& l) EvalParser::make_COMA (const location_type& l)
{ {
@@ -1050,7 +1083,7 @@ namespace isc { namespace eval {
#line 21 "parser.yy" // lalr1.cc:392 #line 21 "parser.yy" // lalr1.cc:392
} } // isc::eval } } // isc::eval
#line 1054 "parser.h" // lalr1.cc:392 #line 1087 "parser.h" // lalr1.cc:392

View File

@@ -45,7 +45,10 @@ using namespace isc::eval;
EQUAL "==" EQUAL "=="
OPTION "option" OPTION "option"
SUBSTRING "substring" SUBSTRING "substring"
TEXT "text"
HEX "hex"
ALL "all" ALL "all"
DOT "."
COMA "," COMA ","
LPAREN "(" LPAREN "("
RPAREN ")" RPAREN ")"
@@ -59,6 +62,35 @@ using namespace isc::eval;
%token <std::string> TOKEN %token <std::string> TOKEN
%printer { yyoutput << $$; } <*>; %printer { yyoutput << $$; } <*>;
%code
{
namespace {
/* Convert option code specified as string to an 16 bit unsigned
representation. If the option code is not within the range of
0..65535 an error is reported. */
uint16_t
convert_option_code(const std::string& option_code,
const isc::eval::EvalParser::location_type& loc,
EvalContext& ctx) {
int n = 0;
try {
n = boost::lexical_cast<int>(option_code);
} catch (const boost::bad_lexical_cast &) {
// This can't happen...
ctx.error(loc, "Option code has invalid value in " + option_code);
}
if (n < 0 || n > 65535) {
ctx.error(loc, "Option code has invalid value in "
+ option_code + ". Allowed range: 0..65535");
}
return (static_cast<uint16_t>(n));
}
}
}
%% %%
// The whole grammar starts with an expression. // The whole grammar starts with an expression.
@@ -86,22 +118,16 @@ string_expr : STRING
TokenPtr hex(new TokenHexString($1)); TokenPtr hex(new TokenHexString($1));
ctx.expression.push_back(hex); ctx.expression.push_back(hex);
} }
| OPTION "[" INTEGER "]" | OPTION "[" INTEGER "]" DOT TEXT
{ {
int n = 0; uint16_t numeric_code = convert_option_code($3, @3, ctx);
try { TokenPtr opt(new TokenOption(numeric_code, TokenOption::TEXTUAL));
n = boost::lexical_cast<int>($3); ctx.expression.push_back(opt);
} catch (const boost::bad_lexical_cast &) {
// This can't happen...
ctx.error(@3,
"Option code has invalid value in " + $3);
} }
if (n < 0 || n > 65535) { | OPTION "[" INTEGER "]" DOT HEX
ctx.error(@3, {
"Option code has invalid value in " uint16_t numeric_code = convert_option_code($3, @3, ctx);
+ $3 + ". Allowed range: 0..65535"); TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
}
TokenPtr opt(new TokenOption(static_cast<uint16_t>(n)));
ctx.expression.push_back(opt); ctx.expression.push_back(opt);
} }
| SUBSTRING "(" string_expr "," start_expr "," length_expr ")" | SUBSTRING "(" string_expr "," start_expr "," length_expr ")"

View File

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

View File

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

View File

@@ -117,7 +117,7 @@ TEST_F(EvalContextTest, basic) {
EvalContext tmp; EvalContext tmp;
EXPECT_NO_THROW(parsed_ = tmp.parseString("option[123] == 'MSFT'")); EXPECT_NO_THROW(parsed_ = tmp.parseString("option[123].text == 'MSFT'"));
EXPECT_TRUE(parsed_); EXPECT_TRUE(parsed_);
} }
@@ -143,7 +143,7 @@ TEST_F(EvalContextTest, integer) {
EvalContext eval; EvalContext eval;
EXPECT_NO_THROW(parsed_ = EXPECT_NO_THROW(parsed_ =
eval.parseString("substring(option[123], 0, 2) == '42'")); eval.parseString("substring(option[123].text, 0, 2) == '42'"));
EXPECT_TRUE(parsed_); EXPECT_TRUE(parsed_);
} }
@@ -198,7 +198,17 @@ TEST_F(EvalContextTest, equal) {
TEST_F(EvalContextTest, option) { TEST_F(EvalContextTest, option) {
EvalContext eval; EvalContext eval;
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123] == 'foo'")); EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'foo'"));
EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size());
checkTokenOption(eval.expression.at(0), 123);
}
// Test parsing of an option represented as hexadecimal string.
TEST_F(EvalContextTest, optionHex) {
EvalContext eval;
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].hex == 0x666F6F"));
EXPECT_TRUE(parsed_); EXPECT_TRUE(parsed_);
ASSERT_EQ(3, eval.expression.size()); ASSERT_EQ(3, eval.expression.size());
checkTokenOption(eval.expression.at(0), 123); checkTokenOption(eval.expression.at(0), 123);
@@ -245,16 +255,20 @@ TEST_F(EvalContextTest, scanParseErrors) {
checkError("0abc", checkError("0abc",
"<string>:1.1: syntax error, unexpected integer"); "<string>:1.1: syntax error, unexpected integer");
checkError("===", "<string>:1.1-2: syntax error, unexpected =="); checkError("===", "<string>:1.1-2: syntax error, unexpected ==");
checkError("option[-1]", checkError("option[-1].text",
"<string>:1.8-9: Option code has invalid " "<string>:1.8-9: Option code has invalid "
"value in -1. Allowed range: 0..65535"); "value in -1. Allowed range: 0..65535");
checkError("option[65536]", checkError("option[65536].text",
"<string>:1.8-12: Option code has invalid " "<string>:1.8-12: Option code has invalid "
"value in 65536. Allowed range: 0..65535"); "value in 65536. Allowed range: 0..65535");
checkError("option[12345678901234567890]", checkError("option[12345678901234567890].text",
"<string>:1.8-27: Failed to convert 12345678901234567890 " "<string>:1.8-27: Failed to convert 12345678901234567890 "
"to an integer."); "to an integer.");
checkError("option[123] < 'foo'", "<string>:1.13: Invalid character: <"); checkError("option[123]",
"<string>:1.12: syntax error, unexpected end of file,"
" expecting .");
checkError("option[123].text < 'foo'", "<string>:1.18: Invalid"
" character: <");
checkError("substring('foo',12345678901234567890,1)", checkError("substring('foo',12345678901234567890,1)",
"<string>:1.17-36: Failed to convert 12345678901234567890 " "<string>:1.17-36: Failed to convert 12345678901234567890 "
"to an integer."); "to an integer.");
@@ -274,11 +288,11 @@ TEST_F(EvalContextTest, parseErrors) {
checkError("option(10) == 'ab'", checkError("option(10) == 'ab'",
"<string>:1.7: syntax error, " "<string>:1.7: syntax error, "
"unexpected (, expecting ["); "unexpected (, expecting [");
checkError("option['ab'] == 'foo'", checkError("option['ab'].text == 'foo'",
"<string>:1.8-11: syntax error, " "<string>:1.8-11: syntax error, "
"unexpected constant string, " "unexpected constant string, "
"expecting integer"); "expecting integer");
checkError("option[0xa] == 'ab'", checkError("option[0xa].text == 'ab'",
"<string>:1.8-10: syntax error, " "<string>:1.8-10: syntax error, "
"unexpected constant hexstring, " "unexpected constant hexstring, "
"expecting integer"); "expecting integer");

View File

@@ -196,7 +196,7 @@ TEST_F(EvaluateTest, packet) {
TokenPtr tstring; TokenPtr tstring;
TokenPtr tequal; TokenPtr tequal;
ASSERT_NO_THROW(toption.reset(new TokenOption(100))); ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::TEXTUAL)));
e_.push_back(toption); e_.push_back(toption);
ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4"))); ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4")));
e_.push_back(tstring); e_.push_back(tstring);
@@ -209,6 +209,25 @@ TEST_F(EvaluateTest, packet) {
EXPECT_FALSE(result_); EXPECT_FALSE(result_);
} }
// A test which compares option value represented in hexadecimal format.
TEST_F(EvaluateTest, optionHex) {
TokenPtr toption;
TokenPtr tstring;
TokenPtr tequal;
ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
e_.push_back(toption);
ASSERT_NO_THROW(tstring.reset(new TokenString("0x68756E6472656434")));
e_.push_back(tstring);
ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
e_.push_back(tequal);
ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
EXPECT_TRUE(result_);
ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
EXPECT_FALSE(result_);
}
// A test using substring on an option. // A test using substring on an option.
TEST_F(EvaluateTest, complex) { TEST_F(EvaluateTest, complex) {
TokenPtr toption; TokenPtr toption;
@@ -219,7 +238,7 @@ TEST_F(EvaluateTest, complex) {
TokenPtr tequal; TokenPtr tequal;
// Get the option, i.e., "hundred[46]" // Get the option, i.e., "hundred[46]"
ASSERT_NO_THROW(toption.reset(new TokenOption(100))); ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::TEXTUAL)));
e_.push_back(toption); e_.push_back(toption);
// Get substring("hundred[46]", 0, 7), i.e., "hundred" // Get substring("hundred[46]", 0, 7), i.e., "hundred"

View File

@@ -253,8 +253,8 @@ TEST_F(TokenTest, optionString4) {
TokenPtr not_found; TokenPtr not_found;
// The packets we use have option 100 with a string in them. // The packets we use have option 100 with a string in them.
ASSERT_NO_THROW(found.reset(new TokenOption(100))); ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::TEXTUAL)));
ASSERT_NO_THROW(not_found.reset(new TokenOption(101))); ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::TEXTUAL)));
// This should evaluate to the content of the option 100 (i.e. "hundred4") // This should evaluate to the content of the option 100 (i.e. "hundred4")
ASSERT_NO_THROW(found->evaluate(*pkt4_, values_)); ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
@@ -274,6 +274,35 @@ TEST_F(TokenTest, optionString4) {
EXPECT_EQ("hundred4", values_.top()); EXPECT_EQ("hundred4", values_.top());
} }
// This test checks if a token representing option value is able to extract
// the option from an IPv4 packet and properly store its value in a
// hexadecimal format.
TEST_F(TokenTest, optionHexString4) {
TokenPtr found;
TokenPtr not_found;
// The packets we use have option 100 with a string in them.
ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::HEXADECIMAL)));
// This should evaluate to the content of the option 100 (i.e. "hundred4")
ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
// This should evaluate to "" as there is no option 101.
ASSERT_NO_THROW(not_found->evaluate(*pkt4_, values_));
// There should be 2 values evaluated.
ASSERT_EQ(2, values_.size());
// This is a stack, so the pop order is inversed. We should get the empty
// string first.
EXPECT_EQ("", values_.top());
values_.pop();
// Then the content of the option 100.
EXPECT_EQ("0x68756E6472656434", values_.top());
}
// This test checks if a token representing an option value is able to extract // This test checks if a token representing an option value is able to extract
// the option from an IPv6 packet and properly store the option's value. // the option from an IPv6 packet and properly store the option's value.
TEST_F(TokenTest, optionString6) { TEST_F(TokenTest, optionString6) {
@@ -281,8 +310,8 @@ TEST_F(TokenTest, optionString6) {
TokenPtr not_found; TokenPtr not_found;
// The packets we use have option 100 with a string in them. // The packets we use have option 100 with a string in them.
ASSERT_NO_THROW(found.reset(new TokenOption(100))); ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::TEXTUAL)));
ASSERT_NO_THROW(not_found.reset(new TokenOption(101))); ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::TEXTUAL)));
// This should evaluate to the content of the option 100 (i.e. "hundred6") // This should evaluate to the content of the option 100 (i.e. "hundred6")
ASSERT_NO_THROW(found->evaluate(*pkt6_, values_)); ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
@@ -302,6 +331,35 @@ TEST_F(TokenTest, optionString6) {
EXPECT_EQ("hundred6", values_.top()); EXPECT_EQ("hundred6", values_.top());
} }
// This test checks if a token representing an option value is able to extract
// the option from an IPv6 packet and properly store its value in hexadecimal
// format.
TEST_F(TokenTest, optionHexString6) {
TokenPtr found;
TokenPtr not_found;
// The packets we use have option 100 with a string in them.
ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::HEXADECIMAL)));
// This should evaluate to the content of the option 100 (i.e. "hundred6")
ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
// This should evaluate to "" as there is no option 101.
ASSERT_NO_THROW(not_found->evaluate(*pkt6_, values_));
// There should be 2 values evaluated.
ASSERT_EQ(2, values_.size());
// This is a stack, so the pop order is inversed. We should get the empty
// string first.
EXPECT_EQ("", values_.top());
values_.pop();
// Then the content of the option 100.
EXPECT_EQ("0x68756E6472656436", values_.top());
}
// This test checks if a token representing an == operator is able to // This test checks if a token representing an == operator is able to
// compare two values (with incorrectly built stack). // compare two values (with incorrectly built stack).
TEST_F(TokenTest, optionEqualInvalid) { TEST_F(TokenTest, optionEqualInvalid) {

View File

@@ -66,7 +66,8 @@ void
TokenOption::evaluate(const Pkt& pkt, ValueStack& values) { TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
OptionPtr opt = pkt.getOption(option_code_); OptionPtr opt = pkt.getOption(option_code_);
if (opt) { if (opt) {
values.push(opt->toString()); values.push(representation_type_ == TEXTUAL ? opt->toString()
: opt->toHexString());
} else { } else {
// Option not found, push empty string // Option not found, push empty string
values.push(""); values.push("");

View File

@@ -146,6 +146,19 @@ protected:
/// option. If the option is not found, an empty string ("") is returned. /// option. If the option is not found, an empty string ("") is returned.
class TokenOption : public Token { class TokenOption : public Token {
public: public:
/// @brief Token representation type.
///
/// There are many possible ways in which option can be presented.
/// Currently the textual and hexadecimal representations are
/// supported. The type of representation is specified in the
/// constructor and it affects the value generated by the
/// @c TokenOption::evaluate function.
enum RepresentationType {
TEXTUAL,
HEXADECIMAL
};
/// @brief Constructor that takes an option code as a parameter /// @brief Constructor that takes an option code as a parameter
/// @param option_code code of the option /// @param option_code code of the option
/// ///
@@ -153,8 +166,9 @@ public:
/// introduce complex dependency of the libkea-eval on libdhcpsrv. /// introduce complex dependency of the libkea-eval on libdhcpsrv.
/// ///
/// @param option_code code of the option to be represented. /// @param option_code code of the option to be represented.
TokenOption(uint16_t option_code) /// @param rep_type Token representation type.
:option_code_(option_code) {} TokenOption(const uint16_t option_code, const RepresentationType& rep_type)
: option_code_(option_code), representation_type_(rep_type) {}
/// @brief Evaluates the values of the option /// @brief Evaluates the values of the option
/// ///
@@ -177,7 +191,8 @@ public:
} }
private: private:
uint16_t option_code_; ///< code of the option to be extracted uint16_t option_code_; ///< Code of the option to be extracted
RepresentationType representation_type_; ///< Representation type.
}; };
/// @brief Token that represents equality operator (compares two other tokens) /// @brief Token that represents equality operator (compares two other tokens)