parser_context.h 10.8 KB
Newer Older
1
// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
// 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.
86
87
88
89
        PARSER_HOOKS_LIBRARY,

        /// This will parse the input as dhcp-ddns. (D2 client config)
        PARSER_DHCP_DDNS
90
    } ParserType;
91

92
93
94
95
96
97
98
    /// @brief Default constructor.
    Parser6Context();

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

    /// @brief JSON elements being parsed.
99
    std::vector<isc::data::ElementPtr> stack_;
100
101

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

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

114
115
    /// @brief Method called after the last tokens are scanned.
    void scanEnd();
116

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

122
123
    /// @brief Run the parser on the string specified.
    ///
124
125
126
127
128
    /// 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.
    ///
129
    /// @param str string to be parsed
130
131
    /// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
    /// @return Element structure representing parsed text.
132
133
    isc::data::ElementPtr parseString(const std::string& str,
                                      ParserType parser_type);
134

135
    /// @brief Run the parser on the file specified.
136
137
138
139
140
141
142
143
144
    ///
    /// 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.
145
146
    isc::data::ElementPtr parseFile(const std::string& filename,
                                    ParserType parser_type);
147

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

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

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

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

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

        ///< Used while parsing top level (that contains Dhcp6, Logging and others)
188
        CONFIG,
189
190

        ///< Used while parsing content of Dhcp6.
191
        DHCP6,
192

193
        // not yet DHCP4,
194
195

        ///< Used while parsing content of Logging
196
        LOGGING,
197
198

        /// Used while parsing Dhcp6/interfaces structures.
199
        INTERFACES_CONFIG,
200
201
202
203

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

204
205
206
        /// Used while parsing Dhcp6/hosts-database structures.
        HOSTS_DATABASE,

207
        /// Used while parsing Dhcp6/mac-sources structures.
208
        MAC_SOURCES,
209
210

        /// Used while parsing Dhcp6/host-reservation-identifiers.
211
        HOST_RESERVATION_IDENTIFIERS,
212
213

        /// Used while parsing Dhcp6/hooks-libraries.
214
        HOOKS_LIBRARIES,
215
216

        /// Used while parsing Dhcp6/Subnet6 structures.
217
        SUBNET6,
218
219

        /// Used while parsing Dhcp6/option-def structures.
220
        OPTION_DEF,
221
222
223
224

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

        /// Used while parsing Dhcp6/client-classes structures.
228
        CLIENT_CLASSES,
229
230

        /// Used while parsing Dhcp6/server-id structures.
231
        SERVER_ID,
232
233

        /// Used while parsing Dhcp6/control-socket structures.
234
        CONTROL_SOCKET,
235
236

        /// Used while parsing Dhcp6/subnet6/pools structures.
237
        POOLS,
238
239

        /// Used while parsing Dhcp6/subnet6/pd-pools structures.
240
        PD_POOLS,
241
242

        /// Used while parsing Dhcp6/reservations structures.
243
        RESERVATIONS,
244
245

        /// Used while parsing Dhcp6/subnet6/relay structures.
246
        RELAY,
247
248

        /// Used while parsing Dhcp6/client-classes structures.
249
        CLIENT_CLASS,
250
251

        /// Used while parsing Logging/loggers structures.
252
        LOGGERS,
253
254

        /// Used while parsing Logging/loggers/output_options structures.
255
256
257
258
        OUTPUT_OPTIONS,

        /// Used while parsing Dhcp6/dhcp-ddns
        DHCP_DDNS
259
    } ParserContext;
260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    /// @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_;

276
    /// @brief Lexer state stack
Tomek Mrugalski's avatar
Tomek Mrugalski committed
277
    std::vector<struct yy_buffer_state*> states_;
278

279
280
281
282
    /// @brief sFile (aka FILE)
    FILE* sfile_;

    /// @brief sFile (aka FILE) stack
283
284
285
286
    ///
    /// 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.
287
288
    std::vector<FILE*> sfiles_;

289
290
291
292
    /// @brief Current syntactic context
    ParserContext ctx_;

    /// @brief Enter a new syntactic context
293
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
294
    /// Entering a new syntactic context is useful in several ways.
295
296
297
298
    /// 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
299
300
301
    /// in DHCP6 mode. Finally, the syntactic context allows the
    /// error message to be more descriptive if the input string
    /// does not parse properly.
302
303
    ///
    /// @param ctx the syntactic context to enter into
304
305
306
    void enter(const ParserContext& ctx);

    /// @brief Leave a syntactic context
307
    ///
308
309
310
    /// @throw isc::Unexpected if unbalanced
    void leave();

311
    /// @brief Get the syntactix context name
312
    ///
313
314
    /// @return printable name of the context.
    const std::string contextName();
315

316
317
318
319
320
321
 private:
    /// @brief Flag determining scanner debugging.
    bool trace_scanning_;

    /// @brief Flag determing parser debugging.
    bool trace_parsing_;
322
323
324

    /// @brief Syntactic context stack
    std::vector<ParserContext> cstack_;
325
326

    /// @brief Common part of parseXXX
327
328
    ///
    /// @return Element structure representing parsed text.
329
    isc::data::ElementPtr parseCommon();
330
331
332
333
334
335
};

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

#endif