\"Control-agent\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::CONFIG:
return AgentParser::make_CONTROL_AGENT(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("Control-agent", driver.loc_);
}
}
\"http-host\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::AGENT:
return AgentParser::make_HTTP_HOST(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("http-host", driver.loc_);
}
}
\"http-port\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::AGENT:
return AgentParser::make_HTTP_PORT(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("http-port", driver.loc_);
}
}
+\"control-sockets\" {
+ switch(driver.ctx_) {
+ case ParserContext::AGENT:
+ return AgentParser::make_CONTROL_SOCKETS(driver.loc_);
+ default:
+ return AgentParser::make_STRING("control-sockets", driver.loc_);
+ }
+}
+
\"dhcp4-server\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::CONTROL_SOCKETS:
return AgentParser::make_DHCP4_SERVER(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("dhcp4-server", driver.loc_);
}
}
\"dhcp6-server\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::CONTROL_SOCKETS:
return AgentParser::make_DHCP6_SERVER(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("dhcp6-server", driver.loc_);
}
}
\"d2-server\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::CONTROL_SOCKETS:
return AgentParser::make_D2_SERVER(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("d2-server", driver.loc_);
}
}
-(\"unix\") {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+\"socket-name\" {
+ switch(driver.ctx_) {
+ case ParserContext::SERVER:
+ return AgentParser::make_SOCKET_NAME(driver.loc_);
+ default:
+ return AgentParser::make_STRING("socket-name", driver.loc_);
+ }
+}
+
+\"socket-type\" {
+ switch(driver.ctx_) {
+ case ParserContext::SERVER:
+ return AgentParser::make_SOCKET_TYPE(driver.loc_);
+ default:
+ return AgentParser::make_STRING("socket-type", driver.loc_);
+ }
+}
+
+\"unix\" {
+ switch(driver.ctx_) {
+ case ParserContext::SOCKET_TYPE:
return AgentParser::make_UNIX(driver.loc_);
+ default:
+ return AgentParser::make_STRING("unix", driver.loc_);
}
- std::string tmp(yytext+1);
- tmp.resize(tmp.size() - 1);
- return AgentParser::make_STRING(tmp, driver.loc_);
}
-\"name\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_NAME(driver.loc_);
- } else {
- return AgentParser::make_STRING("name", driver.loc_);
+\"hooks-libraries\" {
+ switch(driver.ctx_) {
+ case ParserContext::AGENT:
+ return AgentParser::make_HOOKS_LIBRARIES(driver.loc_);
+ default:
+ return AgentParser::make_STRING("hooks-libraries", driver.loc_);
}
}
+\"library\" {
+ switch(driver.ctx_) {
+ case ParserContext::HOOKS_LIBRARIES:
+ return AgentParser::make_LIBRARY(driver.loc_);
+ default:
+ return AgentParser::make_STRING("library", driver.loc_);
+ }
+}
+
+\"parameters\" {
+ switch(driver.ctx_) {
+ case ParserContext::HOOKS_LIBRARIES:
+ return AgentParser::make_PARAMETERS(driver.loc_);
+ default:
+ return AgentParser::make_STRING("parameters", driver.loc_);
+ }
+}
\"Logging\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::CONFIG:
return AgentParser::make_LOGGING(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("Logging", driver.loc_);
}
}
\"loggers\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::LOGGING:
return AgentParser::make_LOGGERS(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("loggers", driver.loc_);
}
}
+\"name\" {
+ switch(driver.ctx_) {
+ case ParserContext::LOGGERS:
+ return AgentParser::make_NAME(driver.loc_);
+ default:
+ return AgentParser::make_STRING("name", driver.loc_);
+ }
+}
+
\"output_options\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::LOGGERS:
return AgentParser::make_OUTPUT_OPTIONS(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("output_options", driver.loc_);
}
}
\"output\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::OUTPUT_OPTIONS:
return AgentParser::make_OUTPUT(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("output", driver.loc_);
}
}
\"debuglevel\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::LOGGERS:
return AgentParser::make_DEBUGLEVEL(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("debuglevel", driver.loc_);
}
}
\"severity\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::LOGGERS:
return AgentParser::make_SEVERITY(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("severity", driver.loc_);
}
}
-\"hooks-libraries\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_HOOKS_LIBRARIES(driver.loc_);
- } else {
- return AgentParser::make_STRING("hooks-libraries", driver.loc_);
- }
-}
-
-
-\"parameters\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_PARAMETERS(driver.loc_);
- } else {
- return AgentParser::make_STRING("parameters", driver.loc_);
- }
-}
-
-\"library\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_LIBRARY(driver.loc_);
- } else {
- return AgentParser::make_STRING("library", driver.loc_);
- }
-}
-
-
-\"control-sockets\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_CONTROL_SOCKETS(driver.loc_);
- } else {
- return AgentParser::make_STRING("control-sockets", driver.loc_);
- }
-}
-
-\"socket-type\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_SOCKET_TYPE(driver.loc_);
- } else {
- return AgentParser::make_STRING("socket-type", driver.loc_);
- }
-}
-
-\"socket-name\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_SOCKET_NAME(driver.loc_);
- } else {
- return AgentParser::make_STRING("socket-name", driver.loc_);
- }
-}
-
\"Dhcp4\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
+ switch(driver.ctx_) {
+ case ParserContext::CONFIG:
return AgentParser::make_DHCP4(driver.loc_);
- } else {
+ default:
return AgentParser::make_STRING("Dhcp4", driver.loc_);
}
}
\"Dhcp6\" {
- if (driver.ctx_ != ParserContext::NO_KEYWORDS) {
- return AgentParser::make_DHCP4(driver.loc_);
- } else {
- return AgentParser::make_STRING("Dhcp4", driver.loc_);
+ switch(driver.ctx_) {
+ case ParserContext::CONFIG:
+ return AgentParser::make_DHCP6(driver.loc_);
+ default:
+ return AgentParser::make_STRING("Dhcp6", driver.loc_);
+ }
+}
+
+\"DhcpDdns\" {
+ switch(driver.ctx_) {
+ case ParserContext::CONFIG:
+ return AgentParser::make_DHCPDDNS(driver.loc_);
+ default:
+ return AgentParser::make_STRING("DhcpDdns", driver.loc_);
}
}
NULL_TYPE "null"
CONTROL_AGENT "Control-agent"
- CONTROL_SOCKETS "control-sockets"
HTTP_HOST "http-host"
HTTP_PORT "http-port"
+
+ CONTROL_SOCKETS "control-sockets"
DHCP4_SERVER "dhcp4-server"
DHCP6_SERVER "dhcp6-server"
D2_SERVER "d2-server"
+ SOCKET_NAME "socket-name"
+ SOCKET_TYPE "socket-type"
+ UNIX "unix"
HOOKS_LIBRARIES "hooks-libraries"
LIBRARY "library"
PARAMETERS "parameters"
- SOCKET_TYPE "socket-type"
- SOCKET_NAME "socket-name"
-
- UNIX "unix"
-
LOGGING "Logging"
LOGGERS "loggers"
+ NAME "name"
OUTPUT_OPTIONS "output_options"
OUTPUT "output"
DEBUGLEVEL "debuglevel"
SEVERITY "severity"
- NAME "name"
DHCP4 "Dhcp4"
DHCP6 "Dhcp6"
%%
// The whole grammar starts with a map, because the config file
-// constists of Control-Agent, DhcpX, Logger and DhcpDdns entries in one big { }.
+// consists of Control-Agent, DhcpX, Logger and DhcpDdns entries in one big { }.
%start start;
// The starting token can be one of those listed below. Note these are
// "fake" tokens. They're produced by the lexer before any input text
// is parsed.
start: START_JSON { ctx.ctx_ = ctx.NO_KEYWORDS; } json
- | START_AGENT { ctx.ctx_ = ctx.KEYWORDS; } agent_syntax_map
- | START_SUB_AGENT { ctx.ctx_ = ctx.KEYWORDS; } sub_agent
+ | START_AGENT { ctx.ctx_ = ctx.CONFIG; } agent_syntax_map
+ | START_SUB_AGENT { ctx.ctx_ = ctx.AGENT; } sub_agent
;
// This rule defines a "shortcut". Instead of specifying the whole structure
// if you want to have a nice expression printed when unknown (mistyped?)
// parameter is found.
unknown_map_entry: STRING COLON {
+ const std::string& where = ctx.contextName();
const std::string& keyword = $1;
error(@1,
- "got unexpected keyword \"" + keyword + "\" in map.");
+ "got unexpected keyword \"" + keyword + "\" in " + where + " map.");
};
// This defines the top-level { } that holds Control-agent, Dhcp6, Dhcp4,
// This define the Control-agent object.
agent_object: CONTROL_AGENT {
- // Let's create a MapElement that will represent it, add it to the top level
- // map (that's already on the stack) and put the new map on the stack as well,
- // so child elements will be able to add themselves to it.
+
+ // Let's create a MapElement that will represent it, add it to the
+ // top level map (that's already on the stack) and put the new map
+ // on the stack as well, so child elements will be able to add
+ // themselves to it.
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("Control-agent", m);
ctx.stack_.push_back(m);
-
- // And tell the lexer that we definitely want keywords to be recognized.
- ctx.enter(ctx.KEYWORDS);
+ ctx.enter(ctx.AGENT);
} COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
- // Ok, we're done with parsing control-agent. Let's take the map off the stack.
+ // Ok, we're done with parsing control-agent. Let's take the map
+ // off the stack.
ctx.stack_.pop_back();
-
- // And tell the lexer to return to its previous state (probably KEYWORDS as well)
ctx.leave();
};
| unknown_map_entry
;
-http_host: HTTP_HOST COLON STRING {
- ElementPtr host(new StringElement($3, ctx.loc2pos(@3)));
+http_host: HTTP_HOST {
+ ctx.enter(ctx.NO_KEYWORDS);
+} COLON STRING {
+ ElementPtr host(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("http-host", host);
+ ctx.leave();
};
http_port: HTTP_PORT COLON INTEGER {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("hooks-libraries", l);
ctx.stack_.push_back(l);
+ ctx.enter(ctx.HOOKS_LIBRARIES);
} COLON LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
hooks_libraries_list: %empty
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("control-sockets", m);
ctx.stack_.push_back(m);
+ ctx.enter(ctx.CONTROL_SOCKETS);
} control_sockets_params RCURLY_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
// This defines what kind of control-sockets parameters we allow.
// Note that empty map is not allowed here, because at least one control socket
// is required.
control_sockets_params: control_socket
- | control_sockets_params COMMA control_socket
- | unknown_map_entry
- ;
+ | control_sockets_params COMMA control_socket
+ ;
// We currently support three types of sockets: DHCPv4, DHCPv6 and D2
// (even though D2 socket support is not yet implemented).
control_socket: dhcp4_server_socket
| dhcp6_server_socket
| d2_server_socket
+ | unknown_map_entry
;
// That's an entry for dhcp4-server socket.
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("dhcp4-server", m);
ctx.stack_.push_back(m);
+ ctx.enter(ctx.SERVER);
} COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
// That's an entry for dhcp6-server socket.
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("dhcp6-server", m);
ctx.stack_.push_back(m);
+ ctx.enter(ctx.SERVER);
} COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
// That's an entry for d2-server socket.
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("d2-server", m);
ctx.stack_.push_back(m);
+ ctx.enter(ctx.SERVER);
} COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
// Socket parameters consist of one or more parameters.
;
// We currently support two socket parameters: type and name.
-control_socket_param: socket_type
- | socket_name
+control_socket_param: socket_name
+ | socket_type
;
-// This rule specifies socket type.
-socket_type: SOCKET_TYPE {
-} COLON socket_type_value {
- ctx.stack_.back()->set("socket-type", $4);
-};
-
-// We currently allow only unix domain sockets
-socket_type_value : UNIX { $$ = ElementPtr(new StringElement("unix", ctx.loc2pos(@1))); }
-
// This rule defines socket-name parameter.
socket_name: SOCKET_NAME {
ctx.enter(ctx.NO_KEYWORDS);
ctx.leave();
};
+// This rule specifies socket type.
+socket_type: SOCKET_TYPE {
+ ctx.enter(ctx.SOCKET_TYPE);
+} COLON socket_type_value {
+ ctx.stack_.back()->set("socket-type", $4);
+ ctx.leave();
+};
+
+// We currently allow only unix domain sockets
+socket_type_value : UNIX { $$ = ElementPtr(new StringElement("unix", ctx.loc2pos(@1))); }
+ ;
+
// --- control-sockets end here ------------------------------------------------
// JSON entries for other global objects (Dhcp4,Dhcp6 and DhcpDdns)
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("Logging", m);
ctx.stack_.push_back(m);
+ ctx.enter(ctx.LOGGING);
} COLON LCURLY_BRACKET logging_params RCURLY_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
// This defines the list of allowed parameters that may appear
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("loggers", l);
ctx.stack_.push_back(l);
+ ctx.enter(ctx.LOGGERS);
} COLON LSQUARE_BRACKET loggers_entries RSQUARE_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
// These are the parameters allowed in loggers: either one logger
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("output_options", l);
ctx.stack_.push_back(l);
+ ctx.enter(ctx.OUTPUT_OPTIONS);
} COLON LSQUARE_BRACKET output_options_list_content RSQUARE_BRACKET {
ctx.stack_.pop_back();
+ ctx.leave();
};
output_options_list_content: output_entry
{
switch (ctx_) {
case NO_KEYWORDS:
- return ("no keywords");
- case KEYWORDS:
- return ("keywords");
+ return ("__no keywords__");
+ case CONFIG:
+ return ("toplevel");
+ case AGENT:
+ return ("Control-agent");
+ case LOGGING:
+ return ("Logging");
+ case CONTROL_SOCKETS:
+ return ("control-sockets");
+ case SERVER:
+ return ("xxx-server");
+ case SOCKET_TYPE:
+ return ("socket-type");
+ case HOOKS_LIBRARIES:
+ return ("hooks-librairies");
+ case LOGGERS:
+ return ("loggers");
+ case OUTPUT_OPTIONS:
+ return ("output-options");
default:
return ("__unknown__");
}
///< This one is used in pure JSON mode.
NO_KEYWORDS,
+ ///< Used while parsing top level (that contains Control-agent, Logging and others)
+ CONFIG,
+
///< Used while parsing content of Agent.
- KEYWORDS
+ AGENT,
+
+ ///< Used while parsing content of Logging.
+ LOGGING,
+
+ ///< Used while parsing Control-agent/control-sockets.
+ CONTROL_SOCKETS,
+
+ ///< Used while parsing Control-agent/control-socket/*-server.
+ SERVER,
+
+ ///< Used while parsing Control-agent/control-socket/*-server/socket-type.
+ SOCKET_TYPE,
+
+ ///< Used while parsing Control-agent/hooks-libraries.
+ HOOKS_LIBRARIES,
+
+ ///< Used while parsing Logging/loggers structures.
+ LOGGERS,
+
+ ///< Used while parsing Logging/loggers/output_options structures.
+ OUTPUT_OPTIONS
+
} LexerContext;
/// @brief File name
testError("{ \"foo\":null }\n",
ParserContext::PARSER_AGENT,
"<string>:1.3-7: got unexpected keyword "
- "\"foo\" in map.");
+ "\"foo\" in toplevel map.");
testError("{ \"Control-agent\" }\n",
ParserContext::PARSER_AGENT,
"<string>:1.19: syntax error, unexpected }, "
" \"topping\": \"Mozarella\" }}\n",
ParserContext::PARSER_AGENT,
"<string>:2.2-10: got unexpected keyword "
- "\"topping\" in map.");
+ "\"topping\" in Control-agent map.");
}
// Check unicode escapes