summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/master_lexer.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/dns/master_lexer.h678
1 files changed, 678 insertions, 0 deletions
diff --git a/src/lib/dns/master_lexer.h b/src/lib/dns/master_lexer.h
new file mode 100644
index 0000000..9ed4e81
--- /dev/null
+++ b/src/lib/dns/master_lexer.h
@@ -0,0 +1,678 @@
+// Copyright (C) 2012-2015 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 MASTER_LEXER_H
+#define MASTER_LEXER_H 1
+
+#include <dns/exceptions.h>
+
+#include <istream>
+#include <string>
+
+#include <stdint.h>
+
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace dns {
+namespace master_lexer_internal {
+class State;
+}
+
+/// \brief Tokens for \c MasterLexer
+///
+/// This is a simple value-class encapsulating a type of a lexer token and
+/// (if it has a value) its value. Essentially, the class provides
+/// constructors corresponding to different types of tokens, and corresponding
+/// getter methods. The type and value are fixed at the time of construction
+/// and will never be modified throughout the lifetime of the object.
+/// The getter methods are still provided to maximize the safety; an
+/// application cannot refer to a value that is invalid for the type of token.
+///
+/// This class is intentionally implemented as copyable and assignable
+/// (using the default version of copy constructor and assignment operator),
+/// but it's mainly for internal implementation convenience. Applications will
+/// simply refer to Token object as a reference via the \c MasterLexer class.
+class MasterToken {
+public:
+ /// \brief Enumeration for token types
+ ///
+ /// \note At the time of initial implementation, all numeric tokens
+ /// that would be extracted from \c MasterLexer should be represented
+ /// as an unsigned 32-bit integer. If we see the need for larger integers
+ /// or negative numbers, we can then extend the token types.
+ enum Type {
+ END_OF_LINE, ///< End of line detected
+ END_OF_FILE, ///< End of file detected
+ INITIAL_WS, ///< White spaces at the beginning of a line after an
+ ///< end of line or at the beginning of file (if asked
+ // for detecting it)
+ NOVALUE_TYPE_MAX = INITIAL_WS, ///< Max integer corresponding to
+ /// no-value (type only) types.
+ /// Mainly for internal use.
+ STRING, ///< A single string
+ QSTRING, ///< A single string quoted by double-quotes (").
+ NUMBER, ///< A decimal number (unsigned 32-bit)
+ ERROR ///< Error detected in getting a token
+ };
+
+ /// \brief Enumeration for lexer error codes
+ enum ErrorCode {
+ NOT_STARTED, ///< The lexer is just initialized and has no token
+ UNBALANCED_PAREN, ///< Unbalanced parentheses detected
+ UNEXPECTED_END, ///< The lexer reaches the end of line or file
+ /// unexpectedly
+ UNBALANCED_QUOTES, ///< Unbalanced quotations detected
+ NO_TOKEN_PRODUCED, ///< No token was produced. This means programmer
+ /// error and should never get out of the lexer.
+ NUMBER_OUT_OF_RANGE, ///< Number was out of range
+ BAD_NUMBER, ///< Number is expected but not recognized
+ UNEXPECTED_QUOTES, ///< Unexpected quotes character detected
+ MAX_ERROR_CODE ///< Max integer corresponding to valid error codes.
+ /// (excluding this one). Mainly for internal use.
+ };
+
+ /// \brief A simple representation of a range of a string.
+ ///
+ /// This is a straightforward pair of the start pointer of a string
+ /// and its length. The \c STRING and \c QSTRING types of tokens
+ /// will be primarily represented in this form.
+ ///
+ /// Any character can be stored in the valid range of the region.
+ /// In particular, there can be a nul character (\0) in the middle of
+ /// the region. So the usual string manipulation API may not work
+ /// as expected.
+ ///
+ /// The `MasterLexer` implementation ensures that there are at least
+ /// len + 1 bytes of valid memory region starting from beg, and that
+ /// beg[len] is \0. This means the application can use the bytes as a
+ /// validly nul-terminated C string if there is no intermediate nul
+ /// character. Note also that due to this property beg is always non
+ /// NULL; for an empty string len will be set to 0 and beg[0] is \0.
+ struct StringRegion {
+ const char* beg; ///< The start address of the string
+ size_t len; ///< The length of the string in bytes
+ };
+
+ /// \brief Constructor for non-value type of token.
+ ///
+ /// \throw InvalidParameter A value type token is specified.
+ /// \param type The type of the token. It must indicate a non-value
+ /// type (not larger than \c NOVALUE_TYPE_MAX).
+ explicit MasterToken(Type type) : type_(type) {
+ if (type > NOVALUE_TYPE_MAX) {
+ isc_throw(InvalidParameter, "Token per-type constructor "
+ "called with invalid type: " << type);
+ }
+ }
+
+ /// \brief Constructor for string and quoted-string types of token.
+ ///
+ /// The optional \c quoted parameter specifies whether it's a quoted or
+ /// non quoted string.
+ ///
+ /// The string is specified as a pair of a pointer to the start address
+ /// and its length. Any character can be contained in any position of
+ /// the valid range (see \c StringRegion).
+ ///
+ /// When it's a quoted string, the quotation marks must be excluded
+ /// from the specified range.
+ ///
+ /// \param str_beg The start address of the string
+ /// \param str_len The size of the string in bytes
+ /// \param quoted true if it's a quoted string; false otherwise.
+ MasterToken(const char* str_beg, size_t str_len, bool quoted = false) :
+ type_(quoted ? QSTRING : STRING)
+ {
+ val_.str_region_.beg = str_beg;
+ val_.str_region_.len = str_len;
+ }
+
+ /// \brief Constructor for number type of token.
+ ///
+ /// \brief number An unsigned 32-bit integer corresponding to the token
+ /// value.
+ explicit MasterToken(uint32_t number) : type_(NUMBER) {
+ val_.number_ = number;
+ }
+
+ /// \brief Constructor for error type of token.
+ ///
+ /// \throw InvalidParameter Invalid error code value is specified.
+ /// \brief error_code A pre-defined constant of \c ErrorCode.
+ explicit MasterToken(ErrorCode error_code) : type_(ERROR) {
+ if (!(error_code < MAX_ERROR_CODE)) {
+ isc_throw(InvalidParameter, "Invalid master lexer error code: "
+ << error_code);
+ }
+ val_.error_code_ = error_code;
+ }
+
+ /// \brief Return the token type.
+ ///
+ /// \throw none
+ Type getType() const { return (type_); }
+
+ /// \brief Return the value of a string-variant token.
+ ///
+ /// \throw InvalidOperation Called on a non string-variant types of token.
+ /// \return A reference to \c StringRegion corresponding to the string
+ /// token value.
+ const StringRegion& getStringRegion() const {
+ if (type_ != STRING && type_ != QSTRING) {
+ isc_throw(InvalidOperation,
+ "Token::getStringRegion() for non string-variant type");
+ }
+ return (val_.str_region_);
+ }
+
+ /// \brief Return the value of a string-variant token as a string object.
+ ///
+ /// Note that the underlying string may contain a nul (\0) character
+ /// in the middle. The returned string object will contain all characters
+ /// of the valid range of the underlying string. So some string
+ /// operations such as c_str() may not work as expected.
+ ///
+ /// \throw InvalidOperation Called on a non string-variant types of token.
+ /// \throw std::bad_alloc Resource allocation failure in constructing the
+ /// string object.
+ /// \return A std::string object corresponding to the string token value.
+ std::string getString() const {
+ std::string ret;
+ getString(ret);
+ return (ret);
+ }
+
+ /// \brief Fill in a string with the value of a string-variant token.
+ ///
+ /// This is similar to the other version of \c getString(), but
+ /// the caller is supposed to pass a placeholder string object.
+ /// This will be more efficient if the caller uses the same
+ /// \c MasterLexer repeatedly and needs to get string token in the
+ /// form of a string object many times as this version could reuse
+ /// the existing internal storage of the passed string.
+ ///
+ /// Any existing content of the passed string will be removed.
+ ///
+ /// \throw InvalidOperation Called on a non string-variant types of token.
+ /// \throw std::bad_alloc Resource allocation failure in constructing the
+ /// string object.
+ ///
+ /// \param ret A string object to be filled with the token string.
+ void getString(std::string& ret) const {
+ if (type_ != STRING && type_ != QSTRING) {
+ isc_throw(InvalidOperation,
+ "Token::getString() for non string-variant type");
+ }
+ ret.assign(val_.str_region_.beg,
+ val_.str_region_.beg + val_.str_region_.len);
+ }
+
+ /// \brief Return the value of a string-variant token as a string object.
+ ///
+ /// \throw InvalidOperation Called on a non number type of token.
+ /// \return The integer corresponding to the number token value.
+ uint32_t getNumber() const {
+ if (type_ != NUMBER) {
+ isc_throw(InvalidOperation,
+ "Token::getNumber() for non number type");
+ }
+ return (val_.number_);
+ }
+
+ /// \brief Return the error code of a error type token.
+ ///
+ /// \throw InvalidOperation Called on a non error type of token.
+ /// \return The error code of the token.
+ ErrorCode getErrorCode() const {
+ if (type_ != ERROR) {
+ isc_throw(InvalidOperation,
+ "Token::getErrorCode() for non error type");
+ }
+ return (val_.error_code_);
+ };
+
+ /// \brief Return a textual description of the error of a error type token.
+ ///
+ /// The returned string would be useful to produce a log message when
+ /// a zone file parser encounters an error.
+ ///
+ /// \throw InvalidOperation Called on a non error type of token.
+ /// \throw std::bad_alloc Resource allocation failure in constructing the
+ /// string object.
+ /// \return A string object that describes the meaning of the error.
+ std::string getErrorText() const;
+
+private:
+ Type type_; // this is not const so the class can be assignable
+
+ // We use a union to represent different types of token values via the
+ // unified Token class. The class integrity should ensure valid operation
+ // on the union; getter methods should only refer to the member set at
+ // the construction.
+ union {
+ StringRegion str_region_;
+ uint32_t number_;
+ ErrorCode error_code_;
+ } val_;
+};
+
+/// \brief Tokenizer for parsing DNS master files.
+///
+/// The \c MasterLexer class provides tokenize interfaces for parsing DNS
+/// master files. It understands some special rules of master files as
+/// defined in RFC 1035, such as comments, character escaping, and multi-line
+/// data, and provides the user application with the actual data in a
+/// more convenient form such as a std::string object.
+///
+/// In order to support the $INCLUDE notation, this class is designed to be
+/// able to operate on multiple files or input streams in the nested way.
+/// The \c pushSource() and \c popSource() methods correspond to the push
+/// and pop operations.
+///
+/// While this class is public, it is less likely to be used by normal
+/// applications; it's mainly expected to be used within this library,
+/// specifically by the \c MasterLoader class and \c Rdata implementation
+/// classes.
+///
+/// \note The error handling policy of this class is slightly different from
+/// that of other classes of this library. We generally throw an exception
+/// for an invalid input, whether it's more likely to be a program error or
+/// a "user error", which means an invalid input that comes from outside of
+/// the library. But, this class returns an error code for some certain
+/// types of user errors instead of throwing an exception. Such cases include
+/// a syntax error identified by the lexer or a misspelled file name that
+/// causes a system error at the time of open. This is based on the assumption
+/// that the main user of this class is a parser of master files, where
+/// we want to give an option to ignore some non fatal errors and continue
+/// the parsing. This will be useful if it just performs overall error
+/// checks on a master file. When the (immediate) caller needs to do explicit
+/// error handling, exceptions are not that a useful tool for error reporting
+/// because we cannot separate the normal and error cases anyway, which would
+/// be one major advantage when we use exceptions. And, exceptions are
+/// generally more expensive, either when it happens or just by being able
+/// to handle with \c try and \c catch (depending on the underlying
+/// implementation of the exception handling). For these reasons, some of
+/// this class does not throw for an error that would be reported as an
+/// exception in other classes.
+class MasterLexer : public boost::noncopyable {
+ friend class master_lexer_internal::State;
+public:
+ /// \brief Exception thrown when we fail to read from the input
+ /// stream or file.
+ class ReadError : public Unexpected {
+ public:
+ ReadError(const char* file, size_t line, const char* what) :
+ Unexpected(file, line, what)
+ {}
+ };
+
+ /// \brief Exception thrown from a wrapper version of
+ /// \c MasterLexer::getNextToken() for non fatal errors.
+ ///
+ /// See the method description for more details.
+ ///
+ /// The \c token_ member variable (read-only) is set to a \c MasterToken
+ /// object of type ERROR indicating the reason for the error.
+ class LexerError : public isc::dns::Exception {
+ public:
+ LexerError(const char* file, size_t line, MasterToken error_token) :
+ isc::dns::Exception(file, line, error_token.getErrorText().c_str()),
+ token_(error_token)
+ {}
+ const MasterToken token_;
+ };
+
+ /// \brief Special value for input source size meaning "unknown".
+ ///
+ /// This constant value will be used as a return value of
+ /// \c getTotalSourceSize() when the size of one of the pushed sources
+ /// is unknown. Note that this value itself is a valid integer in the
+ /// range of the type, so there's still a small possibility of
+ /// ambiguity. In practice, however, the value should be sufficiently
+ /// large that should eliminate the possibility.
+ static const size_t SOURCE_SIZE_UNKNOWN;
+
+ /// \brief Options for getNextToken.
+ ///
+ /// A compound option, indicating multiple options are set, can be
+ /// specified using the logical OR operator (operator|()).
+ enum Options {
+ NONE = 0, ///< No option
+ INITIAL_WS = 1, ///< recognize begin-of-line spaces after an
+ ///< end-of-line
+ QSTRING = 2, ///< recognize quoted string
+ NUMBER = 4 ///< recognize numeric text as integer
+ };
+
+ /// \brief The constructor.
+ ///
+ /// \throw std::bad_alloc Internal resource allocation fails (rare case).
+ MasterLexer();
+
+ /// \brief The destructor.
+ ///
+ /// It internally closes any remaining input sources.
+ ~MasterLexer();
+
+ /// \brief Open a file and make it the current input source of MasterLexer.
+ ///
+ /// The opened file can be explicitly closed by the \c popSource() method;
+ /// if \c popSource() is not called within the lifetime of the
+ /// \c MasterLexer, it will be closed in the destructor.
+ ///
+ /// In the case possible system errors in opening the file (most likely
+ /// because of specifying a non-existent or unreadable file), it returns
+ /// false, and if the optional \c error parameter is non NULL, it will be
+ /// set to a description of the error (any existing content of the string
+ /// will be discarded). If opening the file succeeds, the given
+ /// \c error parameter will be intact.
+ ///
+ /// Note that this method has two styles of error reporting: one by
+ /// returning \c false (and setting \c error optionally) and the other
+ /// by throwing an exception. See the note for the class description
+ /// about the distinction.
+ ///
+ /// \throw InvalidParameter filename is NULL
+ /// \param filename A non NULL string specifying a master file
+ /// \param error If non null, a placeholder to set error description in
+ /// case of failure.
+ ///
+ /// \return true if pushing the file succeeds; false otherwise.
+ bool pushSource(const char* filename, std::string* error = NULL);
+
+ /// \brief Make the given stream the current input source of MasterLexer.
+ ///
+ /// The caller still holds the ownership of the passed stream; it's the
+ /// caller's responsibility to keep it valid as long as it's used in
+ /// \c MasterLexer or to release any resource for the stream after that.
+ /// The caller can explicitly tell \c MasterLexer to stop using the
+ /// stream by calling the \c popSource() method.
+ ///
+ /// The data in \c input must be complete at the time of this call.
+ /// The behavior of the lexer is undefined if the caller builds or adds
+ /// data in \c input after pushing it.
+ ///
+ /// Except for rare case system errors such as memory allocation failure,
+ /// this method is generally expected to be exception free. However,
+ /// it can still throw if it encounters an unexpected failure when it
+ /// tries to identify the "size" of the input source (see
+ /// \c getTotalSourceSize()). It's an unexpected result unless the
+ /// caller intentionally passes a broken stream; otherwise it would mean
+ /// some system-dependent unexpected behavior or possibly an internal bug.
+ /// In these cases it throws an \c Unexpected exception. Note that
+ /// this version of the method doesn't return a boolean unlike the
+ /// other version that takes a file name; since this failure is really
+ /// unexpected and can be critical, it doesn't make sense to give the
+ /// caller an option to continue (other than by explicitly catching the
+ /// exception).
+ ///
+ /// \throw Unexpected An unexpected failure happens in initialization.
+ ///
+ /// \param input An input stream object that produces textual
+ /// representation of DNS RRs.
+ void pushSource(std::istream& input);
+
+ /// \brief Stop using the most recently opened input source (file or
+ /// stream).
+ ///
+ /// If it's a file, the previously opened file will be closed internally.
+ /// If it's a stream, \c MasterLexer will simply stop using
+ /// the stream; the caller can assume it will be never used in
+ /// \c MasterLexer thereafter.
+ ///
+ /// This method must not be called when there is no source pushed for
+ /// \c MasterLexer. This method is otherwise exception free.
+ ///
+ /// \throw isc::InvalidOperation Called with no pushed source.
+ void popSource();
+
+ /// \brief Get number of sources inside the lexer.
+ ///
+ /// This method never throws.
+ size_t getSourceCount() const;
+
+ /// \brief Return the name of the current input source name.
+ ///
+ /// If it's a file, it will be the C string given at the corresponding
+ /// \c pushSource() call, that is, its filename. If it's a stream, it will
+ /// be formatted as \c "stream-%p" where \c %p is hex representation
+ /// of the address of the stream object.
+ ///
+ /// If there is no opened source at the time of the call, this method
+ /// returns an empty string.
+ ///
+ /// \throw std::bad_alloc Resource allocation failed for string
+ /// construction (rare case)
+ ///
+ /// \return A string representation of the current source (see the
+ /// description)
+ std::string getSourceName() const;
+
+ /// \brief Return the input source line number.
+ ///
+ /// If there is an opened source, the return value will be a non-0
+ /// integer indicating the line number of the current source where
+ /// the \c MasterLexer is currently working. The expected usage of
+ /// this value is to print a helpful error message when parsing fails
+ /// by specifically identifying the position of the error.
+ ///
+ /// If there is no opened source at the time of the call, this method
+ /// returns 0.
+ ///
+ /// \throw None
+ ///
+ /// \return The current line number of the source (see the description)
+ size_t getSourceLine() const;
+
+ /// \brief Return the total size of pushed sources.
+ ///
+ /// This method returns the sum of the size of sources that have been
+ /// pushed to the lexer by the time of the call. It would give the
+ /// caller some hint about the amount of data the lexer is working on.
+ ///
+ /// The size of a normal file is equal to the file size at the time of
+ /// the source is pushed. The size of other type of input stream is
+ /// the size of the data available in the stream at the time of the
+ /// source is pushed.
+ ///
+ /// In some special cases, it's possible that the size of the file or
+ /// stream is unknown. It happens, for example, if the standard input
+ /// is associated with a pipe from the output of another process and it's
+ /// specified as an input source. If the size of some of the pushed
+ /// source is unknown, this method returns SOURCE_SIZE_UNKNOWN.
+ ///
+ /// The total size won't change when a source is popped. So the return
+ /// values of this method will monotonically increase or
+ /// \c SOURCE_SIZE_UNKNOWN; once it returns \c SOURCE_SIZE_UNKNOWN,
+ /// any subsequent call will also result in that value, by the above
+ /// definition.
+ ///
+ /// Before pushing any source, it returns 0.
+ ///
+ /// \throw None
+ size_t getTotalSourceSize() const;
+
+ /// \brief Return the position of lexer in the pushed sources so far.
+ ///
+ /// This method returns the position in terms of the number of recognized
+ /// characters from all sources that have been pushed by the time of the
+ /// call. Conceptually, the position in a single source is the offset
+ /// from the beginning of the file or stream to the current "read cursor"
+ /// of the lexer. The return value of this method is the sum of the
+ /// positions in all the pushed sources. If any of the sources has
+ /// already been popped, the position of the source at the time of the
+ /// pop operation will be used for the calculation.
+ ///
+ /// If the lexer reaches the end for each of all the pushed sources,
+ /// the return value should be equal to that of \c getTotalSourceSize().
+ /// It's generally expected that a source is popped when the lexer
+ /// reaches the end of the source. So, when the application of this
+ /// class parses all contents of all sources, possibly with multiple
+ /// pushes and pops, the return value of this method and
+ /// \c getTotalSourceSize() should be identical (unless the latter
+ /// returns SOURCE_SIZE_UNKNOWN). But this is not necessarily
+ /// guaranteed as the application can pop a source in the middle of
+ /// parsing it.
+ ///
+ /// Before pushing any source, it returns 0.
+ ///
+ /// The return values of this method and \c getTotalSourceSize() would
+ /// give the caller an idea of the progress of the lexer at the time of
+ /// the call. Note, however, that since it's not predictable whether
+ /// more sources will be pushed after the call, the progress determined
+ /// this way may not make much sense; it can only give an informational
+ /// hint of the progress.
+ ///
+ /// Note that the conceptual "read cursor" would move backward after a
+ /// call to \c ungetToken(), in which case this method will return a
+ /// smaller value. That is, unlike \c getTotalSourceSize(), return
+ /// values of this method may not always monotonically increase.
+ ///
+ /// \throw None
+ size_t getPosition() const;
+
+ /// \brief Parse and return another token from the input.
+ ///
+ /// It reads a bit of the last opened source and produces another token
+ /// found in it.
+ ///
+ /// This method does not provide the strong exception guarantee. Generally,
+ /// if it throws, the object should not be used any more and should be
+ /// discarded. It was decided all the exceptions thrown from here are
+ /// serious enough that aborting the loading process is the only reasonable
+ /// recovery anyway, so the strong exception guarantee is not needed.
+ ///
+ /// \param options The options can be used to modify the tokenization.
+ /// The method can be made reporting things which are usually ignored
+ /// by this parameter. Multiple options can be passed at once by
+ /// bitwise or (eg. option1 | option 2). See description of available
+ /// options.
+ /// \return Next token found in the input. Note that the token refers to
+ /// some internal data in the lexer. It is valid only until
+ /// getNextToken or ungetToken is called. Also, the token becomes
+ /// invalid when the lexer is destroyed.
+ /// \throw isc::InvalidOperation in case the source is not available. This
+ /// may mean the pushSource() has not been called yet, or that the
+ /// current source has been read past the end.
+ /// \throw ReadError in case there's problem reading from the underlying
+ /// source (eg. I/O error in the file on the disk).
+ /// \throw std::bad_alloc in case allocation of some internal resources
+ /// or the token fail.
+ const MasterToken& getNextToken(Options options = NONE);
+
+ /// \brief Parse the input for the expected type of token.
+ ///
+ /// This method is a wrapper of the other version, customized for the case
+ /// where a particular type of token is expected as the next one.
+ /// More specifically, it's intended to be used to get tokens for RDATA
+ /// fields. Since most RDATA types of fixed format, the token type is
+ /// often predictable and the method interface can be simplified.
+ ///
+ /// This method basically works as follows: it gets the type of the
+ /// expected token, calls the other version of \c getNextToken(Options),
+ /// and returns the token if it's of the expected type (due to the usage
+ /// assumption this should be normally the case). There are some non
+ /// trivial details though:
+ ///
+ /// - If the expected type is MasterToken::QSTRING, both quoted and
+ /// unquoted strings are recognized and returned.
+ /// - A string with quotation marks is not recognized as a
+ /// - MasterToken::STRING. You have to get it as a
+ /// - MasterToken::QSTRING.
+ /// - If the optional \c eol_ok parameter is \c true (very rare case),
+ /// MasterToken::END_OF_LINE and MasterToken::END_OF_FILE are recognized
+ /// and returned if they are found instead of the expected type of
+ /// token.
+ /// - If the next token is not of the expected type (including the case
+ /// a number is expected but it's out of range), ungetToken() is
+ /// internally called so the caller can re-read that token.
+ /// - If other types or errors (such as unbalanced parentheses) are
+ /// detected, the erroneous part isn't "ungotten"; the caller can
+ /// continue parsing after that part.
+ ///
+ /// In some very rare cases where the RDATA has an optional trailing field,
+ /// the \c eol_ok parameter would be set to \c true. This way the caller
+ /// can handle both cases (the field does or does not exist) by a single
+ /// call to this method. In all other cases \c eol_ok should be set to
+ /// \c false, and that is the default and can be omitted.
+ ///
+ /// Unlike the other version of \c getNextToken(Options), this method
+ /// throws an exception of type \c LexerError for non fatal errors such as
+ /// broken syntax or encountering an unexpected type of token. This way
+ /// the caller can write RDATA parser code without bothering to handle
+ /// errors for each field. For example, pseudo parser code for MX RDATA
+ /// would look like this:
+ /// \code
+ /// const uint32_t pref =
+ /// lexer.getNextToken(MasterToken::NUMBER).getNumber();
+ /// // check if pref is the uint16_t range; no other check is needed.
+ /// const Name mx(lexer.getNextToken(MasterToken::STRING).getString());
+ /// \endcode
+ ///
+ /// In the case where \c LexerError exception is thrown, it's expected
+ /// to be handled comprehensively for the parser of the RDATA or at a
+ /// higher layer. The \c token_ member variable of the corresponding
+ /// \c LexerError exception object stores a token of type
+ /// \c MasterToken::ERROR that indicates the reason for the error.
+ ///
+ /// Due to the specific intended usage of this method, only a subset
+ /// of \c MasterToken::Type values are acceptable for the \c expect
+ /// parameter: \c MasterToken::STRING, \c MasterToken::QSTRING, and
+ /// \c MasterToken::NUMBER. Specifying other values will result in
+ /// an \c InvalidParameter exception.
+ ///
+ /// \throw InvalidParameter The expected token type is not allowed for
+ /// this method.
+ /// \throw LexerError The lexer finds non fatal error or it finds an
+ /// \throw other Anything the other version of getNextToken() can throw.
+ ///
+ /// \param expect Expected type of token. Must be either STRING, QSTRING,
+ /// or NUMBER.
+ /// \param eol_ok \c true iff END_OF_LINE or END_OF_FILE is acceptable.
+ /// \return The expected type of token.
+ const MasterToken& getNextToken(MasterToken::Type expect,
+ bool eol_ok = false);
+
+ /// \brief Return the last token back to the lexer.
+ ///
+ /// The method undoes the lasts call to getNextToken(). If you call the
+ /// getNextToken() again with the same options, it'll return the same
+ /// token. If the options are different, it may return a different token,
+ /// but it acts as if the previous getNextToken() was never called.
+ ///
+ /// It is possible to return only one token back in time (you can't call
+ /// ungetToken() twice in a row without calling getNextToken() in between
+ /// successfully).
+ ///
+ /// It does not work after change of source (by pushSource or popSource).
+ ///
+ /// \throw isc::InvalidOperation If called second time in a row or if
+ /// getNextToken() was not called since the last change of the source.
+ void ungetToken();
+
+private:
+ struct MasterLexerImpl;
+ MasterLexerImpl* impl_;
+};
+
+/// \brief Operator to combine \c MasterLexer options
+///
+/// This is a trivial shortcut so that compound options can be specified
+/// in an intuitive way.
+inline MasterLexer::Options
+operator|(MasterLexer::Options o1, MasterLexer::Options o2) {
+ return (static_cast<MasterLexer::Options>(
+ static_cast<unsigned>(o1) | static_cast<unsigned>(o2)));
+}
+
+} // namespace dns
+} // namespace isc
+#endif // MASTER_LEXER_H
+
+// Local Variables:
+// mode: c++
+// End: