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
#include <ios>
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:
};
}

View file

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

View file

@ -1,8 +1,11 @@
#pragma once
#include <ios>
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;

View file

@ -1,12 +1,16 @@
#include "reader.h"
#include "parser.h"
#include <fstream>
#include <iostream>
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;
}

104
map.cpp
View file

@ -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;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();
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 *, Node *> node_map;
node_map m_data;

View file

@ -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;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";
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;

View file

@ -1,30 +1,20 @@
#include "parser.h"
#include "node.h"
#include "token.h"
#include <iostream>
#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);
}
}

View file

@ -1,13 +1,12 @@
#pragma once
#include <ios>
#include <string>
#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;
};
}

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 "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;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
{
public:
Scalar(const std::string& data);
Scalar();
virtual ~Scalar();
virtual void Parse(Scanner *pScanner);
virtual void Write(std::ostream& out, int indent);
protected:
std::string m_data;
};

View file

@ -28,6 +28,20 @@ namespace YAML
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
// . Returns (but does not remove) the next token on the queue, and scans if only we need to.
Token *Scanner::PeekNextToken()

View file

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

View file

@ -1,5 +1,7 @@
#include "sequence.h"
#include "node.h"
#include "scanner.h"
#include "token.h"
namespace YAML
{
@ -13,4 +15,79 @@ namespace YAML
for(unsigned i=0;i<m_data.size();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();
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 <Node *> m_data;
};

105
test.yaml
View file

@ -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}
...

View file

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