Commit 45abe4f7 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[5014] Parser type is now configurable.

parent 3b63aa51
......@@ -25,6 +25,10 @@
// variable will be useful for logging errors.
static isc::dhcp::location loc;
static bool start_token_flag = false;
static isc::dhcp::Parser6Context::ParserType start_token_value;
// To avoid the call to exit... oops!
#define YY_FATAL_ERROR(msg) isc::dhcp::Parser6Context::fatal(msg)
%}
......@@ -81,10 +85,24 @@ JSONString \"{JSONStringCharacter}*\"
%%
%{
// This part of the code is copied over to the verbatim to the top
// of the generated yylex function. Explanation:
// http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html
// Code run each time yylex is called.
loc.step();
int comment_start_line = 0;
if (start_token_flag) {
start_token_flag = false;
switch (start_token_value) {
case Parser6Context::PARSER_DHCP6:
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(loc);
case Parser6Context::PARSER_GENERIC_JSON:
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(loc);
}
}
%}
#.* ;
......@@ -247,8 +265,11 @@ null {
using namespace isc::dhcp;
void
Parser6Context::scanStringBegin()
Parser6Context::scanStringBegin(ParserType parser_type)
{
start_token_flag = true;
start_token_value = parser_type;
loc.initialize(&file_);
yy_flex_debug = trace_scanning_;
YY_BUFFER_STATE buffer;
......@@ -266,7 +287,11 @@ Parser6Context::scanStringEnd()
}
void
Parser6Context::scanFileBegin(FILE * f) {
Parser6Context::scanFileBegin(FILE * f, ParserType parser_type) {
start_token_flag = true;
start_token_value = parser_type;
loc.initialize(&file_);
yy_flex_debug = trace_scanning_;
YY_BUFFER_STATE buffer;
......
......@@ -115,6 +115,11 @@ using namespace std;
OUTPUT "output"
DEBUGLEVEL "debuglevel"
SEVERITY "severity"
// Not real tokens, just a way to signal what the parser is expected to
// parse.
TOPLEVEL_DHCP6
TOPLEVEL_GENERIC_JSON
;
%token <std::string> STRING "constant string"
......@@ -127,11 +132,15 @@ using namespace std;
%printer { yyoutput << $$; } <*>;
%%
// The whole grammar starts with a map, because the config file
// constists of Dhcp, Logger and DhcpDdns entries in one big { }.
// %start map - this will parse everything as generic JSON
// %start dhcp6_map - this will parse everything with Dhcp6 syntax checking
%start syntax_map;
%start start;
start: TOPLEVEL_DHCP6 syntax_map
| TOPLEVEL_GENERIC_JSON map;
// ---- generic JSON parser ---------------------------------
......
......@@ -25,11 +25,11 @@ Parser6Context::~Parser6Context()
}
isc::data::ConstElementPtr
Parser6Context::parseString(const std::string& str)
Parser6Context::parseString(const std::string& str, ParserType parser_type)
{
file_ = "<string>";
string_ = str;
scanStringBegin();
scanStringBegin(parser_type);
isc::dhcp::Dhcp6Parser parser(*this);
// Uncomment this to get detailed parser logs.
// trace_parsing_ = true;
......@@ -48,7 +48,7 @@ Parser6Context::parseString(const std::string& str)
}
isc::data::ConstElementPtr
Parser6Context::parseFile(const std::string& filename) {
Parser6Context::parseFile(const std::string& filename, ParserType parser_type) {
ifstream f;
f.open(filename);
......@@ -66,7 +66,7 @@ Parser6Context::parseFile(const std::string& filename) {
file_ = filename;
scanStringBegin();
scanStringBegin(parser_type);
isc::dhcp::Dhcp6Parser parser(*this);
// Uncomment this to get detailed parser logs.
// trace_parsing_ = true;
......
......@@ -34,6 +34,10 @@ public:
class Parser6Context
{
public:
typedef enum { PARSER_DHCP6,
PARSER_GENERIC_JSON } ParserType;
/// @brief Default constructor.
///
/// @param option_universe Option universe: DHCPv4 or DHCPv6. This is used
......@@ -48,21 +52,23 @@ public:
std::vector<isc::data::ElementPtr> stack_;
/// @brief Method called before scanning starts on a string.
void scanStringBegin();
void scanStringBegin(ParserType type);
/// @brief Method called after the last tokens are scanned from a string.
void scanStringEnd();
void scanFileBegin(FILE * f);
void scanFileBegin(FILE * f, ParserType type);
void scanFileEnd(FILE * f);
/// @brief Run the parser on the string specified.
///
/// @param str string to be written
/// @return true on success.
isc::data::ConstElementPtr parseString(const std::string& str);
isc::data::ConstElementPtr parseString(const std::string& str,
ParserType parser_type);
isc::data::ConstElementPtr parseFile(const std::string& filename);
isc::data::ConstElementPtr parseFile(const std::string& filename,
ParserType parser_type);
/// @brief The name of the file being parsed.
/// Used later to pass the file name to the location tracker.
......
......@@ -17,32 +17,33 @@ void compareJSON(ConstElementPtr a, ConstElementPtr b, bool print = true) {
ASSERT_TRUE(a);
ASSERT_TRUE(b);
if (print) {
std::cout << a->str() << std::endl;
std::cout << b->str() << std::endl;
std::cout << "JSON A: -----" << endl << a->str() << std::endl;
std::cout << "JSON B: -----" << endl << b->str() << std::endl;
cout << "---------" << endl << endl;
}
EXPECT_EQ(a->str(), b->str());
}
void testParser(const std::string& txt) {
void testParser(const std::string& txt, Parser6Context::ParserType parser_type) {
ElementPtr reference_json;
ConstElementPtr test_json;
EXPECT_NO_THROW(reference_json = Element::fromJSON(txt, true));
EXPECT_NO_THROW({
Parser6Context ctx;
test_json = ctx.parseString(txt);
test_json = ctx.parseString(txt, parser_type);
});
// Now compare if both representations are the same.
compareJSON(reference_json, test_json);
}
void testParser2(const std::string& txt) {
void testParser2(const std::string& txt, Parser6Context::ParserType parser_type) {
ConstElementPtr test_json;
EXPECT_NO_THROW({
Parser6Context ctx;
test_json = ctx.parseString(txt);
test_json = ctx.parseString(txt, parser_type);
});
/// @todo: Implement actual validation here. since the original
/// Element::fromJSON does not support several comment types, we don't
......@@ -53,35 +54,35 @@ void testParser2(const std::string& txt) {
TEST(ParserTest, mapInMap) {
string txt = "{ \"Dhcp6\": { \"foo\": 123, \"baz\": 456 } }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, listInList) {
string txt = "{ \"countries\": [ [ \"Britain\", \"Wales\", \"Scotland\" ], "
"[ \"Pomorze\", \"Wielkopolska\", \"Tatry\"] ] }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, nestedMaps) {
string txt = "{ \"europe\": { \"UK\": { \"London\": { \"street\": \"221B Baker\" }}}}";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, nestedLists) {
string txt = "{ \"unity\": [ \"half\", [ \"quarter\", [ \"eighth\", [ \"sixteenth\" ]]]] }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, listsInMaps) {
string txt = "{ \"constellations\": { \"orion\": [ \"rigel\", \"betelguese\" ], "
"\"cygnus\": [ \"deneb\", \"albireo\"] } }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, mapsInLists) {
string txt = "{ \"solar-system\": [ { \"name\": \"earth\", \"gravity\": 1.0 },"
" { \"name\": \"mars\", \"gravity\": 0.376 } ] }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, types) {
......@@ -91,7 +92,7 @@ TEST(ParserTest, types) {
"\"map\": { \"foo\": \"bar\" },"
"\"list\": [ 1, 2, 3 ],"
"\"null\": null }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, bashComments) {
......@@ -111,7 +112,7 @@ TEST(ParserTest, bashComments) {
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }";
testParser(txt);
testParser(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, cComments) {
......@@ -128,7 +129,7 @@ TEST(ParserTest, cComments) {
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }";
testParser2(txt);
testParser2(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, bashComments2) {
......@@ -145,7 +146,7 @@ TEST(ParserTest, bashComments2) {
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }";
testParser2(txt);
testParser2(txt, Parser6Context::PARSER_GENERIC_JSON);
}
TEST(ParserTest, multilineComments) {
......@@ -163,7 +164,7 @@ TEST(ParserTest, multilineComments) {
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }";
testParser2(txt);
testParser2(txt, Parser6Context::PARSER_GENERIC_JSON);
}
......@@ -177,7 +178,7 @@ void testFile(const std::string& fname, bool print) {
try {
Parser6Context ctx;
test_json = ctx.parseFile(fname);
test_json = ctx.parseFile(fname, Parser6Context::PARSER_DHCP6);
} catch (const std::exception &x) {
cout << "EXCEPTION: " << x.what() << endl;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment