1 // Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef PARSER_CONTEXT_H 8 #define PARSER_CONTEXT_H 9 #include <string> 10 #include <map> 11 #include <vector> 12 #include <dhcp6/dhcp6_parser.h> 13 #include <dhcp6/parser_context_decl.h> 14 #include <exceptions/exceptions.h> 15 16 // Tell Flex the lexer's prototype ... 17 #define YY_DECL isc::dhcp::Dhcp6Parser::symbol_type parser6_lex (Parser6Context& driver) 18 19 // ... and declare it for the parser's sake. 20 YY_DECL; 21 22 namespace isc { 23 namespace dhcp { 24 25 /// @brief Evaluation error exception raised when trying to parse. 26 /// 27 /// @todo: This probably should be common for Dhcp4 and Dhcp6. 28 class Dhcp6ParseError : public isc::Exception { 29 public: Dhcp6ParseError(const char * file,size_t line,const char * what)30 Dhcp6ParseError(const char* file, size_t line, const char* what) : 31 isc::Exception(file, line, what) { }; 32 }; 33 34 /// @brief Evaluation context, an interface to the expression evaluation. 35 class Parser6Context 36 { 37 public: 38 39 /// @brief Defines currently supported scopes 40 /// 41 /// Dhcp6Parser is able to parse several types of scope. Usually, 42 /// when it parses a config file, it expects the data to have a map 43 /// with Dhcp6 in it and all the parameters within that Dhcp6 map. 44 /// However, sometimes the parser is expected to parse only a subset 45 /// of that information. For example, it may be asked to parse 46 /// a structure that is host-reservation only, without the global 47 /// 'Dhcp6' or 'reservations' around it. In such case the parser 48 /// is being told to start parsing as PARSER_HOST_RESERVATION6. 49 typedef enum { 50 /// This parser will parse the content as generic JSON. 51 PARSER_JSON, 52 53 /// This parser will parse the content as Dhcp6 config wrapped in a map 54 /// (that's the regular config file) 55 PARSER_DHCP6, 56 57 /// This parser will parse the content of Dhcp6 (without outer { } and 58 /// without "Dhcp6"). It is mostly used in unit-tests as most of the 59 /// unit-tests do not define the outer map and Dhcp6 entity, just the 60 /// contents of it. 61 SUBPARSER_DHCP6, 62 63 /// This will parse the input as interfaces content. 64 PARSER_INTERFACES, 65 66 /// This will parse the input as Subnet6 content. 67 PARSER_SUBNET6, 68 69 /// This will parse the input as pool6 content. 70 PARSER_POOL6, 71 72 /// This will parse the input as pd-pool content. 73 PARSER_PD_POOL, 74 75 /// This will parse the input as host-reservation. 76 PARSER_HOST_RESERVATION, 77 78 /// This will parse the input option definitions (for tests). 79 PARSER_OPTION_DEFS, 80 81 /// This will parse the input as option definition. 82 PARSER_OPTION_DEF, 83 84 /// This will parse the input as option data. 85 PARSER_OPTION_DATA, 86 87 /// This will parse the input as hooks-library. 88 PARSER_HOOKS_LIBRARY, 89 90 /// This will parse the input as dhcp-ddns. (D2 client config) 91 PARSER_DHCP_DDNS, 92 93 /// This will parse the input as config-control. 94 PARSER_CONFIG_CONTROL, 95 } ParserType; 96 97 /// @brief Default constructor. 98 Parser6Context(); 99 100 /// @brief destructor 101 virtual ~Parser6Context(); 102 103 /// @brief JSON elements being parsed. 104 std::vector<isc::data::ElementPtr> stack_; 105 106 /// @brief Method called before scanning starts on a string. 107 /// 108 /// @param str string to be parsed 109 /// @param type specifies expected content 110 void scanStringBegin(const std::string& str, ParserType type); 111 112 /// @brief Method called before scanning starts on a file. 113 /// 114 /// @param f stdio FILE pointer 115 /// @param filename file to be parsed 116 /// @param type specifies expected content 117 void scanFileBegin(FILE* f, const std::string& filename, ParserType type); 118 119 /// @brief Method called after the last tokens are scanned. 120 void scanEnd(); 121 122 /// @brief Divert input to an include file. 123 /// 124 /// @param filename file to be included 125 void includeFile(const std::string& filename); 126 127 /// @brief Run the parser on the string specified. 128 /// 129 /// This method parses specified string. Depending on the value of 130 /// parser_type, parser may either check only that the input is valid 131 /// JSON, or may do more specific syntax checking. See @ref ParserType 132 /// for supported syntax checkers. 133 /// 134 /// @param str string to be parsed 135 /// @param parser_type specifies expected content (usually DHCP6 or generic JSON) 136 /// @return Element structure representing parsed text. 137 isc::data::ElementPtr parseString(const std::string& str, 138 ParserType parser_type); 139 140 /// @brief Run the parser on the file specified. 141 /// 142 /// This method parses specified file. Depending on the value of 143 /// parser_type, parser may either check only that the input is valid 144 /// JSON, or may do more specific syntax checking. See @ref ParserType 145 /// for supported syntax checkers. 146 /// 147 /// @param filename file to be parsed 148 /// @param parser_type specifies expected content (usually DHCP6 or generic JSON) 149 /// @return Element structure representing parsed text. 150 isc::data::ElementPtr parseFile(const std::string& filename, 151 ParserType parser_type); 152 153 /// @brief Error handler 154 /// 155 /// @note The optional position for an error in a string begins by 1 156 /// so the caller should add 1 to the position of the C++ string. 157 /// 158 /// @param loc location within the parsed file when experienced a problem. 159 /// @param what string explaining the nature of the error. 160 /// @param pos optional position for in string errors. 161 /// @throw Dhcp6ParseError 162 void error(const isc::dhcp::location& loc, 163 const std::string& what, 164 size_t pos = 0); 165 166 /// @brief Error handler 167 /// 168 /// This is a simplified error reporting tool for possible future 169 /// cases when the Dhcp6Parser is not able to handle the packet. 170 /// 171 /// @param what string explaining the nature of the error. 172 /// @throw Dhcp6ParseError 173 void error(const std::string& what); 174 175 /// @brief Fatal error handler 176 /// 177 /// This is for should not happen but fatal errors. 178 /// Used by YY_FATAL_ERROR macro so required to be static. 179 /// 180 /// @param what string explaining the nature of the error. 181 /// @throw Dhcp6ParseError 182 static void fatal(const std::string& what); 183 184 /// @brief Converts bison's position to one understandable by isc::data::Element 185 /// 186 /// Convert a bison location into an element position 187 /// (take the begin, the end is lost) 188 /// 189 /// @param loc location in bison format 190 /// @return Position in format accepted by Element 191 isc::data::Element::Position loc2pos(isc::dhcp::location& loc); 192 193 /// @brief Check if a required parameter is present 194 /// 195 /// Check if a required parameter is present in the map at the top 196 /// of the stack and raise an error when it is not. 197 /// 198 /// @param name name of the parameter expected to be present 199 /// @param open_loc location of the opening curly bracket 200 /// @param close_loc location of the closing curly bracket 201 /// @throw Dhcp6ParseError 202 void require(const std::string& name, 203 isc::data::Element::Position open_loc, 204 isc::data::Element::Position close_loc); 205 206 /// @brief Check if a parameter is already present 207 /// 208 /// Check if a parameter is already present in the map at the top 209 /// of the stack and raise an error when it is. 210 /// 211 /// @param name name of the parameter to check 212 /// @param loc location of the current parameter 213 /// @throw Dhcp6ParseError 214 void unique(const std::string& name, 215 isc::data::Element::Position loc); 216 217 /// @brief Defines syntactic contexts for lexical tie-ins 218 typedef enum { 219 ///< This one is used in pure JSON mode. 220 NO_KEYWORD, 221 222 ///< Used while parsing top level (that contains Dhcp6) 223 CONFIG, 224 225 ///< Used while parsing content of Dhcp6. 226 DHCP6, 227 228 /// Used while parsing Dhcp6/interfaces structures. 229 INTERFACES_CONFIG, 230 231 /// Sanity checks. 232 SANITY_CHECKS, 233 234 /// Used while parsing Dhcp6/lease-database structures. 235 LEASE_DATABASE, 236 237 /// Used while parsing Dhcp6/hosts-database[s] structures. 238 HOSTS_DATABASE, 239 240 /// Used while parsing Dhcp6/*-database/type. 241 DATABASE_TYPE, 242 243 /// Used while parsing Dhcp6/*-database/on-fail. 244 DATABASE_ON_FAIL, 245 246 /// Used while parsing Dhcp6/mac-sources structures. 247 MAC_SOURCES, 248 249 /// Used while parsing Dhcp6/host-reservation-identifiers. 250 HOST_RESERVATION_IDENTIFIERS, 251 252 /// Used while parsing Dhcp6/hooks-libraries. 253 HOOKS_LIBRARIES, 254 255 /// Used while parsing Dhcp6/Subnet6 structures. 256 SUBNET6, 257 258 /// Used while parsing shared-networks structures. 259 SHARED_NETWORK, 260 261 /// Used while parsing Dhcp6/reservation-mode. 262 RESERVATION_MODE, 263 264 /// Used while parsing Dhcp6/option-def structures. 265 OPTION_DEF, 266 267 /// Used while parsing Dhcp6/option-data, Dhcp6/subnet6/option-data 268 /// or anywhere option-data is present (client classes, host 269 /// reservations and possibly others). 270 OPTION_DATA, 271 272 /// Used while parsing Dhcp6/client-classes structures. 273 CLIENT_CLASSES, 274 275 /// Used while parsing Dhcp6/expired-leases-processing. 276 EXPIRED_LEASES_PROCESSING, 277 278 /// Used while parsing Dhcp6/server-id structures. 279 SERVER_ID, 280 281 /// Used while parsing Dhcp6/server-id/type structures. 282 DUID_TYPE, 283 284 /// Used while parsing Dhcp6/control-socket structures. 285 CONTROL_SOCKET, 286 287 /// Used while parsing Dhcp6/dhcp-queue-control structures. 288 DHCP_QUEUE_CONTROL, 289 290 /// Used while parsing Dhcp6/multi-threading structures. 291 DHCP_MULTI_THREADING, 292 293 /// Used while parsing Dhcp6/subnet6/pools structures. 294 POOLS, 295 296 /// Used while parsing Dhcp6/subnet6/pd-pools structures. 297 PD_POOLS, 298 299 /// Used while parsing Dhcp6/reservations structures. 300 RESERVATIONS, 301 302 /// Used while parsing Dhcp6/subnet6/relay structures. 303 RELAY, 304 305 /// Used while parsing Dhcp6/loggers structures. 306 LOGGERS, 307 308 /// Used while parsing Dhcp6/loggers/output_options structures. 309 OUTPUT_OPTIONS, 310 311 /// Used while parsing Dhcp6/dhcp-ddns. 312 DHCP_DDNS, 313 314 /// Used while parsing Dhcp6/dhcp-ddns/ncr-protocol 315 NCR_PROTOCOL, 316 317 /// Used while parsing Dhcp6/dhcp-ddns/ncr-format 318 NCR_FORMAT, 319 320 /// Used while parsing Dhcp6/dhcp-ddns/replace-client-name. 321 REPLACE_CLIENT_NAME, 322 323 /// Used while parsing Dhcp6/config-control 324 CONFIG_CONTROL, 325 326 /// Used while parsing config-control/config-databases 327 CONFIG_DATABASE, 328 329 /// Used while parsing compatibility parameters 330 COMPATIBILITY, 331 332 } ParserContext; 333 334 /// @brief File name 335 std::string file_; 336 337 /// @brief File name stack 338 std::vector<std::string> files_; 339 340 /// @brief Location of the current token 341 /// 342 /// The lexer will keep updating it. This variable will be useful 343 /// for logging errors. 344 isc::dhcp::location loc_; 345 346 /// @brief Location stack 347 std::vector<isc::dhcp::location> locs_; 348 349 /// @brief Lexer state stack 350 std::vector<struct yy_buffer_state*> states_; 351 352 /// @brief sFile (aka FILE) 353 FILE* sfile_; 354 355 /// @brief sFile (aka FILE) stack 356 /// 357 /// This is a stack of files. Typically there's only one file (the 358 /// one being currently parsed), but there may be more if one 359 /// file includes another. 360 std::vector<FILE*> sfiles_; 361 362 /// @brief Current syntactic context 363 ParserContext ctx_; 364 365 /// @brief Enter a new syntactic context 366 /// 367 /// Entering a new syntactic context is useful in several ways. 368 /// First, it allows the parser to avoid conflicts. Second, it 369 /// allows the lexer to return different tokens depending on 370 /// context (e.g. if "renew-timer" string is detected, the lexer 371 /// will return STRING token if in JSON mode or RENEW_TIMER if 372 /// in DHCP6 mode. Finally, the syntactic context allows the 373 /// error message to be more descriptive if the input string 374 /// does not parse properly. 375 /// 376 /// @param ctx the syntactic context to enter into 377 void enter(const ParserContext& ctx); 378 379 /// @brief Leave a syntactic context 380 /// 381 /// @throw isc::Unexpected if unbalanced 382 void leave(); 383 384 /// @brief Get the syntactic context name 385 /// 386 /// @return printable name of the context. 387 const std::string contextName(); 388 389 private: 390 /// @brief Flag determining scanner debugging. 391 bool trace_scanning_; 392 393 /// @brief Flag determining parser debugging. 394 bool trace_parsing_; 395 396 /// @brief Syntactic context stack 397 std::vector<ParserContext> cstack_; 398 399 /// @brief Common part of parseXXX 400 /// 401 /// @return Element structure representing parsed text. 402 isc::data::ElementPtr parseCommon(); 403 }; 404 405 }; // end of isc::eval namespace 406 }; // end of isc namespace 407 408 #endif 409