parser_context.h 10.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef PARSER_CONTEXT_H
#define PARSER_CONTEXT_H
#include <string>
#include <map>
#include <vector>
#include <dhcp6/dhcp6_parser.h>
#include <dhcp6/parser_context_decl.h>
#include <exceptions/exceptions.h>

// Tell Flex the lexer's prototype ...
17
#define YY_DECL isc::dhcp::Dhcp6Parser::symbol_type parser6_lex (Parser6Context& driver)
18 19 20 21 22 23 24

// ... and declare it for the parser's sake.
YY_DECL;

namespace isc {
namespace dhcp {

25
/// @brief Evaluation error exception raised when trying to parse.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
26 27
///
/// @todo: This probably should be common for Dhcp4 and Dhcp6.
28
class Dhcp6ParseError : public isc::Exception {
29
public:
30
    Dhcp6ParseError(const char* file, size_t line, const char* what) :
31 32 33 34 35 36 37 38
        isc::Exception(file, line, what) { };
};


/// @brief Evaluation context, an interface to the expression evaluation.
class Parser6Context
{
public:
39

Tomek Mrugalski's avatar
Tomek Mrugalski committed
40 41
    /// @brief Defines currently supported scopes
    ///
42 43 44 45 46 47 48 49
    /// Dhcp6Parser is able to parse several types of scope. Usually,
    /// when it parses a config file, it expects the data to have a map
    /// with Dhcp6 in it and all the parameters within that Dhcp6 map.
    /// However, sometimes the parser is expected to parse only a subset
    /// of that information. For example, it may be asked to parse
    /// a structure that is host-reservation only, without the global
    /// 'Dhcp6' or 'reservations' around it. In such case the parser
    /// is being told to start parsing as PARSER_HOST_RESERVATION6.
50
    typedef enum {
Tomek Mrugalski's avatar
Tomek Mrugalski committed
51
        /// This parser will parse the content as generic JSON.
52
        PARSER_JSON,
Tomek Mrugalski's avatar
Tomek Mrugalski committed
53

54 55
        /// This parser will parse the content as Dhcp6 config wrapped in a map
        /// (that's the regular config file)
Tomek Mrugalski's avatar
Tomek Mrugalski committed
56 57
        PARSER_DHCP6,

58 59 60 61
        /// This parser will parse the content of Dhcp6 (without outer { } and
        /// without "Dhcp6"). It is mostly used in unit-tests as most of the
        /// unit-tests do not define the outer map and Dhcp6 entity, just the
        /// contents of it.
62
        SUBPARSER_DHCP6,
Tomek Mrugalski's avatar
Tomek Mrugalski committed
63

64 65 66
        /// This will parse the input as interfaces content.
        PARSER_INTERFACES,

67
        /// This will parse the input as Subnet6 content.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
68 69
        PARSER_SUBNET6,

70
        /// This will parse the input as pool6 content.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
71 72
        PARSER_POOL6,

73
        /// This will parse the input as pd-pool content.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
74 75
        PARSER_PD_POOL,

76
        /// This will parse the input as host-reservation.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
77 78
        PARSER_HOST_RESERVATION,

79
        /// This will parse the input as option definition.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
80 81
        PARSER_OPTION_DEF,

82
        /// This will parse the input as option data.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
83 84
        PARSER_OPTION_DATA,

85
        /// This will parse the input as hooks-library.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
86
        PARSER_HOOKS_LIBRARY
87
    } ParserType;
88

89 90 91 92 93 94 95
    /// @brief Default constructor.
    Parser6Context();

    /// @brief destructor
    virtual ~Parser6Context();

    /// @brief JSON elements being parsed.
96
    std::vector<isc::data::ElementPtr> stack_;
97 98

    /// @brief Method called before scanning starts on a string.
99 100 101
    ///
    /// @param str string to be parsed
    /// @param parser_type specifies expected content
102
    void scanStringBegin(const std::string& str, ParserType type);
103

104
    /// @brief Method called before scanning starts on a file.
105 106 107 108 109
    ///
    /// @param f stdio FILE pointer
    /// @param filename file to be parsed
    /// @param parser_type specifies expected content
    void scanFileBegin(FILE* f, const std::string& filename, ParserType type);
110

111 112
    /// @brief Method called after the last tokens are scanned.
    void scanEnd();
113

Francis Dupont's avatar
Francis Dupont committed
114
    /// @brief Divert input to an include file.
115 116
    ///
    /// @param filename file to be included
117
    void includeFile(const std::string& filename);
Francis Dupont's avatar
Francis Dupont committed
118

119 120
    /// @brief Run the parser on the string specified.
    ///
121 122 123 124 125
    /// This method parses specified string. Depending on the value of
    /// parser_type, parser may either check only that the input is valid
    /// JSON, or may do more specific syntax checking. See @ref ParserType
    /// for supported syntax checkers.
    ///
126
    /// @param str string to be parsed
127 128
    /// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
    /// @return Element structure representing parsed text.
129 130
    isc::data::ConstElementPtr parseString(const std::string& str,
                                           ParserType parser_type);
131

132
    /// @brief Run the parser on the file specified.
133 134 135 136 137 138 139 140 141
    ///
    /// This method parses specified file. Depending on the value of
    /// parser_type, parser may either check only that the input is valid
    /// JSON, or may do more specific syntax checking. See @ref ParserType
    /// for supported syntax checkers.
    ///
    /// @param filename file to be parsed
    /// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
    /// @return Element structure representing parsed text.
142 143
    isc::data::ConstElementPtr parseFile(const std::string& filename,
                                         ParserType parser_type);
144

145 146 147 148
    /// @brief Error handler
    ///
    /// @param loc location within the parsed file when experienced a problem.
    /// @param what string explaining the nature of the error.
149
    /// @throw Dhcp6ParseError
150
    void error(const isc::dhcp::location& loc, const std::string& what);
151 152 153 154

    /// @brief Error handler
    ///
    /// This is a simplified error reporting tool for possible future
155
    /// cases when the Dhcp6Parser is not able to handle the packet.
156 157 158
    ///
    /// @param what string explaining the nature of the error.
    /// @throw Dhcp6ParseError
159
    void error(const std::string& what);
160 161 162

    /// @brief Fatal error handler
    ///
163 164
    /// This is for should not happen but fatal errors.
    /// Used by YY_FATAL_ERROR macro so required to be static.
165 166 167
    ///
    /// @param what string explaining the nature of the error.
    /// @throw Dhcp6ParseError
168 169
    static void fatal(const std::string& what);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
170
    /// @brief Converts bison's position to one understandable by isc::data::Element
171 172 173
    ///
    /// Convert a bison location into an element position
    /// (take the begin, the end is lost)
174 175
    ///
    /// @param loc location in bison format
176
    /// @return Position in format accepted by Element
177 178
    isc::data::Element::Position loc2pos(isc::dhcp::location& loc);

179 180
    /// @brief Defines syntactic contexts for lexical tie-ins
    typedef enum {
181
        ///< This one is used in pure JSON mode.
182
        NO_KEYWORD,
183 184

        ///< Used while parsing top level (that contains Dhcp6, Logging and others)
185
        CONFIG,
186 187

        ///< Used while parsing content of Dhcp6.
188
        DHCP6,
189

190 191
        // not yet DHCP4,
        // not yet DHCP_DDNS,
192 193

        ///< Used while parsing content of Logging
194
        LOGGING,
195 196

        /// Used while parsing Dhcp6/interfaces structures.
197
        INTERFACES_CONFIG,
198 199 200 201

        /// Used while parsing Dhcp6/lease-database structures.
        LEASE_DATABASE,

202 203 204
        /// Used while parsing Dhcp6/hosts-database structures.
        HOSTS_DATABASE,

205
        /// Used while parsing Dhcp6/mac-sources structures.
206
        MAC_SOURCES,
207 208

        /// Used while parsing Dhcp6/host-reservation-identifiers.
209
        HOST_RESERVATION_IDENTIFIERS,
210 211

        /// Used while parsing Dhcp6/hooks-libraries.
212
        HOOKS_LIBRARIES,
213 214

        /// Used while parsing Dhcp6/Subnet6 structures.
215
        SUBNET6,
216 217

        /// Used while parsing Dhcp6/option-def structures.
218
        OPTION_DEF,
219 220 221 222

        /// Used while parsing Dhcp6/option-data, Dhcp6/subnet6/option-data
        /// or anywhere option-data is present (client classes, host
        /// reservations and possibly others).
223
        OPTION_DATA,
224 225

        /// Used while parsing Dhcp6/client-classes structures.
226
        CLIENT_CLASSES,
227 228

        /// Used while parsing Dhcp6/server-id structures.
229
        SERVER_ID,
230 231

        /// Used while parsing Dhcp6/control-socket structures.
232
        CONTROL_SOCKET,
233 234

        /// Used while parsing Dhcp6/subnet6/pools structures.
235
        POOLS,
236 237

        /// Used while parsing Dhcp6/subnet6/pd-pools structures.
238
        PD_POOLS,
239 240

        /// Used while parsing Dhcp6/reservations structures.
241
        RESERVATIONS,
242 243

        /// Used while parsing Dhcp6/subnet6/relay structures.
244
        RELAY,
245 246

        /// Used while parsing Dhcp6/client-classes structures.
247
        CLIENT_CLASS,
248 249

        /// Used while parsing Logging/loggers structures.
250
        LOGGERS,
251 252

        /// Used while parsing Logging/loggers/output_options structures.
253
        OUTPUT_OPTIONS
254
    } ParserContext;
255

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    /// @brief File name
    std::string file_;

    /// @brief File name stack
    std::vector<std::string> files_;

    /// @brief Location of the current token
    ///
    /// The lexer will keep updating it. This variable will be useful
    /// for logging errors.
    isc::dhcp::location loc_;

    /// @brief Location stack
    std::vector<isc::dhcp::location> locs_;

271
    /// @brief Lexer state stack
Tomek Mrugalski's avatar
Tomek Mrugalski committed
272
    std::vector<struct yy_buffer_state*> states_;
273

274 275 276 277
    /// @brief sFile (aka FILE)
    FILE* sfile_;

    /// @brief sFile (aka FILE) stack
278 279 280 281
    ///
    /// This is a stack of files. Typically there's only one file (the
    /// one being currently parsed), but there may be more if one
    /// file includes another.
282 283
    std::vector<FILE*> sfiles_;

284 285 286 287
    /// @brief Current syntactic context
    ParserContext ctx_;

    /// @brief Enter a new syntactic context
288
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
289
    /// Entering a new syntactic context is useful in several ways.
290 291 292 293
    /// First, it allows the parser to avoid conflicts. Second, it
    /// allows the lexer to return different tokens depending on
    /// context (e.g. if "renew-timer" string is detected, the lexer
    /// will return STRING token if in JSON mode or RENEW_TIMER if
Tomek Mrugalski's avatar
Tomek Mrugalski committed
294 295 296
    /// in DHCP6 mode. Finally, the syntactic context allows the
    /// error message to be more descriptive if the input string
    /// does not parse properly.
297 298
    ///
    /// @param ctx the syntactic context to enter into
299 300 301
    void enter(const ParserContext& ctx);

    /// @brief Leave a syntactic context
302
    ///
303 304 305
    /// @throw isc::Unexpected if unbalanced
    void leave();

306
    /// @brief Get the syntactix context name
307
    ///
308 309
    /// @return printable name of the context.
    const std::string contextName();
310

311 312 313 314 315 316
 private:
    /// @brief Flag determining scanner debugging.
    bool trace_scanning_;

    /// @brief Flag determing parser debugging.
    bool trace_parsing_;
317 318 319

    /// @brief Syntactic context stack
    std::vector<ParserContext> cstack_;
320 321

    /// @brief Common part of parseXXX
322 323
    ///
    /// @return Element structure representing parsed text.
324
    isc::data::ConstElementPtr parseCommon();
325 326 327 328 329 330
};

}; // end of isc::eval namespace
}; // end of isc namespace

#endif