diff --git a/document.cpp b/document.cpp index 750ef65117..953ac6d825 100644 --- a/document.cpp +++ b/document.cpp @@ -1,5 +1,6 @@ #include "document.h" #include "node.h" +#include "parser.h" #include namespace YAML @@ -29,7 +30,10 @@ namespace YAML Clear(); std::ifstream fin(fileName.c_str()); - m_pRoot = new Node; - m_pRoot->Read(fin); + Parser parser(fin); + if(!parser) + return; + + m_pRoot = parser.ReadNextNode(); } } diff --git a/node.cpp b/node.cpp index 0da7c2b0ce..33c688fb13 100644 --- a/node.cpp +++ b/node.cpp @@ -1,5 +1,8 @@ #include "node.h" #include "content.h" +#include "parser.h" +#include "scalar.h" +#include "sequence.h" namespace YAML { @@ -18,7 +21,14 @@ namespace YAML m_pContent = 0; } - void Node::Read(std::istream& in) + void Node::Read(Parser *pParser, const std::string& token) { + Clear(); + + if(token == std::string("") + SeqToken) { + m_pContent = new Sequence(pParser); + } else { + m_pContent = new Scalar(token); + } } } diff --git a/node.h b/node.h index e1e5d1db75..c8bd7e5ba3 100644 --- a/node.h +++ b/node.h @@ -10,6 +10,7 @@ namespace YAML const std::string MapTag = "!!map"; class Content; + class Parser; class Node { @@ -18,7 +19,7 @@ namespace YAML ~Node(); void Clear(); - void Read(std::istream& in); + void Read(Parser *pParser, const std::string& token); private: std::string m_tag; diff --git a/parser.cpp b/parser.cpp new file mode 100644 index 0000000000..999fa90c13 --- /dev/null +++ b/parser.cpp @@ -0,0 +1,141 @@ +#include "parser.h" +#include "node.h" + +namespace YAML +{ + Parser::Parser(std::istream& in): INPUT(in), m_ok(true) + { + m_state.push(State(C_BLOCK, -1, true)); + + // read header + std::string token = ReadNextToken(); + if(token != DocStart) + m_ok = false; + } + + Parser::~Parser() + { + } + + Parser::operator bool() const + { + return m_ok; + } + + bool Parser::operator !() const + { + return !m_ok; + } + + bool Parser::IsWhitespace(char ch) + { + return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); + } + + void Parser::Putback(const std::string& str) + { + for(int i=str.size()-1;i>=0;i--) + INPUT.putback(str[i]); + } + + // StringWhitespace + // . Strips up to n whitespace characters (or as many + // as there are, if n is -1) + void Parser::StripWhitespace(int n) + { + while(--n >= 0 && IsWhitespace(INPUT.peek())) + INPUT.get(); + } + + int Parser::GetNumOfSpaces() + { + // get 'em out + int n = 0; + while(INPUT.peek() == ' ') { + INPUT.get(); + n++; + } + + // put 'em back + for(int i=0;iRead(this, token); + return pNode; + } + + // ReadNextToken + // . Reads: + // . If the first character is non-whitespace, non-special token, then until + // the end of this scalar. + std::string Parser::ReadNextToken() + { + const State& state = m_state.top(); + + if(state.startingNewLine) { + int n = GetNumOfSpaces(); + StripWhitespace(n); + if(n > state.indent) { + m_state.push(State(C_BLOCK, n, true)); + }; + + while(m_state.top().startingNewLine && n < m_state.top().indent) + m_state.pop(); + } + + char ch = INPUT.peek(); + if(IsWhitespace(ch)) + return ""; // TODO + + if(ch == SeqToken) { + // grab token + INPUT.get(); + + // is next token whitespace? + if(!IsWhitespace(INPUT.peek())) { + // read entire line + std::string line; + std::getline(INPUT, line); + return ch + line; + } + + // if so, strip whitespace and go + StripWhitespace(); + + return std::string("") + SeqToken; + } + + // read until end-of-line + std::string line; + std::getline(INPUT, line); + return line; + } +} diff --git a/parser.h b/parser.h new file mode 100644 index 0000000000..fbbae0b216 --- /dev/null +++ b/parser.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include + +namespace YAML +{ + class Node; + + const std::string DocStart = "---"; + const std::string DocEnd = "..."; + + const char SeqToken = '-'; + + enum CONTEXT { C_BLOCK, C_FLOW }; + + class Parser + { + public: + struct State + { + State(CONTEXT context_, int indent_, bool startingNewLine_) + : context(context_), indent(indent_), startingNewLine(startingNewLine_) {} + + CONTEXT context; + int indent; + bool startingNewLine; + }; + + public: + Parser(std::istream& in); + ~Parser(); + + operator bool () const; + bool operator !() const; + + // parse helpers + static bool IsWhitespace(char ch); + void Putback(const std::string& str); + void StripWhitespace(int n = -1); + int GetNumOfSpaces(); + bool SeqContinues(); + + // readers + Node *ReadNextNode(); + std::string ReadNextToken(); + + private: + bool m_ok; + + std::istream& INPUT; + std::stack m_state; + }; +} diff --git a/scalar.cpp b/scalar.cpp index 787e0960a5..4552194b59 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -2,7 +2,7 @@ namespace YAML { - Scalar::Scalar() + Scalar::Scalar(const std::string& data): m_data(data) { } diff --git a/scalar.h b/scalar.h index 5f3e068a16..79b69d6897 100644 --- a/scalar.h +++ b/scalar.h @@ -8,7 +8,7 @@ namespace YAML class Scalar: public Content { public: - Scalar(); + Scalar(const std::string& data); virtual ~Scalar(); protected: diff --git a/sequence.cpp b/sequence.cpp index ef1d33649a..c9d3e4c4ae 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -1,10 +1,12 @@ #include "sequence.h" #include "node.h" +#include "parser.h" namespace YAML { - Sequence::Sequence() + Sequence::Sequence(Parser *pParser) { + Read(pParser); } Sequence::~Sequence() @@ -12,4 +14,12 @@ namespace YAML for(unsigned i=0;iReadNextNode(); + m_data.push_back(pNode); + } while(pParser->SeqContinues()); + } } diff --git a/sequence.h b/sequence.h index cf7d1dd4d7..f230505b7b 100644 --- a/sequence.h +++ b/sequence.h @@ -6,13 +6,16 @@ namespace YAML { class Node; + class Parser; class Sequence: public Content { public: - Sequence(); + Sequence(Parser *pParser); virtual ~Sequence(); + void Read(Parser *pParser); + protected: std::vector m_data; }; diff --git a/test.yaml b/test.yaml index dfd38a095f..7ac0238de2 100644 --- a/test.yaml +++ b/test.yaml @@ -1,2 +1,4 @@ --- -test \ No newline at end of file +- milk +- eggs +- cheese \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index d5ea568d28..a235c5c670 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -181,6 +181,10 @@ RelativePath=".\node.cpp" > + + @@ -211,6 +215,10 @@ RelativePath=".\node.h" > + + @@ -225,6 +233,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + +