Added a peek token command (for the parser to use).

This commit is contained in:
Jesse Beder 2008-06-30 06:21:12 +00:00
parent 07d4cac48f
commit ed6c294749
6 changed files with 109 additions and 113 deletions

View file

@ -5,6 +5,9 @@
#include "exceptions.h" #include "exceptions.h"
#include <fstream> #include <fstream>
#include <iostream>
#include "token.h"
namespace YAML namespace YAML
{ {
Document::Document(): m_pRoot(0) Document::Document(): m_pRoot(0)
@ -34,10 +37,16 @@ namespace YAML
std::ifstream fin(fileName.c_str()); std::ifstream fin(fileName.c_str());
Scanner scanner(fin); Scanner scanner(fin);
scanner.Scan(); // scan and output, for now
while(1) {
Token *pToken = scanner.GetNextToken();
if(!pToken)
break;
std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl;
delete pToken;
}
getchar(); getchar();
// if(!scanner)
// return;
// m_pRoot = parser.ReadNextNode(); // m_pRoot = parser.ReadNextNode();
} }

View file

@ -5,33 +5,34 @@
namespace YAML namespace YAML
{ {
class Exception: public std::exception {}; class Exception: public std::exception {};
class ScannerException: public Exception {};
class UnknownToken: public Exception {}; class UnknownToken: public ScannerException {};
class IllegalBlockEntry: public Exception {}; class IllegalBlockEntry: public ScannerException {};
class IllegalMapKey: public Exception {}; class IllegalMapKey: public ScannerException {};
class IllegalMapValue: public Exception {}; class IllegalMapValue: public ScannerException {};
class IllegalScalar: public Exception {}; class IllegalScalar: public ScannerException {};
class IllegalTabInIndentation: public Exception {}; class IllegalTabInIndentation: public ScannerException {};
class IllegalFlowEnd: public Exception {}; class IllegalFlowEnd: public ScannerException {};
class IllegalDocIndicator: public Exception {}; class IllegalDocIndicator: public ScannerException {};
class IllegalEOF: public Exception {}; class IllegalEOF: public ScannerException {};
class RequiredSimpleKeyNotFound: public Exception {}; class RequiredSimpleKeyNotFound: public ScannerException {};
class ZeroIndentationInBlockScalar: public Exception {}; class ZeroIndentationInBlockScalar: public ScannerException {};
class UnexpectedCharacterInBlockScalar: public Exception {}; class UnexpectedCharacterInBlockScalar: public ScannerException {};
class AnchorNotFound: public Exception {}; class AnchorNotFound: public ScannerException {};
class IllegalCharacterInAnchor: public Exception {}; class IllegalCharacterInAnchor: public ScannerException {};
class UnknownEscapeSequence: public Exception { class UnknownEscapeSequence: public ScannerException {
public: public:
UnknownEscapeSequence(char ch_): ch(ch_) {} UnknownEscapeSequence(char ch_): ch(ch_) {}
char ch; char ch;
}; };
class NonHexNumber: public Exception { class NonHexNumber: public ScannerException {
public: public:
NonHexNumber(char ch_): ch(ch_) {} NonHexNumber(char ch_): ch(ch_) {}
char ch; char ch;
}; };
class InvalidUnicode: public Exception { class InvalidUnicode: public ScannerException {
public: public:
InvalidUnicode(unsigned value_): value(value_) {} InvalidUnicode(unsigned value_): value(value_) {}
unsigned value; unsigned value;

View file

@ -2,7 +2,6 @@
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "exp.h" #include "exp.h"
#include <iostream>
namespace YAML namespace YAML
{ {
@ -23,39 +22,51 @@ namespace YAML
delete *it; delete *it;
} }
/////////////////////////////////////////////////////////////////////// // GetNextToken
// Misc. helpers // . Removes and returns the next token on the queue.
Token *Scanner::GetNextToken()
// IsWhitespaceToBeEaten
// . We can eat whitespace if:
// 1. It's a space
// 2. It's a tab, and we're either:
// a. In the flow context
// b. In the block context but not where a simple key could be allowed
// (i.e., not at the beginning of a line, or following '-', '?', or ':')
bool Scanner::IsWhitespaceToBeEaten(char ch)
{ {
if(ch == ' ') Token *pToken = PeekNextToken();
return true; if(!m_tokens.empty())
m_tokens.pop();
if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) return pToken;
return true;
return false;
} }
// ScanAndEnqueue // PeekNextToken
// . Scans the token, then pushes it in the queue. // . Returns (but does not remove) the next token on the queue, and scans if only we need to.
// . Note: we also use a set of "limbo tokens", i.e., tokens Token *Scanner::PeekNextToken()
// that haven't yet been pushed. This way, if ScanToken()
// throws an exception, we'll be keeping track of 'pToken'
// somewhere, and it will be automatically cleaned up when
// the Scanner destructs.
template <typename T> void Scanner::ScanAndEnqueue(T *pToken)
{ {
m_limboTokens.insert(pToken); while(1) {
m_tokens.push(ScanToken(pToken)); Token *pToken = 0;
m_limboTokens.erase(pToken);
// is there a token in the queue?
if(!m_tokens.empty())
pToken = m_tokens.front();
// (here's where we clean up the impossible tokens)
if(pToken && pToken->status == TS_INVALID) {
m_tokens.pop();
delete pToken;
continue;
}
// on unverified tokens, we just have to wait
if(pToken && pToken->status == TS_UNVERIFIED)
pToken = 0;
// then that's what we want
if(pToken)
return pToken;
// no token? maybe we've actually finished
if(m_endedStream)
break;
// no? then scan...
ScanNextToken();
}
return 0;
} }
// ScanNextToken // ScanNextToken
@ -166,7 +177,8 @@ namespace YAML
break; break;
// otherwise, let's eat the line break and keep going // otherwise, let's eat the line break and keep going
INPUT.EatLineBreak(); int n = Exp::Break.Match(INPUT);
INPUT.Eat(n);
// oh yeah, and let's get rid of that simple key // oh yeah, and let's get rid of that simple key
VerifySimpleKey(); VerifySimpleKey();
@ -177,6 +189,41 @@ namespace YAML
} }
} }
///////////////////////////////////////////////////////////////////////
// Misc. helpers
// IsWhitespaceToBeEaten
// . We can eat whitespace if:
// 1. It's a space
// 2. It's a tab, and we're either:
// a. In the flow context
// b. In the block context but not where a simple key could be allowed
// (i.e., not at the beginning of a line, or following '-', '?', or ':')
bool Scanner::IsWhitespaceToBeEaten(char ch)
{
if(ch == ' ')
return true;
if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed))
return true;
return false;
}
// ScanAndEnqueue
// . Scans the token, then pushes it in the queue.
// . Note: we also use a set of "limbo tokens", i.e., tokens
// that haven't yet been pushed. This way, if ScanToken()
// throws an exception, we'll be keeping track of 'pToken'
// somewhere, and it will be automatically cleaned up when
// the Scanner destructs.
template <typename T> void Scanner::ScanAndEnqueue(T *pToken)
{
m_limboTokens.insert(pToken);
m_tokens.push(ScanToken(pToken));
m_limboTokens.erase(pToken);
}
// PushIndentTo // PushIndentTo
// . Pushes an indentation onto the stack, and enqueues the // . Pushes an indentation onto the stack, and enqueues the
// proper token (sequence start or mapping start). // proper token (sequence start or mapping start).
@ -216,56 +263,4 @@ namespace YAML
m_tokens.push(new BlockEndToken); m_tokens.push(new BlockEndToken);
} }
} }
// GetNextToken
// . Returns the next token on the queue, and scans if only we need to.
Token *Scanner::GetNextToken()
{
while(1) {
Token *pToken = 0;
// is there a token in the queue?
if(!m_tokens.empty())
pToken = m_tokens.front();
// (here's where we clean up the impossible tokens)
if(pToken && pToken->status == TS_INVALID) {
m_tokens.pop();
delete pToken;
continue;
}
// on unverified tokens, we just have to wait
if(pToken && pToken->status == TS_UNVERIFIED)
pToken = 0;
// then that's what we want
if(pToken) {
m_tokens.pop();
return pToken;
}
// no token? maybe we've actually finished
if(m_endedStream)
break;
// no? then scan...
ScanNextToken();
}
return 0;
}
// temporary function for testing
void Scanner::Scan()
{
while(1) {
Token *pToken = GetNextToken();
if(!pToken)
break;
std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl;
delete pToken;
}
}
} }

View file

@ -19,7 +19,7 @@ namespace YAML
~Scanner(); ~Scanner();
Token *GetNextToken(); Token *GetNextToken();
void Scan(); Token *PeekNextToken();
private: private:
// scanning // scanning

View file

@ -32,12 +32,4 @@ namespace YAML
for(int i=0;i<n;i++) for(int i=0;i<n;i++)
GetChar(); GetChar();
} }
// GetLineBreak
// . Eats with no checking
void Stream::EatLineBreak()
{
Eat(1);
column = 0;
}
} }

View file

@ -18,7 +18,6 @@ namespace YAML
char GetChar(); char GetChar();
std::string GetChar(int n); std::string GetChar(int n);
void Eat(int n = 1); void Eat(int n = 1);
void EatLineBreak();
std::istream& input; std::istream& input;
int line, column; int line, column;