Tags, anchors, and aliases are all parsed now.

This commit is contained in:
Jesse Beder 2008-07-01 06:28:10 +00:00
parent 8180a85a3b
commit 4c5a488f68
19 changed files with 303 additions and 93 deletions

View file

@ -1,10 +1,12 @@
#pragma once #pragma once
#include <ios> #include <ios>
#include "parserstate.h"
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
class Parser;
class Content class Content
{ {
@ -12,7 +14,7 @@ namespace YAML
Content(); Content();
virtual ~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; virtual void Write(std::ostream& out, int indent) = 0;
protected: protected:

View file

@ -20,7 +20,7 @@ namespace YAML
m_pRoot = 0; m_pRoot = 0;
} }
void Document::Parse(Scanner *pScanner) void Document::Parse(Scanner *pScanner, const ParserState& state)
{ {
Clear(); Clear();
@ -34,7 +34,7 @@ namespace YAML
// now create our root node and parse it // now create our root node and parse it
m_pRoot = new Node; m_pRoot = new Node;
m_pRoot->Parse(pScanner); m_pRoot->Parse(pScanner, state);
// and finally eat any doc ends we see // and finally eat any doc ends we see
while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END) while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END)

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <ios> #include <ios>
#include "parserstate.h"
namespace YAML namespace YAML
{ {
@ -14,7 +15,7 @@ namespace YAML
~Document(); ~Document();
void Clear(); void Clear();
void Parse(Scanner *pScanner); void Parse(Scanner *pScanner, const ParserState& state);
friend std::ostream& operator << (std::ostream& out, const Document& doc); friend std::ostream& operator << (std::ostream& out, const Document& doc);

View file

@ -8,8 +8,11 @@ int main()
YAML::Parser parser(fin); YAML::Parser parser(fin);
YAML::Document doc; YAML::Document doc;
parser.GetNextDocument(doc); while(parser) {
std::cout << doc; std::cout << "---\n";
parser.GetNextDocument(doc);
std::cout << doc;
}
getchar(); getchar();
return 0; return 0;

18
map.cpp
View file

@ -23,7 +23,7 @@ namespace YAML
m_data.clear(); m_data.clear();
} }
void Map::Parse(Scanner *pScanner) void Map::Parse(Scanner *pScanner, const ParserState& state)
{ {
Clear(); Clear();
@ -31,12 +31,12 @@ namespace YAML
Token *pToken = pScanner->PeekNextToken(); Token *pToken = pScanner->PeekNextToken();
switch(pToken->type) { switch(pToken->type) {
case TT_BLOCK_MAP_START: ParseBlock(pScanner); break; case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break;
case TT_FLOW_MAP_START: ParseFlow(pScanner); 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 // eat start token
pScanner->EatNextToken(); pScanner->EatNextToken();
@ -58,17 +58,17 @@ namespace YAML
m_data[pKey] = pValue; m_data[pKey] = pValue;
// grab key // grab key
pKey->Parse(pScanner); pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) {
pScanner->PopNextToken(); 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 // eat start token
pScanner->EatNextToken(); pScanner->EatNextToken();
@ -95,12 +95,12 @@ namespace YAML
m_data[pKey] = pValue; m_data[pKey] = pValue;
// grab key // grab key
pKey->Parse(pScanner); pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) {
pScanner->PopNextToken(); 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) // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)

6
map.h
View file

@ -14,12 +14,12 @@ namespace YAML
virtual ~Map(); virtual ~Map();
void Clear(); void Clear();
virtual void Parse(Scanner *pScanner); virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(std::ostream& out, int indent); virtual void Write(std::ostream& out, int indent);
private: private:
void ParseBlock(Scanner *pScanner); void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseFlow(Scanner *pScanner); void ParseFlow(Scanner *pScanner, const ParserState& state);
protected: protected:
typedef std::map <Node *, Node *> node_map; typedef std::map <Node *, Node *> node_map;

View file

@ -25,11 +25,11 @@ namespace YAML
m_alias = false; m_alias = false;
} }
void Node::Parse(Scanner *pScanner) void Node::Parse(Scanner *pScanner, const ParserState& state)
{ {
Clear(); Clear();
ParseHeader(pScanner); ParseHeader(pScanner, state);
// is this an alias? if so, it can have no content // is this an alias? if so, it can have no content
if(m_alias) if(m_alias)
@ -43,24 +43,24 @@ namespace YAML
switch(pToken->type) { switch(pToken->type) {
case TT_SCALAR: case TT_SCALAR:
m_pContent = new Scalar; m_pContent = new Scalar;
m_pContent->Parse(pScanner); m_pContent->Parse(pScanner, state);
break; break;
case TT_FLOW_SEQ_START: case TT_FLOW_SEQ_START:
case TT_BLOCK_SEQ_START: case TT_BLOCK_SEQ_START:
case TT_BLOCK_ENTRY: case TT_BLOCK_ENTRY:
m_pContent = new Sequence; m_pContent = new Sequence;
m_pContent->Parse(pScanner); m_pContent->Parse(pScanner, state);
break; break;
case TT_FLOW_MAP_START: case TT_FLOW_MAP_START:
case TT_BLOCK_MAP_START: case TT_BLOCK_MAP_START:
m_pContent = new Map; m_pContent = new Map;
m_pContent->Parse(pScanner); m_pContent->Parse(pScanner, state);
} }
} }
// ParseHeader // ParseHeader
// . Grabs any tag, alias, or anchor tokens and deals with them. // . 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) { while(1) {
Token *pToken = pScanner->PeekNextToken(); Token *pToken = pScanner->PeekNextToken();
@ -68,26 +68,27 @@ namespace YAML
break; break;
switch(pToken->type) { switch(pToken->type) {
case TT_TAG: ParseTag(pScanner); break; case TT_TAG: ParseTag(pScanner, state); break;
case TT_ANCHOR: ParseAnchor(pScanner); break; case TT_ANCHOR: ParseAnchor(pScanner, state); break;
case TT_ALIAS: ParseAlias(pScanner); break; case TT_ALIAS: ParseAlias(pScanner, state); break;
} }
} }
} }
void Node::ParseTag(Scanner *pScanner) void Node::ParseTag(Scanner *pScanner, const ParserState& state)
{ {
if(m_tag != "") if(m_tag != "")
return; // TODO: throw return; // TODO: throw
Token *pToken = pScanner->PeekNextToken(); Token *pToken = pScanner->PeekNextToken();
m_tag = pToken->value; m_tag = state.TranslateTag(pToken->value);
for(unsigned i=0;i<pToken->params.size();i++) for(unsigned i=0;i<pToken->params.size();i++)
m_tag += pToken->params[i]; m_tag += pToken->params[i];
pScanner->PopNextToken(); pScanner->PopNextToken();
} }
void Node::ParseAnchor(Scanner *pScanner) void Node::ParseAnchor(Scanner *pScanner, const ParserState& state)
{ {
if(m_anchor != "") if(m_anchor != "")
return; // TODO: throw return; // TODO: throw
@ -98,7 +99,7 @@ namespace YAML
pScanner->PopNextToken(); pScanner->PopNextToken();
} }
void Node::ParseAlias(Scanner *pScanner) void Node::ParseAlias(Scanner *pScanner, const ParserState& state)
{ {
if(m_anchor != "") if(m_anchor != "")
return; // TODO: throw return; // TODO: throw

11
node.h
View file

@ -2,6 +2,7 @@
#include <string> #include <string>
#include <ios> #include <ios>
#include "parserstate.h"
namespace YAML namespace YAML
{ {
@ -19,14 +20,14 @@ namespace YAML
~Node(); ~Node();
void Clear(); void Clear();
void Parse(Scanner *pScanner); void Parse(Scanner *pScanner, const ParserState& state);
void Write(std::ostream& out, int indent); void Write(std::ostream& out, int indent);
private: private:
void ParseHeader(Scanner *pScanner); void ParseHeader(Scanner *pScanner, const ParserState& state);
void ParseTag(Scanner *pScanner); void ParseTag(Scanner *pScanner, const ParserState& state);
void ParseAnchor(Scanner *pScanner); void ParseAnchor(Scanner *pScanner, const ParserState& state);
void ParseAlias(Scanner *pScanner); void ParseAlias(Scanner *pScanner, const ParserState& state);
private: private:
bool m_alias; bool m_alias;

View file

@ -1,13 +1,14 @@
#include "parser.h" #include "parser.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include <iostream> #include <sstream>
namespace YAML namespace YAML
{ {
Parser::Parser(std::istream& in): m_pScanner(0) Parser::Parser(std::istream& in): m_pScanner(0)
{ {
m_pScanner = new Scanner(in); m_pScanner = new Scanner(in);
m_state.Reset();
} }
Parser::~Parser() Parser::~Parser()
@ -15,19 +16,82 @@ namespace YAML
delete m_pScanner; 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 <std::string>& 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 <std::string>& 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 <std::string>& 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) { while(1) {
Token *pToken = m_pScanner->GetNextToken(); Token *pToken = m_pScanner->GetNextToken();
if(!pToken) if(!pToken)
break; break;
std::cout << *pToken << std::endl; out << *pToken << std::endl;
} }
} }
} }

View file

@ -1,7 +1,11 @@
#pragma once #pragma once
#include <ios> #include <ios>
#include <string>
#include <vector>
#include <map>
#include "document.h" #include "document.h"
#include "parserstate.h"
namespace YAML namespace YAML
{ {
@ -14,10 +18,19 @@ namespace YAML
Parser(std::istream& in); Parser(std::istream& in);
~Parser(); ~Parser();
operator bool() const;
void GetNextDocument(Document& document); void GetNextDocument(Document& document);
void PrintTokens(); void PrintTokens(std::ostream& out);
private:
void ParseDirectives();
void HandleDirective(const std::string& name, const std::vector <std::string>& params);
void HandleYamlDirective(const std::vector <std::string>& params);
void HandleTagDirective(const std::vector <std::string>& params);
private: private:
Scanner *m_pScanner; Scanner *m_pScanner;
ParserState m_state;
}; };
} }

25
parserstate.cpp Normal file
View file

@ -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 <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end())
return handle;
return it->second;
}
}

20
parserstate.h Normal file
View file

@ -0,0 +1,20 @@
#pragma once
#include <string>
#include <map>
namespace YAML
{
struct Version {
int major, minor;
};
struct ParserState
{
Version version;
std::map <std::string, std::string> tags;
void Reset();
std::string TranslateTag(const std::string& handle) const;
};
}

View file

@ -12,7 +12,7 @@ namespace YAML
{ {
} }
void Scalar::Parse(Scanner *pScanner) void Scalar::Parse(Scanner *pScanner, const ParserState& state)
{ {
Token *pToken = pScanner->GetNextToken(); Token *pToken = pScanner->GetNextToken();
m_data = pToken->value; m_data = pToken->value;

View file

@ -11,7 +11,7 @@ namespace YAML
Scalar(); Scalar();
virtual ~Scalar(); virtual ~Scalar();
virtual void Parse(Scanner *pScanner); virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(std::ostream& out, int indent); virtual void Write(std::ostream& out, int indent);
protected: protected:

View file

@ -189,7 +189,7 @@ namespace YAML
void Scanner::ScanAnchorOrAlias() void Scanner::ScanAnchorOrAlias()
{ {
bool alias; bool alias;
std::string tag; std::string name;
// insert a potential simple key // insert a potential simple key
if(m_simpleKeyAllowed) if(m_simpleKeyAllowed)
@ -202,10 +202,10 @@ namespace YAML
// now eat the content // now eat the content
while(Exp::AlphaNumeric.Matches(INPUT)) while(Exp::AlphaNumeric.Matches(INPUT))
tag += INPUT.get(); name += INPUT.get();
// we need to have read SOMETHING! // we need to have read SOMETHING!
if(tag.empty()) if(name.empty())
throw AnchorNotFound(); throw AnchorNotFound();
// and needs to end correctly // and needs to end correctly
@ -214,7 +214,7 @@ namespace YAML
// and we're done // and we're done
Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR); Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR);
pToken->value = tag; pToken->value = name;
m_tokens.push(pToken); m_tokens.push(pToken);
} }
@ -229,7 +229,7 @@ namespace YAML
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
// eat the indicator // eat the indicator
INPUT.eat(1); handle += INPUT.get();
// read the handle // read the handle
while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT))
@ -238,11 +238,15 @@ namespace YAML
// is there a suffix? // is there a suffix?
if(INPUT.peek() == Keys::Tag) { if(INPUT.peek() == Keys::Tag) {
// eat the indicator // eat the indicator
INPUT.eat(1); handle += INPUT.get();
// then read it // then read it
while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT))
suffix += INPUT.get(); 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); Token *pToken = new Token(TT_TAG);

View file

@ -22,7 +22,7 @@ namespace YAML
m_data.clear(); m_data.clear();
} }
void Sequence::Parse(Scanner *pScanner) void Sequence::Parse(Scanner *pScanner, const ParserState& state)
{ {
Clear(); Clear();
@ -30,13 +30,13 @@ namespace YAML
Token *pToken = pScanner->PeekNextToken(); Token *pToken = pScanner->PeekNextToken();
switch(pToken->type) { switch(pToken->type) {
case TT_BLOCK_SEQ_START: ParseBlock(pScanner); break; case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
case TT_BLOCK_ENTRY: ParseImplicit(pScanner); break; case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break;
case TT_FLOW_SEQ_START: ParseFlow(pScanner); 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 // eat start token
pScanner->EatNextToken(); pScanner->EatNextToken();
@ -55,11 +55,11 @@ namespace YAML
Node *pNode = new Node; Node *pNode = new Node;
m_data.push_back(pNode); 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) { while(1) {
Token *pToken = pScanner->PeekNextToken(); Token *pToken = pScanner->PeekNextToken();
@ -75,11 +75,11 @@ namespace YAML
Node *pNode = new Node; Node *pNode = new Node;
m_data.push_back(pNode); 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 // eat start token
pScanner->EatNextToken(); pScanner->EatNextToken();
@ -98,7 +98,7 @@ namespace YAML
// then read the node // then read the node
Node *pNode = new Node; Node *pNode = new Node;
m_data.push_back(pNode); 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) // 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(); pToken = pScanner->PeekNextToken();

View file

@ -14,13 +14,13 @@ namespace YAML
virtual ~Sequence(); virtual ~Sequence();
void Clear(); void Clear();
virtual void Parse(Scanner *pScanner); virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(std::ostream& out, int indent); virtual void Write(std::ostream& out, int indent);
private: private:
void ParseBlock(Scanner *pScanner); void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseImplicit(Scanner *pScanner); void ParseImplicit(Scanner *pScanner, const ParserState& state);
void ParseFlow(Scanner *pScanner); void ParseFlow(Scanner *pScanner, const ParserState& state);
protected: protected:
std::vector <Node *> m_data; std::vector <Node *> m_data;

126
test.yaml
View file

@ -1,29 +1,97 @@
--- !<tag:clarkevans.com,2002:invoice> ---
invoice: 34843 model:
date : 2001-01-23 file: data/models/compound.model
bill-to: &id001 textures: data/materials/compound
given : Chris rooms:
family : Dumars - name: "Room #1"
address: pos: [0, 0, 0]
lines: | size: [1000, 1000, 500]
458 Walkman Dr. height: 500
Suite #292 stairtype: none
city : Royal Oak display: []
state : MI pathfinding:
postal : 48046 tilesize: 50
ship-to: *id001 size: [24, 24]
product: map: |
- 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. -+---------------------
-+-------------------+-
-+-------------------+-
-+-------------------+-
-+-------------------+-
-+-------------------+-
-+-------------------+-
-+-------------------+-
-+-------------------+-
-+++++++++++++++++++++-
-----------------------
- 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

@ -204,6 +204,10 @@
RelativePath=".\parser.cpp" RelativePath=".\parser.cpp"
> >
</File> </File>
<File
RelativePath=".\parserstate.cpp"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Representation" Name="Representation"
@ -278,6 +282,10 @@
RelativePath=".\parser.h" RelativePath=".\parser.h"
> >
</File> </File>
<File
RelativePath=".\parserstate.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Representation" Name="Representation"