Finished parsing of basic data types (scalar, sequence, map).

This commit is contained in:
Jesse Beder 2008-06-30 23:57:58 +00:00
parent c1966ba3fc
commit 121c2e577f
20 changed files with 434 additions and 221 deletions

View file

@ -1,13 +1,20 @@
#pragma once #pragma once
#include <ios>
namespace YAML namespace YAML
{ {
class Scanner;
class Content class Content
{ {
public: public:
Content(); Content();
virtual ~Content(); virtual ~Content();
virtual void Parse(Scanner *pScanner) = 0;
virtual void Write(std::ostream& out, int indent) = 0;
protected: protected:
}; };
} }

View file

@ -1,5 +1,7 @@
#include "document.h" #include "document.h"
#include "node.h" #include "node.h"
#include "token.h"
#include "scanner.h"
namespace YAML namespace YAML
{ {
@ -17,4 +19,36 @@ namespace YAML
delete m_pRoot; delete m_pRoot;
m_pRoot = 0; 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;
}
} }

View file

@ -1,8 +1,11 @@
#pragma once #pragma once
#include <ios>
namespace YAML namespace YAML
{ {
class Node; class Node;
class Scanner;
class Document class Document
{ {
@ -11,6 +14,9 @@ namespace YAML
~Document(); ~Document();
void Clear(); void Clear();
void Parse(Scanner *pScanner);
friend std::ostream& operator << (std::ostream& out, const Document& doc);
private: private:
Node *m_pRoot; Node *m_pRoot;

View file

@ -1,12 +1,16 @@
#include "reader.h" #include "parser.h"
#include <fstream> #include <fstream>
#include <iostream>
int main() int main()
{ {
std::ifstream fin("test.yaml"); std::ifstream fin("test.yaml");
YAML::Reader reader(fin); YAML::Parser parser(fin);
YAML::Document doc; YAML::Document doc;
reader.GetNextDocument(doc); parser.GetNextDocument(doc);
std::cout << doc;
getchar();
return 0; return 0;
} }

104
map.cpp
View file

@ -1,5 +1,7 @@
#include "map.h" #include "map.h"
#include "node.h" #include "node.h"
#include "scanner.h"
#include "token.h"
namespace YAML namespace YAML
{ {
@ -14,4 +16,106 @@ namespace YAML
delete it->second; 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;i<indent;i++)
out << " ";
out << "{map}\n";
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
for(int i=0;i<indent + 1;i++)
out << " ";
out << "{key}\n";
it->first->Write(out, indent + 2);
for(int i=0;i<indent + 1;i++)
out << " ";
out << "{value}\n";
it->second->Write(out, indent + 2);
}
}
} }

7
map.h
View file

@ -13,6 +13,13 @@ namespace YAML
Map(); Map();
virtual ~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: protected:
typedef std::map <Node *, Node *> node_map; typedef std::map <Node *, Node *> node_map;
node_map m_data; node_map m_data;

View file

@ -1,8 +1,11 @@
#include "node.h" #include "node.h"
#include "token.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"
namespace YAML namespace YAML
{ {
@ -20,4 +23,63 @@ namespace YAML
delete m_pContent; delete m_pContent;
m_pContent = 0; 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;i<indent;i++)
out << " ";
out << "{no content}\n";
} else
m_pContent->Write(out, indent);
}
} }

6
node.h
View file

@ -10,6 +10,7 @@ namespace YAML
const std::string MapTag = "!!map"; const std::string MapTag = "!!map";
class Content; class Content;
class Scanner;
class Node class Node
{ {
@ -18,6 +19,11 @@ namespace YAML
~Node(); ~Node();
void Clear(); void Clear();
void Parse(Scanner *pScanner);
void Write(std::ostream& out, int indent);
private:
void ParseHeader(Scanner *pScanner);
private: private:
std::string m_tag; std::string m_tag;

View file

@ -1,30 +1,20 @@
#include "parser.h" #include "parser.h"
#include "node.h" #include "scanner.h"
#include "token.h"
#include <iostream>
namespace YAML 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() Parser::~Parser()
{ {
delete m_pScanner;
} }
void Parser::GetNextDocument(Document& document) void Parser::GetNextDocument(Document& document)
{ {
// scan and output, for now document.Parse(m_pScanner);
while(1) {
Token *pToken = m_scanner.GetNextToken();
if(!pToken)
break;
std::cout << *pToken << std::endl;
delete pToken;
}
getchar();
} }
} }

View file

@ -1,13 +1,12 @@
#pragma once #pragma once
#include <ios> #include <ios>
#include <string>
#include "scanner.h"
#include "document.h" #include "document.h"
namespace YAML namespace YAML
{ {
class Node; class Node;
class Scanner;
class Parser class Parser
{ {
@ -18,6 +17,6 @@ namespace YAML
void GetNextDocument(Document& document); void GetNextDocument(Document& document);
private: private:
Scanner m_scanner; Scanner *m_pScanner;
}; };
} }

View file

@ -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);
}
}

View file

@ -1,21 +0,0 @@
#pragma once
#include <ios>
#include "document.h"
namespace YAML
{
class Parser;
class Reader
{
public:
Reader(std::istream& in);
~Reader();
void GetNextDocument(Document& document);
private:
Parser *m_pParser;
};
}

View file

@ -1,12 +1,31 @@
#include "scalar.h" #include "scalar.h"
#include "scanner.h"
#include "token.h"
namespace YAML namespace YAML
{ {
Scalar::Scalar(const std::string& data): m_data(data) Scalar::Scalar()
{ {
} }
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;i<indent;i++)
out << " ";
out << "{scalar}\n";
for(int i=0;i<indent;i++)
out << " ";
out << m_data << std::endl;
}
} }

View file

@ -8,9 +8,12 @@ namespace YAML
class Scalar: public Content class Scalar: public Content
{ {
public: public:
Scalar(const std::string& data); Scalar();
virtual ~Scalar(); virtual ~Scalar();
virtual void Parse(Scanner *pScanner);
virtual void Write(std::ostream& out, int indent);
protected: protected:
std::string m_data; std::string m_data;
}; };

View file

@ -28,6 +28,20 @@ namespace YAML
return pToken; return pToken;
} }
// PopNextToken
// . Simply removes the next token on the queue.
void Scanner::PopNextToken()
{
GetNextToken();
}
// EatNextToken
// . Removes and deletes the next token on the queue
void Scanner::EatNextToken()
{
delete GetNextToken();
}
// PeekNextToken // PeekNextToken
// . Returns (but does not remove) the next token on the queue, and scans if only we need to. // . Returns (but does not remove) the next token on the queue, and scans if only we need to.
Token *Scanner::PeekNextToken() Token *Scanner::PeekNextToken()

View file

@ -18,6 +18,8 @@ namespace YAML
~Scanner(); ~Scanner();
Token *GetNextToken(); Token *GetNextToken();
void EatNextToken();
void PopNextToken();
Token *PeekNextToken(); Token *PeekNextToken();
private: private:

View file

@ -1,5 +1,7 @@
#include "sequence.h" #include "sequence.h"
#include "node.h" #include "node.h"
#include "scanner.h"
#include "token.h"
namespace YAML namespace YAML
{ {
@ -13,4 +15,79 @@ namespace YAML
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];
} }
void Sequence::Parse(Scanner *pScanner)
{
// grab start token
Token *pToken = pScanner->GetNextToken();
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;i<indent;i++)
out << " ";
out << "{sequence}\n";
for(unsigned i=0;i<m_data.size();i++)
m_data[i]->Write(out, indent + 1);
}
} }

View file

@ -13,6 +13,14 @@ namespace YAML
Sequence(); Sequence();
virtual ~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: protected:
std::vector <Node *> m_data; std::vector <Node *> m_data;
}; };

105
test.yaml
View file

@ -1,97 +1,10 @@
--- ---
model: here's a sequence:
file: data/models/compound.model - item 1
textures: data/materials/compound - item 2
rooms: now an inline sequence: [1, 2, 3]
- name: "Room #1" and here's a map:
pos: [0, 0, 0] name: Jesse
size: [1000, 1000, 500] age: 23
height: 500 and here's an inline map: {state: Illinois, city: Urbana-Champaign}
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]

View file

@ -161,38 +161,10 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File
RelativePath=".\content.cpp"
>
</File>
<File
RelativePath=".\document.cpp"
>
</File>
<File <File
RelativePath=".\main.cpp" RelativePath=".\main.cpp"
> >
</File> </File>
<File
RelativePath=".\map.cpp"
>
</File>
<File
RelativePath=".\node.cpp"
>
</File>
<File
RelativePath=".\reader.cpp"
>
</File>
<File
RelativePath=".\scalar.cpp"
>
</File>
<File
RelativePath=".\sequence.cpp"
>
</File>
<Filter <Filter
Name="Scanner" Name="Scanner"
> >
@ -233,48 +205,44 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="Representation"
>
<File
RelativePath=".\content.cpp"
>
</File>
<File
RelativePath=".\document.cpp"
>
</File>
<File
RelativePath=".\map.cpp"
>
</File>
<File
RelativePath=".\node.cpp"
>
</File>
<File
RelativePath=".\scalar.cpp"
>
</File>
<File
RelativePath=".\sequence.cpp"
>
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="Header Files" Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File
RelativePath=".\content.h"
>
</File>
<File
RelativePath=".\document.h"
>
</File>
<File <File
RelativePath=".\exceptions.h" RelativePath=".\exceptions.h"
> >
</File> </File>
<File
RelativePath=".\map.h"
>
</File>
<File
RelativePath=".\node.h"
>
</File>
<File
RelativePath=".\reader.h"
>
</File>
<File
RelativePath=".\scalar.h"
>
</File>
<File
RelativePath=".\sequence.h"
>
</File>
<File
RelativePath=".\token.h"
>
</File>
<Filter <Filter
Name="Scanner" Name="Scanner"
> >
@ -298,6 +266,10 @@
RelativePath=".\stream.h" RelativePath=".\stream.h"
> >
</File> </File>
<File
RelativePath=".\token.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Parser" Name="Parser"
@ -307,6 +279,34 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="Representation"
>
<File
RelativePath=".\content.h"
>
</File>
<File
RelativePath=".\document.h"
>
</File>
<File
RelativePath=".\map.h"
>
</File>
<File
RelativePath=".\node.h"
>
</File>
<File
RelativePath=".\scalar.h"
>
</File>
<File
RelativePath=".\sequence.h"
>
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="Resource Files" Name="Resource Files"