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