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
// for memory leaks
// for detecting memory leaks
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC

View file

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

View file

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

View file

@ -56,7 +56,7 @@ namespace YAML
return temp;
}
const Node& Iterator::operator * ()
const Node& Iterator::operator * () const
{
if(m_pData->type == IterPriv::IT_SEQ)
return **m_pData->seqIter;
@ -64,15 +64,15 @@ namespace YAML
throw BadDereference();
}
const Node *Iterator::operator -> ()
const Node *Iterator::operator -> () const
{
if(m_pData->type == IterPriv::IT_SEQ)
return &**m_pData->seqIter;
return *m_pData->seqIter;
throw BadDereference();
}
const Node& Iterator::first()
const Node& Iterator::first() const
{
if(m_pData->type == IterPriv::IT_MAP)
return *m_pData->mapIter->first;
@ -80,7 +80,7 @@ namespace YAML
throw BadDereference();
}
const Node& Iterator::second()
const Node& Iterator::second() const
{
if(m_pData->type == IterPriv::IT_MAP)
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;
// IterPriv
// . The implementation for iterators - essentially a union of sequence and map iterators.
struct IterPriv
{
IterPriv();
IterPriv(std::vector <Node *>::const_iterator it);
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it);
IterPriv(): type(IT_NONE) {}
IterPriv(std::vector <Node *>::const_iterator it): seqIter(it), type(IT_SEQ) {}
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): mapIter(it), type(IT_MAP) {}
enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP };
ITER_TYPE type;

View file

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

View file

@ -44,7 +44,7 @@ namespace YAML
return;
// now split based on what kind of node we should be
switch(pScanner->PeekToken().type) {
switch(pScanner->peek().type) {
case TT_SCALAR:
m_pContent = new Scalar;
m_pContent->Parse(pScanner, state);
@ -68,10 +68,10 @@ namespace YAML
void Node::ParseHeader(Scanner *pScanner, const ParserState& state)
{
while(1) {
if(pScanner->IsEmpty())
if(pScanner->empty())
return;
switch(pScanner->PeekToken().type) {
switch(pScanner->peek().type) {
case TT_TAG: ParseTag(pScanner, state); break;
case TT_ANCHOR: ParseAnchor(pScanner, state); break;
case TT_ALIAS: ParseAlias(pScanner, state); break;
@ -82,7 +82,7 @@ namespace YAML
void Node::ParseTag(Scanner *pScanner, const ParserState& state)
{
Token& token = pScanner->PeekToken();
Token& token = pScanner->peek();
if(m_tag != "")
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS);
@ -90,23 +90,23 @@ namespace YAML
for(unsigned i=0;i<token.params.size();i++)
m_tag += token.params[i];
pScanner->PopToken();
pScanner->pop();
}
void Node::ParseAnchor(Scanner *pScanner, const ParserState& state)
{
Token& token = pScanner->PeekToken();
Token& token = pScanner->peek();
if(m_anchor != "")
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS);
m_anchor = token.value;
m_alias = false;
pScanner->PopToken();
pScanner->pop();
}
void Node::ParseAlias(Scanner *pScanner, const ParserState& state)
{
Token& token = pScanner->PeekToken();
Token& token = pScanner->peek();
if(m_anchor != "")
throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES);
if(m_tag != "")
@ -114,7 +114,7 @@ namespace YAML
m_anchor = token.value;
m_alias = true;
pScanner->PopToken();
pScanner->pop();
}
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
{
return !m_pScanner->IsEmpty();
return !m_pScanner->empty();
}
void Parser::Load(std::istream& in)
@ -41,19 +41,19 @@ namespace YAML
ParseDirectives();
// we better have some tokens in the queue
if(m_pScanner->IsEmpty())
if(m_pScanner->empty())
return;
// first eat doc start (optional)
if(m_pScanner->PeekToken().type == TT_DOC_START)
m_pScanner->PopToken();
if(m_pScanner->peek().type == TT_DOC_START)
m_pScanner->pop();
// now parse our root node
document.Parse(m_pScanner, m_state);
// and finally eat any doc ends we see
while(!m_pScanner->IsEmpty() && m_pScanner->PeekToken().type == TT_DOC_END)
m_pScanner->PopToken();
while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
m_pScanner->pop();
}
// ParseDirectives
@ -63,10 +63,10 @@ namespace YAML
bool readDirective = false;
while(1) {
if(m_pScanner->IsEmpty())
if(m_pScanner->empty())
break;
Token& token = m_pScanner->PeekToken();
Token& token = m_pScanner->peek();
if(token.type != TT_DIRECTIVE)
break;
@ -77,7 +77,7 @@ namespace YAML
readDirective = true;
HandleDirective(&token);
m_pScanner->PopToken();
m_pScanner->pop();
}
}
@ -123,11 +123,11 @@ namespace YAML
void Parser::PrintTokens(std::ostream& out)
{
while(1) {
if(m_pScanner->IsEmpty())
if(m_pScanner->empty())
break;
out << m_pScanner->PeekToken() << std::endl;
m_pScanner->PopToken();
out << m_pScanner->peek() << std::endl;
m_pScanner->pop();
}
}
}

View file

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

View file

@ -3,6 +3,7 @@
#include "token.h"
#include "exceptions.h"
#include "exp.h"
#include <cassert>
namespace YAML
{
@ -15,34 +16,46 @@ namespace YAML
{
}
// IsEmpty
// empty
// . 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();
}
// PopToken
// pop
// . 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())
m_tokens.pop();
}
// PeekToken
// . Returns (but does not remove) the next token on the queue, and scans if only we need to.
Token& Scanner::PeekToken()
// peek
// . Returns (but does not remove) the next token on the queue.
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) {
if(!m_tokens.empty()) {
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)
return token;
return;
// here's where we clean up the impossible tokens
if(token.status == TS_INVALID) {
@ -55,13 +68,11 @@ namespace YAML
// no token? maybe we've actually finished
if(m_endedStream)
break;
return;
// no? then scan...
ScanNextToken();
}
// TODO: find something to return here, or assert (but can't do that! maybe split into two functions?)
}
// ScanNextToken

View file

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

View file

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

View file

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