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

View file

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

View file

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

View file

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

18
map.cpp
View file

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

6
map.h
View file

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

View file

@ -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;i<pToken->params.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

11
node.h
View file

@ -2,6 +2,7 @@
#include <string>
#include <ios>
#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;

View file

@ -1,13 +1,14 @@
#include "parser.h"
#include "scanner.h"
#include "token.h"
#include <iostream>
#include <sstream>
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 <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) {
Token *pToken = m_pScanner->GetNextToken();
if(!pToken)
break;
std::cout << *pToken << std::endl;
out << *pToken << std::endl;
}
}
}

View file

@ -1,7 +1,11 @@
#pragma once
#include <ios>
#include <string>
#include <vector>
#include <map>
#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 <std::string>& params);
void HandleYamlDirective(const std::vector <std::string>& params);
void HandleTagDirective(const std::vector <std::string>& params);
private:
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();
m_data = pToken->value;

View file

@ -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:

View file

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

View file

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

View file

@ -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 <Node *> m_data;

126
test.yaml
View file

@ -1,29 +1,97 @@
--- !<tag:clarkevans.com,2002:invoice>
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.
---
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]

View file

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