mirror of https://github.com/axmolengine/axmol.git
191 lines
4.7 KiB
C++
191 lines
4.7 KiB
C++
#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 <cstddef>
|
|
#include <ios>
|
|
#include <map>
|
|
#include <queue>
|
|
#include <set>
|
|
#include <stack>
|
|
#include <string>
|
|
|
|
#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<Token> m_tokens;
|
|
|
|
// state info
|
|
bool m_startedStream, m_endedStream;
|
|
bool m_simpleKeyAllowed;
|
|
bool m_canBeJSONFlow;
|
|
std::stack<SimpleKey> m_simpleKeys;
|
|
std::stack<IndentMarker *> m_indents;
|
|
ptr_vector<IndentMarker> m_indentRefs; // for "garbage collection"
|
|
std::stack<FLOW_MARKER> m_flows;
|
|
};
|
|
}
|
|
|
|
#endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|