From: Francis Dupont Date: Mon, 21 Nov 2016 10:44:01 +0000 (+0100) Subject: [5014] Syntactic contexts almost done X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e94a8666ba65e0de7465fff792890d2e21925a24;p=thirdparty%2Fkea.git [5014] Syntactic contexts almost done --- diff --git a/src/bin/dhcp6/dhcp6.dox b/src/bin/dhcp6/dhcp6.dox index 61a6a2db44..1d29bf012d 100644 --- a/src/bin/dhcp6/dhcp6.dox +++ b/src/bin/dhcp6/dhcp6.dox @@ -225,16 +225,16 @@ MapElement object, but does not remove it. One another important capability required is the ability to parse not only the whole configuration, but a subset of it. This is done by introducing articifical -tokens (TOPLEVEL_DHCP6 and TOPLEVEL_GENERIC_JSON). The Parse6Context::parse() method +tokens (TOPLEVEL_GENERIC_JSON and TOPLEVEL_DHCP6). The Parse6Context::parse() method takes one parameter that specifies, whether the data to be parsed is expected -to have the whole configuration (DHCP6) or a generic JSON. This is only a +to have a generic JSON or the whole configuration (DHCP6). This is only a proof-of-concept, but similar approach can be implemented to parse only subnets, host reservations, options or basically any other elements. For example, to add the ability to parse only pools, the following could be added: @code -start: TOPLEVEL_DHCP6 syntax_map -| TOPLEVEL_GENERIC_JSON map2 +start: TOPLEVEL_GENERIC_JSON map2 +| TOPLEVEL_DHCP6 syntax_map | TOPLEVEL_POOL pool_entry; @endcode diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index 5bd7f8bcef..5473a7e9ba 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -42,6 +42,7 @@ std::vector states; bool start_token_flag = false; isc::dhcp::Parser6Context::ParserType start_token_value; +int comment_start_line = 0; }; @@ -109,8 +110,6 @@ JSONString \"{JSONStringCharacter}*\" // 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) { @@ -163,80 +162,572 @@ JSONString \"{JSONStringCharacter}*\" loc.step(); } -\"Dhcp6\" { return isc::dhcp::Dhcp6Parser::make_DHCP6(loc); } -\"interfaces-config\" { return isc::dhcp::Dhcp6Parser::make_INTERFACES_CONFIG(loc); } -\"interfaces\" { return isc::dhcp::Dhcp6Parser::make_INTERFACES(loc); } - -\"lease-database\" { return isc::dhcp::Dhcp6Parser::make_LEASE_DATABASE(loc); } -\"hosts-database\" { return isc::dhcp::Dhcp6Parser::make_HOSTS_DATABASE(loc); } -\"type\" { return isc::dhcp::Dhcp6Parser::make_TYPE(loc); } -\"user\" { return isc::dhcp::Dhcp6Parser::make_USER(loc); } -\"password\" { return isc::dhcp::Dhcp6Parser::make_PASSWORD(loc); } -\"host\" { return isc::dhcp::Dhcp6Parser::make_HOST(loc); } -\"persist\" { return isc::dhcp::Dhcp6Parser::make_PERSIST(loc); } -\"lfc-interval\" { return isc::dhcp::Dhcp6Parser::make_LFC_INTERVAL(loc); } - -\"preferred-lifetime\" { return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(loc); } -\"valid-lifetime\" { return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(loc); } -\"renew-timer\" { return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(loc); } -\"rebind-timer\" { return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(loc); } -\"subnet6\" { return isc::dhcp::Dhcp6Parser::make_SUBNET6(loc); } -\"option-data\" { return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(loc); } -\"name\" { return isc::dhcp::Dhcp6Parser::make_NAME(loc); } -\"data\" { return isc::dhcp::Dhcp6Parser::make_DATA(loc); } -\"pools\" { return isc::dhcp::Dhcp6Parser::make_POOLS(loc); } - -\"pd-pools\" { return isc::dhcp::Dhcp6Parser::make_PD_POOLS(loc); } -\"prefix\" { return isc::dhcp::Dhcp6Parser::make_PREFIX(loc); } -\"prefix-len\" { return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(loc); } -\"delegated-len\" { return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(loc); } - -\"pool\" { return isc::dhcp::Dhcp6Parser::make_POOL(loc); } -\"subnet\" { return isc::dhcp::Dhcp6Parser::make_SUBNET(loc); } -\"interface\" { return isc::dhcp::Dhcp6Parser::make_INTERFACE(loc); } -\"id\" { return isc::dhcp::Dhcp6Parser::make_ID(loc); } - -\"code\" { return isc::dhcp::Dhcp6Parser::make_CODE(loc); } -\"mac-sources\" { return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(loc); } -\"relay-supplied-options\" { return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(loc); } -\"host-reservation-identifiers\" { return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(loc); } - -\"Logging\" { return isc::dhcp::Dhcp6Parser::make_LOGGING(loc); } -\"loggers\" { return isc::dhcp::Dhcp6Parser::make_LOGGERS(loc); } -\"output_options\" { return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(loc); } -\"output\" { return isc::dhcp::Dhcp6Parser::make_OUTPUT(loc); } -\"debuglevel\" { return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(loc); } -\"severity\" { return isc::dhcp::Dhcp6Parser::make_SEVERITY(loc); } - -\"client-classes\" { return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(loc); } -\"client-class\" { return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(loc); } -\"test\" { return isc::dhcp::Dhcp6Parser::make_TEST(loc); } - -\"reservations\" { return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(loc); } -\"ip-addresses\" { return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(loc); } -\"prefixes\" { return isc::dhcp::Dhcp6Parser::make_PREFIXES(loc); } -\"duid\" { return isc::dhcp::Dhcp6Parser::make_DUID(loc); } -\"hw-address\" { return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(loc); } -\"hostname\" { return isc::dhcp::Dhcp6Parser::make_HOSTNAME(loc); } -\"space\" { return isc::dhcp::Dhcp6Parser::make_SPACE(loc); } -\"csv-format\" { return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(loc); } - -\"hooks-libraries\" { return isc::dhcp::Dhcp6Parser::make_HOOKS_LIBRARIES(loc); } -\"library\" { return isc::dhcp::Dhcp6Parser::make_LIBRARY(loc); } - -\"server-id\" { return isc::dhcp::Dhcp6Parser::make_SERVER_ID(loc); } -\"identifier\" { return isc::dhcp::Dhcp6Parser::make_IDENTIFIER(loc); } -\"htype\" { return isc::dhcp::Dhcp6Parser::make_HTYPE(loc); } -\"time\" { return isc::dhcp::Dhcp6Parser::make_TIME(loc); } -\"enterprise-id\" { return isc::dhcp::Dhcp6Parser::make_ENTERPRISE_ID(loc); } - -\"expired-leases-processing\" { return isc::dhcp::Dhcp6Parser::make_EXPIRED_LEASES_PROCESSING(loc); } - -\"dhcp4o6-port\" { return isc::dhcp::Dhcp6Parser::make_DHCP4O6_PORT(loc); } - -\"dhcp-ddns\" { return isc::dhcp::Dhcp6Parser::make_DHCP_DDNS(loc); } -\"enable-updates\" { return isc::dhcp::Dhcp6Parser::make_ENABLE_UPDATES(loc); } -\"qualifying-suffix\" { return isc::dhcp::Dhcp6Parser::make_QUALIFYING_SUFFIX(loc); } +\"Dhcp6\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::CONFIG: + return isc::dhcp::Dhcp6Parser::make_DHCP6(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("Dhcp6", loc); + } +} + +\"interfaces-config\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_INTERFACES_CONFIG(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("interfaces-config", loc); + } +} + +\"interfaces\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::INTERFACES_CONFIG: + return isc::dhcp::Dhcp6Parser::make_INTERFACES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("interfaces", loc); + } +} + +\"lease-database\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_LEASE_DATABASE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("lease-database", loc); + } +} + +\"hosts-database\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_HOSTS_DATABASE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("hosts-database", loc); + } +} + +\"type\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + case isc::dhcp::Parser6Context::SERVER_ID: + return isc::dhcp::Dhcp6Parser::make_TYPE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("type", loc); + } +} + +\"user\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + return isc::dhcp::Dhcp6Parser::make_USER(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("user", loc); + } +} + +\"password\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + return isc::dhcp::Dhcp6Parser::make_PASSWORD(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("password", loc); + } +} + +\"host\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + return isc::dhcp::Dhcp6Parser::make_HOST(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("host", loc); + } +} + +\"persist\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + case isc::dhcp::Parser6Context::SERVER_ID: + return isc::dhcp::Dhcp6Parser::make_PERSIST(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("persist", loc); + } +} + +\"lfc-interval\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + return isc::dhcp::Dhcp6Parser::make_LFC_INTERVAL(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("lfc-interval", loc); + } +} + +\"preferred-lifetime\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("preferred-lifetime", loc); + } +} + +\"valid-lifetime\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("valid-lifetime", loc); + } +} + +\"renew-timer\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("renew-timer", loc); + } +} + +\"rebind-timer\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("rebind-timer", loc); + } +} + +\"subnet6\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_SUBNET6(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("subnet6", loc); + } +} + +\"option-data\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::POOLS: + case isc::dhcp::Parser6Context::PD_POOLS: + case isc::dhcp::Parser6Context::RESERVATIONS: + case isc::dhcp::Parser6Context::CLIENT_CLASSES: + case isc::dhcp::Parser6Context::CLIENT_CLASS: + return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("option-data", loc); + } +} + +\"name\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DATABASE: + case isc::dhcp::Parser6Context::OPTION_DATA: + case isc::dhcp::Parser6Context::CLIENT_CLASSES: + case isc::dhcp::Parser6Context::CLIENT_CLASS: + case isc::dhcp::Parser6Context::LOGGERS: + return isc::dhcp::Dhcp6Parser::make_NAME(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("name", loc); + } +} + +\"data\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::OPTION_DATA: + return isc::dhcp::Dhcp6Parser::make_DATA(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("data", loc); + } +} + +\"pools\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + return isc::dhcp::Dhcp6Parser::make_POOLS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("pools", loc); + } +} + +\"pd-pools\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + return isc::dhcp::Dhcp6Parser::make_PD_POOLS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("pd-pools", loc); + } +} + +\"prefix\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::PD_POOLS: + return isc::dhcp::Dhcp6Parser::make_PREFIX(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("prefix", loc); + } +} + +\"prefix-len\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::PD_POOLS: + return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("prefix-len", loc); + } +} + +\"delegated-len\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::PD_POOLS: + return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("delegated-len", loc); + } +} + +\"pool\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::POOLS: + return isc::dhcp::Dhcp6Parser::make_POOL(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("pool", loc); + } +} + +\"subnet\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + return isc::dhcp::Dhcp6Parser::make_SUBNET(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("subnet", loc); + } +} + +\"interface\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + return isc::dhcp::Dhcp6Parser::make_INTERFACE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("interface", loc); + } +} + +\"id\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + return isc::dhcp::Dhcp6Parser::make_ID(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("id", loc); + } +} + +\"code\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::OPTION_DATA: + return isc::dhcp::Dhcp6Parser::make_CODE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("code", loc); + } +} + +\"mac-sources\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("mac-sources", loc); + } +} + +\"relay-supplied-options\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("relay-supplied-options", loc); + } +} + +\"host-reservation-identifiers\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("host-reservation-identifiers", loc); + } +} + +\"Logging\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::CONFIG: + return isc::dhcp::Dhcp6Parser::make_LOGGING(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("Logging", loc); + } +} + +\"loggers\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LOGGING: + return isc::dhcp::Dhcp6Parser::make_LOGGERS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("loggers", loc); + } +} + +\"output_options\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LOGGERS: + return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("output_options", loc); + } +} + +\"output\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::OUTPUT_OPTIONS: + return isc::dhcp::Dhcp6Parser::make_OUTPUT(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("output", loc); + } +} + +\"debuglevel\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LOGGERS: + return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("debuglevel", loc); + } +} + +\"severity\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::LOGGERS: + return isc::dhcp::Dhcp6Parser::make_SEVERITY(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("severity", loc); + } +} + +\"client-classes\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + case isc::dhcp::Parser6Context::RESERVATIONS: + return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("client-classes", loc); + } +} + +\"client-class\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + case isc::dhcp::Parser6Context::CLIENT_CLASSES: + return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("client-class", loc); + } +} + +\"test\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::CLIENT_CLASSES: + case isc::dhcp::Parser6Context::CLIENT_CLASS: + return isc::dhcp::Dhcp6Parser::make_TEST(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("test", loc); + } +} + +\"reservations\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SUBNET6: + return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("reservations", loc); + } +} + +\"ip-addresses\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::RESERVATIONS: + return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("ip-addresses", loc); + } +} + +\"prefixes\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::RESERVATIONS: + return isc::dhcp::Dhcp6Parser::make_PREFIXES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("prefixes", loc); + } +} + +\"duid\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::MAC_SOURCES: + case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS: + case isc::dhcp::Parser6Context::RESERVATIONS: + return isc::dhcp::Dhcp6Parser::make_DUID(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("duid", loc); + } +} + +\"hw-address\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::HOST_RESERVATION_IDENTIFIERS: + case isc::dhcp::Parser6Context::RESERVATIONS: + return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("hw-address", loc); + } +} + +\"hostname\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::RESERVATIONS: + return isc::dhcp::Dhcp6Parser::make_HOSTNAME(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("hostname", loc); + } +} + +\"space\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::OPTION_DATA: + return isc::dhcp::Dhcp6Parser::make_SPACE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("space", loc); + } +} + +\"csv-format\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::OPTION_DATA: + return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("csv-format", loc); + } +} + +\"hooks-libraries\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_HOOKS_LIBRARIES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("hooks-libraries", loc); + } +} + +\"library\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::HOOKS_LIBRARIES: + return isc::dhcp::Dhcp6Parser::make_LIBRARY(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("library", loc); + } +} + +\"server-id\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_SERVER_ID(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("server-id", loc); + } +} + +\"identifier\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SERVER_ID: + return isc::dhcp::Dhcp6Parser::make_IDENTIFIER(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("identifier", loc); + } +} + +\"htype\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SERVER_ID: + return isc::dhcp::Dhcp6Parser::make_HTYPE(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("htype", loc); + } +} + +\"time\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SERVER_ID: + return isc::dhcp::Dhcp6Parser::make_TIME(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("time", loc); + } +} + +\"enterprise-id\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::SERVER_ID: + return isc::dhcp::Dhcp6Parser::make_ENTERPRISE_ID(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("enterprise-id", loc); + } +} + +\"expired-leases-processing\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_EXPIRED_LEASES_PROCESSING(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("expired-leases-processing", loc); + } +} + +\"dhcp4o6-port\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_DHCP4O6_PORT(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("dhcp4o6-port", loc); + } +} + +\"dhcp-ddns\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP6: + return isc::dhcp::Dhcp6Parser::make_DHCP_DDNS(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("dhcp-ddns", loc); + } +} + +\"enable-updates\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP_DDNS: + return isc::dhcp::Dhcp6Parser::make_ENABLE_UPDATES(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("enable-updates", loc); + } +} + +\"qualifying-suffix\" { + switch(driver.ctx_) { + case isc::dhcp::Parser6Context::DHCP_DDNS: + return isc::dhcp::Dhcp6Parser::make_QUALIFYING_SUFFIX(loc); + default: + return isc::dhcp::Dhcp6Parser::make_STRING("qualifying-suffix", loc); + } +} {JSONString} { @@ -300,6 +791,7 @@ null { } . driver.error (loc, "Invalid character: " + std::string(yytext)); + <> { if (states.empty()) { return isc::dhcp::Dhcp6Parser::make_END(loc); diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index 8677c51b9c..4128a6bfd2 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -36,6 +36,7 @@ using namespace std; } + %define api.token.prefix {TOKEN_} // Tokens in an order which makes sense and related to the intented use. %token @@ -125,8 +126,8 @@ using namespace std; // Not real tokens, just a way to signal what the parser is expected to // parse. - TOPLEVEL_DHCP6 TOPLEVEL_GENERIC_JSON + TOPLEVEL_DHCP6 ; %token STRING "constant string" @@ -146,20 +147,23 @@ using namespace std; // %start dhcp6_map - this will parse everything with Dhcp6 syntax checking %start start; -start: TOPLEVEL_DHCP6 syntax_map -| TOPLEVEL_GENERIC_JSON map2; +start: TOPLEVEL_GENERIC_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } map2 + | TOPLEVEL_DHCP6 { ctx.ctx_ = ctx.CONFIG; } syntax_map + ; // ---- generic JSON parser --------------------------------- +// Note that ctx_ is NO_KEYWORD here + // Values rule value : INTEGER { $$ = ElementPtr(new IntElement($1)); } - | FLOAT { $$ = ElementPtr(new DoubleElement($1)); } - | BOOLEAN { $$ = ElementPtr(new BoolElement($1)); } - | STRING { $$ = ElementPtr(new StringElement($1)); } - | NULL_TYPE { $$ = ElementPtr(new NullElement()); } - | map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); } - | list_generic { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); } - ; + | FLOAT { $$ = ElementPtr(new DoubleElement($1)); } + | BOOLEAN { $$ = ElementPtr(new BoolElement($1)); } + | STRING { $$ = ElementPtr(new StringElement($1)); } + | NULL_TYPE { $$ = ElementPtr(new NullElement()); } + | map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); } + | list_generic { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); } + ; map2: LCURLY_BRACKET { // This code is executed when we're about to start parsing @@ -174,22 +178,23 @@ map2: LCURLY_BRACKET { // Assignments rule map_content: %empty // empty map - | STRING COLON value { - // map containing a single entry - ctx.stack_.back()->set($1, $3); - } - | map_content COMMA STRING COLON value { - // map consisting of a shorter map followed by comma and string:value - ctx.stack_.back()->set($3, $5); - } - ; + | STRING COLON value { + // map containing a single entry + ctx.stack_.back()->set($1, $3); + } + | map_content COMMA STRING COLON value { + // map consisting of a shorter map followed by + // comma and string:value + ctx.stack_.back()->set($3, $5); + } + ; list_generic: LSQUARE_BRACKET { ElementPtr l(new ListElement()); ctx.stack_.push_back(l); - } list_content RSQUARE_BRACKET { - - } +} list_content RSQUARE_BRACKET { + // list parsing complete. Put any sanity checking here +}; // This one is used in syntax parser. list2: LSQUARE_BRACKET { @@ -200,15 +205,15 @@ list2: LSQUARE_BRACKET { }; list_content: %empty // Empty list - | value { - // List consisting of a single element. - ctx.stack_.back()->add($1); - } - | list_content COMMA value { - // List ending with , and a value. - ctx.stack_.back()->add($3); - } - ; + | value { + // List consisting of a single element. + ctx.stack_.back()->add($1); + } + | list_content COMMA value { + // List ending with , and a value. + ctx.stack_.back()->add($3); + } + ; // ---- generic JSON parser ends here ---------------------------------- @@ -216,6 +221,7 @@ list_content: %empty // Empty list // This defines the top-level { } that holds Dhcp6, Dhcp4, DhcpDdns or Logging // objects. +// ctx_ = CONFIG syntax_map: LCURLY_BRACKET { // This code is executed when we're about to start parsing // the content of the map @@ -229,52 +235,54 @@ syntax_map: LCURLY_BRACKET { // This represents a single top level entry, e.g. Dhcp6 or DhcpDdns. global_object: dhcp6_object -| logging_object; + | logging_object + ; // This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging -global_objects -: global_object -| global_objects COMMA global_object -; +global_objects: global_object + | global_objects COMMA global_object + ; -dhcp6_object: DHCP6 COLON LCURLY_BRACKET { +dhcp6_object: DHCP6 { // This code is executed when we're about to start parsing // the content of the map ElementPtr m(new MapElement()); ctx.stack_.back()->set("Dhcp6", m); ctx.stack_.push_back(m); -} global_params RCURLY_BRACKET { + ctx.enter(ctx.DHCP6); +} COLON LCURLY_BRACKET global_params RCURLY_BRACKET { // map parsing completed. If we ever want to do any wrap up // (maybe some sanity checking), this would be the best place // for it. ctx.stack_.pop_back(); + ctx.leave(); }; global_params: global_param -| global_params COMMA global_param; + | global_params COMMA global_param + ; // These are the parameters that are allowed in the top-level for // Dhcp6. -global_param -: preferred_lifetime -| valid_lifetime -| renew_timer -| rebind_timer -| subnet6_list -| interfaces_config -| lease_database -| hosts_database -| mac_sources -| relay_supplied_options -| host_reservation_identifiers -| client_classes -| option_data_list -| hooks_libraries -| expired_leases_processing -| server_id -| dhcp4o6_port -| dhcp_ddns -; +global_param: preferred_lifetime + | valid_lifetime + | renew_timer + | rebind_timer + | subnet6_list + | interfaces_config + | lease_database + | hosts_database + | mac_sources + | relay_supplied_options + | host_reservation_identifiers + | client_classes + | option_data_list + | hooks_libraries + | expired_leases_processing + | server_id + | dhcp4o6_port + | dhcp_ddns + ; preferred_lifetime: PREFERRED_LIFETIME COLON INTEGER { ElementPtr prf(new IntElement($3)); @@ -296,75 +304,97 @@ rebind_timer: REBIND_TIMER COLON INTEGER { ctx.stack_.back()->set("rebind-timer", prf); }; -interfaces_config: INTERFACES_CONFIG COLON { +interfaces_config: INTERFACES_CONFIG { ElementPtr i(new MapElement()); ctx.stack_.back()->set("interfaces-config", i); ctx.stack_.push_back(i); - } LCURLY_BRACKET interface_config_map RCURLY_BRACKET { + ctx.enter(ctx.INTERFACES_CONFIG); +} COLON LCURLY_BRACKET interface_config_map RCURLY_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; interface_config_map: INTERFACES { ElementPtr l(new ListElement()); ctx.stack_.back()->set("interfaces", l); ctx.stack_.push_back(l); - } COLON list2 { - ctx.stack_.pop_back(); - } + ctx.enter(ctx.NO_KEYWORD); +} COLON list2 { + ctx.stack_.pop_back(); + ctx.leave(); +}; lease_database: LEASE_DATABASE { ElementPtr i(new MapElement()); ctx.stack_.back()->set("lease-database", i); ctx.stack_.push_back(i); -} -COLON LCURLY_BRACKET database_map_params { - ctx.stack_.pop_back(); -} RCURLY_BRACKET; + ctx.enter(ctx.DATABASE); +} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET { + ctx.stack_.pop_back(); + ctx.leave(); +}; hosts_database: HOSTS_DATABASE { ElementPtr i(new MapElement()); ctx.stack_.back()->set("hosts-database", i); ctx.stack_.push_back(i); -} -COLON LCURLY_BRACKET database_map_params { - ctx.stack_.pop_back(); -} RCURLY_BRACKET; - -database_map_params: lease_database_map_param -| database_map_params COMMA lease_database_map_param; - -lease_database_map_param: type -| user -| password -| host -| name -| persist -| lfc_interval; + ctx.enter(ctx.DATABASE); +} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET { + ctx.stack_.pop_back(); + ctx.leave(); +}; + +database_map_params: database_map_param + | database_map_params COMMA database_map_param + ; + +database_map_param: type + | user + | password + | host + | name + | persist + | lfc_interval; ; -type: TYPE COLON STRING { - ElementPtr prf(new StringElement($3)); +type: TYPE { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr prf(new StringElement($4)); ctx.stack_.back()->set("type", prf); + ctx.leave(); }; -user: USER COLON STRING { - ElementPtr user(new StringElement($3)); +user: USER { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr user(new StringElement($4)); ctx.stack_.back()->set("user", user); + ctx.leave(); }; -password: PASSWORD COLON STRING { - ElementPtr pwd(new StringElement($3)); +password: PASSWORD { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr pwd(new StringElement($4)); ctx.stack_.back()->set("password", pwd); + ctx.leave(); }; -host: HOST COLON STRING { - ElementPtr h(new StringElement($3)); +host: HOST { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr h(new StringElement($4)); ctx.stack_.back()->set("host", h); + ctx.leave(); }; -name: NAME COLON STRING { - ElementPtr n(new StringElement($3)); +name: NAME { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr n(new StringElement($4)); ctx.stack_.back()->set("name", n); + ctx.leave(); }; persist: PERSIST COLON BOOLEAN { @@ -381,56 +411,74 @@ mac_sources: MAC_SOURCES { ElementPtr l(new ListElement()); ctx.stack_.back()->set("mac-sources", l); ctx.stack_.push_back(l); + ctx.enter(ctx.MAC_SOURCES); } COLON LSQUARE_BRACKET mac_sources_list RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; mac_sources_list: mac_sources_value -| mac_sources_list COMMA mac_sources_value; + | mac_sources_list COMMA mac_sources_value +; mac_sources_value: DUID { - ElementPtr duid(new StringElement("duid")); ctx.stack_.back()->add(duid); -}| STRING { - ElementPtr duid(new StringElement($1)); ctx.stack_.back()->add(duid); -}; - -host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS COLON LSQUARE_BRACKET { + ElementPtr duid(new StringElement("duid")); + ctx.stack_.back()->add(duid); + } + | STRING { + ElementPtr duid(new StringElement($1)); + ctx.stack_.back()->add(duid); + } + ; + +host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("host-reservation-identifiers", l); ctx.stack_.push_back(l); -} host_reservation_identifiers_list RSQUARE_BRACKET { + ctx.enter(ctx.HOST_RESERVATION_IDENTIFIERS); +} COLON LSQUARE_BRACKET host_reservation_identifiers_list RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; host_reservation_identifiers_list: host_reservation_identifier -| host_reservation_identifiers_list COMMA host_reservation_identifier; + | host_reservation_identifiers_list COMMA host_reservation_identifier + ; host_reservation_identifier: DUID { - ElementPtr duid(new StringElement("duid")); ctx.stack_.back()->add(duid); -} -| HW_ADDRESS { - ElementPtr hwaddr(new StringElement("hw-address")); ctx.stack_.back()->add(hwaddr); -} + ElementPtr duid(new StringElement("duid")); + ctx.stack_.back()->add(duid); + } + | HW_ADDRESS { + ElementPtr hwaddr(new StringElement("hw-address")); + ctx.stack_.back()->add(hwaddr); + } + ; relay_supplied_options: RELAY_SUPPLIED_OPTIONS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("relay-supplied-options", l); ctx.stack_.push_back(l); + ctx.enter(ctx.NO_KEYWORD); } COLON list2 { ctx.stack_.pop_back(); + ctx.leave(); }; -hooks_libraries: HOOKS_LIBRARIES COLON { +hooks_libraries: HOOKS_LIBRARIES { ElementPtr l(new ListElement()); ctx.stack_.back()->set("hooks-libraries", l); ctx.stack_.push_back(l); -} LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET { + ctx.enter(ctx.HOOKS_LIBRARIES); +} COLON LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; hooks_libraries_list: %empty -| hooks_library -| hooks_libraries_list COMMA hooks_library; + | hooks_library + | hooks_libraries_list COMMA hooks_library + ; hooks_library: LCURLY_BRACKET { ElementPtr m(new MapElement()); @@ -441,49 +489,60 @@ hooks_library: LCURLY_BRACKET { }; hooks_params: hooks_param -| hooks_params hooks_param; + | hooks_params hooks_param + ; -hooks_param: LIBRARY COLON STRING { - ElementPtr lib(new StringElement($3)); ctx.stack_.back()->set("library", lib); +hooks_param: LIBRARY { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr lib(new StringElement($4)); + ctx.stack_.back()->set("library", lib); + ctx.leave(); }; // --- expired-leases-processing ------------------------ -expired_leases_processing: EXPIRED_LEASES_PROCESSING COLON LCURLY_BRACKET { +expired_leases_processing: EXPIRED_LEASES_PROCESSING { ElementPtr m(new MapElement()); ctx.stack_.back()->set("expired-leases-processing", m); ctx.stack_.push_back(m); -} expired_leases_params RCURLY_BRACKET { + ctx.enter(ctx.NO_KEYWORD); +} COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; expired_leases_params: expired_leases_param -| expired_leases_params COMMA expired_leases_param; + | expired_leases_params COMMA expired_leases_param + ; // This is a bit of a simplification. But it can also serve as an example. // Instead of explicitly listing all allowed expired leases parameters, we // simply say that all of them as integers. expired_leases_param: STRING COLON INTEGER { - ElementPtr value(new IntElement($3)); ctx.stack_.back()->set($1, value); + ElementPtr value(new IntElement($3)); + ctx.stack_.back()->set($1, value); } // --- subnet6 ------------------------------------------ // This defines subnet6 as a list of maps. // "subnet6": [ ... ] -subnet6_list: SUBNET6 COLON LSQUARE_BRACKET { +subnet6_list: SUBNET6 { ElementPtr l(new ListElement()); ctx.stack_.back()->set("subnet6", l); ctx.stack_.push_back(l); -} subnet6_list_content RSQUARE_BRACKET { + ctx.enter(ctx.SUBNET6); +} COLON LSQUARE_BRACKET subnet6_list_content RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; // This defines the ... in "subnet6": [ ... ] // It can either be empty (no subnets defined), have one subnet // or have multiple subnets separate by comma. subnet6_list_content: %empty -| subnet6 -| subnet6_list_content COMMA subnet6 -; + | subnet6 + | subnet6_list_content COMMA subnet6 + ; // --- Subnet definitions ------------------------------- @@ -493,7 +552,7 @@ subnet6: LCURLY_BRACKET { ElementPtr m(new MapElement()); ctx.stack_.back()->add(m); ctx.stack_.push_back(m); -} subnet6_params { +} subnet6_params RCURLY_BRACKET { // Once we reached this place, the subnet parsing is now complete. // If we want to, we can implement default values here. // In particular we can do things like this: @@ -510,38 +569,51 @@ subnet6: LCURLY_BRACKET { // } // } ctx.stack_.pop_back(); -} RCURLY_BRACKET; +}; // This defines that subnet can have one or more parameters. subnet6_params: subnet6_param -| subnet6_params COMMA subnet6_param; + | subnet6_params COMMA subnet6_param + ; // This defines a list of allowed parameters for each subnet. subnet6_param: option_data_list -| pools_list -| pd_pools_list -| subnet -| interface -| id -| client_class -| reservations -; - -subnet: SUBNET COLON STRING { - ElementPtr subnet(new StringElement($3)); ctx.stack_.back()->set("subnet", subnet); -}; - -interface: INTERFACE COLON STRING { - ElementPtr iface(new StringElement($3)); ctx.stack_.back()->set("interface", iface); -}; - -subnet: CLIENT_CLASS COLON STRING { - ElementPtr cls(new StringElement($3)); ctx.stack_.back()->set("client-class", cls); + | pools_list + | pd_pools_list + | subnet + | interface + | id + | client_class + | reservations + ; + +subnet: SUBNET { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr subnet(new StringElement($4)); + ctx.stack_.back()->set("subnet", subnet); + ctx.leave(); +}; + +interface: INTERFACE { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr iface(new StringElement($4)); + ctx.stack_.back()->set("interface", iface); + ctx.leave(); +}; + +client_class: CLIENT_CLASS { + ctx.enter(ctx.CLIENT_CLASS); +} COLON STRING { + ElementPtr cls(new StringElement($4)); + ctx.stack_.back()->set("client-class", cls); + ctx.leave(); }; id: ID COLON INTEGER { - ElementPtr id(new IntElement($3)); ctx.stack_.back()->set("id", id); - + ElementPtr id(new IntElement($3)); + ctx.stack_.back()->set("id", id); }; // ---- option-data -------------------------- @@ -552,15 +624,18 @@ option_data_list: OPTION_DATA { ElementPtr l(new ListElement()); ctx.stack_.back()->set("option-data", l); ctx.stack_.push_back(l); + ctx.enter(ctx.OPTION_DATA); } COLON LSQUARE_BRACKET option_data_list_content RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; // This defines the content of option-data. It may be empty, // have one entry or multiple entries separated by comma. option_data_list_content: %empty -| option_data_entry -| option_data_list_content COMMA option_data_entry; + | option_data_entry + | option_data_list_content COMMA option_data_entry + ; // This defines th content of a single entry { ... } within // option-data list. @@ -575,55 +650,73 @@ option_data_entry: LCURLY_BRACKET { // This defines parameters specified inside the map that itself // is an entry in option-data list. option_data_params: option_data_param -| option_data_params COMMA option_data_param; + | option_data_params COMMA option_data_param + ; option_data_param: %empty -| option_data_name -| option_data_data -| option_data_code -| option_data_space -| option_data_csv_format -; - - -option_data_name: NAME COLON STRING { - ElementPtr name(new StringElement($3)); ctx.stack_.back()->set("name", name); + | option_data_name + | option_data_data + | option_data_code + | option_data_space + | option_data_csv_format + ; + + +option_data_name: NAME { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr name(new StringElement($4)); + ctx.stack_.back()->set("name", name); + ctx.leave(); }; -option_data_data: DATA COLON STRING { - ElementPtr data(new StringElement($3)); ctx.stack_.back()->set("data", data); +option_data_data: DATA { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr data(new StringElement($4)); + ctx.stack_.back()->set("data", data); + ctx.leave(); }; option_data_code: CODE COLON INTEGER { - ElementPtr code(new IntElement($3)); ctx.stack_.back()->set("code", code); + ElementPtr code(new IntElement($3)); + ctx.stack_.back()->set("code", code); }; -option_data_space: SPACE COLON STRING { - ElementPtr space(new StringElement($3)); ctx.stack_.back()->set("space", space); +option_data_space: SPACE { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr space(new StringElement($4)); + ctx.stack_.back()->set("space", space); + ctx.leave(); }; option_data_csv_format: CSV_FORMAT COLON BOOLEAN { - ElementPtr space(new BoolElement($3)); ctx.stack_.back()->set("csv-format", space); + ElementPtr space(new BoolElement($3)); + ctx.stack_.back()->set("csv-format", space); }; // ---- pools ------------------------------------ // This defines the "pools": [ ... ] entry that may appear in subnet6. -pools_list: POOLS COLON { +pools_list: POOLS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("pools", l); ctx.stack_.push_back(l); -} LSQUARE_BRACKET pools_list_content RSQUARE_BRACKET { + ctx.enter(ctx.POOLS); +} COLON LSQUARE_BRACKET pools_list_content RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; // Pools may be empty, contain a single pool entry or multiple entries // separate by commas. pools_list_content: %empty -| pool_entry -| pools_list_content COMMA pool_entry; + | pool_list_entry + | pools_list_content COMMA pool_list_entry + ; -pool_entry: LCURLY_BRACKET { +pool_list_entry: LCURLY_BRACKET { ElementPtr m(new MapElement()); ctx.stack_.back()->add(m); ctx.stack_.push_back(m); @@ -632,28 +725,40 @@ pool_entry: LCURLY_BRACKET { }; pool_params: pool_param -| pool_params COMMA pool_param; + | pool_params COMMA pool_param + ; + +pool_param: pool_entry + | option_data_list + ; + +pool_entry: POOL { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr pool(new StringElement($4)); + ctx.stack_.back()->set("pool", pool); + ctx.leave(); +}; -pool_param: POOL COLON STRING { - ElementPtr pool(new StringElement($3)); ctx.stack_.back()->set("pool", pool); -} -| option_data_list; // --- end of pools definition ------------------------------- // --- pd-pools ---------------------------------------------- -pd_pools_list: PD_POOLS COLON { +pd_pools_list: PD_POOLS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("pd-pools", l); ctx.stack_.push_back(l); -} LSQUARE_BRACKET pd_pools_list_content RSQUARE_BRACKET { + ctx.enter(ctx.PD_POOLS); +} COLON LSQUARE_BRACKET pd_pools_list_content RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; // Pools may be empty, contain a single pool entry or multiple entries // separate by commas. pd_pools_list_content: %empty -| pd_pool_entry -| pd_pools_list_content COMMA pd_pool_entry; + | pd_pool_entry + | pd_pools_list_content COMMA pd_pool_entry + ; pd_pool_entry: LCURLY_BRACKET { ElementPtr m(new MapElement()); @@ -664,42 +769,50 @@ pd_pool_entry: LCURLY_BRACKET { }; pd_pool_params: pd_pool_param -| pd_pool_params COMMA pd_pool_param; + | pd_pool_params COMMA pd_pool_param + ; pd_pool_param: pd_prefix -| pd_prefix_len -| pd_delegated_len -| option_data_list -; - -pd_prefix: PREFIX COLON STRING { - ElementPtr prf(new StringElement($3)); ctx.stack_.back()->set("prefix", prf); + | pd_prefix_len + | pd_delegated_len + | option_data_list + ; + +pd_prefix: PREFIX { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr prf(new StringElement($4)); + ctx.stack_.back()->set("prefix", prf); + ctx.leave(); } pd_prefix_len: PREFIX_LEN COLON INTEGER { - ElementPtr prf(new IntElement($3)); ctx.stack_.back()->set("prefix-len", prf); + ElementPtr prf(new IntElement($3)); + ctx.stack_.back()->set("prefix-len", prf); } pd_delegated_len: DELEGATED_LEN COLON INTEGER { - ElementPtr deleg(new IntElement($3)); ctx.stack_.back()->set("delegated-len", deleg); + ElementPtr deleg(new IntElement($3)); + ctx.stack_.back()->set("delegated-len", deleg); } - - // --- end of pd-pools --------------------------------------- // --- reservations ------------------------------------------ -reservations: RESERVATIONS COLON LSQUARE_BRACKET { +reservations: RESERVATIONS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("reservations", l); ctx.stack_.push_back(l); -} reservations_list { + ctx.enter(ctx.RESERVATIONS); +} COLON LSQUARE_BRACKET reservations_list RSQUARE_BRACKET { ctx.stack_.pop_back(); -} RSQUARE_BRACKET; + ctx.leave(); +}; reservations_list: %empty -| reservation -| reservations_list COMMA reservation; + | reservation + | reservations_list COMMA reservation + ; reservation: LCURLY_BRACKET { ElementPtr m(new MapElement()); @@ -710,68 +823,90 @@ reservation: LCURLY_BRACKET { }; reservation_params: reservation_param -| reservation_params COMMA reservation_param; + | reservation_params COMMA reservation_param + ; // @todo probably need to add mac-address as well here reservation_param: %empty -| duid -| reservation_client_classes -| ip_addresses -| prefixes -| hw_address -| hostname -| option_data_list -; - -ip_addresses: IP_ADDRESSES COLON { + | duid + | reservation_client_classes + | ip_addresses + | prefixes + | hw_address + | hostname + | option_data_list + ; + +ip_addresses: IP_ADDRESSES { ElementPtr l(new ListElement()); ctx.stack_.back()->set("ip-addresses", l); ctx.stack_.push_back(l); -} list2 { + ctx.enter(ctx.NO_KEYWORD); +} COLON list2 { ctx.stack_.pop_back(); + ctx.leave(); }; -prefixes: PREFIXES COLON { +prefixes: PREFIXES { ElementPtr l(new ListElement()); ctx.stack_.back()->set("prefixes", l); ctx.stack_.push_back(l); -} list2 { + ctx.enter(ctx.NO_KEYWORD); +} COLON list2 { ctx.stack_.pop_back(); + ctx.leave(); }; -duid: DUID COLON STRING { - ElementPtr d(new StringElement($3)); ctx.stack_.back()->set("duid", d); +duid: DUID { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr d(new StringElement($4)); + ctx.stack_.back()->set("duid", d); + ctx.leave(); }; -hw_address: HW_ADDRESS COLON STRING { - ElementPtr hw(new StringElement($3)); ctx.stack_.back()->set("hw-address", hw); +hw_address: HW_ADDRESS { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr hw(new StringElement($4)); + ctx.stack_.back()->set("hw-address", hw); + ctx.leave(); }; -hostname: HOSTNAME COLON STRING { - ElementPtr host(new StringElement($3)); ctx.stack_.back()->set("hostname", host); +hostname: HOSTNAME { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr host(new StringElement($4)); + ctx.stack_.back()->set("hostname", host); + ctx.leave(); } -reservation_client_classes: CLIENT_CLASSES COLON { +reservation_client_classes: CLIENT_CLASSES { ElementPtr c(new ListElement()); ctx.stack_.back()->set("client-classes", c); ctx.stack_.push_back(c); -} list2 { + ctx.enter(ctx.NO_KEYWORD); +} COLON list2 { ctx.stack_.pop_back(); - }; + ctx.leave(); +}; // --- end of reservations definitions ----------------------- // --- client classes ---------------------------------------- -client_classes: CLIENT_CLASSES COLON LSQUARE_BRACKET { +client_classes: CLIENT_CLASSES { ElementPtr l(new ListElement()); ctx.stack_.back()->set("client-classes", l); ctx.stack_.push_back(l); -} client_classes_list RSQUARE_BRACKET { + ctx.enter(ctx.CLIENT_CLASSES); +} COLON LSQUARE_BRACKET client_classes_list RSQUARE_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; client_classes_list: client_class -| client_classes_list COMMA client_class; + | client_classes_list COMMA client_class + ; client_class: LCURLY_BRACKET { ElementPtr m(new MapElement()); @@ -782,54 +917,68 @@ client_class: LCURLY_BRACKET { }; client_class_params: client_class_param -| client_class_params COMMA client_class_param; + | client_class_params COMMA client_class_param + ; client_class_param: %empty -| client_class_name -| client_class_test -| option_data_list -; - -client_class_name: NAME COLON STRING { - ElementPtr name(new StringElement($3)); + | client_class_name + | client_class_test + | option_data_list + ; + +client_class_name: NAME { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr name(new StringElement($4)); ctx.stack_.back()->set("name", name); + ctx.leave(); }; -client_class_test: TEST COLON STRING { - ElementPtr test(new StringElement($3)); +client_class_test: TEST { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr test(new StringElement($4)); ctx.stack_.back()->set("test", test); + ctx.leave(); } // --- end of client classes --------------------------------- // --- server-id --------------------------------------------- -server_id: SERVER_ID COLON LCURLY_BRACKET { +server_id: SERVER_ID { ElementPtr m(new MapElement()); ctx.stack_.back()->set("server-id", m); ctx.stack_.push_back(m); -} server_id_params RCURLY_BRACKET { + ctx.enter(ctx.SERVER_ID); +} COLON LCURLY_BRACKET server_id_params RCURLY_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; server_id_params: server_id_param -| server_id_params COMMA server_id_param; + | server_id_params COMMA server_id_param + ; server_id_param: type -| identifier -| time -| htype -| enterprise_id -| persist; + | identifier + | time + | htype + | enterprise_id + | persist + ; htype: HTYPE COLON INTEGER { ElementPtr htype(new IntElement($3)); ctx.stack_.back()->set("htype", htype); }; -identifier: IDENTIFIER COLON STRING { - ElementPtr id(new StringElement($3)); +identifier: IDENTIFIER { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr id(new StringElement($4)); ctx.stack_.back()->set("identifier", id); + ctx.leave(); }; time: TIME COLON INTEGER { @@ -854,37 +1003,43 @@ dhcp4o6_port: DHCP4O6_PORT COLON INTEGER { // This defines the top level "Logging" object. It parses // the following "Logging": { ... }. The ... is defined // by logging_params -logging_object: LOGGING COLON LCURLY_BRACKET { +logging_object: LOGGING { ElementPtr m(new MapElement()); ctx.stack_.back()->set("Logging", m); ctx.stack_.push_back(m); -} logging_params RCURLY_BRACKET { + 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 // in the top-level Logging object. It can either be a single // parameter or several parameters separated by commas. logging_params: logging_param -| logging_params COMMA logging_param; + | logging_params COMMA logging_param + ; // There's currently only one parameter defined, which is "loggers". logging_param: loggers; // "loggers", the only parameter currently defined in "Logging" object, // is "Loggers": [ ... ]. -loggers: LOGGERS COLON { +loggers: LOGGERS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("loggers", l); ctx.stack_.push_back(l); -} LSQUARE_BRACKET loggers_entries RSQUARE_BRACKET { + 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 // entry or multiple entries separate by commas. loggers_entries: logger_entry -| loggers_entries COMMA logger_entry; + | loggers_entries COMMA logger_entry + ; // This defines a single entry defined in loggers in Logging. logger_entry: LCURLY_BRACKET { @@ -896,35 +1051,48 @@ logger_entry: LCURLY_BRACKET { }; logger_params: logger_param -| logger_params COMMA logger_param; + | logger_params COMMA logger_param + ; logger_param: logger_name -| output_options_list -| debuglevel -| severity -; - -logger_name: NAME COLON STRING { - ElementPtr name(new StringElement($3)); ctx.stack_.back()->set("name", name); + | output_options_list + | debuglevel + | severity + ; + +logger_name: NAME { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr name(new StringElement($4)); + ctx.stack_.back()->set("name", name); + ctx.leave(); }; debuglevel: DEBUGLEVEL COLON INTEGER { - ElementPtr dl(new IntElement($3)); ctx.stack_.back()->set("debuglevel", dl); + ElementPtr dl(new IntElement($3)); + ctx.stack_.back()->set("debuglevel", dl); }; -severity: SEVERITY COLON STRING { - ElementPtr sev(new StringElement($3)); ctx.stack_.back()->set("severity", sev); +severity: SEVERITY { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr sev(new StringElement($4)); + ctx.stack_.back()->set("severity", sev); + ctx.leave(); }; -output_options_list: OUTPUT_OPTIONS COLON { +output_options_list: OUTPUT_OPTIONS { ElementPtr l(new ListElement()); ctx.stack_.back()->set("output_options", l); ctx.stack_.push_back(l); -} LSQUARE_BRACKET output_options_list_content RSQUARE_BRACKET { + 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 -| output_options_list_content COMMA output_entry; + | output_options_list_content COMMA output_entry + ; output_entry: LCURLY_BRACKET { ElementPtr m(new MapElement()); @@ -935,36 +1103,46 @@ output_entry: LCURLY_BRACKET { }; output_params: output_param -| output_params COMMA output_param; + | output_params COMMA output_param + ; -output_param: OUTPUT COLON STRING { - ElementPtr sev(new StringElement($3)); ctx.stack_.back()->set("output", sev); +output_param: OUTPUT { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr sev(new StringElement($4)); + ctx.stack_.back()->set("output", sev); + ctx.leave(); }; -dhcp_ddns: DHCP_DDNS COLON LCURLY_BRACKET { +dhcp_ddns: DHCP_DDNS { ElementPtr m(new MapElement()); ctx.stack_.back()->set("dhcp-ddns", m); ctx.stack_.push_back(m); -} dhcp_ddns_params RCURLY_BRACKET { + ctx.enter(ctx.DHCP_DDNS); +} COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET { ctx.stack_.pop_back(); + ctx.leave(); }; dhcp_ddns_params: dhcp_ddns_param -| dhcp_ddns_params COMMA dhcp_ddns_param -; + | dhcp_ddns_params COMMA dhcp_ddns_param + ; dhcp_ddns_param: enable_updates -| qualifying_suffix -; + | qualifying_suffix + ; enable_updates: ENABLE_UPDATES COLON BOOLEAN { ElementPtr b(new BoolElement($3)); ctx.stack_.back()->set("enable-updates", b); }; -qualifying_suffix: QUALIFYING_SUFFIX COLON STRING { - ElementPtr qs(new StringElement($3)); +qualifying_suffix: QUALIFYING_SUFFIX { + ctx.enter(ctx.NO_KEYWORD); +} COLON STRING { + ElementPtr qs(new StringElement($4)); ctx.stack_.back()->set("qualifying-suffix", qs); + ctx.leave(); }; %% diff --git a/src/bin/dhcp6/parser_context.cc b/src/bin/dhcp6/parser_context.cc index 1c77efc980..96666f516b 100644 --- a/src/bin/dhcp6/parser_context.cc +++ b/src/bin/dhcp6/parser_context.cc @@ -89,5 +89,24 @@ Parser6Context::fatal (const std::string& what) isc_throw(Unexpected, what); } +void +Parser6Context::enter(const ParserContext& ctx) +{ + cstack_.push_back(ctx_); + ctx_ = ctx; +} + +void +Parser6Context::leave() +{ +#if 1 + if (cstack_.empty()) { + fatal("unbalanced syntactic context"); + } +#endif + ctx_ = cstack_.back(); + cstack_.pop_back(); +} + }; }; diff --git a/src/bin/dhcp6/parser_context.h b/src/bin/dhcp6/parser_context.h index ed895cd69e..22bc6b3161 100644 --- a/src/bin/dhcp6/parser_context.h +++ b/src/bin/dhcp6/parser_context.h @@ -37,8 +37,8 @@ public: /// @brief Defines currently support the content supported typedef enum { - PARSER_DHCP6, // This will parse the content as DHCP6 config - PARSER_GENERIC_JSON // This will parse the content as generic JSON + PARSER_GENERIC_JSON, // This will parse the content as generic JSON + PARSER_DHCP6 // This will parse the content as DHCP6 config } ParserType; /// @brief Default constructor. @@ -95,12 +95,58 @@ public: /// Used by YY_FATAL_ERROR macro so required to be static. static void fatal(const std::string& what); + /// @brief Defines syntactic contexts for lexical tie-ins + typedef enum { + /// at toplevel + NO_KEYWORD, + CONFIG, + /// in config + DHCP6, + // not yet DHCP4, + // not yet DHCP_DDNS, + LOGGING, + /// Dhcp6 + INTERFACES_CONFIG, + DATABASE, + MAC_SOURCES, + HOST_RESERVATION_IDENTIFIERS, + HOOKS_LIBRARIES, + SUBNET6, + OPTION_DATA, + CLIENT_CLASSES, + SERVER_ID, + DHCP_DDNS, + /// subnet6 + POOLS, + PD_POOLS, + RESERVATIONS, + /// client-classes + CLIENT_CLASS, + /// Logging + LOGGERS, + /// loggers + OUTPUT_OPTIONS + } ParserContext; + + /// @brief Current syntactic context + ParserContext ctx_; + + /// @brief Enter a new syntactic context + void enter(const ParserContext& ctx); + + /// @brief Leave a syntactic context + /// @throw isc::Unexpected if unbalanced + void leave(); + private: /// @brief Flag determining scanner debugging. bool trace_scanning_; /// @brief Flag determing parser debugging. bool trace_parsing_; + + /// @brief Syntactic context stack + std::vector cstack_; }; }; // end of isc::eval namespace