#ifndef SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #if defined(_MSC_VER) || \ (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif #include #include #include #include #include #include "ptr_vector.h" #include "stream.h" #include "token.h" #include "yaml-cpp/mark.h" namespace YAML { class Node; class RegEx; /** * A scanner transforms a stream of characters into a stream of tokens. */ class Scanner { public: explicit Scanner(std::istream &in); ~Scanner(); /** Returns true if there are no more tokens to be read. */ bool empty(); /** Removes the next token in the queue. */ void pop(); /** Returns, but does not remove, the next token in the queue. */ Token &peek(); /** Returns the current mark in the input stream. */ Mark mark() const; private: struct IndentMarker { enum INDENT_TYPE { MAP, SEQ, NONE }; enum STATUS { VALID, INVALID, UNKNOWN }; IndentMarker(int column_, INDENT_TYPE type_) : column(column_), type(type_), status(VALID), pStartToken(nullptr) {} int column; INDENT_TYPE type; STATUS status; Token *pStartToken; }; enum FLOW_MARKER { FLOW_MAP, FLOW_SEQ }; private: // scanning /** * Scans until there's a valid token at the front of the queue, or the queue * is empty. The state can be checked by {@link #empty}, and the next token * retrieved by {@link #peek}. */ void EnsureTokensInQueue(); /** * The main scanning function; this method branches out to scan whatever the * next token should be. */ void ScanNextToken(); /** Eats the input stream until it reaches the next token-like thing. */ void ScanToNextToken(); /** Sets the initial conditions for starting a stream. */ void StartStream(); /** Closes out the stream, finish up, etc. */ void EndStream(); Token *PushToken(Token::TYPE type); bool InFlowContext() const { return !m_flows.empty(); } bool InBlockContext() const { return m_flows.empty(); } std::size_t GetFlowLevel() const { return m_flows.size(); } Token::TYPE GetStartTokenFor(IndentMarker::INDENT_TYPE type) const; /** * Pushes an indentation onto the stack, and enqueues the proper token * (sequence start or mapping start). * * @return the indent marker it generates (if any). */ IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); /** * Pops indentations off the stack until it reaches the current indentation * level, and enqueues the proper token each time. Then pops all invalid * indentations off. */ void PopIndentToHere(); /** * Pops all indentations (except for the base empty one) off the stack, and * enqueues the proper token each time. */ void PopAllIndents(); /** Pops a single indent, pushing the proper token. */ void PopIndent(); int GetTopIndent() const; // checking input bool CanInsertPotentialSimpleKey() const; bool ExistsActiveSimpleKey() const; void InsertPotentialSimpleKey(); void InvalidateSimpleKey(); bool VerifySimpleKey(); void PopAllSimpleKeys(); /** * Throws a ParserException with the current token location (if available), * and does not parse any more tokens. */ void ThrowParserException(const std::string &msg) const; bool IsWhitespaceToBeEaten(char ch); /** * Returns the appropriate regex to check if the next token is a value token. */ const RegEx &GetValueRegex() const; struct SimpleKey { SimpleKey(const Mark &mark_, std::size_t flowLevel_); void Validate(); void Invalidate(); Mark mark; std::size_t flowLevel; IndentMarker *pIndent; Token *pMapStart, *pKey; }; // and the tokens void ScanDirective(); void ScanDocStart(); void ScanDocEnd(); void ScanBlockSeqStart(); void ScanBlockMapSTart(); void ScanBlockEnd(); void ScanBlockEntry(); void ScanFlowStart(); void ScanFlowEnd(); void ScanFlowEntry(); void ScanKey(); void ScanValue(); void ScanAnchorOrAlias(); void ScanTag(); void ScanPlainScalar(); void ScanQuotedScalar(); void ScanBlockScalar(); private: // the stream Stream INPUT; // the output (tokens) std::queue m_tokens; // state info bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; bool m_canBeJSONFlow; std::stack m_simpleKeys; std::stack m_indents; ptr_vector m_indentRefs; // for "garbage collection" std::stack m_flows; }; } #endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66