Small changes in the iterator code.

Changed the public interface of Scanner to resemble an STL container.
This commit is contained in:
Jesse Beder
2008-07-23 04:38:18 +00:00
parent cc87c83b01
commit d45bb667b6
14 changed files with 108 additions and 112 deletions

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
// for memory leaks // for detecting memory leaks
#ifdef _DEBUG #ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC #define _CRTDBG_MAP_ALLOC

View File

@@ -13,15 +13,16 @@ namespace YAML
Iterator(const Iterator& rhs); Iterator(const Iterator& rhs);
~Iterator(); ~Iterator();
friend bool operator == (const Iterator& it, const Iterator& jt);
friend bool operator != (const Iterator& it, const Iterator& jt);
Iterator& operator = (const Iterator& rhs); Iterator& operator = (const Iterator& rhs);
Iterator& operator ++ (); Iterator& operator ++ ();
Iterator operator ++ (int); Iterator operator ++ (int);
const Node& operator * (); const Node& operator * () const;
const Node *operator -> (); const Node *operator -> () const;
const Node& first(); const Node& first() const;
const Node& second(); const Node& second() const;
friend bool operator == (const Iterator& it, const Iterator& jt);
friend bool operator != (const Iterator& it, const Iterator& jt);
private: private:
IterPriv *m_pData; IterPriv *m_pData;

View File

@@ -30,6 +30,11 @@ namespace YAML
void HandleYamlDirective(Token *pToken); void HandleYamlDirective(Token *pToken);
void HandleTagDirective(Token *pToken); void HandleTagDirective(Token *pToken);
private:
// can't copy this
Parser(const Parser& rhs) {}
Parser& operator = (const Parser& rhs) { return *this; }
private: private:
Scanner *m_pScanner; Scanner *m_pScanner;
ParserState m_state; ParserState m_state;

View File

@@ -56,7 +56,7 @@ namespace YAML
return temp; return temp;
} }
const Node& Iterator::operator * () const Node& Iterator::operator * () const
{ {
if(m_pData->type == IterPriv::IT_SEQ) if(m_pData->type == IterPriv::IT_SEQ)
return **m_pData->seqIter; return **m_pData->seqIter;
@@ -64,15 +64,15 @@ namespace YAML
throw BadDereference(); throw BadDereference();
} }
const Node *Iterator::operator -> () const Node *Iterator::operator -> () const
{ {
if(m_pData->type == IterPriv::IT_SEQ) if(m_pData->type == IterPriv::IT_SEQ)
return &**m_pData->seqIter; return *m_pData->seqIter;
throw BadDereference(); throw BadDereference();
} }
const Node& Iterator::first() const Node& Iterator::first() const
{ {
if(m_pData->type == IterPriv::IT_MAP) if(m_pData->type == IterPriv::IT_MAP)
return *m_pData->mapIter->first; return *m_pData->mapIter->first;
@@ -80,7 +80,7 @@ namespace YAML
throw BadDereference(); throw BadDereference();
} }
const Node& Iterator::second() const Node& Iterator::second() const
{ {
if(m_pData->type == IterPriv::IT_MAP) if(m_pData->type == IterPriv::IT_MAP)
return *m_pData->mapIter->second; return *m_pData->mapIter->second;

View File

@@ -1,17 +0,0 @@
#include "crt.h"
#include "iterpriv.h"
namespace YAML
{
IterPriv::IterPriv(): type(IT_NONE)
{
}
IterPriv::IterPriv(std::vector <Node *>::const_iterator it): seqIter(it), type(IT_SEQ)
{
}
IterPriv::IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): mapIter(it), type(IT_MAP)
{
}
}

View File

@@ -8,11 +8,13 @@ namespace YAML
{ {
class Node; class Node;
// IterPriv
// . The implementation for iterators - essentially a union of sequence and map iterators.
struct IterPriv struct IterPriv
{ {
IterPriv(); IterPriv(): type(IT_NONE) {}
IterPriv(std::vector <Node *>::const_iterator it); IterPriv(std::vector <Node *>::const_iterator it): seqIter(it), type(IT_SEQ) {}
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it); IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): mapIter(it), type(IT_MAP) {}
enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP };
ITER_TYPE type; ITER_TYPE type;

View File

@@ -42,9 +42,7 @@ namespace YAML
Clear(); Clear();
// split based on start token // split based on start token
Token& token = pScanner->PeekToken(); switch(pScanner->peek().type) {
switch(token.type) {
case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break;
case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break;
} }
@@ -53,17 +51,17 @@ namespace YAML
void Map::ParseBlock(Scanner *pScanner, const ParserState& state) void Map::ParseBlock(Scanner *pScanner, const ParserState& state)
{ {
// eat start token // eat start token
pScanner->PopToken(); pScanner->pop();
while(1) { while(1) {
if(pScanner->IsEmpty()) if(pScanner->empty())
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); throw ParserException(-1, -1, ErrorMsg::END_OF_MAP);
Token token = pScanner->PeekToken(); Token token = pScanner->peek();
if(token.type != TT_KEY && token.type != TT_BLOCK_END) if(token.type != TT_KEY && token.type != TT_BLOCK_END)
throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP); throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP);
pScanner->PopToken(); pScanner->pop();
if(token.type == TT_BLOCK_END) if(token.type == TT_BLOCK_END)
break; break;
@@ -75,8 +73,8 @@ namespace YAML
pKey->Parse(pScanner, state); pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(!pScanner->IsEmpty() && pScanner->PeekToken().type == TT_VALUE) { if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
pScanner->PopToken(); pScanner->pop();
pValue->Parse(pScanner, state); pValue->Parse(pScanner, state);
} }
@@ -92,16 +90,16 @@ namespace YAML
void Map::ParseFlow(Scanner *pScanner, const ParserState& state) void Map::ParseFlow(Scanner *pScanner, const ParserState& state)
{ {
// eat start token // eat start token
pScanner->PopToken(); pScanner->pop();
while(1) { while(1) {
if(pScanner->IsEmpty()) if(pScanner->empty())
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW);
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
// first check for end // first check for end
if(token.type == TT_FLOW_MAP_END) { if(token.type == TT_FLOW_MAP_END) {
pScanner->PopToken(); pScanner->pop();
break; break;
} }
@@ -109,7 +107,7 @@ namespace YAML
if(token.type != TT_KEY) if(token.type != TT_KEY)
throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW); throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW);
pScanner->PopToken(); pScanner->pop();
Node *pKey = new Node; Node *pKey = new Node;
Node *pValue = new Node; Node *pValue = new Node;
@@ -119,15 +117,15 @@ namespace YAML
pKey->Parse(pScanner, state); pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(!pScanner->IsEmpty() && pScanner->PeekToken().type == TT_VALUE) { if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
pScanner->PopToken(); pScanner->pop();
pValue->Parse(pScanner, state); 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)
Token& nextToken = pScanner->PeekToken(); Token& nextToken = pScanner->peek();
if(nextToken.type == TT_FLOW_ENTRY) if(nextToken.type == TT_FLOW_ENTRY)
pScanner->PopToken(); pScanner->pop();
else if(nextToken.type != TT_FLOW_MAP_END) else if(nextToken.type != TT_FLOW_MAP_END)
throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW);

View File

@@ -44,7 +44,7 @@ namespace YAML
return; return;
// now split based on what kind of node we should be // now split based on what kind of node we should be
switch(pScanner->PeekToken().type) { switch(pScanner->peek().type) {
case TT_SCALAR: case TT_SCALAR:
m_pContent = new Scalar; m_pContent = new Scalar;
m_pContent->Parse(pScanner, state); m_pContent->Parse(pScanner, state);
@@ -68,10 +68,10 @@ namespace YAML
void Node::ParseHeader(Scanner *pScanner, const ParserState& state) void Node::ParseHeader(Scanner *pScanner, const ParserState& state)
{ {
while(1) { while(1) {
if(pScanner->IsEmpty()) if(pScanner->empty())
return; return;
switch(pScanner->PeekToken().type) { switch(pScanner->peek().type) {
case TT_TAG: ParseTag(pScanner, state); break; case TT_TAG: ParseTag(pScanner, state); break;
case TT_ANCHOR: ParseAnchor(pScanner, state); break; case TT_ANCHOR: ParseAnchor(pScanner, state); break;
case TT_ALIAS: ParseAlias(pScanner, state); break; case TT_ALIAS: ParseAlias(pScanner, state); break;
@@ -82,7 +82,7 @@ namespace YAML
void Node::ParseTag(Scanner *pScanner, const ParserState& state) void Node::ParseTag(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
if(m_tag != "") if(m_tag != "")
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS); throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS);
@@ -90,23 +90,23 @@ namespace YAML
for(unsigned i=0;i<token.params.size();i++) for(unsigned i=0;i<token.params.size();i++)
m_tag += token.params[i]; m_tag += token.params[i];
pScanner->PopToken(); pScanner->pop();
} }
void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) void Node::ParseAnchor(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
if(m_anchor != "") if(m_anchor != "")
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS); throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS);
m_anchor = token.value; m_anchor = token.value;
m_alias = false; m_alias = false;
pScanner->PopToken(); pScanner->pop();
} }
void Node::ParseAlias(Scanner *pScanner, const ParserState& state) void Node::ParseAlias(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
if(m_anchor != "") if(m_anchor != "")
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES); throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES);
if(m_tag != "") if(m_tag != "")
@@ -114,7 +114,7 @@ namespace YAML
m_anchor = token.value; m_anchor = token.value;
m_alias = true; m_alias = true;
pScanner->PopToken(); pScanner->pop();
} }
void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const

View File

@@ -19,7 +19,7 @@ namespace YAML
Parser::operator bool() const Parser::operator bool() const
{ {
return !m_pScanner->IsEmpty(); return !m_pScanner->empty();
} }
void Parser::Load(std::istream& in) void Parser::Load(std::istream& in)
@@ -41,19 +41,19 @@ namespace YAML
ParseDirectives(); ParseDirectives();
// we better have some tokens in the queue // we better have some tokens in the queue
if(m_pScanner->IsEmpty()) if(m_pScanner->empty())
return; return;
// first eat doc start (optional) // first eat doc start (optional)
if(m_pScanner->PeekToken().type == TT_DOC_START) if(m_pScanner->peek().type == TT_DOC_START)
m_pScanner->PopToken(); m_pScanner->pop();
// now parse our root node // now parse our root node
document.Parse(m_pScanner, m_state); document.Parse(m_pScanner, m_state);
// and finally eat any doc ends we see // and finally eat any doc ends we see
while(!m_pScanner->IsEmpty() && m_pScanner->PeekToken().type == TT_DOC_END) while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
m_pScanner->PopToken(); m_pScanner->pop();
} }
// ParseDirectives // ParseDirectives
@@ -63,10 +63,10 @@ namespace YAML
bool readDirective = false; bool readDirective = false;
while(1) { while(1) {
if(m_pScanner->IsEmpty()) if(m_pScanner->empty())
break; break;
Token& token = m_pScanner->PeekToken(); Token& token = m_pScanner->peek();
if(token.type != TT_DIRECTIVE) if(token.type != TT_DIRECTIVE)
break; break;
@@ -77,7 +77,7 @@ namespace YAML
readDirective = true; readDirective = true;
HandleDirective(&token); HandleDirective(&token);
m_pScanner->PopToken(); m_pScanner->pop();
} }
} }
@@ -123,11 +123,11 @@ namespace YAML
void Parser::PrintTokens(std::ostream& out) void Parser::PrintTokens(std::ostream& out)
{ {
while(1) { while(1) {
if(m_pScanner->IsEmpty()) if(m_pScanner->empty())
break; break;
out << m_pScanner->PeekToken() << std::endl; out << m_pScanner->peek() << std::endl;
m_pScanner->PopToken(); m_pScanner->pop();
} }
} }
} }

View File

@@ -17,9 +17,9 @@ namespace YAML
void Scalar::Parse(Scanner *pScanner, const ParserState& state) void Scalar::Parse(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
m_data = token.value; m_data = token.value;
pScanner->PopToken(); pScanner->pop();
} }
void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)

View File

@@ -3,6 +3,7 @@
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "exp.h" #include "exp.h"
#include <cassert>
namespace YAML namespace YAML
{ {
@@ -15,34 +16,46 @@ namespace YAML
{ {
} }
// IsEmpty // empty
// . Returns true if there are no more tokens to be read // . Returns true if there are no more tokens to be read
bool Scanner::IsEmpty() bool Scanner::empty()
{ {
PeekToken(); // to ensure that there are tokens in the queue, if possible EnsureTokensInQueue();
return m_tokens.empty(); return m_tokens.empty();
} }
// PopToken // pop
// . Simply removes the next token on the queue. // . Simply removes the next token on the queue.
void Scanner::PopToken() void Scanner::pop()
{ {
PeekToken(); // to ensure that there are tokens in the queue EnsureTokensInQueue();
if(!m_tokens.empty()) if(!m_tokens.empty())
m_tokens.pop(); m_tokens.pop();
} }
// PeekToken // peek
// . 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.
Token& Scanner::PeekToken() Token& Scanner::peek()
{
EnsureTokensInQueue();
assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking
// if it's empty before peeking.
return m_tokens.front();
}
// EnsureTokensInQueue
// . Scan until there's a valid token at the front of the queue,
// or we're sure the queue is empty.
void Scanner::EnsureTokensInQueue()
{ {
while(1) { while(1) {
if(!m_tokens.empty()) { if(!m_tokens.empty()) {
Token& token = m_tokens.front(); Token& token = m_tokens.front();
// return this guy if it's valid // if this guy's valid, then we're done
if(token.status == TS_VALID) if(token.status == TS_VALID)
return token; return;
// here's where we clean up the impossible tokens // here's where we clean up the impossible tokens
if(token.status == TS_INVALID) { if(token.status == TS_INVALID) {
@@ -55,13 +68,11 @@ namespace YAML
// no token? maybe we've actually finished // no token? maybe we've actually finished
if(m_endedStream) if(m_endedStream)
break; return;
// no? then scan... // no? then scan...
ScanNextToken(); ScanNextToken();
} }
// TODO: find something to return here, or assert (but can't do that! maybe split into two functions?)
} }
// ScanNextToken // ScanNextToken

View File

@@ -16,16 +16,18 @@ namespace YAML
Scanner(std::istream& in); Scanner(std::istream& in);
~Scanner(); ~Scanner();
bool IsEmpty(); // token queue management (hopefully this looks kinda stl-ish)
void PopToken(); bool empty();
Token& PeekToken(); void pop();
Token& peek();
private: private:
// scanning // scanning
void StartStream(); void EnsureTokensInQueue();
void EndStream();
void ScanNextToken(); void ScanNextToken();
void ScanToNextToken(); void ScanToNextToken();
void StartStream();
void EndStream();
Token *PushIndentTo(int column, bool sequence); Token *PushIndentTo(int column, bool sequence);
void PopIndentTo(int column); void PopIndentTo(int column);

View File

@@ -52,9 +52,7 @@ namespace YAML
Clear(); Clear();
// split based on start token // split based on start token
Token& token = pScanner->PeekToken(); switch(pScanner->peek().type) {
switch(token.type) {
case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break;
case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break;
@@ -64,17 +62,17 @@ namespace YAML
void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state)
{ {
// eat start token // eat start token
pScanner->PopToken(); pScanner->pop();
while(1) { while(1) {
if(pScanner->IsEmpty()) if(pScanner->empty())
throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ);
Token token = pScanner->PeekToken(); Token token = pScanner->peek();
if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END)
throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ); throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ);
pScanner->PopToken(); pScanner->pop();
if(token.type == TT_BLOCK_END) if(token.type == TT_BLOCK_END)
break; break;
@@ -88,15 +86,15 @@ namespace YAML
{ {
while(1) { while(1) {
// we're actually *allowed* to have no tokens at some point // we're actually *allowed* to have no tokens at some point
if(pScanner->IsEmpty()) if(pScanner->empty())
break; break;
// and we end at anything other than a block entry // and we end at anything other than a block entry
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
if(token.type != TT_BLOCK_ENTRY) if(token.type != TT_BLOCK_ENTRY)
break; break;
pScanner->PopToken(); pScanner->pop();
Node *pNode = new Node; Node *pNode = new Node;
m_data.push_back(pNode); m_data.push_back(pNode);
@@ -107,15 +105,15 @@ namespace YAML
void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state)
{ {
// eat start token // eat start token
pScanner->PopToken(); pScanner->pop();
while(1) { while(1) {
if(pScanner->IsEmpty()) if(pScanner->empty())
throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW);
// first check for end // first check for end
if(pScanner->PeekToken().type == TT_FLOW_SEQ_END) { if(pScanner->peek().type == TT_FLOW_SEQ_END) {
pScanner->PopToken(); pScanner->pop();
break; break;
} }
@@ -125,9 +123,9 @@ namespace YAML
pNode->Parse(pScanner, state); 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)
Token& token = pScanner->PeekToken(); Token& token = pScanner->peek();
if(token.type == TT_FLOW_ENTRY) if(token.type == TT_FLOW_ENTRY)
pScanner->PopToken(); pScanner->pop();
else if(token.type != TT_FLOW_SEQ_END) else if(token.type != TT_FLOW_SEQ_END)
throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW); throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW);
} }

View File

@@ -175,10 +175,6 @@
RelativePath=".\src\iterator.cpp" RelativePath=".\src\iterator.cpp"
> >
</File> </File>
<File
RelativePath=".\src\iterpriv.cpp"
>
</File>
<File <File
RelativePath=".\src\map.cpp" RelativePath=".\src\map.cpp"
> >