diff --git a/content.h b/content.h index d251bb1862..12a2b86569 100644 --- a/content.h +++ b/content.h @@ -1,13 +1,20 @@ #pragma once +#include + namespace YAML { + class Scanner; + class Content { public: Content(); virtual ~Content(); + virtual void Parse(Scanner *pScanner) = 0; + virtual void Write(std::ostream& out, int indent) = 0; + protected: }; } diff --git a/document.cpp b/document.cpp index 74286e99a7..fd526e2c38 100644 --- a/document.cpp +++ b/document.cpp @@ -1,5 +1,7 @@ #include "document.h" #include "node.h" +#include "token.h" +#include "scanner.h" namespace YAML { @@ -17,4 +19,36 @@ namespace YAML delete m_pRoot; m_pRoot = 0; } + + void Document::Parse(Scanner *pScanner) + { + Clear(); + + // we better have some tokens in the queue + if(!pScanner->PeekNextToken()) + return; + + // first eat doc start (optional) + if(pScanner->PeekNextToken()->type == TT_DOC_START) + pScanner->EatNextToken(); + + // now create our root node and parse it + m_pRoot = new Node; + m_pRoot->Parse(pScanner); + + // and finally eat any doc ends we see + while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END) + pScanner->EatNextToken(); + } + + std::ostream& operator << (std::ostream& out, const Document& doc) + { + if(!doc.m_pRoot) { + out << "{empty node}\n"; + return out; + } + + doc.m_pRoot->Write(out, 0); + return out; + } } diff --git a/document.h b/document.h index 62be716125..e0189815c9 100644 --- a/document.h +++ b/document.h @@ -1,8 +1,11 @@ #pragma once +#include + namespace YAML { class Node; + class Scanner; class Document { @@ -11,6 +14,9 @@ namespace YAML ~Document(); void Clear(); + void Parse(Scanner *pScanner); + + friend std::ostream& operator << (std::ostream& out, const Document& doc); private: Node *m_pRoot; diff --git a/main.cpp b/main.cpp index 2a8898ab13..dba870d960 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,16 @@ -#include "reader.h" +#include "parser.h" #include +#include int main() { std::ifstream fin("test.yaml"); - YAML::Reader reader(fin); + YAML::Parser parser(fin); + YAML::Document doc; - reader.GetNextDocument(doc); + parser.GetNextDocument(doc); + std::cout << doc; + getchar(); return 0; } \ No newline at end of file diff --git a/map.cpp b/map.cpp index 882ad15012..ef93d35f46 100644 --- a/map.cpp +++ b/map.cpp @@ -1,5 +1,7 @@ #include "map.h" #include "node.h" +#include "scanner.h" +#include "token.h" namespace YAML { @@ -14,4 +16,106 @@ namespace YAML delete it->second; } } + + void Map::Parse(Scanner *pScanner) + { + // grab start token + Token *pToken = pScanner->GetNextToken(); + + switch(pToken->type) { + case TT_BLOCK_MAP_START: ParseBlock(pScanner); break; + case TT_FLOW_MAP_START: ParseFlow(pScanner); break; + } + + delete pToken; + } + + void Map::ParseBlock(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END) + break; // TODO: throw? + + pScanner->PopNextToken(); + if(pToken->type == TT_BLOCK_END) + break; + + Node *pKey = new Node; + Node *pValue = new Node; + m_data[pKey] = pValue; + + // grab key + pKey->Parse(pScanner); + + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner); + } + } + } + + void Map::ParseFlow(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + // first check for end + if(pToken->type == TT_FLOW_MAP_END) { + pScanner->EatNextToken(); + break; + } + + // now it better be a key + if(pToken->type != TT_KEY) + break; // TODO: throw? + + pScanner->PopNextToken(); + + Node *pKey = new Node; + Node *pValue = new Node; + m_data[pKey] = pValue; + + // grab key + pKey->Parse(pScanner); + + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner); + } + + // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node) + pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_FLOW_ENTRY) + pScanner->EatNextToken(); + else if(pToken->type != TT_FLOW_MAP_END) + break; // TODO: throw? + } + } + + void Map::Write(std::ostream& out, int indent) + { + for(int i=0;ifirst->Write(out, indent + 2); + + for(int i=0;isecond->Write(out, indent + 2); + } + } } diff --git a/map.h b/map.h index b165ac5ae1..391d3f23d0 100644 --- a/map.h +++ b/map.h @@ -13,6 +13,13 @@ namespace YAML Map(); virtual ~Map(); + virtual void Parse(Scanner *pScanner); + virtual void Write(std::ostream& out, int indent); + + private: + void ParseBlock(Scanner *pScanner); + void ParseFlow(Scanner *pScanner); + protected: typedef std::map node_map; node_map m_data; diff --git a/node.cpp b/node.cpp index c3ca6a45aa..844f045a0f 100644 --- a/node.cpp +++ b/node.cpp @@ -1,8 +1,11 @@ #include "node.h" +#include "token.h" +#include "scanner.h" #include "content.h" #include "parser.h" #include "scalar.h" #include "sequence.h" +#include "map.h" namespace YAML { @@ -20,4 +23,63 @@ namespace YAML delete m_pContent; m_pContent = 0; } + + void Node::Parse(Scanner *pScanner) + { + ParseHeader(pScanner); + + // now split based on what kind of node we should be + Token *pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_DOC_END) + return; + + switch(pToken->type) { + case TT_SCALAR: + m_pContent = new Scalar; + m_pContent->Parse(pScanner); + break; + case TT_FLOW_SEQ_START: + case TT_BLOCK_SEQ_START: + case TT_BLOCK_ENTRY: + m_pContent = new Sequence; + m_pContent->Parse(pScanner); + break; + case TT_FLOW_MAP_START: + case TT_BLOCK_MAP_START: + m_pContent = new Map; + m_pContent->Parse(pScanner); + } + } + + // ParseHeader + // . Grabs any tag, alias, or anchor tokens and deals with them. + void Node::ParseHeader(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken || pToken->type != TT_TAG || pToken->type != TT_ANCHOR || pToken->type != TT_ALIAS) + break; + + pScanner->PopNextToken(); + switch(pToken->type) { + case TT_TAG: + break; + case TT_ANCHOR: + break; + case TT_ALIAS: + break; + } + delete pToken; + } + } + + void Node::Write(std::ostream& out, int indent) + { + if(!m_pContent) { + for(int i=0;iWrite(out, indent); + } } diff --git a/node.h b/node.h index b553faab74..ab15fbf495 100644 --- a/node.h +++ b/node.h @@ -10,6 +10,7 @@ namespace YAML const std::string MapTag = "!!map"; class Content; + class Scanner; class Node { @@ -18,6 +19,11 @@ namespace YAML ~Node(); void Clear(); + void Parse(Scanner *pScanner); + void Write(std::ostream& out, int indent); + + private: + void ParseHeader(Scanner *pScanner); private: std::string m_tag; diff --git a/parser.cpp b/parser.cpp index 75c014c739..4b4411da6d 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,30 +1,20 @@ #include "parser.h" -#include "node.h" -#include "token.h" - -#include +#include "scanner.h" namespace YAML { - Parser::Parser(std::istream& in): m_scanner(in) + Parser::Parser(std::istream& in): m_pScanner(0) { + m_pScanner = new Scanner(in); } Parser::~Parser() { + delete m_pScanner; } void Parser::GetNextDocument(Document& document) { - // scan and output, for now - while(1) { - Token *pToken = m_scanner.GetNextToken(); - if(!pToken) - break; - - std::cout << *pToken << std::endl; - delete pToken; - } - getchar(); + document.Parse(m_pScanner); } } diff --git a/parser.h b/parser.h index 6b4602b6bd..4f198522bc 100644 --- a/parser.h +++ b/parser.h @@ -1,13 +1,12 @@ #pragma once #include -#include -#include "scanner.h" #include "document.h" namespace YAML { class Node; + class Scanner; class Parser { @@ -18,6 +17,6 @@ namespace YAML void GetNextDocument(Document& document); private: - Scanner m_scanner; + Scanner *m_pScanner; }; } diff --git a/reader.cpp b/reader.cpp deleted file mode 100644 index 4d94459066..0000000000 --- a/reader.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "reader.h" -#include "scanner.h" -#include "parser.h" - -namespace YAML -{ - Reader::Reader(std::istream& in): m_pParser(0) - { - m_pParser = new Parser(in); - } - - Reader::~Reader() - { - delete m_pParser; - } - - void Reader::GetNextDocument(Document& document) - { - m_pParser->GetNextDocument(document); - } -} diff --git a/reader.h b/reader.h deleted file mode 100644 index 3226af9c8e..0000000000 --- a/reader.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include "document.h" - -namespace YAML -{ - class Parser; - - class Reader - { - public: - Reader(std::istream& in); - ~Reader(); - - void GetNextDocument(Document& document); - - private: - Parser *m_pParser; - }; -} diff --git a/scalar.cpp b/scalar.cpp index 4552194b59..9fe73a652a 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -1,12 +1,31 @@ #include "scalar.h" +#include "scanner.h" +#include "token.h" namespace YAML { - Scalar::Scalar(const std::string& data): m_data(data) + Scalar::Scalar() { } Scalar::~Scalar() { } + + void Scalar::Parse(Scanner *pScanner) + { + Token *pToken = pScanner->GetNextToken(); + m_data = pToken->value; + delete pToken; + } + + void Scalar::Write(std::ostream& out, int indent) + { + for(int i=0;iGetNextToken(); + + switch(pToken->type) { + case TT_BLOCK_SEQ_START: ParseBlock(pScanner); break; + case TT_BLOCK_ENTRY: ParseImplicit(pScanner); break; + case TT_FLOW_SEQ_START: ParseFlow(pScanner); break; + } + + delete pToken; + } + + void Sequence::ParseBlock(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + if(pToken->type != TT_BLOCK_ENTRY && pToken->type != TT_BLOCK_END) + break; // TODO: throw? + + pScanner->PopNextToken(); + if(pToken->type == TT_BLOCK_END) + break; + + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner); + } + } + + void Sequence::ParseImplicit(Scanner *pScanner) + { + // TODO + } + + void Sequence::ParseFlow(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + // first check for end + if(pToken->type == TT_FLOW_SEQ_END) { + pScanner->PopNextToken(); + break; + } + + // then read the node + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner); + + // now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node) + pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_FLOW_ENTRY) + pScanner->EatNextToken(); + else if(pToken->type != TT_FLOW_SEQ_END) + break; // TODO: throw? + } + } + + void Sequence::Write(std::ostream& out, int indent) + { + for(int i=0;iWrite(out, indent + 1); + } } diff --git a/sequence.h b/sequence.h index cf7d1dd4d7..928f53c952 100644 --- a/sequence.h +++ b/sequence.h @@ -13,6 +13,14 @@ namespace YAML Sequence(); virtual ~Sequence(); + virtual void Parse(Scanner *pScanner); + virtual void Write(std::ostream& out, int indent); + + private: + void ParseBlock(Scanner *pScanner); + void ParseImplicit(Scanner *pScanner); + void ParseFlow(Scanner *pScanner); + protected: std::vector m_data; }; diff --git a/test.yaml b/test.yaml index 8a9714cfc8..1840d58a8b 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,10 @@ --- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +here's a sequence: + - item 1 + - item 2 +now an inline sequence: [1, 2, 3] +and here's a map: + name: Jesse + age: 23 +and here's an inline map: {state: Illinois, city: Urbana-Champaign} +... \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 46a4707a09..4f8d382f50 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -161,38 +161,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > - - - - - - - - - - - - - - @@ -233,48 +205,44 @@ > + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - @@ -298,6 +266,10 @@ RelativePath=".\stream.h" > + + + + + + + + + + + + + + + +