mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Set the eol style to native for all files.
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// for detecting memory leaks
|
// for detecting memory leaks
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
||||||
#define _CRTDBG_MAP_ALLOC
|
#define _CRTDBG_MAP_ALLOC
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <crtdbg.h>
|
#include <crtdbg.h>
|
||||||
|
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
|
@@ -1,59 +1,59 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Exception: public std::exception {};
|
class Exception: public std::exception {};
|
||||||
class ParserException: public Exception {
|
class ParserException: public Exception {
|
||||||
public:
|
public:
|
||||||
ParserException(int line_, int column_, const std::string& msg_)
|
ParserException(int line_, int column_, const std::string& msg_)
|
||||||
: line(line_), column(column_), msg(msg_) {}
|
: line(line_), column(column_), msg(msg_) {}
|
||||||
virtual ~ParserException() throw () {}
|
virtual ~ParserException() throw () {}
|
||||||
|
|
||||||
int line, column;
|
int line, column;
|
||||||
std::string msg;
|
std::string msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RepresentationException: public Exception {};
|
class RepresentationException: public Exception {};
|
||||||
|
|
||||||
// representation exceptions
|
// representation exceptions
|
||||||
class InvalidScalar: public RepresentationException {};
|
class InvalidScalar: public RepresentationException {};
|
||||||
class BadDereference: public RepresentationException {};
|
class BadDereference: public RepresentationException {};
|
||||||
|
|
||||||
// error messages
|
// error messages
|
||||||
namespace ErrorMsg
|
namespace ErrorMsg
|
||||||
{
|
{
|
||||||
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
|
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
|
||||||
const std::string YAML_VERSION = "bad YAML version: ";
|
const std::string YAML_VERSION = "bad YAML version: ";
|
||||||
const std::string YAML_MAJOR_VERSION = "YAML major version too large";
|
const std::string YAML_MAJOR_VERSION = "YAML major version too large";
|
||||||
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
|
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
|
||||||
const std::string END_OF_MAP = "end of map not found";
|
const std::string END_OF_MAP = "end of map not found";
|
||||||
const std::string END_OF_MAP_FLOW = "end of map flow not found";
|
const std::string END_OF_MAP_FLOW = "end of map flow not found";
|
||||||
const std::string END_OF_SEQ = "end of sequence not found";
|
const std::string END_OF_SEQ = "end of sequence not found";
|
||||||
const std::string END_OF_SEQ_FLOW = "end of sequence flow not found";
|
const std::string END_OF_SEQ_FLOW = "end of sequence flow not found";
|
||||||
const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node";
|
const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node";
|
||||||
const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node";
|
const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node";
|
||||||
const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node";
|
const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node";
|
||||||
const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags";
|
const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags";
|
||||||
const std::string INVALID_HEX = "bad character found while scanning hex number";
|
const std::string INVALID_HEX = "bad character found while scanning hex number";
|
||||||
const std::string INVALID_UNICODE = "invalid unicode: ";
|
const std::string INVALID_UNICODE = "invalid unicode: ";
|
||||||
const std::string INVALID_ESCAPE = "unknown escape character: ";
|
const std::string INVALID_ESCAPE = "unknown escape character: ";
|
||||||
const std::string UNKNOWN_TOKEN = "unknown token";
|
const std::string UNKNOWN_TOKEN = "unknown token";
|
||||||
const std::string DOC_IN_SCALAR = "illegal document indicator in scalar";
|
const std::string DOC_IN_SCALAR = "illegal document indicator in scalar";
|
||||||
const std::string EOF_IN_SCALAR = "illegal EOF in scalar";
|
const std::string EOF_IN_SCALAR = "illegal EOF in scalar";
|
||||||
const std::string CHAR_IN_SCALAR = "illegal character in scalar";
|
const std::string CHAR_IN_SCALAR = "illegal character in scalar";
|
||||||
const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation";
|
const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation";
|
||||||
const std::string FLOW_END = "illegal flow end";
|
const std::string FLOW_END = "illegal flow end";
|
||||||
const std::string BLOCK_ENTRY = "illegal block entry";
|
const std::string BLOCK_ENTRY = "illegal block entry";
|
||||||
const std::string MAP_KEY = "illegal map key";
|
const std::string MAP_KEY = "illegal map key";
|
||||||
const std::string MAP_VALUE = "illegal map value";
|
const std::string MAP_VALUE = "illegal map value";
|
||||||
const std::string ALIAS_NOT_FOUND = "alias not found after *";
|
const std::string ALIAS_NOT_FOUND = "alias not found after *";
|
||||||
const std::string ANCHOR_NOT_FOUND = "anchor not found after &";
|
const std::string ANCHOR_NOT_FOUND = "anchor not found after &";
|
||||||
const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias";
|
const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias";
|
||||||
const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor";
|
const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor";
|
||||||
const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar";
|
const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar";
|
||||||
const std::string CHAR_IN_BLOCK = "unexpected character in block scalar";
|
const std::string CHAR_IN_BLOCK = "unexpected character in block scalar";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,30 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
struct IterPriv;
|
struct IterPriv;
|
||||||
|
|
||||||
class Iterator
|
class Iterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Iterator();
|
Iterator();
|
||||||
Iterator(IterPriv *pData);
|
Iterator(IterPriv *pData);
|
||||||
Iterator(const Iterator& rhs);
|
Iterator(const Iterator& rhs);
|
||||||
~Iterator();
|
~Iterator();
|
||||||
|
|
||||||
Iterator& operator = (const Iterator& rhs);
|
Iterator& operator = (const Iterator& rhs);
|
||||||
Iterator& operator ++ ();
|
Iterator& operator ++ ();
|
||||||
Iterator operator ++ (int);
|
Iterator operator ++ (int);
|
||||||
const Node& operator * () const;
|
const Node& operator * () const;
|
||||||
const Node *operator -> () const;
|
const Node *operator -> () const;
|
||||||
const Node& first() const;
|
const Node& first() const;
|
||||||
const Node& second() const;
|
const Node& second() const;
|
||||||
|
|
||||||
friend bool operator == (const Iterator& it, const Iterator& jt);
|
friend bool operator == (const Iterator& it, const Iterator& jt);
|
||||||
friend bool operator != (const Iterator& it, const Iterator& jt);
|
friend bool operator != (const Iterator& it, const Iterator& jt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IterPriv *m_pData;
|
IterPriv *m_pData;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
184
include/node.h
184
include/node.h
@@ -1,92 +1,92 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "parserstate.h"
|
#include "parserstate.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Content;
|
class Content;
|
||||||
class Scanner;
|
class Scanner;
|
||||||
|
|
||||||
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
|
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
|
||||||
|
|
||||||
class Node
|
class Node
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Node();
|
Node();
|
||||||
~Node();
|
~Node();
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void Parse(Scanner *pScanner, const ParserState& state);
|
void Parse(Scanner *pScanner, const ParserState& state);
|
||||||
void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const;
|
void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const;
|
||||||
|
|
||||||
CONTENT_TYPE GetType() const;
|
CONTENT_TYPE GetType() const;
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
Iterator begin() const;
|
Iterator begin() const;
|
||||||
Iterator end() const;
|
Iterator end() const;
|
||||||
unsigned size() const;
|
unsigned size() const;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const Node& GetValue(const T& key) const {
|
const Node& GetValue(const T& key) const {
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
|
|
||||||
for(Iterator it=begin();it!=end();++it) {
|
for(Iterator it=begin();it!=end();++it) {
|
||||||
T t;
|
T t;
|
||||||
try {
|
try {
|
||||||
it.first() >> t;
|
it.first() >> t;
|
||||||
if(key == t)
|
if(key == t)
|
||||||
return it.second();
|
return it.second();
|
||||||
} catch(RepresentationException&) {
|
} catch(RepresentationException&) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const Node& operator [] (const T& key) const {
|
const Node& operator [] (const T& key) const {
|
||||||
return GetValue(key);
|
return GetValue(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& operator [] (const char *key) const {
|
const Node& operator [] (const char *key) const {
|
||||||
return GetValue(std::string(key));
|
return GetValue(std::string(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& operator [] (unsigned u) const;
|
const Node& operator [] (unsigned u) const;
|
||||||
const Node& operator [] (int i) const;
|
const Node& operator [] (int i) const;
|
||||||
|
|
||||||
// extraction
|
// extraction
|
||||||
friend void operator >> (const Node& node, std::string& s);
|
friend void operator >> (const Node& node, std::string& s);
|
||||||
friend void operator >> (const Node& node, int& i);
|
friend void operator >> (const Node& node, int& i);
|
||||||
friend void operator >> (const Node& node, unsigned& u);
|
friend void operator >> (const Node& node, unsigned& u);
|
||||||
friend void operator >> (const Node& node, long& l);
|
friend void operator >> (const Node& node, long& l);
|
||||||
friend void operator >> (const Node& node, float& f);
|
friend void operator >> (const Node& node, float& f);
|
||||||
friend void operator >> (const Node& node, double& d);
|
friend void operator >> (const Node& node, double& d);
|
||||||
friend void operator >> (const Node& node, char& c);
|
friend void operator >> (const Node& node, char& c);
|
||||||
|
|
||||||
// insertion
|
// insertion
|
||||||
friend std::ostream& operator << (std::ostream& out, const Node& node);
|
friend std::ostream& operator << (std::ostream& out, const Node& node);
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
int Compare(const Node& rhs) const;
|
int Compare(const Node& rhs) const;
|
||||||
friend bool operator < (const Node& n1, const Node& n2);
|
friend bool operator < (const Node& n1, const Node& n2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ParseHeader(Scanner *pScanner, const ParserState& state);
|
void ParseHeader(Scanner *pScanner, const ParserState& state);
|
||||||
void ParseTag(Scanner *pScanner, const ParserState& state);
|
void ParseTag(Scanner *pScanner, const ParserState& state);
|
||||||
void ParseAnchor(Scanner *pScanner, const ParserState& state);
|
void ParseAnchor(Scanner *pScanner, const ParserState& state);
|
||||||
void ParseAlias(Scanner *pScanner, const ParserState& state);
|
void ParseAlias(Scanner *pScanner, const ParserState& state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_anchor, m_tag;
|
std::string m_anchor, m_tag;
|
||||||
Content *m_pContent;
|
Content *m_pContent;
|
||||||
bool m_alias;
|
bool m_alias;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,42 +1,42 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "parserstate.h"
|
#include "parserstate.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Scanner;
|
class Scanner;
|
||||||
struct Token;
|
struct Token;
|
||||||
|
|
||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Parser(std::istream& in);
|
Parser(std::istream& in);
|
||||||
~Parser();
|
~Parser();
|
||||||
|
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
|
||||||
void Load(std::istream& in);
|
void Load(std::istream& in);
|
||||||
void GetNextDocument(Node& document);
|
void GetNextDocument(Node& document);
|
||||||
void PrintTokens(std::ostream& out);
|
void PrintTokens(std::ostream& out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ParseDirectives();
|
void ParseDirectives();
|
||||||
void HandleDirective(Token *pToken);
|
void HandleDirective(Token *pToken);
|
||||||
void HandleYamlDirective(Token *pToken);
|
void HandleYamlDirective(Token *pToken);
|
||||||
void HandleTagDirective(Token *pToken);
|
void HandleTagDirective(Token *pToken);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// can't copy this
|
// can't copy this
|
||||||
Parser(const Parser& rhs) {}
|
Parser(const Parser& rhs) {}
|
||||||
Parser& operator = (const Parser& rhs) { return *this; }
|
Parser& operator = (const Parser& rhs) { return *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scanner *m_pScanner;
|
Scanner *m_pScanner;
|
||||||
ParserState m_state;
|
ParserState m_state;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
struct Version {
|
struct Version {
|
||||||
int major, minor;
|
int major, minor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ParserState
|
struct ParserState
|
||||||
{
|
{
|
||||||
Version version;
|
Version version;
|
||||||
std::map <std::string, std::string> tags;
|
std::map <std::string, std::string> tags;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
std::string TranslateTag(const std::string& handle) const;
|
std::string TranslateTag(const std::string& handle) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "iterator.h"
|
#include "iterator.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "content.h"
|
#include "content.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Content::Content()
|
Content::Content()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Content::~Content()
|
Content::~Content()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
110
src/content.h
110
src/content.h
@@ -1,55 +1,55 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "parserstate.h"
|
#include "parserstate.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "ltnode.h"
|
#include "ltnode.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Scanner;
|
class Scanner;
|
||||||
class Parser;
|
class Parser;
|
||||||
class Node;
|
class Node;
|
||||||
class Scalar;
|
class Scalar;
|
||||||
class Sequence;
|
class Sequence;
|
||||||
class Map;
|
class Map;
|
||||||
|
|
||||||
class Content
|
class Content
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Content();
|
Content();
|
||||||
virtual ~Content();
|
virtual ~Content();
|
||||||
|
|
||||||
virtual void Parse(Scanner *pScanner, const ParserState& state) = 0;
|
virtual void Parse(Scanner *pScanner, const ParserState& state) = 0;
|
||||||
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0;
|
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0;
|
||||||
|
|
||||||
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const { return false; }
|
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const { return false; }
|
||||||
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
|
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
|
||||||
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const { return false; }
|
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const { return false; }
|
||||||
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
|
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
|
||||||
virtual Node *GetNode(unsigned i) const { return 0; }
|
virtual Node *GetNode(unsigned i) const { return 0; }
|
||||||
virtual unsigned GetSize() const { return 0; }
|
virtual unsigned GetSize() const { return 0; }
|
||||||
virtual bool IsScalar() const { return false; }
|
virtual bool IsScalar() const { return false; }
|
||||||
virtual bool IsMap() const { return false; }
|
virtual bool IsMap() const { return false; }
|
||||||
virtual bool IsSequence() const { return false; }
|
virtual bool IsSequence() const { return false; }
|
||||||
|
|
||||||
// extraction
|
// extraction
|
||||||
virtual void Read(std::string& s) { throw InvalidScalar(); }
|
virtual void Read(std::string& s) { throw InvalidScalar(); }
|
||||||
virtual void Read(int& i) { throw InvalidScalar(); }
|
virtual void Read(int& i) { throw InvalidScalar(); }
|
||||||
virtual void Read(unsigned& u) { throw InvalidScalar(); }
|
virtual void Read(unsigned& u) { throw InvalidScalar(); }
|
||||||
virtual void Read(long& l) { throw InvalidScalar(); }
|
virtual void Read(long& l) { throw InvalidScalar(); }
|
||||||
virtual void Read(float& f) { throw InvalidScalar(); }
|
virtual void Read(float& f) { throw InvalidScalar(); }
|
||||||
virtual void Read(double& d) { throw InvalidScalar(); }
|
virtual void Read(double& d) { throw InvalidScalar(); }
|
||||||
virtual void Read(char& c) { throw InvalidScalar(); }
|
virtual void Read(char& c) { throw InvalidScalar(); }
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
virtual int Compare(Content *pContent) { return 0; }
|
virtual int Compare(Content *pContent) { return 0; }
|
||||||
virtual int Compare(Scalar *pScalar) { return 0; }
|
virtual int Compare(Scalar *pScalar) { return 0; }
|
||||||
virtual int Compare(Sequence *pSeq) { return 0; }
|
virtual int Compare(Sequence *pSeq) { return 0; }
|
||||||
virtual int Compare(Map *pMap) { return 0; }
|
virtual int Compare(Map *pMap) { return 0; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
226
src/exp.cpp
226
src/exp.cpp
@@ -1,113 +1,113 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
namespace Exp
|
namespace Exp
|
||||||
{
|
{
|
||||||
unsigned ParseHex(const std::string& str, int line, int column)
|
unsigned ParseHex(const std::string& str, int line, int column)
|
||||||
{
|
{
|
||||||
unsigned value = 0;
|
unsigned value = 0;
|
||||||
for(unsigned i=0;i<str.size();i++) {
|
for(unsigned i=0;i<str.size();i++) {
|
||||||
char ch = str[i];
|
char ch = str[i];
|
||||||
int digit = 0;
|
int digit = 0;
|
||||||
if('a' <= ch && ch <= 'f')
|
if('a' <= ch && ch <= 'f')
|
||||||
digit = ch - 'a' + 10;
|
digit = ch - 'a' + 10;
|
||||||
else if('A' <= ch && ch <= 'F')
|
else if('A' <= ch && ch <= 'F')
|
||||||
digit = ch - 'A' + 10;
|
digit = ch - 'A' + 10;
|
||||||
else if('0' <= ch && ch <= '9')
|
else if('0' <= ch && ch <= '9')
|
||||||
digit = ch - '0';
|
digit = ch - '0';
|
||||||
else
|
else
|
||||||
throw ParserException(line, column, ErrorMsg::INVALID_HEX);
|
throw ParserException(line, column, ErrorMsg::INVALID_HEX);
|
||||||
|
|
||||||
value = (value << 4) + digit;
|
value = (value << 4) + digit;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Str(char ch)
|
std::string Str(char ch)
|
||||||
{
|
{
|
||||||
return std::string("") + ch;
|
return std::string("") + ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape
|
// Escape
|
||||||
// . Translates the next 'codeLength' characters into a hex number and returns the result.
|
// . Translates the next 'codeLength' characters into a hex number and returns the result.
|
||||||
// . Throws if it's not actually hex.
|
// . Throws if it's not actually hex.
|
||||||
std::string Escape(Stream& in, int codeLength)
|
std::string Escape(Stream& in, int codeLength)
|
||||||
{
|
{
|
||||||
// grab string
|
// grab string
|
||||||
std::string str;
|
std::string str;
|
||||||
for(int i=0;i<codeLength;i++)
|
for(int i=0;i<codeLength;i++)
|
||||||
str += in.get();
|
str += in.get();
|
||||||
|
|
||||||
// get the value
|
// get the value
|
||||||
unsigned value = ParseHex(str, in.line, in.column);
|
unsigned value = ParseHex(str, in.line, in.column);
|
||||||
|
|
||||||
// legal unicode?
|
// legal unicode?
|
||||||
if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
|
if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
|
||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
msg << ErrorMsg::INVALID_UNICODE << value;
|
msg << ErrorMsg::INVALID_UNICODE << value;
|
||||||
throw ParserException(in.line, in.column, msg.str());
|
throw ParserException(in.line, in.column, msg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// now break it up into chars
|
// now break it up into chars
|
||||||
if(value <= 0x7F)
|
if(value <= 0x7F)
|
||||||
return Str(value);
|
return Str(value);
|
||||||
else if(value <= 0x7FF)
|
else if(value <= 0x7FF)
|
||||||
return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F));
|
return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F));
|
||||||
else if(value <= 0xFFFF)
|
else if(value <= 0xFFFF)
|
||||||
return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
|
return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
|
||||||
else
|
else
|
||||||
return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) +
|
return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) +
|
||||||
Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
|
Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape
|
// Escape
|
||||||
// . Escapes the sequence starting 'in' (it must begin with a '\' or single quote)
|
// . Escapes the sequence starting 'in' (it must begin with a '\' or single quote)
|
||||||
// and returns the result.
|
// and returns the result.
|
||||||
// . Throws if it's an unknown escape character.
|
// . Throws if it's an unknown escape character.
|
||||||
std::string Escape(Stream& in)
|
std::string Escape(Stream& in)
|
||||||
{
|
{
|
||||||
// eat slash
|
// eat slash
|
||||||
char escape = in.get();
|
char escape = in.get();
|
||||||
|
|
||||||
// switch on escape character
|
// switch on escape character
|
||||||
char ch = in.get();
|
char ch = in.get();
|
||||||
|
|
||||||
// first do single quote, since it's easier
|
// first do single quote, since it's easier
|
||||||
if(escape == '\'' && ch == '\'')
|
if(escape == '\'' && ch == '\'')
|
||||||
return "\'";
|
return "\'";
|
||||||
|
|
||||||
// now do the slash (we're not gonna check if it's a slash - you better pass one!)
|
// now do the slash (we're not gonna check if it's a slash - you better pass one!)
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case '0': return "\0";
|
case '0': return "\0";
|
||||||
case 'a': return "\x07";
|
case 'a': return "\x07";
|
||||||
case 'b': return "\x08";
|
case 'b': return "\x08";
|
||||||
case 't':
|
case 't':
|
||||||
case '\t': return "\x09";
|
case '\t': return "\x09";
|
||||||
case 'n': return "\x0A";
|
case 'n': return "\x0A";
|
||||||
case 'v': return "\x0B";
|
case 'v': return "\x0B";
|
||||||
case 'f': return "\x0C";
|
case 'f': return "\x0C";
|
||||||
case 'r': return "\x0D";
|
case 'r': return "\x0D";
|
||||||
case 'e': return "\x1B";
|
case 'e': return "\x1B";
|
||||||
case ' ': return "\x20";
|
case ' ': return "\x20";
|
||||||
case '\"': return "\"";
|
case '\"': return "\"";
|
||||||
case '\'': return "\'";
|
case '\'': return "\'";
|
||||||
case '\\': return "\\";
|
case '\\': return "\\";
|
||||||
case 'N': return "\xC2\x85"; // NEL (#x85)
|
case 'N': return "\xC2\x85"; // NEL (#x85)
|
||||||
case '_': return "\xC2\xA0"; // #xA0
|
case '_': return "\xC2\xA0"; // #xA0
|
||||||
case 'L': return "\xE2\x80\xA8"; // LS (#x2028)
|
case 'L': return "\xE2\x80\xA8"; // LS (#x2028)
|
||||||
case 'P': return "\xE2\x80\xA9"; // PS (#x2029)
|
case 'P': return "\xE2\x80\xA9"; // PS (#x2029)
|
||||||
case 'x': return Escape(in, 2);
|
case 'x': return Escape(in, 2);
|
||||||
case 'u': return Escape(in, 4);
|
case 'u': return Escape(in, 4);
|
||||||
case 'U': return Escape(in, 8);
|
case 'U': return Escape(in, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch);
|
throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
142
src/exp.h
142
src/exp.h
@@ -1,71 +1,71 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "regex.h"
|
#include "regex.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Here we store a bunch of expressions for matching different parts of the file.
|
// Here we store a bunch of expressions for matching different parts of the file.
|
||||||
|
|
||||||
namespace Exp
|
namespace Exp
|
||||||
{
|
{
|
||||||
// misc
|
// misc
|
||||||
const RegEx Blank = RegEx(' ') || RegEx('\t');
|
const RegEx Blank = RegEx(' ') || RegEx('\t');
|
||||||
const RegEx Break = RegEx('\n') || RegEx("\r\n");
|
const RegEx Break = RegEx('\n') || RegEx("\r\n");
|
||||||
const RegEx BlankOrBreak = Blank || Break;
|
const RegEx BlankOrBreak = Blank || Break;
|
||||||
const RegEx Digit = RegEx('0', '9');
|
const RegEx Digit = RegEx('0', '9');
|
||||||
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
|
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
|
||||||
const RegEx AlphaNumeric = Alpha || Digit;
|
const RegEx AlphaNumeric = Alpha || Digit;
|
||||||
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
|
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
|
||||||
|
|
||||||
// actual tags
|
// actual tags
|
||||||
|
|
||||||
const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx());
|
const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx());
|
||||||
const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx());
|
const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx());
|
||||||
const RegEx DocIndicator = DocStart || DocEnd;
|
const RegEx DocIndicator = DocStart || DocEnd;
|
||||||
const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF));
|
const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF));
|
||||||
const RegEx Key = RegEx('?'),
|
const RegEx Key = RegEx('?'),
|
||||||
KeyInFlow = RegEx('?') + BlankOrBreak;
|
KeyInFlow = RegEx('?') + BlankOrBreak;
|
||||||
const RegEx Value = RegEx(':') + BlankOrBreak,
|
const RegEx Value = RegEx(':') + BlankOrBreak,
|
||||||
ValueInFlow = RegEx(':') + BlankOrBreak;
|
ValueInFlow = RegEx(':') + BlankOrBreak;
|
||||||
const RegEx Comment = RegEx('#');
|
const RegEx Comment = RegEx('#');
|
||||||
const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak;
|
const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak;
|
||||||
|
|
||||||
// Plain scalar rules:
|
// Plain scalar rules:
|
||||||
// . Cannot start with a blank.
|
// . Cannot start with a blank.
|
||||||
// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ `
|
// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ `
|
||||||
// . In the block context - ? : must be not be followed with a space.
|
// . In the block context - ? : must be not be followed with a space.
|
||||||
// . In the flow context ? is illegal and : and - must not be followed with a space.
|
// . In the flow context ? is illegal and : and - must not be followed with a space.
|
||||||
const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)),
|
const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)),
|
||||||
PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank));
|
PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank));
|
||||||
const RegEx EndScalar = RegEx(':') + BlankOrBreak,
|
const RegEx EndScalar = RegEx(':') + BlankOrBreak,
|
||||||
EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR);
|
EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR);
|
||||||
|
|
||||||
const RegEx EscSingleQuote = RegEx("\'\'");
|
const RegEx EscSingleQuote = RegEx("\'\'");
|
||||||
const RegEx EscBreak = RegEx('\\') + Break;
|
const RegEx EscBreak = RegEx('\\') + Break;
|
||||||
|
|
||||||
const RegEx ChompIndicator = RegEx("+-", REGEX_OR);
|
const RegEx ChompIndicator = RegEx("+-", REGEX_OR);
|
||||||
const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit;
|
const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit;
|
||||||
|
|
||||||
// and some functions
|
// and some functions
|
||||||
std::string Escape(Stream& in);
|
std::string Escape(Stream& in);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Keys
|
namespace Keys
|
||||||
{
|
{
|
||||||
const char Directive = '%';
|
const char Directive = '%';
|
||||||
const char FlowSeqStart = '[';
|
const char FlowSeqStart = '[';
|
||||||
const char FlowSeqEnd = ']';
|
const char FlowSeqEnd = ']';
|
||||||
const char FlowMapStart = '{';
|
const char FlowMapStart = '{';
|
||||||
const char FlowMapEnd = '}';
|
const char FlowMapEnd = '}';
|
||||||
const char FlowEntry = ',';
|
const char FlowEntry = ',';
|
||||||
const char Alias = '*';
|
const char Alias = '*';
|
||||||
const char Anchor = '&';
|
const char Anchor = '&';
|
||||||
const char Tag = '!';
|
const char Tag = '!';
|
||||||
const char LiteralScalar = '|';
|
const char LiteralScalar = '|';
|
||||||
const char FoldedScalar = '>';
|
const char FoldedScalar = '>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
216
src/iterator.cpp
216
src/iterator.cpp
@@ -1,108 +1,108 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "iterpriv.h"
|
#include "iterpriv.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Iterator::Iterator(): m_pData(0)
|
Iterator::Iterator(): m_pData(0)
|
||||||
{
|
{
|
||||||
m_pData = new IterPriv;
|
m_pData = new IterPriv;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator::Iterator(IterPriv *pData): m_pData(pData)
|
Iterator::Iterator(IterPriv *pData): m_pData(pData)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator::Iterator(const Iterator& rhs): m_pData(0)
|
Iterator::Iterator(const Iterator& rhs): m_pData(0)
|
||||||
{
|
{
|
||||||
m_pData = new IterPriv(*rhs.m_pData);
|
m_pData = new IterPriv(*rhs.m_pData);
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator& Iterator::operator = (const Iterator& rhs)
|
Iterator& Iterator::operator = (const Iterator& rhs)
|
||||||
{
|
{
|
||||||
if(this == &rhs)
|
if(this == &rhs)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
delete m_pData;
|
delete m_pData;
|
||||||
m_pData = new IterPriv(*rhs.m_pData);
|
m_pData = new IterPriv(*rhs.m_pData);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator::~Iterator()
|
Iterator::~Iterator()
|
||||||
{
|
{
|
||||||
delete m_pData;
|
delete m_pData;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator& Iterator::operator ++ ()
|
Iterator& Iterator::operator ++ ()
|
||||||
{
|
{
|
||||||
if(m_pData->type == IterPriv::IT_SEQ)
|
if(m_pData->type == IterPriv::IT_SEQ)
|
||||||
++m_pData->seqIter;
|
++m_pData->seqIter;
|
||||||
else if(m_pData->type == IterPriv::IT_MAP)
|
else if(m_pData->type == IterPriv::IT_MAP)
|
||||||
++m_pData->mapIter;
|
++m_pData->mapIter;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator Iterator::operator ++ (int)
|
Iterator Iterator::operator ++ (int)
|
||||||
{
|
{
|
||||||
Iterator temp = *this;
|
Iterator temp = *this;
|
||||||
|
|
||||||
if(m_pData->type == IterPriv::IT_SEQ)
|
if(m_pData->type == IterPriv::IT_SEQ)
|
||||||
++m_pData->seqIter;
|
++m_pData->seqIter;
|
||||||
else if(m_pData->type == IterPriv::IT_MAP)
|
else if(m_pData->type == IterPriv::IT_MAP)
|
||||||
++m_pData->mapIter;
|
++m_pData->mapIter;
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Iterator::operator * () const
|
const Node& Iterator::operator * () const
|
||||||
{
|
{
|
||||||
if(m_pData->type == IterPriv::IT_SEQ)
|
if(m_pData->type == IterPriv::IT_SEQ)
|
||||||
return **m_pData->seqIter;
|
return **m_pData->seqIter;
|
||||||
|
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node *Iterator::operator -> () const
|
const Node *Iterator::operator -> () const
|
||||||
{
|
{
|
||||||
if(m_pData->type == IterPriv::IT_SEQ)
|
if(m_pData->type == IterPriv::IT_SEQ)
|
||||||
return *m_pData->seqIter;
|
return *m_pData->seqIter;
|
||||||
|
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Iterator::first() const
|
const Node& Iterator::first() const
|
||||||
{
|
{
|
||||||
if(m_pData->type == IterPriv::IT_MAP)
|
if(m_pData->type == IterPriv::IT_MAP)
|
||||||
return *m_pData->mapIter->first;
|
return *m_pData->mapIter->first;
|
||||||
|
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Iterator::second() const
|
const Node& Iterator::second() const
|
||||||
{
|
{
|
||||||
if(m_pData->type == IterPriv::IT_MAP)
|
if(m_pData->type == IterPriv::IT_MAP)
|
||||||
return *m_pData->mapIter->second;
|
return *m_pData->mapIter->second;
|
||||||
|
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator == (const Iterator& it, const Iterator& jt)
|
bool operator == (const Iterator& it, const Iterator& jt)
|
||||||
{
|
{
|
||||||
if(it.m_pData->type != jt.m_pData->type)
|
if(it.m_pData->type != jt.m_pData->type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(it.m_pData->type == IterPriv::IT_SEQ)
|
if(it.m_pData->type == IterPriv::IT_SEQ)
|
||||||
return it.m_pData->seqIter == jt.m_pData->seqIter;
|
return it.m_pData->seqIter == jt.m_pData->seqIter;
|
||||||
else if(it.m_pData->type == IterPriv::IT_MAP)
|
else if(it.m_pData->type == IterPriv::IT_MAP)
|
||||||
return it.m_pData->mapIter == jt.m_pData->mapIter;
|
return it.m_pData->mapIter == jt.m_pData->mapIter;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator != (const Iterator& it, const Iterator& jt)
|
bool operator != (const Iterator& it, const Iterator& jt)
|
||||||
{
|
{
|
||||||
return !(it == jt);
|
return !(it == jt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ltnode.h"
|
#include "ltnode.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
// IterPriv
|
// IterPriv
|
||||||
// . The implementation for iterators - essentially a union of sequence and map iterators.
|
// . The implementation for iterators - essentially a union of sequence and map iterators.
|
||||||
struct IterPriv
|
struct IterPriv
|
||||||
{
|
{
|
||||||
IterPriv(): type(IT_NONE) {}
|
IterPriv(): type(IT_NONE) {}
|
||||||
IterPriv(std::vector <Node *>::const_iterator it): type(IT_SEQ), seqIter(it) {}
|
IterPriv(std::vector <Node *>::const_iterator it): type(IT_SEQ), seqIter(it) {}
|
||||||
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): type(IT_MAP), mapIter(it) {}
|
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): type(IT_MAP), mapIter(it) {}
|
||||||
|
|
||||||
enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP };
|
enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP };
|
||||||
ITER_TYPE type;
|
ITER_TYPE type;
|
||||||
|
|
||||||
std::vector <Node *>::const_iterator seqIter;
|
std::vector <Node *>::const_iterator seqIter;
|
||||||
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
|
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
20
src/ltnode.h
20
src/ltnode.h
@@ -1,10 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
struct ltnode {
|
struct ltnode {
|
||||||
bool operator()(const Node *pNode1, const Node *pNode2) const;
|
bool operator()(const Node *pNode1, const Node *pNode2) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
392
src/map.cpp
392
src/map.cpp
@@ -1,196 +1,196 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Map::Map()
|
Map::Map()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Map::~Map()
|
Map::~Map()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::Clear()
|
void Map::Clear()
|
||||||
{
|
{
|
||||||
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
|
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
|
||||||
delete it->first;
|
delete it->first;
|
||||||
delete it->second;
|
delete it->second;
|
||||||
}
|
}
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
|
bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
|
||||||
{
|
{
|
||||||
it = m_data.begin();
|
it = m_data.begin();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const
|
bool Map::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const
|
||||||
{
|
{
|
||||||
it = m_data.end();
|
it = m_data.end();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::Parse(Scanner *pScanner, const ParserState& state)
|
void Map::Parse(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
// split based on start token
|
// split based on start token
|
||||||
switch(pScanner->peek().type) {
|
switch(pScanner->peek().type) {
|
||||||
case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break;
|
case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break;
|
||||||
case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break;
|
case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::ParseBlock(Scanner *pScanner, const ParserState& state)
|
void Map::ParseBlock(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
// eat start token
|
// eat start token
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(pScanner->empty())
|
if(pScanner->empty())
|
||||||
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP);
|
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP);
|
||||||
|
|
||||||
Token token = pScanner->peek();
|
Token token = pScanner->peek();
|
||||||
if(token.type != TT_KEY && token.type != TT_BLOCK_END)
|
if(token.type != TT_KEY && token.type != TT_BLOCK_END)
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP);
|
throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP);
|
||||||
|
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
if(token.type == TT_BLOCK_END)
|
if(token.type == TT_BLOCK_END)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Node *pKey = new Node;
|
Node *pKey = new Node;
|
||||||
Node *pValue = new Node;
|
Node *pValue = new Node;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// grab key
|
// grab key
|
||||||
pKey->Parse(pScanner, state);
|
pKey->Parse(pScanner, state);
|
||||||
|
|
||||||
// now grab value (optional)
|
// now grab value (optional)
|
||||||
if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
|
if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
pValue->Parse(pScanner, state);
|
pValue->Parse(pScanner, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data[pKey] = pValue;
|
m_data[pKey] = pValue;
|
||||||
} catch(Exception& e) {
|
} catch(Exception& e) {
|
||||||
delete pKey;
|
delete pKey;
|
||||||
delete pValue;
|
delete pValue;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::ParseFlow(Scanner *pScanner, const ParserState& state)
|
void Map::ParseFlow(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
// eat start token
|
// eat start token
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(pScanner->empty())
|
if(pScanner->empty())
|
||||||
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW);
|
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW);
|
||||||
|
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
// first check for end
|
// first check for end
|
||||||
if(token.type == TT_FLOW_MAP_END) {
|
if(token.type == TT_FLOW_MAP_END) {
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now it better be a key
|
// now it better be a key
|
||||||
if(token.type != TT_KEY)
|
if(token.type != TT_KEY)
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW);
|
throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW);
|
||||||
|
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
|
|
||||||
Node *pKey = new Node;
|
Node *pKey = new Node;
|
||||||
Node *pValue = new Node;
|
Node *pValue = new Node;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// grab key
|
// grab key
|
||||||
pKey->Parse(pScanner, state);
|
pKey->Parse(pScanner, state);
|
||||||
|
|
||||||
// now grab value (optional)
|
// now grab value (optional)
|
||||||
if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
|
if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
pValue->Parse(pScanner, state);
|
pValue->Parse(pScanner, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
|
// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
|
||||||
Token& nextToken = pScanner->peek();
|
Token& nextToken = pScanner->peek();
|
||||||
if(nextToken.type == TT_FLOW_ENTRY)
|
if(nextToken.type == TT_FLOW_ENTRY)
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
else if(nextToken.type != TT_FLOW_MAP_END)
|
else if(nextToken.type != TT_FLOW_MAP_END)
|
||||||
throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW);
|
throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW);
|
||||||
|
|
||||||
m_data[pKey] = pValue;
|
m_data[pKey] = pValue;
|
||||||
} catch(Exception& e) {
|
} catch(Exception& e) {
|
||||||
// clean up and rethrow
|
// clean up and rethrow
|
||||||
delete pKey;
|
delete pKey;
|
||||||
delete pValue;
|
delete pValue;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
||||||
{
|
{
|
||||||
if(startedLine && !onlyOneCharOnLine)
|
if(startedLine && !onlyOneCharOnLine)
|
||||||
out << "\n";
|
out << "\n";
|
||||||
|
|
||||||
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
|
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
|
||||||
if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) {
|
if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) {
|
||||||
for(int i=0;i<indent;i++)
|
for(int i=0;i<indent;i++)
|
||||||
out << " ";
|
out << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "? ";
|
out << "? ";
|
||||||
it->first->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine);
|
it->first->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine);
|
||||||
|
|
||||||
for(int i=0;i<indent;i++)
|
for(int i=0;i<indent;i++)
|
||||||
out << " ";
|
out << " ";
|
||||||
out << ": ";
|
out << ": ";
|
||||||
it->second->Write(out, indent + 1, true, true);
|
it->second->Write(out, indent + 1, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_data.empty())
|
if(m_data.empty())
|
||||||
out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
int Map::Compare(Content *pContent)
|
int Map::Compare(Content *pContent)
|
||||||
{
|
{
|
||||||
return -pContent->Compare(this);
|
return -pContent->Compare(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Map::Compare(Map *pMap)
|
int Map::Compare(Map *pMap)
|
||||||
{
|
{
|
||||||
node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin();
|
node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin();
|
||||||
while(1) {
|
while(1) {
|
||||||
if(it == m_data.end()) {
|
if(it == m_data.end()) {
|
||||||
if(jt == pMap->m_data.end())
|
if(jt == pMap->m_data.end())
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(jt == pMap->m_data.end())
|
if(jt == pMap->m_data.end())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
int cmp = it->first->Compare(*jt->first);
|
int cmp = it->first->Compare(*jt->first);
|
||||||
if(cmp != 0)
|
if(cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
|
|
||||||
cmp = it->second->Compare(*jt->second);
|
cmp = it->second->Compare(*jt->second);
|
||||||
if(cmp != 0)
|
if(cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
76
src/map.h
76
src/map.h
@@ -1,38 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "content.h"
|
#include "content.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
class Map: public Content
|
class Map: public Content
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Map();
|
Map();
|
||||||
virtual ~Map();
|
virtual ~Map();
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
|
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
|
||||||
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
|
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
|
||||||
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
||||||
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
||||||
|
|
||||||
virtual bool IsMap() const { return true; }
|
virtual bool IsMap() const { return true; }
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
virtual int Compare(Content *pContent);
|
virtual int Compare(Content *pContent);
|
||||||
virtual int Compare(Scalar *pScalar) { return 1; }
|
virtual int Compare(Scalar *pScalar) { return 1; }
|
||||||
virtual int Compare(Sequence *pSeq) { return 1; }
|
virtual int Compare(Sequence *pSeq) { return 1; }
|
||||||
virtual int Compare(Map *pMap);
|
virtual int Compare(Map *pMap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ParseBlock(Scanner *pScanner, const ParserState& state);
|
void ParseBlock(Scanner *pScanner, const ParserState& state);
|
||||||
void ParseFlow(Scanner *pScanner, const ParserState& state);
|
void ParseFlow(Scanner *pScanner, const ParserState& state);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::map <Node *, Node *, ltnode> node_map;
|
typedef std::map <Node *, Node *, ltnode> node_map;
|
||||||
node_map m_data;
|
node_map m_data;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
634
src/node.cpp
634
src/node.cpp
@@ -1,317 +1,317 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "content.h"
|
#include "content.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "scalar.h"
|
#include "scalar.h"
|
||||||
#include "sequence.h"
|
#include "sequence.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "iterpriv.h"
|
#include "iterpriv.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
// the ordering!
|
// the ordering!
|
||||||
bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const
|
bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const
|
||||||
{
|
{
|
||||||
return *pNode1 < *pNode2;
|
return *pNode1 < *pNode2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::Node(): m_pContent(0), m_alias(false)
|
Node::Node(): m_pContent(0), m_alias(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::~Node()
|
Node::~Node()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::Clear()
|
void Node::Clear()
|
||||||
{
|
{
|
||||||
delete m_pContent;
|
delete m_pContent;
|
||||||
m_pContent = 0;
|
m_pContent = 0;
|
||||||
m_alias = false;
|
m_alias = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::Parse(Scanner *pScanner, const ParserState& state)
|
void Node::Parse(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
ParseHeader(pScanner, state);
|
ParseHeader(pScanner, state);
|
||||||
|
|
||||||
// is this an alias? if so, it can have no content
|
// is this an alias? if so, it can have no content
|
||||||
if(m_alias)
|
if(m_alias)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// now split based on what kind of node we should be
|
// now split based on what kind of node we should be
|
||||||
switch(pScanner->peek().type) {
|
switch(pScanner->peek().type) {
|
||||||
case TT_SCALAR:
|
case TT_SCALAR:
|
||||||
m_pContent = new Scalar;
|
m_pContent = new Scalar;
|
||||||
m_pContent->Parse(pScanner, state);
|
m_pContent->Parse(pScanner, state);
|
||||||
break;
|
break;
|
||||||
case TT_FLOW_SEQ_START:
|
case TT_FLOW_SEQ_START:
|
||||||
case TT_BLOCK_SEQ_START:
|
case TT_BLOCK_SEQ_START:
|
||||||
case TT_BLOCK_ENTRY:
|
case TT_BLOCK_ENTRY:
|
||||||
m_pContent = new Sequence;
|
m_pContent = new Sequence;
|
||||||
m_pContent->Parse(pScanner, state);
|
m_pContent->Parse(pScanner, state);
|
||||||
break;
|
break;
|
||||||
case TT_FLOW_MAP_START:
|
case TT_FLOW_MAP_START:
|
||||||
case TT_BLOCK_MAP_START:
|
case TT_BLOCK_MAP_START:
|
||||||
m_pContent = new Map;
|
m_pContent = new Map;
|
||||||
m_pContent->Parse(pScanner, state);
|
m_pContent->Parse(pScanner, state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseHeader
|
// ParseHeader
|
||||||
// . Grabs any tag, alias, or anchor tokens and deals with them.
|
// . Grabs any tag, alias, or anchor tokens and deals with them.
|
||||||
void Node::ParseHeader(Scanner *pScanner, const ParserState& state)
|
void Node::ParseHeader(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
if(pScanner->empty())
|
if(pScanner->empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch(pScanner->peek().type) {
|
switch(pScanner->peek().type) {
|
||||||
case TT_TAG: ParseTag(pScanner, state); break;
|
case TT_TAG: ParseTag(pScanner, state); break;
|
||||||
case TT_ANCHOR: ParseAnchor(pScanner, state); break;
|
case TT_ANCHOR: ParseAnchor(pScanner, state); break;
|
||||||
case TT_ALIAS: ParseAlias(pScanner, state); break;
|
case TT_ALIAS: ParseAlias(pScanner, state); break;
|
||||||
default: return;
|
default: return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::ParseTag(Scanner *pScanner, const ParserState& state)
|
void Node::ParseTag(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
if(m_tag != "")
|
if(m_tag != "")
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS);
|
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS);
|
||||||
|
|
||||||
m_tag = state.TranslateTag(token.value);
|
m_tag = state.TranslateTag(token.value);
|
||||||
|
|
||||||
for(unsigned i=0;i<token.params.size();i++)
|
for(unsigned i=0;i<token.params.size();i++)
|
||||||
m_tag += token.params[i];
|
m_tag += token.params[i];
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::ParseAnchor(Scanner *pScanner, const ParserState& state)
|
void Node::ParseAnchor(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
if(m_anchor != "")
|
if(m_anchor != "")
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS);
|
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS);
|
||||||
|
|
||||||
m_anchor = token.value;
|
m_anchor = token.value;
|
||||||
m_alias = false;
|
m_alias = false;
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::ParseAlias(Scanner *pScanner, const ParserState& state)
|
void Node::ParseAlias(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
if(m_anchor != "")
|
if(m_anchor != "")
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES);
|
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES);
|
||||||
if(m_tag != "")
|
if(m_tag != "")
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT);
|
throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT);
|
||||||
|
|
||||||
m_anchor = token.value;
|
m_anchor = token.value;
|
||||||
m_alias = true;
|
m_alias = true;
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const
|
void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const
|
||||||
{
|
{
|
||||||
// write anchor/alias
|
// write anchor/alias
|
||||||
if(m_anchor != "") {
|
if(m_anchor != "") {
|
||||||
if(m_alias)
|
if(m_alias)
|
||||||
out << std::string("*");
|
out << std::string("*");
|
||||||
else
|
else
|
||||||
out << std::string("&");
|
out << std::string("&");
|
||||||
out << m_anchor << std::string(" ");
|
out << m_anchor << std::string(" ");
|
||||||
startedLine = true;
|
startedLine = true;
|
||||||
onlyOneCharOnLine = false;
|
onlyOneCharOnLine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write tag
|
// write tag
|
||||||
if(m_tag != "") {
|
if(m_tag != "") {
|
||||||
out << std::string("!<") << m_tag << std::string("> ");
|
out << std::string("!<") << m_tag << std::string("> ");
|
||||||
startedLine = true;
|
startedLine = true;
|
||||||
onlyOneCharOnLine = false;
|
onlyOneCharOnLine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_pContent) {
|
if(!m_pContent) {
|
||||||
out << std::string("\n");
|
out << std::string("\n");
|
||||||
} else {
|
} else {
|
||||||
m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine);
|
m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CONTENT_TYPE Node::GetType() const
|
CONTENT_TYPE Node::GetType() const
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
return CT_NONE;
|
return CT_NONE;
|
||||||
|
|
||||||
if(m_pContent->IsScalar())
|
if(m_pContent->IsScalar())
|
||||||
return CT_SCALAR;
|
return CT_SCALAR;
|
||||||
else if(m_pContent->IsSequence())
|
else if(m_pContent->IsSequence())
|
||||||
return CT_SEQUENCE;
|
return CT_SEQUENCE;
|
||||||
else if(m_pContent->IsMap())
|
else if(m_pContent->IsMap())
|
||||||
return CT_MAP;
|
return CT_MAP;
|
||||||
|
|
||||||
return CT_NONE;
|
return CT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin
|
// begin
|
||||||
// Returns an iterator to the beginning of this (sequence or map).
|
// Returns an iterator to the beginning of this (sequence or map).
|
||||||
Iterator Node::begin() const
|
Iterator Node::begin() const
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
return Iterator();
|
return Iterator();
|
||||||
|
|
||||||
std::vector <Node *>::const_iterator seqIter;
|
std::vector <Node *>::const_iterator seqIter;
|
||||||
if(m_pContent->GetBegin(seqIter))
|
if(m_pContent->GetBegin(seqIter))
|
||||||
return Iterator(new IterPriv(seqIter));
|
return Iterator(new IterPriv(seqIter));
|
||||||
|
|
||||||
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
|
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
|
||||||
if(m_pContent->GetBegin(mapIter))
|
if(m_pContent->GetBegin(mapIter))
|
||||||
return Iterator(new IterPriv(mapIter));
|
return Iterator(new IterPriv(mapIter));
|
||||||
|
|
||||||
return Iterator();
|
return Iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
// end
|
// end
|
||||||
// . Returns an iterator to the end of this (sequence or map).
|
// . Returns an iterator to the end of this (sequence or map).
|
||||||
Iterator Node::end() const
|
Iterator Node::end() const
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
return Iterator();
|
return Iterator();
|
||||||
|
|
||||||
std::vector <Node *>::const_iterator seqIter;
|
std::vector <Node *>::const_iterator seqIter;
|
||||||
if(m_pContent->GetEnd(seqIter))
|
if(m_pContent->GetEnd(seqIter))
|
||||||
return Iterator(new IterPriv(seqIter));
|
return Iterator(new IterPriv(seqIter));
|
||||||
|
|
||||||
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
|
std::map <Node *, Node *, ltnode>::const_iterator mapIter;
|
||||||
if(m_pContent->GetEnd(mapIter))
|
if(m_pContent->GetEnd(mapIter))
|
||||||
return Iterator(new IterPriv(mapIter));
|
return Iterator(new IterPriv(mapIter));
|
||||||
|
|
||||||
return Iterator();
|
return Iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
// size
|
// size
|
||||||
// . Returns the size of this node, if it's a sequence node.
|
// . Returns the size of this node, if it's a sequence node.
|
||||||
// . Otherwise, returns zero.
|
// . Otherwise, returns zero.
|
||||||
unsigned Node::size() const
|
unsigned Node::size() const
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return m_pContent->GetSize();
|
return m_pContent->GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Node::operator [] (unsigned u) const
|
const Node& Node::operator [] (unsigned u) const
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
|
|
||||||
Node *pNode = m_pContent->GetNode(u);
|
Node *pNode = m_pContent->GetNode(u);
|
||||||
if(pNode)
|
if(pNode)
|
||||||
return *pNode;
|
return *pNode;
|
||||||
|
|
||||||
return GetValue(u);
|
return GetValue(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Node::operator [] (int i) const
|
const Node& Node::operator [] (int i) const
|
||||||
{
|
{
|
||||||
if(!m_pContent)
|
if(!m_pContent)
|
||||||
throw BadDereference();
|
throw BadDereference();
|
||||||
|
|
||||||
Node *pNode = m_pContent->GetNode(i);
|
Node *pNode = m_pContent->GetNode(i);
|
||||||
if(pNode)
|
if(pNode)
|
||||||
return *pNode;
|
return *pNode;
|
||||||
|
|
||||||
return GetValue(i);
|
return GetValue(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// Extraction
|
// Extraction
|
||||||
|
|
||||||
void operator >> (const Node& node, std::string& s)
|
void operator >> (const Node& node, std::string& s)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(s);
|
node.m_pContent->Read(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator >> (const Node& node, int& i)
|
void operator >> (const Node& node, int& i)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(i);
|
node.m_pContent->Read(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator >> (const Node& node, unsigned& u)
|
void operator >> (const Node& node, unsigned& u)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(u);
|
node.m_pContent->Read(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator >> (const Node& node, long& l)
|
void operator >> (const Node& node, long& l)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(l);
|
node.m_pContent->Read(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator >> (const Node& node, float& f)
|
void operator >> (const Node& node, float& f)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(f);
|
node.m_pContent->Read(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator >> (const Node& node, double& d)
|
void operator >> (const Node& node, double& d)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(d);
|
node.m_pContent->Read(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator >> (const Node& node, char& c)
|
void operator >> (const Node& node, char& c)
|
||||||
{
|
{
|
||||||
if(!node.m_pContent)
|
if(!node.m_pContent)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
node.m_pContent->Read(c);
|
node.m_pContent->Read(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator << (std::ostream& out, const Node& node)
|
std::ostream& operator << (std::ostream& out, const Node& node)
|
||||||
{
|
{
|
||||||
node.Write(out, 0, false, false);
|
node.Write(out, 0, false, false);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Node::Compare(const Node& rhs) const
|
int Node::Compare(const Node& rhs) const
|
||||||
{
|
{
|
||||||
// Step 1: no content is the smallest
|
// Step 1: no content is the smallest
|
||||||
if(!m_pContent) {
|
if(!m_pContent) {
|
||||||
if(rhs.m_pContent)
|
if(rhs.m_pContent)
|
||||||
return -1;
|
return -1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(!rhs.m_pContent)
|
if(!rhs.m_pContent)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return m_pContent->Compare(rhs.m_pContent);
|
return m_pContent->Compare(rhs.m_pContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator < (const Node& n1, const Node& n2)
|
bool operator < (const Node& n1, const Node& n2)
|
||||||
{
|
{
|
||||||
return n1.Compare(n2) < 0;
|
return n1.Compare(n2) < 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
266
src/parser.cpp
266
src/parser.cpp
@@ -1,133 +1,133 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Parser::Parser(std::istream& in): m_pScanner(0)
|
Parser::Parser(std::istream& in): m_pScanner(0)
|
||||||
{
|
{
|
||||||
Load(in);
|
Load(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::~Parser()
|
Parser::~Parser()
|
||||||
{
|
{
|
||||||
delete m_pScanner;
|
delete m_pScanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::operator bool() const
|
Parser::operator bool() const
|
||||||
{
|
{
|
||||||
return !m_pScanner->empty();
|
return !m_pScanner->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::Load(std::istream& in)
|
void Parser::Load(std::istream& in)
|
||||||
{
|
{
|
||||||
delete m_pScanner;
|
delete m_pScanner;
|
||||||
m_pScanner = new Scanner(in);
|
m_pScanner = new Scanner(in);
|
||||||
m_state.Reset();
|
m_state.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNextDocument
|
// GetNextDocument
|
||||||
// . Reads the next document in the queue (of tokens).
|
// . Reads the next document in the queue (of tokens).
|
||||||
// . Throws a ParserException on error.
|
// . Throws a ParserException on error.
|
||||||
void Parser::GetNextDocument(Node& document)
|
void Parser::GetNextDocument(Node& document)
|
||||||
{
|
{
|
||||||
// clear node
|
// clear node
|
||||||
document.Clear();
|
document.Clear();
|
||||||
|
|
||||||
// first read directives
|
// first read directives
|
||||||
ParseDirectives();
|
ParseDirectives();
|
||||||
|
|
||||||
// we better have some tokens in the queue
|
// we better have some tokens in the queue
|
||||||
if(m_pScanner->empty())
|
if(m_pScanner->empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// first eat doc start (optional)
|
// first eat doc start (optional)
|
||||||
if(m_pScanner->peek().type == TT_DOC_START)
|
if(m_pScanner->peek().type == TT_DOC_START)
|
||||||
m_pScanner->pop();
|
m_pScanner->pop();
|
||||||
|
|
||||||
// now parse our root node
|
// now parse our root node
|
||||||
document.Parse(m_pScanner, m_state);
|
document.Parse(m_pScanner, m_state);
|
||||||
|
|
||||||
// and finally eat any doc ends we see
|
// and finally eat any doc ends we see
|
||||||
while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
|
while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
|
||||||
m_pScanner->pop();
|
m_pScanner->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDirectives
|
// ParseDirectives
|
||||||
// . Reads any directives that are next in the queue.
|
// . Reads any directives that are next in the queue.
|
||||||
void Parser::ParseDirectives()
|
void Parser::ParseDirectives()
|
||||||
{
|
{
|
||||||
bool readDirective = false;
|
bool readDirective = false;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(m_pScanner->empty())
|
if(m_pScanner->empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Token& token = m_pScanner->peek();
|
Token& token = m_pScanner->peek();
|
||||||
if(token.type != TT_DIRECTIVE)
|
if(token.type != TT_DIRECTIVE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// we keep the directives from the last document if none are specified;
|
// we keep the directives from the last document if none are specified;
|
||||||
// but if any directives are specific, then we reset them
|
// but if any directives are specific, then we reset them
|
||||||
if(!readDirective)
|
if(!readDirective)
|
||||||
m_state.Reset();
|
m_state.Reset();
|
||||||
|
|
||||||
readDirective = true;
|
readDirective = true;
|
||||||
HandleDirective(&token);
|
HandleDirective(&token);
|
||||||
m_pScanner->pop();
|
m_pScanner->pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::HandleDirective(Token *pToken)
|
void Parser::HandleDirective(Token *pToken)
|
||||||
{
|
{
|
||||||
if(pToken->value == "YAML")
|
if(pToken->value == "YAML")
|
||||||
HandleYamlDirective(pToken);
|
HandleYamlDirective(pToken);
|
||||||
else if(pToken->value == "TAG")
|
else if(pToken->value == "TAG")
|
||||||
HandleTagDirective(pToken);
|
HandleTagDirective(pToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleYamlDirective
|
// HandleYamlDirective
|
||||||
// . Should be of the form 'major.minor' (like a version number)
|
// . Should be of the form 'major.minor' (like a version number)
|
||||||
void Parser::HandleYamlDirective(Token *pToken)
|
void Parser::HandleYamlDirective(Token *pToken)
|
||||||
{
|
{
|
||||||
if(pToken->params.size() != 1)
|
if(pToken->params.size() != 1)
|
||||||
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS);
|
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS);
|
||||||
|
|
||||||
std::stringstream str(pToken->params[0]);
|
std::stringstream str(pToken->params[0]);
|
||||||
str >> m_state.version.major;
|
str >> m_state.version.major;
|
||||||
str.get();
|
str.get();
|
||||||
str >> m_state.version.minor;
|
str >> m_state.version.minor;
|
||||||
if(!str || str.peek() != EOF)
|
if(!str || str.peek() != EOF)
|
||||||
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]);
|
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]);
|
||||||
|
|
||||||
if(m_state.version.major > 1)
|
if(m_state.version.major > 1)
|
||||||
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION);
|
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION);
|
||||||
|
|
||||||
// TODO: warning on major == 1, minor > 2?
|
// TODO: warning on major == 1, minor > 2?
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleTagDirective
|
// HandleTagDirective
|
||||||
// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
|
// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
|
||||||
void Parser::HandleTagDirective(Token *pToken)
|
void Parser::HandleTagDirective(Token *pToken)
|
||||||
{
|
{
|
||||||
if(pToken->params.size() != 2)
|
if(pToken->params.size() != 2)
|
||||||
throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS);
|
throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS);
|
||||||
|
|
||||||
std::string handle = pToken->params[0], prefix = pToken->params[1];
|
std::string handle = pToken->params[0], prefix = pToken->params[1];
|
||||||
m_state.tags[handle] = prefix;
|
m_state.tags[handle] = prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::PrintTokens(std::ostream& out)
|
void Parser::PrintTokens(std::ostream& out)
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
if(m_pScanner->empty())
|
if(m_pScanner->empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
out << m_pScanner->peek() << "\n";
|
out << m_pScanner->peek() << "\n";
|
||||||
m_pScanner->pop();
|
m_pScanner->pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,26 +1,26 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "parserstate.h"
|
#include "parserstate.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
void ParserState::Reset()
|
void ParserState::Reset()
|
||||||
{
|
{
|
||||||
// version
|
// version
|
||||||
version.major = 1;
|
version.major = 1;
|
||||||
version.minor = 2;
|
version.minor = 2;
|
||||||
|
|
||||||
// and tags
|
// and tags
|
||||||
tags.clear();
|
tags.clear();
|
||||||
tags["!"] = "!";
|
tags["!"] = "!";
|
||||||
tags["!!"] = "tag:yaml.org,2002:";
|
tags["!!"] = "tag:yaml.org,2002:";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ParserState::TranslateTag(const std::string& handle) const
|
std::string ParserState::TranslateTag(const std::string& handle) const
|
||||||
{
|
{
|
||||||
std::map <std::string, std::string>::const_iterator it = tags.find(handle);
|
std::map <std::string, std::string>::const_iterator it = tags.find(handle);
|
||||||
if(it == tags.end())
|
if(it == tags.end())
|
||||||
return handle;
|
return handle;
|
||||||
|
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
612
src/regex.cpp
612
src/regex.cpp
@@ -1,306 +1,306 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "regex.h"
|
#include "regex.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0)
|
RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0)
|
||||||
{
|
{
|
||||||
SetOp();
|
SetOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx::RegEx(const RegEx& rhs): m_pOp(0)
|
RegEx::RegEx(const RegEx& rhs): m_pOp(0)
|
||||||
{
|
{
|
||||||
m_op = rhs.m_op;
|
m_op = rhs.m_op;
|
||||||
m_a = rhs.m_a;
|
m_a = rhs.m_a;
|
||||||
m_z = rhs.m_z;
|
m_z = rhs.m_z;
|
||||||
m_params = rhs.m_params;
|
m_params = rhs.m_params;
|
||||||
|
|
||||||
SetOp();
|
SetOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0)
|
RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0)
|
||||||
{
|
{
|
||||||
SetOp();
|
SetOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch)
|
RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch)
|
||||||
{
|
{
|
||||||
SetOp();
|
SetOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z)
|
RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z)
|
||||||
{
|
{
|
||||||
SetOp();
|
SetOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0)
|
RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0)
|
||||||
{
|
{
|
||||||
for(unsigned i=0;i<str.size();i++)
|
for(unsigned i=0;i<str.size();i++)
|
||||||
m_params.push_back(RegEx(str[i]));
|
m_params.push_back(RegEx(str[i]));
|
||||||
|
|
||||||
SetOp();
|
SetOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx::~RegEx()
|
RegEx::~RegEx()
|
||||||
{
|
{
|
||||||
delete m_pOp;
|
delete m_pOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx& RegEx::operator = (const RegEx& rhs)
|
RegEx& RegEx::operator = (const RegEx& rhs)
|
||||||
{
|
{
|
||||||
delete m_pOp;
|
delete m_pOp;
|
||||||
m_pOp = 0;
|
m_pOp = 0;
|
||||||
|
|
||||||
m_op = rhs.m_op;
|
m_op = rhs.m_op;
|
||||||
m_a = rhs.m_a;
|
m_a = rhs.m_a;
|
||||||
m_z = rhs.m_z;
|
m_z = rhs.m_z;
|
||||||
m_params = rhs.m_params;
|
m_params = rhs.m_params;
|
||||||
|
|
||||||
SetOp();
|
SetOp();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegEx::SetOp()
|
void RegEx::SetOp()
|
||||||
{
|
{
|
||||||
delete m_pOp;
|
delete m_pOp;
|
||||||
m_pOp = 0;
|
m_pOp = 0;
|
||||||
switch(m_op) {
|
switch(m_op) {
|
||||||
case REGEX_MATCH: m_pOp = new MatchOperator; break;
|
case REGEX_MATCH: m_pOp = new MatchOperator; break;
|
||||||
case REGEX_RANGE: m_pOp = new RangeOperator; break;
|
case REGEX_RANGE: m_pOp = new RangeOperator; break;
|
||||||
case REGEX_OR: m_pOp = new OrOperator; break;
|
case REGEX_OR: m_pOp = new OrOperator; break;
|
||||||
case REGEX_AND: m_pOp = new AndOperator; break;
|
case REGEX_AND: m_pOp = new AndOperator; break;
|
||||||
case REGEX_NOT: m_pOp = new NotOperator; break;
|
case REGEX_NOT: m_pOp = new NotOperator; break;
|
||||||
case REGEX_SEQ: m_pOp = new SeqOperator; break;
|
case REGEX_SEQ: m_pOp = new SeqOperator; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegEx::Matches(char ch) const
|
bool RegEx::Matches(char ch) const
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
str += ch;
|
str += ch;
|
||||||
return Matches(str);
|
return Matches(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegEx::Matches(const std::string& str) const
|
bool RegEx::Matches(const std::string& str) const
|
||||||
{
|
{
|
||||||
return Match(str) >= 0;
|
return Match(str) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegEx::Matches(std::istream& in) const
|
bool RegEx::Matches(std::istream& in) const
|
||||||
{
|
{
|
||||||
return Match(in) >= 0;
|
return Match(in) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RegEx::Matches(Stream& in) const
|
bool RegEx::Matches(Stream& in) const
|
||||||
{
|
{
|
||||||
return Match(in) >= 0;
|
return Match(in) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match
|
// Match
|
||||||
// . Matches the given string against this regular expression.
|
// . Matches the given string against this regular expression.
|
||||||
// . Returns the number of characters matched.
|
// . Returns the number of characters matched.
|
||||||
// . Returns -1 if no characters were matched (the reason for
|
// . Returns -1 if no characters were matched (the reason for
|
||||||
// not returning zero is that we may have an empty regex
|
// not returning zero is that we may have an empty regex
|
||||||
// which is ALWAYS successful at matching zero characters).
|
// which is ALWAYS successful at matching zero characters).
|
||||||
int RegEx::Match(const std::string& str) const
|
int RegEx::Match(const std::string& str) const
|
||||||
{
|
{
|
||||||
if(!m_pOp)
|
if(!m_pOp)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return m_pOp->Match(str, *this);
|
return m_pOp->Match(str, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match
|
// Match
|
||||||
int RegEx::Match(Stream& in) const
|
int RegEx::Match(Stream& in) const
|
||||||
{
|
{
|
||||||
return Match(in.stream());
|
return Match(in.stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match
|
// Match
|
||||||
// . The stream version does the same thing as the string version;
|
// . The stream version does the same thing as the string version;
|
||||||
// REMEMBER that we only match from the start of the stream!
|
// REMEMBER that we only match from the start of the stream!
|
||||||
// . Note: the istream is not a const reference, but we guarantee
|
// . Note: the istream is not a const reference, but we guarantee
|
||||||
// that the pointer will be in the same spot, and we'll clear its
|
// that the pointer will be in the same spot, and we'll clear its
|
||||||
// flags before we end.
|
// flags before we end.
|
||||||
int RegEx::Match(std::istream& in) const
|
int RegEx::Match(std::istream& in) const
|
||||||
{
|
{
|
||||||
if(!m_pOp)
|
if(!m_pOp)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int pos = in.tellg();
|
int pos = in.tellg();
|
||||||
int ret = m_pOp->Match(in, *this);
|
int ret = m_pOp->Match(in, *this);
|
||||||
|
|
||||||
// reset input stream!
|
// reset input stream!
|
||||||
in.clear();
|
in.clear();
|
||||||
in.seekg(pos);
|
in.seekg(pos);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx operator ! (const RegEx& ex)
|
RegEx operator ! (const RegEx& ex)
|
||||||
{
|
{
|
||||||
RegEx ret(REGEX_NOT);
|
RegEx ret(REGEX_NOT);
|
||||||
ret.m_params.push_back(ex);
|
ret.m_params.push_back(ex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx operator || (const RegEx& ex1, const RegEx& ex2)
|
RegEx operator || (const RegEx& ex1, const RegEx& ex2)
|
||||||
{
|
{
|
||||||
RegEx ret(REGEX_OR);
|
RegEx ret(REGEX_OR);
|
||||||
ret.m_params.push_back(ex1);
|
ret.m_params.push_back(ex1);
|
||||||
ret.m_params.push_back(ex2);
|
ret.m_params.push_back(ex2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx operator && (const RegEx& ex1, const RegEx& ex2)
|
RegEx operator && (const RegEx& ex1, const RegEx& ex2)
|
||||||
{
|
{
|
||||||
RegEx ret(REGEX_AND);
|
RegEx ret(REGEX_AND);
|
||||||
ret.m_params.push_back(ex1);
|
ret.m_params.push_back(ex1);
|
||||||
ret.m_params.push_back(ex2);
|
ret.m_params.push_back(ex2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegEx operator + (const RegEx& ex1, const RegEx& ex2)
|
RegEx operator + (const RegEx& ex1, const RegEx& ex2)
|
||||||
{
|
{
|
||||||
RegEx ret(REGEX_SEQ);
|
RegEx ret(REGEX_SEQ);
|
||||||
ret.m_params.push_back(ex1);
|
ret.m_params.push_back(ex1);
|
||||||
ret.m_params.push_back(ex2);
|
ret.m_params.push_back(ex2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Operators
|
// Operators
|
||||||
|
|
||||||
// MatchOperator
|
// MatchOperator
|
||||||
int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const
|
int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
if(str.empty() || str[0] != regex.m_a)
|
if(str.empty() || str[0] != regex.m_a)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const
|
int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
if(!in || in.peek() != regex.m_a)
|
if(!in || in.peek() != regex.m_a)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RangeOperator
|
// RangeOperator
|
||||||
int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const
|
int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0])
|
if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0])
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const
|
int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
if(!in || regex.m_a > in.peek() || regex.m_z < in.peek())
|
if(!in || regex.m_a > in.peek() || regex.m_z < in.peek())
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrOperator
|
// OrOperator
|
||||||
int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const
|
int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
for(unsigned i=0;i<regex.m_params.size();i++) {
|
for(unsigned i=0;i<regex.m_params.size();i++) {
|
||||||
int n = regex.m_params[i].Match(str);
|
int n = regex.m_params[i].Match(str);
|
||||||
if(n >= 0)
|
if(n >= 0)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const
|
int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
for(unsigned i=0;i<regex.m_params.size();i++) {
|
for(unsigned i=0;i<regex.m_params.size();i++) {
|
||||||
int n = regex.m_params[i].Match(in);
|
int n = regex.m_params[i].Match(in);
|
||||||
if(n >= 0)
|
if(n >= 0)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AndOperator
|
// AndOperator
|
||||||
// Note: 'AND' is a little funny, since we may be required to match things
|
// Note: 'AND' is a little funny, since we may be required to match things
|
||||||
// of different lengths. If we find a match, we return the length of
|
// of different lengths. If we find a match, we return the length of
|
||||||
// the FIRST entry on the list.
|
// the FIRST entry on the list.
|
||||||
int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const
|
int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
int first = -1;
|
int first = -1;
|
||||||
for(unsigned i=0;i<regex.m_params.size();i++) {
|
for(unsigned i=0;i<regex.m_params.size();i++) {
|
||||||
int n = regex.m_params[i].Match(str);
|
int n = regex.m_params[i].Match(str);
|
||||||
if(n == -1)
|
if(n == -1)
|
||||||
return -1;
|
return -1;
|
||||||
if(i == 0)
|
if(i == 0)
|
||||||
first = n;
|
first = n;
|
||||||
}
|
}
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegEx::AndOperator::Match(std::istream& in, const RegEx& regex) const
|
int RegEx::AndOperator::Match(std::istream& in, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
int first = -1;
|
int first = -1;
|
||||||
for(unsigned i=0;i<regex.m_params.size();i++) {
|
for(unsigned i=0;i<regex.m_params.size();i++) {
|
||||||
int n = regex.m_params[i].Match(in);
|
int n = regex.m_params[i].Match(in);
|
||||||
if(n == -1)
|
if(n == -1)
|
||||||
return -1;
|
return -1;
|
||||||
if(i == 0)
|
if(i == 0)
|
||||||
first = n;
|
first = n;
|
||||||
}
|
}
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotOperator
|
// NotOperator
|
||||||
int RegEx::NotOperator::Match(const std::string& str, const RegEx& regex) const
|
int RegEx::NotOperator::Match(const std::string& str, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
if(regex.m_params.empty())
|
if(regex.m_params.empty())
|
||||||
return -1;
|
return -1;
|
||||||
if(regex.m_params[0].Match(str) >= 0)
|
if(regex.m_params[0].Match(str) >= 0)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const
|
int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
if(regex.m_params.empty())
|
if(regex.m_params.empty())
|
||||||
return -1;
|
return -1;
|
||||||
if(regex.m_params[0].Match(in) >= 0)
|
if(regex.m_params[0].Match(in) >= 0)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeqOperator
|
// SeqOperator
|
||||||
int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const
|
int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for(unsigned i=0;i<regex.m_params.size();i++) {
|
for(unsigned i=0;i<regex.m_params.size();i++) {
|
||||||
int n = regex.m_params[i].Match(str.substr(offset));
|
int n = regex.m_params[i].Match(str.substr(offset));
|
||||||
if(n == -1)
|
if(n == -1)
|
||||||
return -1;
|
return -1;
|
||||||
offset += n;
|
offset += n;
|
||||||
}
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegEx::SeqOperator::Match(std::istream& in, const RegEx& regex) const
|
int RegEx::SeqOperator::Match(std::istream& in, const RegEx& regex) const
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for(unsigned i=0;i<regex.m_params.size();i++) {
|
for(unsigned i=0;i<regex.m_params.size();i++) {
|
||||||
int n = regex.m_params[i].Match(in);
|
int n = regex.m_params[i].Match(in);
|
||||||
if(n == -1)
|
if(n == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
offset += n;
|
offset += n;
|
||||||
in.ignore(n);
|
in.ignore(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
180
src/regex.h
180
src/regex.h
@@ -1,90 +1,90 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
struct Stream;
|
struct Stream;
|
||||||
|
|
||||||
enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_AND, REGEX_NOT, REGEX_SEQ };
|
enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_AND, REGEX_NOT, REGEX_SEQ };
|
||||||
|
|
||||||
// simplified regular expressions
|
// simplified regular expressions
|
||||||
// . Only straightforward matches (no repeated characters)
|
// . Only straightforward matches (no repeated characters)
|
||||||
// . Only matches from start of string
|
// . Only matches from start of string
|
||||||
class RegEx
|
class RegEx
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
struct Operator {
|
struct Operator {
|
||||||
virtual ~Operator() {}
|
virtual ~Operator() {}
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const = 0;
|
virtual int Match(const std::string& str, const RegEx& regex) const = 0;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const = 0;
|
virtual int Match(std::istream& in, const RegEx& regex) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MatchOperator: public Operator {
|
struct MatchOperator: public Operator {
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const;
|
virtual int Match(const std::string& str, const RegEx& regex) const;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const;
|
virtual int Match(std::istream& in, const RegEx& regex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RangeOperator: public Operator {
|
struct RangeOperator: public Operator {
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const;
|
virtual int Match(const std::string& str, const RegEx& regex) const;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const;
|
virtual int Match(std::istream& in, const RegEx& regex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrOperator: public Operator {
|
struct OrOperator: public Operator {
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const;
|
virtual int Match(const std::string& str, const RegEx& regex) const;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const;
|
virtual int Match(std::istream& in, const RegEx& regex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AndOperator: public Operator {
|
struct AndOperator: public Operator {
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const;
|
virtual int Match(const std::string& str, const RegEx& regex) const;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const;
|
virtual int Match(std::istream& in, const RegEx& regex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NotOperator: public Operator {
|
struct NotOperator: public Operator {
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const;
|
virtual int Match(const std::string& str, const RegEx& regex) const;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const;
|
virtual int Match(std::istream& in, const RegEx& regex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SeqOperator: public Operator {
|
struct SeqOperator: public Operator {
|
||||||
virtual int Match(const std::string& str, const RegEx& regex) const;
|
virtual int Match(const std::string& str, const RegEx& regex) const;
|
||||||
virtual int Match(std::istream& in, const RegEx& regex) const;
|
virtual int Match(std::istream& in, const RegEx& regex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
friend struct Operator;
|
friend struct Operator;
|
||||||
|
|
||||||
RegEx();
|
RegEx();
|
||||||
RegEx(char ch);
|
RegEx(char ch);
|
||||||
RegEx(char a, char z);
|
RegEx(char a, char z);
|
||||||
RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ);
|
RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ);
|
||||||
RegEx(const RegEx& rhs);
|
RegEx(const RegEx& rhs);
|
||||||
~RegEx();
|
~RegEx();
|
||||||
|
|
||||||
RegEx& operator = (const RegEx& rhs);
|
RegEx& operator = (const RegEx& rhs);
|
||||||
|
|
||||||
bool Matches(char ch) const;
|
bool Matches(char ch) const;
|
||||||
bool Matches(const std::string& str) const;
|
bool Matches(const std::string& str) const;
|
||||||
bool Matches(std::istream& in) const;
|
bool Matches(std::istream& in) const;
|
||||||
bool Matches(Stream& in) const;
|
bool Matches(Stream& in) const;
|
||||||
int Match(const std::string& str) const;
|
int Match(const std::string& str) const;
|
||||||
int Match(std::istream& in) const;
|
int Match(std::istream& in) const;
|
||||||
int Match(Stream& in) const;
|
int Match(Stream& in) const;
|
||||||
|
|
||||||
friend RegEx operator ! (const RegEx& ex);
|
friend RegEx operator ! (const RegEx& ex);
|
||||||
friend RegEx operator || (const RegEx& ex1, const RegEx& ex2);
|
friend RegEx operator || (const RegEx& ex1, const RegEx& ex2);
|
||||||
friend RegEx operator && (const RegEx& ex1, const RegEx& ex2);
|
friend RegEx operator && (const RegEx& ex1, const RegEx& ex2);
|
||||||
friend RegEx operator + (const RegEx& ex1, const RegEx& ex2);
|
friend RegEx operator + (const RegEx& ex1, const RegEx& ex2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RegEx(REGEX_OP op);
|
RegEx(REGEX_OP op);
|
||||||
void SetOp();
|
void SetOp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
REGEX_OP m_op;
|
REGEX_OP m_op;
|
||||||
Operator *m_pOp;
|
Operator *m_pOp;
|
||||||
char m_a, m_z;
|
char m_a, m_z;
|
||||||
std::vector <RegEx> m_params;
|
std::vector <RegEx> m_params;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
216
src/scalar.cpp
216
src/scalar.cpp
@@ -1,108 +1,108 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "scalar.h"
|
#include "scalar.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Scalar::Scalar()
|
Scalar::Scalar()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Scalar::~Scalar()
|
Scalar::~Scalar()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Parse(Scanner *pScanner, const ParserState& state)
|
void Scalar::Parse(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
m_data = token.value;
|
m_data = token.value;
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
||||||
{
|
{
|
||||||
out << "\"";
|
out << "\"";
|
||||||
for(unsigned i=0;i<m_data.size();i++) {
|
for(unsigned i=0;i<m_data.size();i++) {
|
||||||
switch(m_data[i]) {
|
switch(m_data[i]) {
|
||||||
case '\\': out << "\\\\"; break;
|
case '\\': out << "\\\\"; break;
|
||||||
case '\t': out << "\\t"; break;
|
case '\t': out << "\\t"; break;
|
||||||
case '\n': out << "\\n"; break;
|
case '\n': out << "\\n"; break;
|
||||||
case '\r': out << "\\r"; break;
|
case '\r': out << "\\r"; break;
|
||||||
default: out << m_data[i]; break;
|
default: out << m_data[i]; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out << "\"\n";
|
out << "\"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(std::string& s)
|
void Scalar::Read(std::string& s)
|
||||||
{
|
{
|
||||||
s = m_data;
|
s = m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(int& i)
|
void Scalar::Read(int& i)
|
||||||
{
|
{
|
||||||
std::stringstream data(m_data);
|
std::stringstream data(m_data);
|
||||||
data >> i;
|
data >> i;
|
||||||
if(!data)
|
if(!data)
|
||||||
throw InvalidScalar();
|
throw InvalidScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(unsigned& u)
|
void Scalar::Read(unsigned& u)
|
||||||
{
|
{
|
||||||
std::stringstream data(m_data);
|
std::stringstream data(m_data);
|
||||||
data >> u;
|
data >> u;
|
||||||
if(!data)
|
if(!data)
|
||||||
throw InvalidScalar();
|
throw InvalidScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(long& l)
|
void Scalar::Read(long& l)
|
||||||
{
|
{
|
||||||
std::stringstream data(m_data);
|
std::stringstream data(m_data);
|
||||||
data >> l;
|
data >> l;
|
||||||
if(!data)
|
if(!data)
|
||||||
throw InvalidScalar();
|
throw InvalidScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(float& f)
|
void Scalar::Read(float& f)
|
||||||
{
|
{
|
||||||
std::stringstream data(m_data);
|
std::stringstream data(m_data);
|
||||||
data >> f;
|
data >> f;
|
||||||
if(!data)
|
if(!data)
|
||||||
throw InvalidScalar();
|
throw InvalidScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(double& d)
|
void Scalar::Read(double& d)
|
||||||
{
|
{
|
||||||
std::stringstream data(m_data);
|
std::stringstream data(m_data);
|
||||||
data >> d;
|
data >> d;
|
||||||
if(!data)
|
if(!data)
|
||||||
throw InvalidScalar();
|
throw InvalidScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scalar::Read(char& c)
|
void Scalar::Read(char& c)
|
||||||
{
|
{
|
||||||
std::stringstream data(m_data);
|
std::stringstream data(m_data);
|
||||||
data >> c;
|
data >> c;
|
||||||
if(!data)
|
if(!data)
|
||||||
throw InvalidScalar();
|
throw InvalidScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Scalar::Compare(Content *pContent)
|
int Scalar::Compare(Content *pContent)
|
||||||
{
|
{
|
||||||
return -pContent->Compare(this);
|
return -pContent->Compare(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Scalar::Compare(Scalar *pScalar)
|
int Scalar::Compare(Scalar *pScalar)
|
||||||
{
|
{
|
||||||
if(m_data < pScalar->m_data)
|
if(m_data < pScalar->m_data)
|
||||||
return -1;
|
return -1;
|
||||||
else if(m_data > pScalar->m_data)
|
else if(m_data > pScalar->m_data)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
74
src/scalar.h
74
src/scalar.h
@@ -1,37 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "content.h"
|
#include "content.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Scalar: public Content
|
class Scalar: public Content
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Scalar();
|
Scalar();
|
||||||
virtual ~Scalar();
|
virtual ~Scalar();
|
||||||
|
|
||||||
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
||||||
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
||||||
|
|
||||||
virtual bool IsScalar() const { return true; }
|
virtual bool IsScalar() const { return true; }
|
||||||
|
|
||||||
// extraction
|
// extraction
|
||||||
virtual void Read(std::string& s);
|
virtual void Read(std::string& s);
|
||||||
virtual void Read(int& i);
|
virtual void Read(int& i);
|
||||||
virtual void Read(unsigned& u);
|
virtual void Read(unsigned& u);
|
||||||
virtual void Read(long& l);
|
virtual void Read(long& l);
|
||||||
virtual void Read(float& f);
|
virtual void Read(float& f);
|
||||||
virtual void Read(double& d);
|
virtual void Read(double& d);
|
||||||
virtual void Read(char& c);
|
virtual void Read(char& c);
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
virtual int Compare(Content *pContent);
|
virtual int Compare(Content *pContent);
|
||||||
virtual int Compare(Scalar *pScalar);
|
virtual int Compare(Scalar *pScalar);
|
||||||
virtual int Compare(Sequence *pSeq) { return -1; }
|
virtual int Compare(Sequence *pSeq) { return -1; }
|
||||||
virtual int Compare(Map *pMap) { return -1; }
|
virtual int Compare(Map *pMap) { return -1; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_data;
|
std::string m_data;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
552
src/scanner.cpp
552
src/scanner.cpp
@@ -1,276 +1,276 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Scanner::Scanner(std::istream& in)
|
Scanner::Scanner(std::istream& in)
|
||||||
: INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0)
|
: INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Scanner::~Scanner()
|
Scanner::~Scanner()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty
|
// empty
|
||||||
// . Returns true if there are no more tokens to be read
|
// . Returns true if there are no more tokens to be read
|
||||||
bool Scanner::empty()
|
bool Scanner::empty()
|
||||||
{
|
{
|
||||||
EnsureTokensInQueue();
|
EnsureTokensInQueue();
|
||||||
return m_tokens.empty();
|
return m_tokens.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop
|
// pop
|
||||||
// . Simply removes the next token on the queue.
|
// . Simply removes the next token on the queue.
|
||||||
void Scanner::pop()
|
void Scanner::pop()
|
||||||
{
|
{
|
||||||
EnsureTokensInQueue();
|
EnsureTokensInQueue();
|
||||||
if(!m_tokens.empty())
|
if(!m_tokens.empty())
|
||||||
m_tokens.pop();
|
m_tokens.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// peek
|
// peek
|
||||||
// . Returns (but does not remove) the next token on the queue.
|
// . Returns (but does not remove) the next token on the queue.
|
||||||
Token& Scanner::peek()
|
Token& Scanner::peek()
|
||||||
{
|
{
|
||||||
EnsureTokensInQueue();
|
EnsureTokensInQueue();
|
||||||
assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking
|
assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking
|
||||||
// if it's empty before peeking.
|
// if it's empty before peeking.
|
||||||
|
|
||||||
return m_tokens.front();
|
return m_tokens.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnsureTokensInQueue
|
// EnsureTokensInQueue
|
||||||
// . Scan until there's a valid token at the front of the queue,
|
// . Scan until there's a valid token at the front of the queue,
|
||||||
// or we're sure the queue is empty.
|
// or we're sure the queue is empty.
|
||||||
void Scanner::EnsureTokensInQueue()
|
void Scanner::EnsureTokensInQueue()
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
if(!m_tokens.empty()) {
|
if(!m_tokens.empty()) {
|
||||||
Token& token = m_tokens.front();
|
Token& token = m_tokens.front();
|
||||||
|
|
||||||
// if this guy's valid, then we're done
|
// if this guy's valid, then we're done
|
||||||
if(token.status == TS_VALID)
|
if(token.status == TS_VALID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// here's where we clean up the impossible tokens
|
// here's where we clean up the impossible tokens
|
||||||
if(token.status == TS_INVALID) {
|
if(token.status == TS_INVALID) {
|
||||||
m_tokens.pop();
|
m_tokens.pop();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: what's left are the unverified tokens
|
// note: what's left are the unverified tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
// no token? maybe we've actually finished
|
// no token? maybe we've actually finished
|
||||||
if(m_endedStream)
|
if(m_endedStream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// no? then scan...
|
// no? then scan...
|
||||||
ScanNextToken();
|
ScanNextToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanNextToken
|
// ScanNextToken
|
||||||
// . The main scanning function; here we branch out and
|
// . The main scanning function; here we branch out and
|
||||||
// scan whatever the next token should be.
|
// scan whatever the next token should be.
|
||||||
void Scanner::ScanNextToken()
|
void Scanner::ScanNextToken()
|
||||||
{
|
{
|
||||||
if(m_endedStream)
|
if(m_endedStream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!m_startedStream)
|
if(!m_startedStream)
|
||||||
return StartStream();
|
return StartStream();
|
||||||
|
|
||||||
// get rid of whitespace, etc. (in between tokens it should be irrelevent)
|
// get rid of whitespace, etc. (in between tokens it should be irrelevent)
|
||||||
ScanToNextToken();
|
ScanToNextToken();
|
||||||
|
|
||||||
// check the latest simple key
|
// check the latest simple key
|
||||||
VerifySimpleKey();
|
VerifySimpleKey();
|
||||||
|
|
||||||
// maybe need to end some blocks
|
// maybe need to end some blocks
|
||||||
PopIndentTo(INPUT.column);
|
PopIndentTo(INPUT.column);
|
||||||
|
|
||||||
// *****
|
// *****
|
||||||
// And now branch based on the next few characters!
|
// And now branch based on the next few characters!
|
||||||
// *****
|
// *****
|
||||||
|
|
||||||
// end of stream
|
// end of stream
|
||||||
if(INPUT.peek() == EOF)
|
if(INPUT.peek() == EOF)
|
||||||
return EndStream();
|
return EndStream();
|
||||||
|
|
||||||
if(INPUT.column == 0 && INPUT.peek() == Keys::Directive)
|
if(INPUT.column == 0 && INPUT.peek() == Keys::Directive)
|
||||||
return ScanDirective();
|
return ScanDirective();
|
||||||
|
|
||||||
// document token
|
// document token
|
||||||
if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT))
|
if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT))
|
||||||
return ScanDocStart();
|
return ScanDocStart();
|
||||||
|
|
||||||
if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT))
|
if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT))
|
||||||
return ScanDocEnd();
|
return ScanDocEnd();
|
||||||
|
|
||||||
// flow start/end/entry
|
// flow start/end/entry
|
||||||
if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart)
|
if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart)
|
||||||
return ScanFlowStart();
|
return ScanFlowStart();
|
||||||
|
|
||||||
if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd)
|
if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd)
|
||||||
return ScanFlowEnd();
|
return ScanFlowEnd();
|
||||||
|
|
||||||
if(INPUT.peek() == Keys::FlowEntry)
|
if(INPUT.peek() == Keys::FlowEntry)
|
||||||
return ScanFlowEntry();
|
return ScanFlowEntry();
|
||||||
|
|
||||||
// block/map stuff
|
// block/map stuff
|
||||||
if(Exp::BlockEntry.Matches(INPUT))
|
if(Exp::BlockEntry.Matches(INPUT))
|
||||||
return ScanBlockEntry();
|
return ScanBlockEntry();
|
||||||
|
|
||||||
if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT))
|
if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT))
|
||||||
return ScanKey();
|
return ScanKey();
|
||||||
|
|
||||||
if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT))
|
if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT))
|
||||||
return ScanValue();
|
return ScanValue();
|
||||||
|
|
||||||
// alias/anchor
|
// alias/anchor
|
||||||
if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor)
|
if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor)
|
||||||
return ScanAnchorOrAlias();
|
return ScanAnchorOrAlias();
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
if(INPUT.peek() == Keys::Tag)
|
if(INPUT.peek() == Keys::Tag)
|
||||||
return ScanTag();
|
return ScanTag();
|
||||||
|
|
||||||
// special scalars
|
// special scalars
|
||||||
if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar))
|
if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar))
|
||||||
return ScanBlockScalar();
|
return ScanBlockScalar();
|
||||||
|
|
||||||
if(INPUT.peek() == '\'' || INPUT.peek() == '\"')
|
if(INPUT.peek() == '\'' || INPUT.peek() == '\"')
|
||||||
return ScanQuotedScalar();
|
return ScanQuotedScalar();
|
||||||
|
|
||||||
// plain scalars
|
// plain scalars
|
||||||
if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT))
|
if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT))
|
||||||
return ScanPlainScalar();
|
return ScanPlainScalar();
|
||||||
|
|
||||||
// don't know what it is!
|
// don't know what it is!
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanToNextToken
|
// ScanToNextToken
|
||||||
// . Eats input until we reach the next token-like thing.
|
// . Eats input until we reach the next token-like thing.
|
||||||
void Scanner::ScanToNextToken()
|
void Scanner::ScanToNextToken()
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
// first eat whitespace
|
// first eat whitespace
|
||||||
while(IsWhitespaceToBeEaten(INPUT.peek()))
|
while(IsWhitespaceToBeEaten(INPUT.peek()))
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
|
|
||||||
// then eat a comment
|
// then eat a comment
|
||||||
if(Exp::Comment.Matches(INPUT)) {
|
if(Exp::Comment.Matches(INPUT)) {
|
||||||
// eat until line break
|
// eat until line break
|
||||||
while(INPUT && !Exp::Break.Matches(INPUT))
|
while(INPUT && !Exp::Break.Matches(INPUT))
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it's NOT a line break, then we're done!
|
// if it's NOT a line break, then we're done!
|
||||||
if(!Exp::Break.Matches(INPUT))
|
if(!Exp::Break.Matches(INPUT))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// otherwise, let's eat the line break and keep going
|
// otherwise, let's eat the line break and keep going
|
||||||
int n = Exp::Break.Match(INPUT);
|
int n = Exp::Break.Match(INPUT);
|
||||||
INPUT.eat(n);
|
INPUT.eat(n);
|
||||||
|
|
||||||
// oh yeah, and let's get rid of that simple key
|
// oh yeah, and let's get rid of that simple key
|
||||||
VerifySimpleKey();
|
VerifySimpleKey();
|
||||||
|
|
||||||
// new line - we may be able to accept a simple key now
|
// new line - we may be able to accept a simple key now
|
||||||
if(m_flowLevel == 0)
|
if(m_flowLevel == 0)
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
// Misc. helpers
|
// Misc. helpers
|
||||||
|
|
||||||
// IsWhitespaceToBeEaten
|
// IsWhitespaceToBeEaten
|
||||||
// . We can eat whitespace if:
|
// . We can eat whitespace if:
|
||||||
// 1. It's a space
|
// 1. It's a space
|
||||||
// 2. It's a tab, and we're either:
|
// 2. It's a tab, and we're either:
|
||||||
// a. In the flow context
|
// a. In the flow context
|
||||||
// b. In the block context but not where a simple key could be allowed
|
// b. In the block context but not where a simple key could be allowed
|
||||||
// (i.e., not at the beginning of a line, or following '-', '?', or ':')
|
// (i.e., not at the beginning of a line, or following '-', '?', or ':')
|
||||||
bool Scanner::IsWhitespaceToBeEaten(char ch)
|
bool Scanner::IsWhitespaceToBeEaten(char ch)
|
||||||
{
|
{
|
||||||
if(ch == ' ')
|
if(ch == ' ')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed))
|
if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartStream
|
// StartStream
|
||||||
// . Set the initial conditions for starting a stream.
|
// . Set the initial conditions for starting a stream.
|
||||||
void Scanner::StartStream()
|
void Scanner::StartStream()
|
||||||
{
|
{
|
||||||
m_startedStream = true;
|
m_startedStream = true;
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
m_indents.push(-1);
|
m_indents.push(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndStream
|
// EndStream
|
||||||
// . Close out the stream, finish up, etc.
|
// . Close out the stream, finish up, etc.
|
||||||
void Scanner::EndStream()
|
void Scanner::EndStream()
|
||||||
{
|
{
|
||||||
// force newline
|
// force newline
|
||||||
if(INPUT.column > 0)
|
if(INPUT.column > 0)
|
||||||
INPUT.column = 0;
|
INPUT.column = 0;
|
||||||
|
|
||||||
PopIndentTo(-1);
|
PopIndentTo(-1);
|
||||||
VerifyAllSimpleKeys();
|
VerifyAllSimpleKeys();
|
||||||
|
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
m_endedStream = true;
|
m_endedStream = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushIndentTo
|
// PushIndentTo
|
||||||
// . Pushes an indentation onto the stack, and enqueues the
|
// . Pushes an indentation onto the stack, and enqueues the
|
||||||
// proper token (sequence start or mapping start).
|
// proper token (sequence start or mapping start).
|
||||||
// . Returns the token it generates (if any).
|
// . Returns the token it generates (if any).
|
||||||
Token *Scanner::PushIndentTo(int column, bool sequence)
|
Token *Scanner::PushIndentTo(int column, bool sequence)
|
||||||
{
|
{
|
||||||
// are we in flow?
|
// are we in flow?
|
||||||
if(m_flowLevel > 0)
|
if(m_flowLevel > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// is this actually an indentation?
|
// is this actually an indentation?
|
||||||
if(column <= m_indents.top())
|
if(column <= m_indents.top())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// now push
|
// now push
|
||||||
m_indents.push(column);
|
m_indents.push(column);
|
||||||
if(sequence)
|
if(sequence)
|
||||||
m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column));
|
m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column));
|
||||||
else
|
else
|
||||||
m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column));
|
m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column));
|
||||||
|
|
||||||
return &m_tokens.back();
|
return &m_tokens.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// PopIndentTo
|
// PopIndentTo
|
||||||
// . Pops indentations off the stack until we reach 'column' indentation,
|
// . Pops indentations off the stack until we reach 'column' indentation,
|
||||||
// and enqueues the proper token each time.
|
// and enqueues the proper token each time.
|
||||||
void Scanner::PopIndentTo(int column)
|
void Scanner::PopIndentTo(int column)
|
||||||
{
|
{
|
||||||
// are we in flow?
|
// are we in flow?
|
||||||
if(m_flowLevel > 0)
|
if(m_flowLevel > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// now pop away
|
// now pop away
|
||||||
while(!m_indents.empty() && m_indents.top() > column) {
|
while(!m_indents.empty() && m_indents.top() > column) {
|
||||||
m_indents.pop();
|
m_indents.pop();
|
||||||
m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column));
|
m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
170
src/scanner.h
170
src/scanner.h
@@ -1,85 +1,85 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Scanner
|
class Scanner
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Scanner(std::istream& in);
|
Scanner(std::istream& in);
|
||||||
~Scanner();
|
~Scanner();
|
||||||
|
|
||||||
// token queue management (hopefully this looks kinda stl-ish)
|
// token queue management (hopefully this looks kinda stl-ish)
|
||||||
bool empty();
|
bool empty();
|
||||||
void pop();
|
void pop();
|
||||||
Token& peek();
|
Token& peek();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// scanning
|
// scanning
|
||||||
void EnsureTokensInQueue();
|
void EnsureTokensInQueue();
|
||||||
void ScanNextToken();
|
void ScanNextToken();
|
||||||
void ScanToNextToken();
|
void ScanToNextToken();
|
||||||
void StartStream();
|
void StartStream();
|
||||||
void EndStream();
|
void EndStream();
|
||||||
Token *PushIndentTo(int column, bool sequence);
|
Token *PushIndentTo(int column, bool sequence);
|
||||||
void PopIndentTo(int column);
|
void PopIndentTo(int column);
|
||||||
|
|
||||||
// checking input
|
// checking input
|
||||||
void InsertSimpleKey();
|
void InsertSimpleKey();
|
||||||
bool VerifySimpleKey();
|
bool VerifySimpleKey();
|
||||||
void VerifyAllSimpleKeys();
|
void VerifyAllSimpleKeys();
|
||||||
|
|
||||||
bool IsWhitespaceToBeEaten(char ch);
|
bool IsWhitespaceToBeEaten(char ch);
|
||||||
|
|
||||||
struct SimpleKey {
|
struct SimpleKey {
|
||||||
SimpleKey(int pos_, int line_, int column_, int flowLevel_);
|
SimpleKey(int pos_, int line_, int column_, int flowLevel_);
|
||||||
|
|
||||||
void Validate();
|
void Validate();
|
||||||
void Invalidate();
|
void Invalidate();
|
||||||
|
|
||||||
int pos, line, column, flowLevel;
|
int pos, line, column, flowLevel;
|
||||||
Token *pMapStart, *pKey;
|
Token *pMapStart, *pKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
// and the tokens
|
// and the tokens
|
||||||
void ScanDirective();
|
void ScanDirective();
|
||||||
void ScanDocStart();
|
void ScanDocStart();
|
||||||
void ScanDocEnd();
|
void ScanDocEnd();
|
||||||
void ScanBlockSeqStart();
|
void ScanBlockSeqStart();
|
||||||
void ScanBlockMapSTart();
|
void ScanBlockMapSTart();
|
||||||
void ScanBlockEnd();
|
void ScanBlockEnd();
|
||||||
void ScanBlockEntry();
|
void ScanBlockEntry();
|
||||||
void ScanFlowStart();
|
void ScanFlowStart();
|
||||||
void ScanFlowEnd();
|
void ScanFlowEnd();
|
||||||
void ScanFlowEntry();
|
void ScanFlowEntry();
|
||||||
void ScanKey();
|
void ScanKey();
|
||||||
void ScanValue();
|
void ScanValue();
|
||||||
void ScanAnchorOrAlias();
|
void ScanAnchorOrAlias();
|
||||||
void ScanTag();
|
void ScanTag();
|
||||||
void ScanPlainScalar();
|
void ScanPlainScalar();
|
||||||
void ScanQuotedScalar();
|
void ScanQuotedScalar();
|
||||||
void ScanBlockScalar();
|
void ScanBlockScalar();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// the stream
|
// the stream
|
||||||
Stream INPUT;
|
Stream INPUT;
|
||||||
|
|
||||||
// the output (tokens)
|
// the output (tokens)
|
||||||
std::queue <Token> m_tokens;
|
std::queue <Token> m_tokens;
|
||||||
|
|
||||||
// state info
|
// state info
|
||||||
bool m_startedStream, m_endedStream;
|
bool m_startedStream, m_endedStream;
|
||||||
bool m_simpleKeyAllowed;
|
bool m_simpleKeyAllowed;
|
||||||
int m_flowLevel; // number of unclosed '[' and '{' indicators
|
int m_flowLevel; // number of unclosed '[' and '{' indicators
|
||||||
bool m_isLastKeyValid;
|
bool m_isLastKeyValid;
|
||||||
std::stack <SimpleKey> m_simpleKeys;
|
std::stack <SimpleKey> m_simpleKeys;
|
||||||
std::stack <int> m_indents;
|
std::stack <int> m_indents;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,154 +1,154 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "scanscalar.h"
|
#include "scanscalar.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
// ScanScalar
|
// ScanScalar
|
||||||
// . This is where the scalar magic happens.
|
// . This is where the scalar magic happens.
|
||||||
//
|
//
|
||||||
// . We do the scanning in three phases:
|
// . We do the scanning in three phases:
|
||||||
// 1. Scan until newline
|
// 1. Scan until newline
|
||||||
// 2. Eat newline
|
// 2. Eat newline
|
||||||
// 3. Scan leading blanks.
|
// 3. Scan leading blanks.
|
||||||
//
|
//
|
||||||
// . Depending on the parameters given, we store or stop
|
// . Depending on the parameters given, we store or stop
|
||||||
// and different places in the above flow.
|
// and different places in the above flow.
|
||||||
std::string ScanScalar(Stream& INPUT, ScanScalarParams& params)
|
std::string ScanScalar(Stream& INPUT, ScanScalarParams& params)
|
||||||
{
|
{
|
||||||
bool foundNonEmptyLine = false, pastOpeningBreak = false;
|
bool foundNonEmptyLine = false, pastOpeningBreak = false;
|
||||||
bool emptyLine = false, moreIndented = false;
|
bool emptyLine = false, moreIndented = false;
|
||||||
std::string scalar;
|
std::string scalar;
|
||||||
params.leadingSpaces = false;
|
params.leadingSpaces = false;
|
||||||
|
|
||||||
while(INPUT) {
|
while(INPUT) {
|
||||||
// ********************************
|
// ********************************
|
||||||
// Phase #1: scan until line ending
|
// Phase #1: scan until line ending
|
||||||
while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) {
|
while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) {
|
||||||
if(INPUT.peek() == EOF)
|
if(INPUT.peek() == EOF)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// document indicator?
|
// document indicator?
|
||||||
if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) {
|
if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) {
|
||||||
if(params.onDocIndicator == BREAK)
|
if(params.onDocIndicator == BREAK)
|
||||||
break;
|
break;
|
||||||
else if(params.onDocIndicator == THROW)
|
else if(params.onDocIndicator == THROW)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::DOC_IN_SCALAR);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::DOC_IN_SCALAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
foundNonEmptyLine = true;
|
foundNonEmptyLine = true;
|
||||||
pastOpeningBreak = true;
|
pastOpeningBreak = true;
|
||||||
|
|
||||||
// escaped newline? (only if we're escaping on slash)
|
// escaped newline? (only if we're escaping on slash)
|
||||||
if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) {
|
if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) {
|
||||||
int n = Exp::EscBreak.Match(INPUT);
|
int n = Exp::EscBreak.Match(INPUT);
|
||||||
INPUT.eat(n);
|
INPUT.eat(n);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// escape this?
|
// escape this?
|
||||||
if(INPUT.peek() == params.escape) {
|
if(INPUT.peek() == params.escape) {
|
||||||
scalar += Exp::Escape(INPUT);
|
scalar += Exp::Escape(INPUT);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, just add the damn character
|
// otherwise, just add the damn character
|
||||||
scalar += INPUT.get();
|
scalar += INPUT.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eof? if we're looking to eat something, then we throw
|
// eof? if we're looking to eat something, then we throw
|
||||||
if(INPUT.peek() == EOF) {
|
if(INPUT.peek() == EOF) {
|
||||||
if(params.eatEnd)
|
if(params.eatEnd)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::EOF_IN_SCALAR);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::EOF_IN_SCALAR);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// doc indicator?
|
// doc indicator?
|
||||||
if(params.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT))
|
if(params.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// are we done via character match?
|
// are we done via character match?
|
||||||
int n = params.end.Match(INPUT);
|
int n = params.end.Match(INPUT);
|
||||||
if(n >= 0) {
|
if(n >= 0) {
|
||||||
if(params.eatEnd)
|
if(params.eatEnd)
|
||||||
INPUT.eat(n);
|
INPUT.eat(n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ********************************
|
// ********************************
|
||||||
// Phase #2: eat line ending
|
// Phase #2: eat line ending
|
||||||
n = Exp::Break.Match(INPUT);
|
n = Exp::Break.Match(INPUT);
|
||||||
INPUT.eat(n);
|
INPUT.eat(n);
|
||||||
|
|
||||||
// ********************************
|
// ********************************
|
||||||
// Phase #3: scan initial spaces
|
// Phase #3: scan initial spaces
|
||||||
|
|
||||||
// first the required indentation
|
// first the required indentation
|
||||||
while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine)))
|
while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine)))
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
|
|
||||||
// update indent if we're auto-detecting
|
// update indent if we're auto-detecting
|
||||||
if(params.detectIndent && !foundNonEmptyLine)
|
if(params.detectIndent && !foundNonEmptyLine)
|
||||||
params.indent = std::max(params.indent, INPUT.column);
|
params.indent = std::max(params.indent, INPUT.column);
|
||||||
|
|
||||||
// and then the rest of the whitespace
|
// and then the rest of the whitespace
|
||||||
while(Exp::Blank.Matches(INPUT)) {
|
while(Exp::Blank.Matches(INPUT)) {
|
||||||
// we check for tabs that masquerade as indentation
|
// we check for tabs that masquerade as indentation
|
||||||
if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW)
|
if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::TAB_IN_INDENTATION);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::TAB_IN_INDENTATION);
|
||||||
|
|
||||||
if(!params.eatLeadingWhitespace)
|
if(!params.eatLeadingWhitespace)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// was this an empty line?
|
// was this an empty line?
|
||||||
bool nextEmptyLine = Exp::Break.Matches(INPUT);
|
bool nextEmptyLine = Exp::Break.Matches(INPUT);
|
||||||
bool nextMoreIndented = (INPUT.peek() == ' ');
|
bool nextMoreIndented = (INPUT.peek() == ' ');
|
||||||
|
|
||||||
// for block scalars, we always start with a newline, so we should ignore it (not fold or keep)
|
// for block scalars, we always start with a newline, so we should ignore it (not fold or keep)
|
||||||
bool useNewLine = pastOpeningBreak;
|
bool useNewLine = pastOpeningBreak;
|
||||||
// and for folded scalars, we don't fold the very last newline to a space
|
// and for folded scalars, we don't fold the very last newline to a space
|
||||||
if(params.fold && !emptyLine && INPUT.column < params.indent)
|
if(params.fold && !emptyLine && INPUT.column < params.indent)
|
||||||
useNewLine = false;
|
useNewLine = false;
|
||||||
|
|
||||||
if(useNewLine) {
|
if(useNewLine) {
|
||||||
if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented)
|
if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented)
|
||||||
scalar += " ";
|
scalar += " ";
|
||||||
else
|
else
|
||||||
scalar += "\n";
|
scalar += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyLine = nextEmptyLine;
|
emptyLine = nextEmptyLine;
|
||||||
moreIndented = nextMoreIndented;
|
moreIndented = nextMoreIndented;
|
||||||
pastOpeningBreak = true;
|
pastOpeningBreak = true;
|
||||||
|
|
||||||
// are we done via indentation?
|
// are we done via indentation?
|
||||||
if(!emptyLine && INPUT.column < params.indent) {
|
if(!emptyLine && INPUT.column < params.indent) {
|
||||||
params.leadingSpaces = true;
|
params.leadingSpaces = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// post-processing
|
// post-processing
|
||||||
if(params.trimTrailingSpaces) {
|
if(params.trimTrailingSpaces) {
|
||||||
unsigned pos = scalar.find_last_not_of(' ');
|
unsigned pos = scalar.find_last_not_of(' ');
|
||||||
if(pos < scalar.size())
|
if(pos < scalar.size())
|
||||||
scalar.erase(pos + 1);
|
scalar.erase(pos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(params.chomp <= 0) {
|
if(params.chomp <= 0) {
|
||||||
unsigned pos = scalar.find_last_not_of('\n');
|
unsigned pos = scalar.find_last_not_of('\n');
|
||||||
if(params.chomp == 0 && pos + 1 < scalar.size())
|
if(params.chomp == 0 && pos + 1 < scalar.size())
|
||||||
scalar.erase(pos + 2);
|
scalar.erase(pos + 2);
|
||||||
else if(params.chomp == -1 && pos < scalar.size())
|
else if(params.chomp == -1 && pos < scalar.size())
|
||||||
scalar.erase(pos + 1);
|
scalar.erase(pos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return scalar;
|
return scalar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,35 +1,35 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "regex.h"
|
#include "regex.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
enum CHOMP { STRIP = -1, CLIP, KEEP };
|
enum CHOMP { STRIP = -1, CLIP, KEEP };
|
||||||
enum ACTION { NONE, BREAK, THROW };
|
enum ACTION { NONE, BREAK, THROW };
|
||||||
|
|
||||||
struct ScanScalarParams {
|
struct ScanScalarParams {
|
||||||
ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false),
|
ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false),
|
||||||
trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {}
|
trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {}
|
||||||
|
|
||||||
// input:
|
// input:
|
||||||
RegEx end; // what condition ends this scalar?
|
RegEx end; // what condition ends this scalar?
|
||||||
bool eatEnd; // should we eat that condition when we see it?
|
bool eatEnd; // should we eat that condition when we see it?
|
||||||
int indent; // what level of indentation should be eaten and ignored?
|
int indent; // what level of indentation should be eaten and ignored?
|
||||||
bool detectIndent; // should we try to autodetect the indent?
|
bool detectIndent; // should we try to autodetect the indent?
|
||||||
bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces?
|
bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces?
|
||||||
char escape; // what character do we escape on (i.e., slash or single quote) (0 for none)
|
char escape; // what character do we escape on (i.e., slash or single quote) (0 for none)
|
||||||
bool fold; // do we fold line ends?
|
bool fold; // do we fold line ends?
|
||||||
bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end)
|
bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end)
|
||||||
CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end)
|
CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end)
|
||||||
// Note: strip means kill all, clip means keep at most one, keep means keep all
|
// Note: strip means kill all, clip means keep at most one, keep means keep all
|
||||||
ACTION onDocIndicator; // what do we do if we see a document indicator?
|
ACTION onDocIndicator; // what do we do if we see a document indicator?
|
||||||
ACTION onTabInIndentation; // what do we do if we see a tab where we should be seeing indentation spaces
|
ACTION onTabInIndentation; // what do we do if we see a tab where we should be seeing indentation spaces
|
||||||
|
|
||||||
// output:
|
// output:
|
||||||
bool leadingSpaces;
|
bool leadingSpaces;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string ScanScalar(Stream& INPUT, ScanScalarParams& info);
|
std::string ScanScalar(Stream& INPUT, ScanScalarParams& info);
|
||||||
}
|
}
|
||||||
|
@@ -1,405 +1,405 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
#include "scanscalar.h"
|
#include "scanscalar.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
// Specialization for scanning specific tokens
|
// Specialization for scanning specific tokens
|
||||||
|
|
||||||
// Directive
|
// Directive
|
||||||
// . Note: no semantic checking is done here (that's for the parser to do)
|
// . Note: no semantic checking is done here (that's for the parser to do)
|
||||||
void Scanner::ScanDirective()
|
void Scanner::ScanDirective()
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector <std::string> params;
|
std::vector <std::string> params;
|
||||||
|
|
||||||
// pop indents and simple keys
|
// pop indents and simple keys
|
||||||
PopIndentTo(-1);
|
PopIndentTo(-1);
|
||||||
VerifyAllSimpleKeys();
|
VerifyAllSimpleKeys();
|
||||||
|
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// store pos and eat indicator
|
// store pos and eat indicator
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
|
|
||||||
// read name
|
// read name
|
||||||
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
|
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
|
||||||
name += INPUT.get();
|
name += INPUT.get();
|
||||||
|
|
||||||
// read parameters
|
// read parameters
|
||||||
while(1) {
|
while(1) {
|
||||||
// first get rid of whitespace
|
// first get rid of whitespace
|
||||||
while(Exp::Blank.Matches(INPUT))
|
while(Exp::Blank.Matches(INPUT))
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
|
|
||||||
// break on newline or comment
|
// break on newline or comment
|
||||||
if(INPUT.peek() == EOF || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT))
|
if(INPUT.peek() == EOF || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// now read parameter
|
// now read parameter
|
||||||
std::string param;
|
std::string param;
|
||||||
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
|
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
|
||||||
param += INPUT.get();
|
param += INPUT.get();
|
||||||
|
|
||||||
params.push_back(param);
|
params.push_back(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token token(TT_DIRECTIVE, line, column);
|
Token token(TT_DIRECTIVE, line, column);
|
||||||
token.value = name;
|
token.value = name;
|
||||||
token.params = params;
|
token.params = params;
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocStart
|
// DocStart
|
||||||
void Scanner::ScanDocStart()
|
void Scanner::ScanDocStart()
|
||||||
{
|
{
|
||||||
PopIndentTo(INPUT.column);
|
PopIndentTo(INPUT.column);
|
||||||
VerifyAllSimpleKeys();
|
VerifyAllSimpleKeys();
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(3);
|
INPUT.eat(3);
|
||||||
m_tokens.push(Token(TT_DOC_START, line, column));
|
m_tokens.push(Token(TT_DOC_START, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocEnd
|
// DocEnd
|
||||||
void Scanner::ScanDocEnd()
|
void Scanner::ScanDocEnd()
|
||||||
{
|
{
|
||||||
PopIndentTo(-1);
|
PopIndentTo(-1);
|
||||||
VerifyAllSimpleKeys();
|
VerifyAllSimpleKeys();
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(3);
|
INPUT.eat(3);
|
||||||
m_tokens.push(Token(TT_DOC_END, line, column));
|
m_tokens.push(Token(TT_DOC_END, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlowStart
|
// FlowStart
|
||||||
void Scanner::ScanFlowStart()
|
void Scanner::ScanFlowStart()
|
||||||
{
|
{
|
||||||
// flows can be simple keys
|
// flows can be simple keys
|
||||||
InsertSimpleKey();
|
InsertSimpleKey();
|
||||||
m_flowLevel++;
|
m_flowLevel++;
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
char ch = INPUT.get();
|
char ch = INPUT.get();
|
||||||
TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START);
|
TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START);
|
||||||
m_tokens.push(Token(type, line, column));
|
m_tokens.push(Token(type, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlowEnd
|
// FlowEnd
|
||||||
void Scanner::ScanFlowEnd()
|
void Scanner::ScanFlowEnd()
|
||||||
{
|
{
|
||||||
if(m_flowLevel == 0)
|
if(m_flowLevel == 0)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::FLOW_END);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::FLOW_END);
|
||||||
|
|
||||||
m_flowLevel--;
|
m_flowLevel--;
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
char ch = INPUT.get();
|
char ch = INPUT.get();
|
||||||
TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END);
|
TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END);
|
||||||
m_tokens.push(Token(type, line, column));
|
m_tokens.push(Token(type, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlowEntry
|
// FlowEntry
|
||||||
void Scanner::ScanFlowEntry()
|
void Scanner::ScanFlowEntry()
|
||||||
{
|
{
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
m_tokens.push(Token(TT_FLOW_ENTRY, line, column));
|
m_tokens.push(Token(TT_FLOW_ENTRY, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockEntry
|
// BlockEntry
|
||||||
void Scanner::ScanBlockEntry()
|
void Scanner::ScanBlockEntry()
|
||||||
{
|
{
|
||||||
// we better be in the block context!
|
// we better be in the block context!
|
||||||
if(m_flowLevel > 0)
|
if(m_flowLevel > 0)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY);
|
||||||
|
|
||||||
// can we put it here?
|
// can we put it here?
|
||||||
if(!m_simpleKeyAllowed)
|
if(!m_simpleKeyAllowed)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY);
|
||||||
|
|
||||||
PushIndentTo(INPUT.column, true);
|
PushIndentTo(INPUT.column, true);
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
m_tokens.push(Token(TT_BLOCK_ENTRY, line, column));
|
m_tokens.push(Token(TT_BLOCK_ENTRY, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key
|
// Key
|
||||||
void Scanner::ScanKey()
|
void Scanner::ScanKey()
|
||||||
{
|
{
|
||||||
// handle keys diffently in the block context (and manage indents)
|
// handle keys diffently in the block context (and manage indents)
|
||||||
if(m_flowLevel == 0) {
|
if(m_flowLevel == 0) {
|
||||||
if(!m_simpleKeyAllowed)
|
if(!m_simpleKeyAllowed)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_KEY);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_KEY);
|
||||||
|
|
||||||
PushIndentTo(INPUT.column, false);
|
PushIndentTo(INPUT.column, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// can only put a simple key here if we're in block context
|
// can only put a simple key here if we're in block context
|
||||||
if(m_flowLevel == 0)
|
if(m_flowLevel == 0)
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
else
|
else
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
m_tokens.push(Token(TT_KEY, line, column));
|
m_tokens.push(Token(TT_KEY, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value
|
// Value
|
||||||
void Scanner::ScanValue()
|
void Scanner::ScanValue()
|
||||||
{
|
{
|
||||||
// does this follow a simple key?
|
// does this follow a simple key?
|
||||||
if(m_isLastKeyValid) {
|
if(m_isLastKeyValid) {
|
||||||
// can't follow a simple key with another simple key (dunno why, though - it seems fine)
|
// can't follow a simple key with another simple key (dunno why, though - it seems fine)
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
} else {
|
} else {
|
||||||
// handle values diffently in the block context (and manage indents)
|
// handle values diffently in the block context (and manage indents)
|
||||||
if(m_flowLevel == 0) {
|
if(m_flowLevel == 0) {
|
||||||
if(!m_simpleKeyAllowed)
|
if(!m_simpleKeyAllowed)
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_VALUE);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_VALUE);
|
||||||
|
|
||||||
PushIndentTo(INPUT.column, false);
|
PushIndentTo(INPUT.column, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// can only put a simple key here if we're in block context
|
// can only put a simple key here if we're in block context
|
||||||
if(m_flowLevel == 0)
|
if(m_flowLevel == 0)
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
else
|
else
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
m_tokens.push(Token(TT_VALUE, line, column));
|
m_tokens.push(Token(TT_VALUE, line, column));
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnchorOrAlias
|
// AnchorOrAlias
|
||||||
void Scanner::ScanAnchorOrAlias()
|
void Scanner::ScanAnchorOrAlias()
|
||||||
{
|
{
|
||||||
bool alias;
|
bool alias;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
// insert a potential simple key
|
// insert a potential simple key
|
||||||
if(m_simpleKeyAllowed)
|
if(m_simpleKeyAllowed)
|
||||||
InsertSimpleKey();
|
InsertSimpleKey();
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// eat the indicator
|
// eat the indicator
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
char indicator = INPUT.get();
|
char indicator = INPUT.get();
|
||||||
alias = (indicator == Keys::Alias);
|
alias = (indicator == Keys::Alias);
|
||||||
|
|
||||||
// now eat the content
|
// now eat the content
|
||||||
while(Exp::AlphaNumeric.Matches(INPUT))
|
while(Exp::AlphaNumeric.Matches(INPUT))
|
||||||
name += INPUT.get();
|
name += INPUT.get();
|
||||||
|
|
||||||
// we need to have read SOMETHING!
|
// we need to have read SOMETHING!
|
||||||
if(name.empty())
|
if(name.empty())
|
||||||
throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND);
|
throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND);
|
||||||
|
|
||||||
// and needs to end correctly
|
// and needs to end correctly
|
||||||
if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT))
|
if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT))
|
||||||
throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR);
|
throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR);
|
||||||
|
|
||||||
// and we're done
|
// and we're done
|
||||||
Token token(alias ? TT_ALIAS : TT_ANCHOR, line, column);
|
Token token(alias ? TT_ALIAS : TT_ANCHOR, line, column);
|
||||||
token.value = name;
|
token.value = name;
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag
|
// Tag
|
||||||
void Scanner::ScanTag()
|
void Scanner::ScanTag()
|
||||||
{
|
{
|
||||||
std::string handle, suffix;
|
std::string handle, suffix;
|
||||||
|
|
||||||
// insert a potential simple key
|
// insert a potential simple key
|
||||||
if(m_simpleKeyAllowed)
|
if(m_simpleKeyAllowed)
|
||||||
InsertSimpleKey();
|
InsertSimpleKey();
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
// eat the indicator
|
// eat the indicator
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
handle += INPUT.get();
|
handle += INPUT.get();
|
||||||
|
|
||||||
// read the handle
|
// read the handle
|
||||||
while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT))
|
while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT))
|
||||||
handle += INPUT.get();
|
handle += INPUT.get();
|
||||||
|
|
||||||
// is there a suffix?
|
// is there a suffix?
|
||||||
if(INPUT.peek() == Keys::Tag) {
|
if(INPUT.peek() == Keys::Tag) {
|
||||||
// eat the indicator
|
// eat the indicator
|
||||||
handle += INPUT.get();
|
handle += INPUT.get();
|
||||||
|
|
||||||
// then read it
|
// then read it
|
||||||
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
|
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
|
||||||
suffix += INPUT.get();
|
suffix += INPUT.get();
|
||||||
} else {
|
} else {
|
||||||
// this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix
|
// this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix
|
||||||
suffix = handle.substr(1);
|
suffix = handle.substr(1);
|
||||||
handle = "!";
|
handle = "!";
|
||||||
}
|
}
|
||||||
|
|
||||||
Token token(TT_TAG, line, column);
|
Token token(TT_TAG, line, column);
|
||||||
token.value = handle;
|
token.value = handle;
|
||||||
token.params.push_back(suffix);
|
token.params.push_back(suffix);
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlainScalar
|
// PlainScalar
|
||||||
void Scanner::ScanPlainScalar()
|
void Scanner::ScanPlainScalar()
|
||||||
{
|
{
|
||||||
std::string scalar;
|
std::string scalar;
|
||||||
|
|
||||||
// set up the scanning parameters
|
// set up the scanning parameters
|
||||||
ScanScalarParams params;
|
ScanScalarParams params;
|
||||||
params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment);
|
params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment);
|
||||||
params.eatEnd = false;
|
params.eatEnd = false;
|
||||||
params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1);
|
params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1);
|
||||||
params.fold = true;
|
params.fold = true;
|
||||||
params.eatLeadingWhitespace = true;
|
params.eatLeadingWhitespace = true;
|
||||||
params.trimTrailingSpaces = true;
|
params.trimTrailingSpaces = true;
|
||||||
params.chomp = CLIP;
|
params.chomp = CLIP;
|
||||||
params.onDocIndicator = BREAK;
|
params.onDocIndicator = BREAK;
|
||||||
params.onTabInIndentation = THROW;
|
params.onTabInIndentation = THROW;
|
||||||
|
|
||||||
// insert a potential simple key
|
// insert a potential simple key
|
||||||
if(m_simpleKeyAllowed)
|
if(m_simpleKeyAllowed)
|
||||||
InsertSimpleKey();
|
InsertSimpleKey();
|
||||||
|
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
scalar = ScanScalar(INPUT, params);
|
scalar = ScanScalar(INPUT, params);
|
||||||
|
|
||||||
// can have a simple key only if we ended the scalar by starting a new line
|
// can have a simple key only if we ended the scalar by starting a new line
|
||||||
m_simpleKeyAllowed = params.leadingSpaces;
|
m_simpleKeyAllowed = params.leadingSpaces;
|
||||||
|
|
||||||
// finally, check and see if we ended on an illegal character
|
// finally, check and see if we ended on an illegal character
|
||||||
//if(Exp::IllegalCharInScalar.Matches(INPUT))
|
//if(Exp::IllegalCharInScalar.Matches(INPUT))
|
||||||
// throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR);
|
// throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR);
|
||||||
|
|
||||||
Token token(TT_SCALAR, line, column);
|
Token token(TT_SCALAR, line, column);
|
||||||
token.value = scalar;
|
token.value = scalar;
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuotedScalar
|
// QuotedScalar
|
||||||
void Scanner::ScanQuotedScalar()
|
void Scanner::ScanQuotedScalar()
|
||||||
{
|
{
|
||||||
std::string scalar;
|
std::string scalar;
|
||||||
|
|
||||||
// eat single or double quote
|
// eat single or double quote
|
||||||
char quote = INPUT.get();
|
char quote = INPUT.get();
|
||||||
bool single = (quote == '\'');
|
bool single = (quote == '\'');
|
||||||
|
|
||||||
// setup the scanning parameters
|
// setup the scanning parameters
|
||||||
ScanScalarParams params;
|
ScanScalarParams params;
|
||||||
params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote));
|
params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote));
|
||||||
params.eatEnd = true;
|
params.eatEnd = true;
|
||||||
params.escape = (single ? '\'' : '\\');
|
params.escape = (single ? '\'' : '\\');
|
||||||
params.indent = 0;
|
params.indent = 0;
|
||||||
params.fold = true;
|
params.fold = true;
|
||||||
params.eatLeadingWhitespace = true;
|
params.eatLeadingWhitespace = true;
|
||||||
params.trimTrailingSpaces = false;
|
params.trimTrailingSpaces = false;
|
||||||
params.chomp = CLIP;
|
params.chomp = CLIP;
|
||||||
params.onDocIndicator = THROW;
|
params.onDocIndicator = THROW;
|
||||||
|
|
||||||
// insert a potential simple key
|
// insert a potential simple key
|
||||||
if(m_simpleKeyAllowed)
|
if(m_simpleKeyAllowed)
|
||||||
InsertSimpleKey();
|
InsertSimpleKey();
|
||||||
|
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
scalar = ScanScalar(INPUT, params);
|
scalar = ScanScalar(INPUT, params);
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
|
||||||
Token token(TT_SCALAR, line, column);
|
Token token(TT_SCALAR, line, column);
|
||||||
token.value = scalar;
|
token.value = scalar;
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockScalarToken
|
// BlockScalarToken
|
||||||
// . These need a little extra processing beforehand.
|
// . These need a little extra processing beforehand.
|
||||||
// . We need to scan the line where the indicator is (this doesn't count as part of the scalar),
|
// . We need to scan the line where the indicator is (this doesn't count as part of the scalar),
|
||||||
// and then we need to figure out what level of indentation we'll be using.
|
// and then we need to figure out what level of indentation we'll be using.
|
||||||
void Scanner::ScanBlockScalar()
|
void Scanner::ScanBlockScalar()
|
||||||
{
|
{
|
||||||
std::string scalar;
|
std::string scalar;
|
||||||
|
|
||||||
ScanScalarParams params;
|
ScanScalarParams params;
|
||||||
params.indent = 1;
|
params.indent = 1;
|
||||||
params.detectIndent = true;
|
params.detectIndent = true;
|
||||||
|
|
||||||
// eat block indicator ('|' or '>')
|
// eat block indicator ('|' or '>')
|
||||||
int line = INPUT.line, column = INPUT.column;
|
int line = INPUT.line, column = INPUT.column;
|
||||||
char indicator = INPUT.get();
|
char indicator = INPUT.get();
|
||||||
params.fold = (indicator == Keys::FoldedScalar);
|
params.fold = (indicator == Keys::FoldedScalar);
|
||||||
|
|
||||||
// eat chomping/indentation indicators
|
// eat chomping/indentation indicators
|
||||||
int n = Exp::Chomp.Match(INPUT);
|
int n = Exp::Chomp.Match(INPUT);
|
||||||
for(int i=0;i<n;i++) {
|
for(int i=0;i<n;i++) {
|
||||||
char ch = INPUT.get();
|
char ch = INPUT.get();
|
||||||
if(ch == '+')
|
if(ch == '+')
|
||||||
params.chomp = KEEP;
|
params.chomp = KEEP;
|
||||||
else if(ch == '-')
|
else if(ch == '-')
|
||||||
params.chomp = STRIP;
|
params.chomp = STRIP;
|
||||||
else if(Exp::Digit.Matches(ch)) {
|
else if(Exp::Digit.Matches(ch)) {
|
||||||
if(ch == '0')
|
if(ch == '0')
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::ZERO_INDENT_IN_BLOCK);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::ZERO_INDENT_IN_BLOCK);
|
||||||
|
|
||||||
params.indent = ch - '0';
|
params.indent = ch - '0';
|
||||||
params.detectIndent = false;
|
params.detectIndent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now eat whitespace
|
// now eat whitespace
|
||||||
while(Exp::Blank.Matches(INPUT))
|
while(Exp::Blank.Matches(INPUT))
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
|
|
||||||
// and comments to the end of the line
|
// and comments to the end of the line
|
||||||
if(Exp::Comment.Matches(INPUT))
|
if(Exp::Comment.Matches(INPUT))
|
||||||
while(INPUT && !Exp::Break.Matches(INPUT))
|
while(INPUT && !Exp::Break.Matches(INPUT))
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
|
|
||||||
// if it's not a line break, then we ran into a bad character inline
|
// if it's not a line break, then we ran into a bad character inline
|
||||||
if(INPUT && !Exp::Break.Matches(INPUT))
|
if(INPUT && !Exp::Break.Matches(INPUT))
|
||||||
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_BLOCK);
|
throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_BLOCK);
|
||||||
|
|
||||||
// set the initial indentation
|
// set the initial indentation
|
||||||
if(m_indents.top() >= 0)
|
if(m_indents.top() >= 0)
|
||||||
params.indent += m_indents.top();
|
params.indent += m_indents.top();
|
||||||
|
|
||||||
params.eatLeadingWhitespace = false;
|
params.eatLeadingWhitespace = false;
|
||||||
params.trimTrailingSpaces = false;
|
params.trimTrailingSpaces = false;
|
||||||
params.onTabInIndentation = THROW;
|
params.onTabInIndentation = THROW;
|
||||||
|
|
||||||
scalar = ScanScalar(INPUT, params);
|
scalar = ScanScalar(INPUT, params);
|
||||||
|
|
||||||
// simple keys always ok after block scalars (since we're gonna start a new line anyways)
|
// simple keys always ok after block scalars (since we're gonna start a new line anyways)
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
|
|
||||||
Token token(TT_SCALAR, line, column);
|
Token token(TT_SCALAR, line, column);
|
||||||
token.value = scalar;
|
token.value = scalar;
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
350
src/sequence.cpp
350
src/sequence.cpp
@@ -1,175 +1,175 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "sequence.h"
|
#include "sequence.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Sequence::Sequence()
|
Sequence::Sequence()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequence::~Sequence()
|
Sequence::~Sequence()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::Clear()
|
void Sequence::Clear()
|
||||||
{
|
{
|
||||||
for(unsigned i=0;i<m_data.size();i++)
|
for(unsigned i=0;i<m_data.size();i++)
|
||||||
delete m_data[i];
|
delete m_data[i];
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const
|
bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const
|
||||||
{
|
{
|
||||||
it = m_data.begin();
|
it = m_data.begin();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::GetEnd(std::vector <Node *>::const_iterator& it) const
|
bool Sequence::GetEnd(std::vector <Node *>::const_iterator& it) const
|
||||||
{
|
{
|
||||||
it = m_data.end();
|
it = m_data.end();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *Sequence::GetNode(unsigned i) const
|
Node *Sequence::GetNode(unsigned i) const
|
||||||
{
|
{
|
||||||
if(i < m_data.size())
|
if(i < m_data.size())
|
||||||
return m_data[i];
|
return m_data[i];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Sequence::GetSize() const
|
unsigned Sequence::GetSize() const
|
||||||
{
|
{
|
||||||
return m_data.size();
|
return m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::Parse(Scanner *pScanner, const ParserState& state)
|
void Sequence::Parse(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
// split based on start token
|
// split based on start token
|
||||||
switch(pScanner->peek().type) {
|
switch(pScanner->peek().type) {
|
||||||
case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
|
case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
|
||||||
case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break;
|
case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break;
|
||||||
case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break;
|
case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state)
|
void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
// eat start token
|
// eat start token
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(pScanner->empty())
|
if(pScanner->empty())
|
||||||
throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ);
|
throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ);
|
||||||
|
|
||||||
Token token = pScanner->peek();
|
Token token = pScanner->peek();
|
||||||
if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END)
|
if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END)
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ);
|
throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ);
|
||||||
|
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
if(token.type == TT_BLOCK_END)
|
if(token.type == TT_BLOCK_END)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Node *pNode = new Node;
|
Node *pNode = new Node;
|
||||||
m_data.push_back(pNode);
|
m_data.push_back(pNode);
|
||||||
pNode->Parse(pScanner, state);
|
pNode->Parse(pScanner, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state)
|
void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
// we're actually *allowed* to have no tokens at some point
|
// we're actually *allowed* to have no tokens at some point
|
||||||
if(pScanner->empty())
|
if(pScanner->empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// and we end at anything other than a block entry
|
// and we end at anything other than a block entry
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
if(token.type != TT_BLOCK_ENTRY)
|
if(token.type != TT_BLOCK_ENTRY)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
|
|
||||||
Node *pNode = new Node;
|
Node *pNode = new Node;
|
||||||
m_data.push_back(pNode);
|
m_data.push_back(pNode);
|
||||||
pNode->Parse(pScanner, state);
|
pNode->Parse(pScanner, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state)
|
void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state)
|
||||||
{
|
{
|
||||||
// eat start token
|
// eat start token
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
if(pScanner->empty())
|
if(pScanner->empty())
|
||||||
throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW);
|
throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW);
|
||||||
|
|
||||||
// first check for end
|
// first check for end
|
||||||
if(pScanner->peek().type == TT_FLOW_SEQ_END) {
|
if(pScanner->peek().type == TT_FLOW_SEQ_END) {
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// then read the node
|
// then read the node
|
||||||
Node *pNode = new Node;
|
Node *pNode = new Node;
|
||||||
m_data.push_back(pNode);
|
m_data.push_back(pNode);
|
||||||
pNode->Parse(pScanner, state);
|
pNode->Parse(pScanner, state);
|
||||||
|
|
||||||
// now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node)
|
// now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node)
|
||||||
Token& token = pScanner->peek();
|
Token& token = pScanner->peek();
|
||||||
if(token.type == TT_FLOW_ENTRY)
|
if(token.type == TT_FLOW_ENTRY)
|
||||||
pScanner->pop();
|
pScanner->pop();
|
||||||
else if(token.type != TT_FLOW_SEQ_END)
|
else if(token.type != TT_FLOW_SEQ_END)
|
||||||
throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW);
|
throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
||||||
{
|
{
|
||||||
if(startedLine && !onlyOneCharOnLine)
|
if(startedLine && !onlyOneCharOnLine)
|
||||||
out << "\n";
|
out << "\n";
|
||||||
|
|
||||||
for(unsigned i=0;i<m_data.size();i++) {
|
for(unsigned i=0;i<m_data.size();i++) {
|
||||||
if((startedLine && !onlyOneCharOnLine) || i > 0) {
|
if((startedLine && !onlyOneCharOnLine) || i > 0) {
|
||||||
for(int j=0;j<indent;j++)
|
for(int j=0;j<indent;j++)
|
||||||
out << " ";
|
out << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "- ";
|
out << "- ";
|
||||||
m_data[i]->Write(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine);
|
m_data[i]->Write(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_data.empty())
|
if(m_data.empty())
|
||||||
out << "\n";
|
out << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sequence::Compare(Content *pContent)
|
int Sequence::Compare(Content *pContent)
|
||||||
{
|
{
|
||||||
return -pContent->Compare(this);
|
return -pContent->Compare(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Sequence::Compare(Sequence *pSeq)
|
int Sequence::Compare(Sequence *pSeq)
|
||||||
{
|
{
|
||||||
unsigned n = m_data.size(), m = pSeq->m_data.size();
|
unsigned n = m_data.size(), m = pSeq->m_data.size();
|
||||||
if(n < m)
|
if(n < m)
|
||||||
return -1;
|
return -1;
|
||||||
else if(n > m)
|
else if(n > m)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for(unsigned i=0;i<n;i++) {
|
for(unsigned i=0;i<n;i++) {
|
||||||
int cmp = m_data[i]->Compare(*pSeq->m_data[i]);
|
int cmp = m_data[i]->Compare(*pSeq->m_data[i]);
|
||||||
if(cmp != 0)
|
if(cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,41 +1,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "content.h"
|
#include "content.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
class Node;
|
class Node;
|
||||||
|
|
||||||
class Sequence: public Content
|
class Sequence: public Content
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Sequence();
|
Sequence();
|
||||||
virtual ~Sequence();
|
virtual ~Sequence();
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const;
|
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const;
|
||||||
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const;
|
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const;
|
||||||
virtual Node *GetNode(unsigned i) const;
|
virtual Node *GetNode(unsigned i) const;
|
||||||
virtual unsigned GetSize() const;
|
virtual unsigned GetSize() const;
|
||||||
|
|
||||||
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
||||||
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
||||||
|
|
||||||
virtual bool IsSequence() const { return true; }
|
virtual bool IsSequence() const { return true; }
|
||||||
|
|
||||||
// ordering
|
// ordering
|
||||||
virtual int Compare(Content *pContent);
|
virtual int Compare(Content *pContent);
|
||||||
virtual int Compare(Scalar *pScalar) { return 1; }
|
virtual int Compare(Scalar *pScalar) { return 1; }
|
||||||
virtual int Compare(Sequence *pSeq);
|
virtual int Compare(Sequence *pSeq);
|
||||||
virtual int Compare(Map *pMap) { return -1; }
|
virtual int Compare(Map *pMap) { return -1; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ParseBlock(Scanner *pScanner, const ParserState& state);
|
void ParseBlock(Scanner *pScanner, const ParserState& state);
|
||||||
void ParseImplicit(Scanner *pScanner, const ParserState& state);
|
void ParseImplicit(Scanner *pScanner, const ParserState& state);
|
||||||
void ParseFlow(Scanner *pScanner, const ParserState& state);
|
void ParseFlow(Scanner *pScanner, const ParserState& state);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector <Node *> m_data;
|
std::vector <Node *> m_data;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,102 +1,102 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "exp.h"
|
#include "exp.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_)
|
Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_)
|
||||||
: pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), pMapStart(0), pKey(0)
|
: pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), pMapStart(0), pKey(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::SimpleKey::Validate()
|
void Scanner::SimpleKey::Validate()
|
||||||
{
|
{
|
||||||
if(pMapStart)
|
if(pMapStart)
|
||||||
pMapStart->status = TS_VALID;
|
pMapStart->status = TS_VALID;
|
||||||
if(pKey)
|
if(pKey)
|
||||||
pKey->status = TS_VALID;
|
pKey->status = TS_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::SimpleKey::Invalidate()
|
void Scanner::SimpleKey::Invalidate()
|
||||||
{
|
{
|
||||||
if(pMapStart)
|
if(pMapStart)
|
||||||
pMapStart->status = TS_INVALID;
|
pMapStart->status = TS_INVALID;
|
||||||
if(pKey)
|
if(pKey)
|
||||||
pKey->status = TS_INVALID;
|
pKey->status = TS_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertSimpleKey
|
// InsertSimpleKey
|
||||||
// . Adds a potential simple key to the queue,
|
// . Adds a potential simple key to the queue,
|
||||||
// and saves it on a stack.
|
// and saves it on a stack.
|
||||||
void Scanner::InsertSimpleKey()
|
void Scanner::InsertSimpleKey()
|
||||||
{
|
{
|
||||||
SimpleKey key(INPUT.pos(), INPUT.line, INPUT.column, m_flowLevel);
|
SimpleKey key(INPUT.pos(), INPUT.line, INPUT.column, m_flowLevel);
|
||||||
|
|
||||||
// first add a map start, if necessary
|
// first add a map start, if necessary
|
||||||
key.pMapStart = PushIndentTo(INPUT.column, false);
|
key.pMapStart = PushIndentTo(INPUT.column, false);
|
||||||
if(key.pMapStart)
|
if(key.pMapStart)
|
||||||
key.pMapStart->status = TS_UNVERIFIED;
|
key.pMapStart->status = TS_UNVERIFIED;
|
||||||
|
|
||||||
// then add the (now unverified) key
|
// then add the (now unverified) key
|
||||||
m_tokens.push(Token(TT_KEY, INPUT.line, INPUT.column));
|
m_tokens.push(Token(TT_KEY, INPUT.line, INPUT.column));
|
||||||
key.pKey = &m_tokens.back();
|
key.pKey = &m_tokens.back();
|
||||||
key.pKey->status = TS_UNVERIFIED;
|
key.pKey->status = TS_UNVERIFIED;
|
||||||
|
|
||||||
m_simpleKeys.push(key);
|
m_simpleKeys.push(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySimpleKey
|
// VerifySimpleKey
|
||||||
// . Determines whether the latest simple key to be added is valid,
|
// . Determines whether the latest simple key to be added is valid,
|
||||||
// and if so, makes it valid.
|
// and if so, makes it valid.
|
||||||
bool Scanner::VerifySimpleKey()
|
bool Scanner::VerifySimpleKey()
|
||||||
{
|
{
|
||||||
m_isLastKeyValid = false;
|
m_isLastKeyValid = false;
|
||||||
if(m_simpleKeys.empty())
|
if(m_simpleKeys.empty())
|
||||||
return m_isLastKeyValid;
|
return m_isLastKeyValid;
|
||||||
|
|
||||||
// grab top key
|
// grab top key
|
||||||
SimpleKey key = m_simpleKeys.top();
|
SimpleKey key = m_simpleKeys.top();
|
||||||
|
|
||||||
// only validate if we're in the correct flow level
|
// only validate if we're in the correct flow level
|
||||||
if(key.flowLevel != m_flowLevel)
|
if(key.flowLevel != m_flowLevel)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_simpleKeys.pop();
|
m_simpleKeys.pop();
|
||||||
|
|
||||||
bool isValid = true;
|
bool isValid = true;
|
||||||
|
|
||||||
// needs to be followed immediately by a value
|
// needs to be followed immediately by a value
|
||||||
if(m_flowLevel > 0 && !Exp::ValueInFlow.Matches(INPUT))
|
if(m_flowLevel > 0 && !Exp::ValueInFlow.Matches(INPUT))
|
||||||
isValid = false;
|
isValid = false;
|
||||||
if(m_flowLevel == 0 && !Exp::Value.Matches(INPUT))
|
if(m_flowLevel == 0 && !Exp::Value.Matches(INPUT))
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
|
||||||
// also needs to be less than 1024 characters and inline
|
// also needs to be less than 1024 characters and inline
|
||||||
if(INPUT.line != key.line || INPUT.pos() - key.pos > 1024)
|
if(INPUT.line != key.line || INPUT.pos() - key.pos > 1024)
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
|
||||||
// invalidate key
|
// invalidate key
|
||||||
if(isValid)
|
if(isValid)
|
||||||
key.Validate();
|
key.Validate();
|
||||||
else
|
else
|
||||||
key.Invalidate();
|
key.Invalidate();
|
||||||
|
|
||||||
// In block style, remember that we've pushed an indent for this potential simple key (if it was starting).
|
// In block style, remember that we've pushed an indent for this potential simple key (if it was starting).
|
||||||
// If it was invalid, then we need to pop it off.
|
// If it was invalid, then we need to pop it off.
|
||||||
// Note: we're guaranteed to be popping the right one (i.e., there couldn't have been anything in
|
// Note: we're guaranteed to be popping the right one (i.e., there couldn't have been anything in
|
||||||
// between) since keys have to be inline, and will be invalidated immediately on a newline.
|
// between) since keys have to be inline, and will be invalidated immediately on a newline.
|
||||||
if(!isValid && m_flowLevel == 0)
|
if(!isValid && m_flowLevel == 0)
|
||||||
m_indents.pop();
|
m_indents.pop();
|
||||||
|
|
||||||
m_isLastKeyValid = isValid;
|
m_isLastKeyValid = isValid;
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scanner::VerifyAllSimpleKeys()
|
void Scanner::VerifyAllSimpleKeys()
|
||||||
{
|
{
|
||||||
while(!m_simpleKeys.empty())
|
while(!m_simpleKeys.empty())
|
||||||
VerifySimpleKey();
|
VerifySimpleKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
106
src/stream.cpp
106
src/stream.cpp
@@ -1,53 +1,53 @@
|
|||||||
#include "crt.h"
|
#include "crt.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
int Stream::pos() const
|
int Stream::pos() const
|
||||||
{
|
{
|
||||||
return input.tellg();
|
return input.tellg();
|
||||||
}
|
}
|
||||||
|
|
||||||
char Stream::peek()
|
char Stream::peek()
|
||||||
{
|
{
|
||||||
return input.peek();
|
return input.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::operator bool()
|
Stream::operator bool()
|
||||||
{
|
{
|
||||||
return input.good();
|
return input.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get
|
// get
|
||||||
// . Extracts a character from the stream and updates our position
|
// . Extracts a character from the stream and updates our position
|
||||||
char Stream::get()
|
char Stream::get()
|
||||||
{
|
{
|
||||||
char ch = input.get();
|
char ch = input.get();
|
||||||
column++;
|
column++;
|
||||||
if(ch == '\n') {
|
if(ch == '\n') {
|
||||||
column = 0;
|
column = 0;
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get
|
// get
|
||||||
// . Extracts 'n' characters from the stream and updates our position
|
// . Extracts 'n' characters from the stream and updates our position
|
||||||
std::string Stream::get(int n)
|
std::string Stream::get(int n)
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
for(int i=0;i<n;i++)
|
for(int i=0;i<n;i++)
|
||||||
ret += get();
|
ret += get();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
// . Eats 'n' characters and updates our position.
|
// . Eats 'n' characters and updates our position.
|
||||||
void Stream::eat(int n)
|
void Stream::eat(int n)
|
||||||
{
|
{
|
||||||
for(int i=0;i<n;i++)
|
for(int i=0;i<n;i++)
|
||||||
get();
|
get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
50
src/stream.h
50
src/stream.h
@@ -1,25 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
struct Stream
|
struct Stream
|
||||||
{
|
{
|
||||||
Stream(std::istream& input_): input(input_), line(0), column(0) {}
|
Stream(std::istream& input_): input(input_), line(0), column(0) {}
|
||||||
|
|
||||||
int pos() const;
|
int pos() const;
|
||||||
operator bool();
|
operator bool();
|
||||||
bool operator !() { return !(*this); }
|
bool operator !() { return !(*this); }
|
||||||
|
|
||||||
std::istream& stream() const { return input; }
|
std::istream& stream() const { return input; }
|
||||||
char peek();
|
char peek();
|
||||||
char get();
|
char get();
|
||||||
std::string get(int n);
|
std::string get(int n);
|
||||||
void eat(int n = 1);
|
void eat(int n = 1);
|
||||||
|
|
||||||
std::istream& input;
|
std::istream& input;
|
||||||
int line, column;
|
int line, column;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
136
src/token.h
136
src/token.h
@@ -1,68 +1,68 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED };
|
enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED };
|
||||||
enum TOKEN_TYPE {
|
enum TOKEN_TYPE {
|
||||||
TT_DIRECTIVE,
|
TT_DIRECTIVE,
|
||||||
TT_DOC_START,
|
TT_DOC_START,
|
||||||
TT_DOC_END,
|
TT_DOC_END,
|
||||||
TT_BLOCK_SEQ_START,
|
TT_BLOCK_SEQ_START,
|
||||||
TT_BLOCK_MAP_START,
|
TT_BLOCK_MAP_START,
|
||||||
TT_BLOCK_END,
|
TT_BLOCK_END,
|
||||||
TT_BLOCK_ENTRY,
|
TT_BLOCK_ENTRY,
|
||||||
TT_FLOW_SEQ_START,
|
TT_FLOW_SEQ_START,
|
||||||
TT_FLOW_MAP_START,
|
TT_FLOW_MAP_START,
|
||||||
TT_FLOW_SEQ_END,
|
TT_FLOW_SEQ_END,
|
||||||
TT_FLOW_MAP_END,
|
TT_FLOW_MAP_END,
|
||||||
TT_FLOW_ENTRY,
|
TT_FLOW_ENTRY,
|
||||||
TT_KEY,
|
TT_KEY,
|
||||||
TT_VALUE,
|
TT_VALUE,
|
||||||
TT_ANCHOR,
|
TT_ANCHOR,
|
||||||
TT_ALIAS,
|
TT_ALIAS,
|
||||||
TT_TAG,
|
TT_TAG,
|
||||||
TT_SCALAR,
|
TT_SCALAR,
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string TokenNames[] = {
|
const std::string TokenNames[] = {
|
||||||
"DIRECTIVE",
|
"DIRECTIVE",
|
||||||
"DOC_START",
|
"DOC_START",
|
||||||
"DOC_END",
|
"DOC_END",
|
||||||
"BLOCK_SEQ_START",
|
"BLOCK_SEQ_START",
|
||||||
"BLOCK_MAP_START",
|
"BLOCK_MAP_START",
|
||||||
"BLOCK_END",
|
"BLOCK_END",
|
||||||
"BLOCK_ENTRY",
|
"BLOCK_ENTRY",
|
||||||
"FLOW_SEQ_START",
|
"FLOW_SEQ_START",
|
||||||
"FLOW_MAP_START",
|
"FLOW_MAP_START",
|
||||||
"FLOW_SEQ_END",
|
"FLOW_SEQ_END",
|
||||||
"FLOW_MAP_END",
|
"FLOW_MAP_END",
|
||||||
"FLOW_ENTRY",
|
"FLOW_ENTRY",
|
||||||
"KEY",
|
"KEY",
|
||||||
"VALUE",
|
"VALUE",
|
||||||
"ANCHOR",
|
"ANCHOR",
|
||||||
"ALIAS",
|
"ALIAS",
|
||||||
"TAG",
|
"TAG",
|
||||||
"SCALAR",
|
"SCALAR",
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
Token(TOKEN_TYPE type_, int line_, int column_): status(TS_VALID), type(type_), line(line_), column(column_) {}
|
Token(TOKEN_TYPE type_, int line_, int column_): status(TS_VALID), type(type_), line(line_), column(column_) {}
|
||||||
|
|
||||||
friend std::ostream& operator << (std::ostream& out, const Token& token) {
|
friend std::ostream& operator << (std::ostream& out, const Token& token) {
|
||||||
out << TokenNames[token.type] << std::string(": ") << token.value;
|
out << TokenNames[token.type] << std::string(": ") << token.value;
|
||||||
for(unsigned i=0;i<token.params.size();i++)
|
for(unsigned i=0;i<token.params.size();i++)
|
||||||
out << std::string(" ") << token.params[i];
|
out << std::string(" ") << token.params[i];
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
TOKEN_STATUS status;
|
TOKEN_STATUS status;
|
||||||
TOKEN_TYPE type;
|
TOKEN_TYPE type;
|
||||||
int line, column;
|
int line, column;
|
||||||
std::string value;
|
std::string value;
|
||||||
std::vector <std::string> params;
|
std::vector <std::string> params;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,41 +1,41 @@
|
|||||||
#include "yaml.h"
|
#include "yaml.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#pragma comment(lib, "yamlcppd.lib")
|
#pragma comment(lib, "yamlcppd.lib")
|
||||||
#else
|
#else
|
||||||
#pragma comment(lib, "yamlcpp.lib")
|
#pragma comment(lib, "yamlcpp.lib")
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
std::ifstream fin("tests/test.yaml");
|
std::ifstream fin("tests/test.yaml");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
YAML::Parser parser(fin);
|
YAML::Parser parser(fin);
|
||||||
parser.PrintTokens(std::cout);
|
parser.PrintTokens(std::cout);
|
||||||
} catch(YAML::Exception&) {
|
} catch(YAML::Exception&) {
|
||||||
std::cout << "Error parsing the yaml!\n";
|
std::cout << "Error parsing the yaml!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
for(int i=1;i<argc;i++) {
|
for(int i=1;i<argc;i++) {
|
||||||
if(strcmp(argv[i], "-v") == 0)
|
if(strcmp(argv[i], "-v") == 0)
|
||||||
verbose = true;
|
verbose = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
|
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
|
||||||
#endif // WINDOWS
|
#endif // WINDOWS
|
||||||
Test::RunAll(verbose);
|
Test::RunAll(verbose);
|
||||||
run();
|
run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -1,88 +1,88 @@
|
|||||||
#include "yaml.h"
|
#include "yaml.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace Test
|
namespace Test
|
||||||
{
|
{
|
||||||
// runs all the tests on all data we have
|
// runs all the tests on all data we have
|
||||||
void RunAll(bool verbose)
|
void RunAll(bool verbose)
|
||||||
{
|
{
|
||||||
std::vector <std::string> files;
|
std::vector <std::string> files;
|
||||||
files.push_back("tests/simple.yaml");
|
files.push_back("tests/simple.yaml");
|
||||||
files.push_back("tests/mixed.yaml");
|
files.push_back("tests/mixed.yaml");
|
||||||
files.push_back("tests/scalars.yaml");
|
files.push_back("tests/scalars.yaml");
|
||||||
files.push_back("tests/directives.yaml");
|
files.push_back("tests/directives.yaml");
|
||||||
|
|
||||||
bool passed = true;
|
bool passed = true;
|
||||||
for(unsigned i=0;i<files.size();i++) {
|
for(unsigned i=0;i<files.size();i++) {
|
||||||
if(!Inout(files[i], verbose)) {
|
if(!Inout(files[i], verbose)) {
|
||||||
std::cout << "Inout test failed on " << files[i] << "\n";
|
std::cout << "Inout test failed on " << files[i] << "\n";
|
||||||
passed = false;
|
passed = false;
|
||||||
} else
|
} else
|
||||||
std::cout << "Inout test passed: " << files[i] << "\n";
|
std::cout << "Inout test passed: " << files[i] << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(passed)
|
if(passed)
|
||||||
std::cout << "All tests passed!\n";
|
std::cout << "All tests passed!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// loads the given YAML file, outputs it, and then loads the outputted file,
|
// loads the given YAML file, outputs it, and then loads the outputted file,
|
||||||
// outputs again, and makes sure that the two outputs are the same
|
// outputs again, and makes sure that the two outputs are the same
|
||||||
bool Inout(const std::string& file, bool verbose)
|
bool Inout(const std::string& file, bool verbose)
|
||||||
{
|
{
|
||||||
std::ifstream fin(file.c_str());
|
std::ifstream fin(file.c_str());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// read and output
|
// read and output
|
||||||
YAML::Parser parser(fin);
|
YAML::Parser parser(fin);
|
||||||
if(!parser)
|
if(!parser)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
YAML::Node doc;
|
YAML::Node doc;
|
||||||
parser.GetNextDocument(doc);
|
parser.GetNextDocument(doc);
|
||||||
|
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
out << doc;
|
out << doc;
|
||||||
// and save
|
// and save
|
||||||
std::string firstTry = out.str();
|
std::string firstTry = out.str();
|
||||||
|
|
||||||
// and now again
|
// and now again
|
||||||
parser.Load(out);
|
parser.Load(out);
|
||||||
if(!parser)
|
if(!parser)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
parser.GetNextDocument(doc);
|
parser.GetNextDocument(doc);
|
||||||
std::stringstream out2;
|
std::stringstream out2;
|
||||||
out2 << doc;
|
out2 << doc;
|
||||||
// and save
|
// and save
|
||||||
std::string secondTry = out2.str();
|
std::string secondTry = out2.str();
|
||||||
|
|
||||||
// now compare
|
// now compare
|
||||||
if(firstTry == secondTry)
|
if(firstTry == secondTry)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::ofstream fout("tests/out.yaml");
|
std::ofstream fout("tests/out.yaml");
|
||||||
fout << "---\n";
|
fout << "---\n";
|
||||||
fout << firstTry << std::endl;
|
fout << firstTry << std::endl;
|
||||||
fout << "---\n";
|
fout << "---\n";
|
||||||
fout << secondTry << std::endl;
|
fout << secondTry << std::endl;
|
||||||
} catch(YAML::ParserException& e) {
|
} catch(YAML::ParserException& e) {
|
||||||
std::cout << file << " (line " << e.line + 1 << ", col " << e.column + 1 << "): " << e.msg << std::endl;
|
std::cout << file << " (line " << e.line + 1 << ", col " << e.column + 1 << "): " << e.msg << std::endl;
|
||||||
|
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
std::cout << "Token queue:\n";
|
std::cout << "Token queue:\n";
|
||||||
std::ifstream f(file.c_str());
|
std::ifstream f(file.c_str());
|
||||||
YAML::Parser p(f);
|
YAML::Parser p(f);
|
||||||
p.PrintTokens(std::cout);
|
p.PrintTokens(std::cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Test {
|
namespace Test {
|
||||||
void RunAll(bool verbose);
|
void RunAll(bool verbose);
|
||||||
bool Inout(const std::string& file, bool verbose);
|
bool Inout(const std::string& file, bool verbose);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
%TAG ! !howdy
|
%TAG ! !howdy
|
||||||
---
|
---
|
||||||
- basic node
|
- basic node
|
||||||
- ! yeah baby
|
- ! yeah baby
|
@@ -1,32 +1,32 @@
|
|||||||
- the main thing is a sequence
|
- the main thing is a sequence
|
||||||
- here's a key: value
|
- here's a key: value
|
||||||
and another: value
|
and another: value
|
||||||
- let's inline: [1, 2, 3]
|
- let's inline: [1, 2, 3]
|
||||||
and an inline map: {key: value, 243: 101}
|
and an inline map: {key: value, 243: 101}
|
||||||
- and multiple indents:
|
- and multiple indents:
|
||||||
- here's
|
- here's
|
||||||
- a
|
- a
|
||||||
- list
|
- list
|
||||||
and another:
|
and another:
|
||||||
- list
|
- list
|
||||||
- of
|
- of
|
||||||
- things
|
- things
|
||||||
- maybe now:
|
- maybe now:
|
||||||
let's: get
|
let's: get
|
||||||
pretty:
|
pretty:
|
||||||
deep: here
|
deep: here
|
||||||
in:
|
in:
|
||||||
the: nesting
|
the: nesting
|
||||||
just: to
|
just: to
|
||||||
confuse:
|
confuse:
|
||||||
the: heck
|
the: heck
|
||||||
out:
|
out:
|
||||||
- of
|
- of
|
||||||
- the: parser
|
- the: parser
|
||||||
if:
|
if:
|
||||||
- we
|
- we
|
||||||
- can
|
- can
|
||||||
- do: that
|
- do: that
|
||||||
what: do
|
what: do
|
||||||
you: think?
|
you: think?
|
||||||
|
|
@@ -1,35 +1,35 @@
|
|||||||
- normal scalar, but
|
- normal scalar, but
|
||||||
over several lines
|
over several lines
|
||||||
- |
|
- |
|
||||||
literal scalar - so we can draw ASCII:
|
literal scalar - so we can draw ASCII:
|
||||||
|
|
||||||
- -
|
- -
|
||||||
| - |
|
| - |
|
||||||
------
|
------
|
||||||
- >
|
- >
|
||||||
and a folded scalar... so we
|
and a folded scalar... so we
|
||||||
can just keep writing various
|
can just keep writing various
|
||||||
things. And if we want to keep indentation:
|
things. And if we want to keep indentation:
|
||||||
|
|
||||||
we just indent a little
|
we just indent a little
|
||||||
see, this stays indented
|
see, this stays indented
|
||||||
- >-
|
- >-
|
||||||
Here's a folded scalar
|
Here's a folded scalar
|
||||||
that gets chomped.
|
that gets chomped.
|
||||||
- |-
|
- |-
|
||||||
And here's a literal scalar
|
And here's a literal scalar
|
||||||
that gets chomped.
|
that gets chomped.
|
||||||
- >2
|
- >2
|
||||||
Here's a folded scalar
|
Here's a folded scalar
|
||||||
that starts with some indentation.
|
that starts with some indentation.
|
||||||
- ::vector
|
- ::vector
|
||||||
- ": - ()"
|
- ": - ()"
|
||||||
- Up, up, and away!
|
- Up, up, and away!
|
||||||
- -123
|
- -123
|
||||||
- http://example.com/foo#bar
|
- http://example.com/foo#bar
|
||||||
# Inside flow collection:
|
# Inside flow collection:
|
||||||
- [ ::vector,
|
- [ ::vector,
|
||||||
": - ()",
|
": - ()",
|
||||||
"Up, up and away!",
|
"Up, up and away!",
|
||||||
-123,
|
-123,
|
||||||
http://example.com/foo#bar ]
|
http://example.com/foo#bar ]
|
@@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
just a scalar
|
just a scalar
|
||||||
---
|
---
|
||||||
and another scalar
|
and another scalar
|
||||||
---
|
---
|
||||||
now an end document
|
now an end document
|
||||||
...
|
...
|
||||||
---
|
---
|
||||||
and now two
|
and now two
|
||||||
...
|
...
|
||||||
...
|
...
|
||||||
---
|
---
|
||||||
and that's it
|
and that's it
|
@@ -1,3 +1,3 @@
|
|||||||
- it's just
|
- it's just
|
||||||
- one thing
|
- one thing
|
||||||
- after another
|
- after another
|
||||||
|
Reference in New Issue
Block a user