diff --git a/content.h b/content.h index 12a2b86569..ce23447733 100644 --- a/content.h +++ b/content.h @@ -1,10 +1,12 @@ #pragma once #include +#include "parserstate.h" namespace YAML { class Scanner; + class Parser; class Content { @@ -12,7 +14,7 @@ namespace YAML Content(); virtual ~Content(); - virtual void Parse(Scanner *pScanner) = 0; + virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(std::ostream& out, int indent) = 0; protected: diff --git a/document.cpp b/document.cpp index fd526e2c38..c5d1996511 100644 --- a/document.cpp +++ b/document.cpp @@ -20,7 +20,7 @@ namespace YAML m_pRoot = 0; } - void Document::Parse(Scanner *pScanner) + void Document::Parse(Scanner *pScanner, const ParserState& state) { Clear(); @@ -34,7 +34,7 @@ namespace YAML // now create our root node and parse it m_pRoot = new Node; - m_pRoot->Parse(pScanner); + m_pRoot->Parse(pScanner, state); // and finally eat any doc ends we see while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END) diff --git a/document.h b/document.h index e0189815c9..257f57035b 100644 --- a/document.h +++ b/document.h @@ -1,6 +1,7 @@ #pragma once #include +#include "parserstate.h" namespace YAML { @@ -14,7 +15,7 @@ namespace YAML ~Document(); void Clear(); - void Parse(Scanner *pScanner); + void Parse(Scanner *pScanner, const ParserState& state); friend std::ostream& operator << (std::ostream& out, const Document& doc); diff --git a/main.cpp b/main.cpp index dba870d960..22d0b1b41b 100644 --- a/main.cpp +++ b/main.cpp @@ -8,8 +8,11 @@ int main() YAML::Parser parser(fin); YAML::Document doc; - parser.GetNextDocument(doc); - std::cout << doc; + while(parser) { + std::cout << "---\n"; + parser.GetNextDocument(doc); + std::cout << doc; + } getchar(); return 0; diff --git a/map.cpp b/map.cpp index d3cba8f1da..e759f37839 100644 --- a/map.cpp +++ b/map.cpp @@ -23,7 +23,7 @@ namespace YAML m_data.clear(); } - void Map::Parse(Scanner *pScanner) + void Map::Parse(Scanner *pScanner, const ParserState& state) { Clear(); @@ -31,12 +31,12 @@ namespace YAML Token *pToken = pScanner->PeekNextToken(); switch(pToken->type) { - case TT_BLOCK_MAP_START: ParseBlock(pScanner); break; - case TT_FLOW_MAP_START: ParseFlow(pScanner); break; + case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; + case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; } } - void Map::ParseBlock(Scanner *pScanner) + void Map::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -58,17 +58,17 @@ namespace YAML m_data[pKey] = pValue; // grab key - pKey->Parse(pScanner); + pKey->Parse(pScanner, state); // now grab value (optional) if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { pScanner->PopNextToken(); - pValue->Parse(pScanner); + pValue->Parse(pScanner, state); } } } - void Map::ParseFlow(Scanner *pScanner) + void Map::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -95,12 +95,12 @@ namespace YAML m_data[pKey] = pValue; // grab key - pKey->Parse(pScanner); + pKey->Parse(pScanner, state); // now grab value (optional) if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { pScanner->PopNextToken(); - pValue->Parse(pScanner); + 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) diff --git a/map.h b/map.h index 0da12b3648..9f2929875c 100644 --- a/map.h +++ b/map.h @@ -14,12 +14,12 @@ namespace YAML virtual ~Map(); void Clear(); - virtual void Parse(Scanner *pScanner); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); private: - void ParseBlock(Scanner *pScanner); - void ParseFlow(Scanner *pScanner); + void ParseBlock(Scanner *pScanner, const ParserState& state); + void ParseFlow(Scanner *pScanner, const ParserState& state); protected: typedef std::map node_map; diff --git a/node.cpp b/node.cpp index 439bdd6f27..47e2080d9c 100644 --- a/node.cpp +++ b/node.cpp @@ -25,11 +25,11 @@ namespace YAML m_alias = false; } - void Node::Parse(Scanner *pScanner) + void Node::Parse(Scanner *pScanner, const ParserState& state) { Clear(); - ParseHeader(pScanner); + ParseHeader(pScanner, state); // is this an alias? if so, it can have no content if(m_alias) @@ -43,24 +43,24 @@ namespace YAML switch(pToken->type) { case TT_SCALAR: m_pContent = new Scalar; - m_pContent->Parse(pScanner); + m_pContent->Parse(pScanner, state); break; case TT_FLOW_SEQ_START: case TT_BLOCK_SEQ_START: case TT_BLOCK_ENTRY: m_pContent = new Sequence; - m_pContent->Parse(pScanner); + m_pContent->Parse(pScanner, state); break; case TT_FLOW_MAP_START: case TT_BLOCK_MAP_START: m_pContent = new Map; - m_pContent->Parse(pScanner); + m_pContent->Parse(pScanner, state); } } // ParseHeader // . Grabs any tag, alias, or anchor tokens and deals with them. - void Node::ParseHeader(Scanner *pScanner) + void Node::ParseHeader(Scanner *pScanner, const ParserState& state) { while(1) { Token *pToken = pScanner->PeekNextToken(); @@ -68,26 +68,27 @@ namespace YAML break; switch(pToken->type) { - case TT_TAG: ParseTag(pScanner); break; - case TT_ANCHOR: ParseAnchor(pScanner); break; - case TT_ALIAS: ParseAlias(pScanner); break; + case TT_TAG: ParseTag(pScanner, state); break; + case TT_ANCHOR: ParseAnchor(pScanner, state); break; + case TT_ALIAS: ParseAlias(pScanner, state); break; } } } - void Node::ParseTag(Scanner *pScanner) + void Node::ParseTag(Scanner *pScanner, const ParserState& state) { if(m_tag != "") return; // TODO: throw Token *pToken = pScanner->PeekNextToken(); - m_tag = pToken->value; + m_tag = state.TranslateTag(pToken->value); + for(unsigned i=0;iparams.size();i++) m_tag += pToken->params[i]; pScanner->PopNextToken(); } - void Node::ParseAnchor(Scanner *pScanner) + void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) { if(m_anchor != "") return; // TODO: throw @@ -98,7 +99,7 @@ namespace YAML pScanner->PopNextToken(); } - void Node::ParseAlias(Scanner *pScanner) + void Node::ParseAlias(Scanner *pScanner, const ParserState& state) { if(m_anchor != "") return; // TODO: throw diff --git a/node.h b/node.h index d6e872719e..f8cfe5c0f3 100644 --- a/node.h +++ b/node.h @@ -2,6 +2,7 @@ #include #include +#include "parserstate.h" namespace YAML { @@ -19,14 +20,14 @@ namespace YAML ~Node(); void Clear(); - void Parse(Scanner *pScanner); + void Parse(Scanner *pScanner, const ParserState& state); void Write(std::ostream& out, int indent); private: - void ParseHeader(Scanner *pScanner); - void ParseTag(Scanner *pScanner); - void ParseAnchor(Scanner *pScanner); - void ParseAlias(Scanner *pScanner); + void ParseHeader(Scanner *pScanner, const ParserState& state); + void ParseTag(Scanner *pScanner, const ParserState& state); + void ParseAnchor(Scanner *pScanner, const ParserState& state); + void ParseAlias(Scanner *pScanner, const ParserState& state); private: bool m_alias; diff --git a/parser.cpp b/parser.cpp index 8db28eae15..053c83eaee 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,13 +1,14 @@ #include "parser.h" #include "scanner.h" #include "token.h" -#include +#include namespace YAML { Parser::Parser(std::istream& in): m_pScanner(0) { m_pScanner = new Scanner(in); + m_state.Reset(); } Parser::~Parser() @@ -15,19 +16,82 @@ namespace YAML delete m_pScanner; } - void Parser::GetNextDocument(Document& document) + Parser::operator bool() const { - document.Parse(m_pScanner); + return m_pScanner->PeekNextToken() != 0; } - void Parser::PrintTokens() + void Parser::GetNextDocument(Document& document) + { + // first read directives + ParseDirectives(); + + // then parse the document + document.Parse(m_pScanner, m_state); + } + + void Parser::ParseDirectives() + { + bool readDirective = false; + + while(1) { + Token *pToken = m_pScanner->PeekNextToken(); + if(!pToken || pToken->type != TT_DIRECTIVE) + break; + + // we keep the directives from the last document if none are specified; + // but if any directives are specific, then we reset them + if(!readDirective) + m_state.Reset(); + + readDirective = true; + HandleDirective(pToken->value, pToken->params); + m_pScanner->PopNextToken(); + } + } + + void Parser::HandleDirective(const std::string& name, const std::vector & params) + { + if(name == "YAML") + HandleYamlDirective(params); + else if(name == "TAG") + HandleTagDirective(params); + } + + // HandleYamlDirective + // . Should be of the form 'major.minor' (like a version number) + void Parser::HandleYamlDirective(const std::vector & params) + { + if(params.empty()) + return; // TODO: throw? (or throw on params.size() > 1?) + + std::stringstream str(params[0]); + str >> m_state.version.major; + str.get(); + str >> m_state.version.minor; + if(!str) + return; // TODO: throw? (or throw if there are any more characters in the stream?) + + // TODO: throw on major > 1? warning on major == 1, minor > 1? + } + + void Parser::HandleTagDirective(const std::vector & params) + { + if(params.size() != 2) + return; // TODO: throw? + + std::string handle = params[0], prefix = params[1]; + m_state.tags[handle] = prefix; + } + + void Parser::PrintTokens(std::ostream& out) { while(1) { Token *pToken = m_pScanner->GetNextToken(); if(!pToken) break; - std::cout << *pToken << std::endl; + out << *pToken << std::endl; } } } diff --git a/parser.h b/parser.h index 95bb663fd5..cd42017320 100644 --- a/parser.h +++ b/parser.h @@ -1,7 +1,11 @@ #pragma once #include +#include +#include +#include #include "document.h" +#include "parserstate.h" namespace YAML { @@ -14,10 +18,19 @@ namespace YAML Parser(std::istream& in); ~Parser(); + operator bool() const; + void GetNextDocument(Document& document); - void PrintTokens(); + void PrintTokens(std::ostream& out); + + private: + void ParseDirectives(); + void HandleDirective(const std::string& name, const std::vector & params); + void HandleYamlDirective(const std::vector & params); + void HandleTagDirective(const std::vector & params); private: Scanner *m_pScanner; + ParserState m_state; }; } diff --git a/parserstate.cpp b/parserstate.cpp new file mode 100644 index 0000000000..d0b5209209 --- /dev/null +++ b/parserstate.cpp @@ -0,0 +1,25 @@ +#include "parserstate.h" + +namespace YAML +{ + void ParserState::Reset() + { + // version + version.major = 1; + version.minor = 1; + + // and tags + tags.clear(); + tags["!"] = "!"; + tags["!!"] = "tag:yaml.org,2002:"; + } + + std::string ParserState::TranslateTag(const std::string& handle) const + { + std::map ::const_iterator it = tags.find(handle); + if(it == tags.end()) + return handle; + + return it->second; + } +} diff --git a/parserstate.h b/parserstate.h new file mode 100644 index 0000000000..e98667da89 --- /dev/null +++ b/parserstate.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace YAML +{ + struct Version { + int major, minor; + }; + + struct ParserState + { + Version version; + std::map tags; + + void Reset(); + std::string TranslateTag(const std::string& handle) const; + }; +} diff --git a/scalar.cpp b/scalar.cpp index 9fe73a652a..5176e527c7 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -12,7 +12,7 @@ namespace YAML { } - void Scalar::Parse(Scanner *pScanner) + void Scalar::Parse(Scanner *pScanner, const ParserState& state) { Token *pToken = pScanner->GetNextToken(); m_data = pToken->value; diff --git a/scalar.h b/scalar.h index bea56af4fa..90f2583da1 100644 --- a/scalar.h +++ b/scalar.h @@ -11,7 +11,7 @@ namespace YAML Scalar(); virtual ~Scalar(); - virtual void Parse(Scanner *pScanner); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); protected: diff --git a/scantoken.cpp b/scantoken.cpp index fca7ae6106..05bae3dbfa 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -189,7 +189,7 @@ namespace YAML void Scanner::ScanAnchorOrAlias() { bool alias; - std::string tag; + std::string name; // insert a potential simple key if(m_simpleKeyAllowed) @@ -202,10 +202,10 @@ namespace YAML // now eat the content while(Exp::AlphaNumeric.Matches(INPUT)) - tag += INPUT.get(); + name += INPUT.get(); // we need to have read SOMETHING! - if(tag.empty()) + if(name.empty()) throw AnchorNotFound(); // and needs to end correctly @@ -214,7 +214,7 @@ namespace YAML // and we're done Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR); - pToken->value = tag; + pToken->value = name; m_tokens.push(pToken); } @@ -229,7 +229,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - INPUT.eat(1); + handle += INPUT.get(); // read the handle while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) @@ -238,11 +238,15 @@ namespace YAML // is there a suffix? if(INPUT.peek() == Keys::Tag) { // eat the indicator - INPUT.eat(1); + handle += INPUT.get(); // then read it while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) suffix += INPUT.get(); + } else { + // this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix + suffix = handle.substr(1); + handle = "!"; } Token *pToken = new Token(TT_TAG); diff --git a/sequence.cpp b/sequence.cpp index 8332e130a0..8d0ca1354b 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -22,7 +22,7 @@ namespace YAML m_data.clear(); } - void Sequence::Parse(Scanner *pScanner) + void Sequence::Parse(Scanner *pScanner, const ParserState& state) { Clear(); @@ -30,13 +30,13 @@ namespace YAML Token *pToken = pScanner->PeekNextToken(); 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; + case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; + case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; + case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; } } - void Sequence::ParseBlock(Scanner *pScanner) + void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -55,11 +55,11 @@ namespace YAML Node *pNode = new Node; m_data.push_back(pNode); - pNode->Parse(pScanner); + pNode->Parse(pScanner, state); } } - void Sequence::ParseImplicit(Scanner *pScanner) + void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state) { while(1) { Token *pToken = pScanner->PeekNextToken(); @@ -75,11 +75,11 @@ namespace YAML Node *pNode = new Node; m_data.push_back(pNode); - pNode->Parse(pScanner); + pNode->Parse(pScanner, state); } } - void Sequence::ParseFlow(Scanner *pScanner) + void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -98,7 +98,7 @@ namespace YAML // then read the node Node *pNode = new Node; m_data.push_back(pNode); - pNode->Parse(pScanner); + 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) pToken = pScanner->PeekNextToken(); diff --git a/sequence.h b/sequence.h index 42e9fbb932..85fcf8a829 100644 --- a/sequence.h +++ b/sequence.h @@ -14,13 +14,13 @@ namespace YAML virtual ~Sequence(); void Clear(); - virtual void Parse(Scanner *pScanner); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); private: - void ParseBlock(Scanner *pScanner); - void ParseImplicit(Scanner *pScanner); - void ParseFlow(Scanner *pScanner); + void ParseBlock(Scanner *pScanner, const ParserState& state); + void ParseImplicit(Scanner *pScanner, const ParserState& state); + void ParseFlow(Scanner *pScanner, const ParserState& state); protected: std::vector m_data; diff --git a/test.yaml b/test.yaml index 4b98eeaec1..8a9714cfc8 100644 --- a/test.yaml +++ b/test.yaml @@ -1,29 +1,97 @@ ---- ! -invoice: 34843 -date : 2001-01-23 -bill-to: &id001 - given : Chris - family : Dumars - address: - lines: | - 458 Walkman Dr. - Suite #292 - city : Royal Oak - state : MI - postal : 48046 -ship-to: *id001 -product: - - sku : BL394D - quantity : 4 - description : Basketball - price : 450.00 - - sku : BL4438H - quantity : 1 - description : Super Hoop - price : 2392.00 -tax : 251.42 -total: 4443.52 -comments: - Late afternoon is best. - Backup contact is Nancy - Billsmer @ 338-4338. \ No newline at end of file +--- +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] diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 4f8d382f50..62387b0fac 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -204,6 +204,10 @@ RelativePath=".\parser.cpp" > + + + +