09. TokenPtr str(new TokenString($1));
10. ctx.expression.push_back(str);
11.}
-12.| OPTION {
-13. TokenPtr opt(new TokenOption($1));
-14. ctx.expression.push_back(opt);
-15.};
+12. HEXSTRING {
+13. TokenPtr hex(new TokenHexString($1));
+14. ctx.expression.push_back(hex);
+15.}
+16.| OPTION {
+17. TokenPtr opt(new TokenOption($1));
+18. ctx.expression.push_back(opt);
+19.}
+20.;
@endcode
This code determines that the grammar starts from expression (line 1).
The actual definition of expression (lines 3-5) may either be a
single token or an expression "token == token" (EQUAL has been defined as
"==" elsewhere). Token is further
-defined in lines 7-15: it may either be a string (lines 8-11) or option
-(lines 12-15). When the actual case is determined, the respective C++ action
+defined in lines 7-15: it may either be a string (lines 8-11),
+a hex string (lines 12-15) or option (lines 16-19).
+When the actual case is determined, the respective C++ action
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.
/* These are not token expressions yet, just convenience expressions that
can be used during actual token definitions. */
int [0-9]+
+hex [0-9a-fA-F]+
blank [ \t]
-str [a-zA-Z_0-9]*
+str [a-zA-Z_0-9]*
%{
// This code run each time a pattern is matched. It updates the location
return isc::eval::EvalParser::make_STRING(tmp, loc);
}
+0[xX]{hex} {
+ // A hex string has been matched. It contains the '0x' or '0X' header
+ // followed by at least one hexadecimal digit.
+ return isc::eval::EvalParser::make_HEXSTRING(yytext, loc);
+}
+
option\[{int}\] {
// option[123] token found. Let's see if the numeric value can be
// converted to integer and if it has a reasonable value.
RPAREN ")"
;
%token <std::string> STRING "constant string"
+%token <std::string> HEXSTRING "constant hexstring"
%token <int> OPTION "option code"
%printer { yyoutput << $$; } <*>;
%%
%start expression;
// Expression can either be a single token or a (something == something) expression
+
expression:
token EQUAL token {
TokenPtr eq(new TokenEqual());
ctx.expression.push_back(eq);
-}
-| token;
+ }
+| token
+;
token:
STRING {
TokenPtr str(new TokenString($1));
ctx.expression.push_back(str);
-}
+ }
+| HEXSTRING {
+ TokenPtr hex(new TokenHexString($1));
+ ctx.expression.push_back(hex);
+ }
| OPTION {
TokenPtr opt(new TokenOption($1));
ctx.expression.push_back(opt);
-}
+ }
| SUBSTRING "(" token "," token "," token ")" {
/* push back TokenSubstring */
}
+;
%%
void
EXPECT_EQ(expected, values.top());
}
+ void checkTokenHexString(const TokenPtr& token,
+ const std::string& expected) {
+ ASSERT_TRUE(token);
+ boost::shared_ptr<TokenHexString> hex =
+ boost::dynamic_pointer_cast<TokenHexString>(token);
+ ASSERT_TRUE(hex);
+
+ Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 12345));
+ ValueStack values;
+
+ EXPECT_NO_THROW(token->evaluate(*pkt4, values));
+
+ ASSERT_EQ(1, values.size());
+
+ EXPECT_EQ(expected, values.top());
+ }
+
void checkTokenEq(const TokenPtr& token) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenEqual> eq =
checkTokenString(tmp, "foo");
}
+TEST_F(EvalContextTest, hexstring) {
+ EvalContext eval;
+
+ EXPECT_NO_THROW(eval.parseString("0x666f6f"));
+
+ ASSERT_EQ(1, eval.expression.size());
+
+ TokenPtr tmp = eval.expression.at(0);
+
+ checkTokenHexString(tmp, "foo");
+}
+
TEST_F(EvalContextTest, equal) {
EvalContext eval;