1 // Copyright (C) 2017-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 <d2/d2_parser.h> 13 #include <d2/parser_context_decl.h> 14 #include <exceptions/exceptions.h> 15 16 // Tell Flex the lexer's prototype ... 17 #define YY_DECL isc::d2::D2Parser::symbol_type d2_parser_lex (D2ParserContext& driver) 18 19 // ... and declare it for the parser's sake. 20 YY_DECL; 21 22 namespace isc { 23 namespace d2 { 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 D2ParseError : public isc::Exception { 29 public: D2ParseError(const char * file,size_t line,const char * what)30 D2ParseError(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 D2ParserContext 36 { 37 public: 38 39 /// @brief Defines currently supported scopes 40 /// 41 /// D2Parser may eventually support multiple levels of parsing scope. 42 /// Currently it supports only the D2 module scope which expects the data 43 /// to be parsed to be a map containing the DhcpDdns element and its 44 /// constituents. 45 /// 46 typedef enum { 47 /// This parser will parse the content as generic JSON. 48 PARSER_JSON, 49 50 ///< Used for parsing top level (contains DhcpDdns) 51 PARSER_DHCPDDNS, 52 53 ///< Used for parsing content of DhcpDdns. 54 PARSER_SUB_DHCPDDNS, 55 56 ///< Used for parsing content of a TSIG key. 57 PARSER_TSIG_KEY, 58 59 ///< Used for parsing a list of TSIG Keys. 60 PARSER_TSIG_KEYS, 61 62 ///< Used for parsing content of a DDNS Domain. 63 PARSER_DDNS_DOMAIN, 64 65 ///< Used for parsing a list a DDNS Domains. 66 PARSER_DDNS_DOMAINS, 67 68 ///< Used for parsing content of a DNS Server. 69 PARSER_DNS_SERVER, 70 71 ///< Used for parsing a list of DNS servers. 72 PARSER_DNS_SERVERS, 73 74 ///< Used for parsing content of hooks libraries. 75 PARSER_HOOKS_LIBRARY 76 } ParserType; 77 78 /// @brief Default constructor. 79 D2ParserContext(); 80 81 /// @brief destructor. 82 virtual ~D2ParserContext(); 83 84 /// @brief JSON elements being parsed. 85 std::vector<isc::data::ElementPtr> stack_; 86 87 /// @brief Method called before scanning starts on a string. 88 /// 89 /// @param str string to be parsed 90 /// @param type specifies expected content 91 void scanStringBegin(const std::string& str, ParserType type); 92 93 /// @brief Method called before scanning starts on a file. 94 /// 95 /// @param f stdio FILE pointer 96 /// @param filename file to be parsed 97 /// @param type specifies expected content 98 void scanFileBegin(FILE* f, const std::string& filename, ParserType type); 99 100 /// @brief Method called after the last tokens are scanned. 101 void scanEnd(); 102 103 /// @brief Divert input to an include file. 104 /// 105 /// @param filename file to be included 106 void includeFile(const std::string& filename); 107 108 /// @brief Run the parser on the string specified. 109 /// 110 /// This method parses specified string. Depending on the value of 111 /// parser_type, parser may either check only that the input is valid 112 /// JSON, or may do more specific syntax checking. See @ref ParserType 113 /// for supported syntax checkers. 114 /// 115 /// @param str string to be parsed 116 /// @param parser_type specifies expected content 117 /// @return Element structure representing parsed text. 118 isc::data::ElementPtr parseString(const std::string& str, 119 ParserType parser_type); 120 121 /// @brief Run the parser on the file specified. 122 /// 123 /// This method parses specified file. Depending on the value of 124 /// parser_type, parser may either check only that the input is valid 125 /// JSON, or may do more specific syntax checking. See @ref ParserType 126 /// for supported syntax checkers. 127 /// 128 /// @param filename file to be parsed 129 /// @param parser_type specifies expected content 130 /// @return Element structure representing parsed text. 131 isc::data::ElementPtr parseFile(const std::string& filename, 132 ParserType parser_type); 133 134 /// @brief Error handler 135 /// 136 /// @note The optional position for an error in a string begins by 1 137 /// so the caller should add 1 to the position of the C++ string. 138 /// 139 /// @param loc location within the parsed file when experienced a problem. 140 /// @param what string explaining the nature of the error. 141 /// @param pos optional position for in string errors. 142 /// @throw D2ParseError 143 void error(const isc::d2::location& loc, 144 const std::string& what, 145 size_t pos = 0); 146 147 /// @brief Error handler 148 /// 149 /// This is a simplified error reporting tool for reporting 150 /// parsing errors. 151 /// 152 /// @param what string explaining the nature of the error. 153 /// @throw D2ParseError 154 void error(const std::string& what); 155 156 /// @brief Fatal error handler 157 /// 158 /// This is for should not happen but fatal errors. 159 /// Used by YY_FATAL_ERROR macro so required to be static. 160 /// 161 /// @param what string explaining the nature of the error. 162 /// @throw D2ParseError 163 static void fatal(const std::string& what); 164 165 /// @brief Converts bison's position to one understood by isc::data::Element 166 /// 167 /// Convert a bison location into an element position 168 /// (take the begin, the end is lost) 169 /// 170 /// @param loc location in bison format 171 /// @return Position in format accepted by Element 172 isc::data::Element::Position loc2pos(isc::d2::location& loc); 173 174 /// @brief Check if a required parameter is present 175 /// 176 /// Check if a required parameter is present in the map at the top 177 /// of the stack and raise an error when it is not. 178 /// 179 /// @param name name of the parameter to check 180 /// @param open_loc location of the opening curly bracket 181 /// @param close_loc location of the closing curly bracket 182 /// @throw D2ParseError 183 void require(const std::string& name, 184 isc::data::Element::Position open_loc, 185 isc::data::Element::Position close_loc); 186 187 /// @brief Check if a parameter is already present 188 /// 189 /// Check if a parameter is already present in the map at the top 190 /// of the stack and raise an error when it is. 191 /// 192 /// @param name name of the parameter to check 193 /// @param loc location of the current parameter 194 /// @throw D2ParseError 195 void unique(const std::string& name, 196 isc::data::Element::Position loc); 197 198 /// @brief Defines syntactic contexts for lexical tie-ins 199 typedef enum { 200 ///< This one is used in pure JSON mode. 201 NO_KEYWORD, 202 203 ///< Used while parsing top level (contains DhcpDdns). 204 CONFIG, 205 206 ///< Used while parsing content of DhcpDdns. 207 DHCPDDNS, 208 209 ///< Used while parsing content of a tsig-key 210 TSIG_KEY, 211 212 ///< Used while parsing a list of tsig-keys 213 TSIG_KEYS, 214 215 ///< Used while parsing content of DhcpDdns/tsig-keys/algorithm 216 ALGORITHM, 217 218 ///< Used while parsing content of DhcpDdns/tsig-keys/digest-bits 219 DIGEST_BITS, 220 221 ///< Used while parsing content of DhcpDdns/tsig-keys/secret 222 SECRET, 223 224 ///< Used while parsing content of DhcpDdns/forward-ddns 225 FORWARD_DDNS, 226 227 ///< Used while parsing content of DhcpDdns/reverse-ddns 228 REVERSE_DDNS, 229 230 ///< Used while parsing content of a ddns-domain 231 DDNS_DOMAIN, 232 233 ///< Used while parsing a list of ddns-domains 234 DDNS_DOMAINS, 235 236 ///< Used while parsing content of a dns-server 237 DNS_SERVER, 238 239 ///< Used while parsing content of list of dns-servers 240 DNS_SERVERS, 241 242 ///< Used while parsing content of a control-socket 243 CONTROL_SOCKET, 244 245 /// Used while parsing DhcpDdns/loggers structures. 246 LOGGERS, 247 248 /// Used while parsing DhcpDdns/loggers/output_options structures. 249 OUTPUT_OPTIONS, 250 251 /// Used while parsing DhcpDdns/ncr-protocol 252 NCR_PROTOCOL, 253 254 /// Used while parsing DhcpDdns/ncr-format 255 NCR_FORMAT, 256 257 /// Used while parsing DhcpDdns/hooks-libraries. 258 HOOKS_LIBRARIES 259 260 } ParserContext; 261 262 /// @brief File name 263 std::string file_; 264 265 /// @brief File name stack 266 std::vector<std::string> files_; 267 268 /// @brief Location of the current token 269 /// 270 /// The lexer will keep updating it. This variable will be useful 271 /// for logging errors. 272 isc::d2::location loc_; 273 274 /// @brief Location stack 275 std::vector<isc::d2::location> locs_; 276 277 /// @brief Lexer state stack 278 std::vector<struct yy_buffer_state*> states_; 279 280 /// @brief sFile (aka FILE) 281 FILE* sfile_; 282 283 /// @brief sFile (aka FILE) stack 284 /// 285 /// This is a stack of files. Typically there's only one file (the 286 /// one being currently parsed), but there may be more if one 287 /// file includes another. 288 std::vector<FILE*> sfiles_; 289 290 /// @brief Current syntactic context 291 ParserContext ctx_; 292 293 /// @brief Enter a new syntactic context 294 /// 295 /// Entering a new syntactic context is useful in several ways. 296 /// First, it allows the parser to avoid conflicts. Second, it 297 /// allows the lexer to return different tokens depending on 298 /// context (e.g. if "name" string is detected, the lexer 299 /// will return STRING token if in JSON mode or NAME if 300 /// in TSIG_KEY mode. Finally, the syntactic context allows the 301 /// error message to be more descriptive if the input string 302 /// does not parse properly. 303 /// 304 /// @param ctx the syntactic context to enter into 305 void enter(const ParserContext& ctx); 306 307 /// @brief Leave a syntactic context 308 /// 309 /// @throw isc::Unexpected if unbalanced 310 void leave(); 311 312 /// @brief Get the syntax context name 313 /// 314 /// @return printable name of the context. 315 const std::string contextName(); 316 317 private: 318 /// @brief Flag determining scanner debugging. 319 bool trace_scanning_; 320 321 /// @brief Flag determining parser debugging. 322 bool trace_parsing_; 323 324 /// @brief Syntactic context stack 325 std::vector<ParserContext> cstack_; 326 327 /// @brief Common part of parseXXX 328 /// 329 /// @return Element structure representing parsed text. 330 isc::data::ElementPtr parseCommon(); 331 }; 332 333 } // end of isc::eval namespace 334 } // end of isc namespace 335 336 #endif 337