Commit 45322566 authored by Jesse Beder's avatar Jesse Beder
Browse files

Set the eol style to native for all files.

parent a45f083e
#pragma once #pragma once
// for detecting memory leaks // for detecting memory leaks
#ifdef _DEBUG #ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC #define _CRTDBG_MAP_ALLOC
#include <stdlib.h> #include <stdlib.h>
#include <crtdbg.h> #include <crtdbg.h>
#endif // _DEBUG #endif // _DEBUG
#pragma once #pragma once
#include <exception> #include <exception>
#include <string> #include <string>
namespace YAML namespace YAML
{ {
class Exception: public std::exception {}; class Exception: public std::exception {};
class ParserException: public Exception { class ParserException: public Exception {
public: public:
ParserException(int line_, int column_, const std::string& msg_) ParserException(int line_, int column_, const std::string& msg_)
: line(line_), column(column_), msg(msg_) {} : line(line_), column(column_), msg(msg_) {}
virtual ~ParserException() throw () {} virtual ~ParserException() throw () {}
int line, column; int line, column;
std::string msg; std::string msg;
}; };
class RepresentationException: public Exception {}; class RepresentationException: public Exception {};
// representation exceptions // representation exceptions
class InvalidScalar: public RepresentationException {}; class InvalidScalar: public RepresentationException {};
class BadDereference: public RepresentationException {}; class BadDereference: public RepresentationException {};
// error messages // error messages
namespace ErrorMsg namespace ErrorMsg
{ {
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
const std::string YAML_VERSION = "bad YAML version: "; const std::string YAML_VERSION = "bad YAML version: ";
const std::string YAML_MAJOR_VERSION = "YAML major version too large"; const std::string YAML_MAJOR_VERSION = "YAML major version too large";
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
const std::string END_OF_MAP = "end of map not found"; const std::string END_OF_MAP = "end of map not found";
const std::string END_OF_MAP_FLOW = "end of map flow not found"; const std::string END_OF_MAP_FLOW = "end of map flow not found";
const std::string END_OF_SEQ = "end of sequence not found"; const std::string END_OF_SEQ = "end of sequence not found";
const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; const std::string END_OF_SEQ_FLOW = "end of sequence flow not found";
const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node";
const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node";
const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node";
const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags";
const std::string INVALID_HEX = "bad character found while scanning hex number"; const std::string INVALID_HEX = "bad character found while scanning hex number";
const std::string INVALID_UNICODE = "invalid unicode: "; const std::string INVALID_UNICODE = "invalid unicode: ";
const std::string INVALID_ESCAPE = "unknown escape character: "; const std::string INVALID_ESCAPE = "unknown escape character: ";
const std::string UNKNOWN_TOKEN = "unknown token"; const std::string UNKNOWN_TOKEN = "unknown token";
const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; const std::string DOC_IN_SCALAR = "illegal document indicator in scalar";
const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; const std::string EOF_IN_SCALAR = "illegal EOF in scalar";
const std::string CHAR_IN_SCALAR = "illegal character in scalar"; const std::string CHAR_IN_SCALAR = "illegal character in scalar";
const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation";
const std::string FLOW_END = "illegal flow end"; const std::string FLOW_END = "illegal flow end";
const std::string BLOCK_ENTRY = "illegal block entry"; const std::string BLOCK_ENTRY = "illegal block entry";
const std::string MAP_KEY = "illegal map key"; const std::string MAP_KEY = "illegal map key";
const std::string MAP_VALUE = "illegal map value"; const std::string MAP_VALUE = "illegal map value";
const std::string ALIAS_NOT_FOUND = "alias not found after *"; const std::string ALIAS_NOT_FOUND = "alias not found after *";
const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; const std::string ANCHOR_NOT_FOUND = "anchor not found after &";
const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias";
const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor";
const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar";
const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; const std::string CHAR_IN_BLOCK = "unexpected character in block scalar";
} }
} }
#pragma once #pragma once
namespace YAML namespace YAML
{ {
class Node; class Node;
struct IterPriv; struct IterPriv;
class Iterator class Iterator
{ {
public: public:
Iterator(); Iterator();
Iterator(IterPriv *pData); Iterator(IterPriv *pData);
Iterator(const Iterator& rhs); Iterator(const Iterator& rhs);
~Iterator(); ~Iterator();
Iterator& operator = (const Iterator& rhs); Iterator& operator = (const Iterator& rhs);
Iterator& operator ++ (); Iterator& operator ++ ();
Iterator operator ++ (int); Iterator operator ++ (int);
const Node& operator * () const; const Node& operator * () const;
const Node *operator -> () const; const Node *operator -> () const;
const Node& first() const; const Node& first() const;
const Node& second() const; const Node& second() const;
friend bool operator == (const Iterator& it, const Iterator& jt); friend bool operator == (const Iterator& it, const Iterator& jt);
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;
}; };
} }
#pragma once #pragma once
#include <string> #include <string>
#include <ios> #include <ios>
#include <vector> #include <vector>
#include <map> #include <map>
#include "parserstate.h" #include "parserstate.h"
#include "exceptions.h" #include "exceptions.h"
#include "iterator.h" #include "iterator.h"
namespace YAML namespace YAML
{ {
class Content; class Content;
class Scanner; class Scanner;
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
class Node class Node
{ {
public: public:
Node(); Node();
~Node(); ~Node();
void Clear(); void Clear();
void Parse(Scanner *pScanner, const ParserState& state); void Parse(Scanner *pScanner, const ParserState& state);
void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const; void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const;
CONTENT_TYPE GetType() const; CONTENT_TYPE GetType() const;
// accessors // accessors
Iterator begin() const; Iterator begin() const;
Iterator end() const; Iterator end() const;
unsigned size() const; unsigned size() const;
template <typename T> template <typename T>
const Node& GetValue(const T& key) const { const Node& GetValue(const T& key) const {
if(!m_pContent) if(!m_pContent)
throw BadDereference(); throw BadDereference();
for(Iterator it=begin();it!=end();++it) { for(Iterator it=begin();it!=end();++it) {
T t; T t;
try { try {
it.first() >> t; it.first() >> t;
if(key == t) if(key == t)
return it.second(); return it.second();
} catch(RepresentationException&) { } catch(RepresentationException&) {
} }
} }
throw BadDereference(); throw BadDereference();
} }
template <typename T> template <typename T>
const Node& operator [] (const T& key) const { const Node& operator [] (const T& key) const {
return GetValue(key); return GetValue(key);
} }
const Node& operator [] (const char *key) const { const Node& operator [] (const char *key) const {
return GetValue(std::string(key)); return GetValue(std::string(key));
} }
const Node& operator [] (unsigned u) const; const Node& operator [] (unsigned u) const;
const Node& operator [] (int i) const; const Node& operator [] (int i) const;
// extraction // extraction
friend void operator >> (const Node& node, std::string& s); friend void operator >> (const Node& node, std::string& s);
friend void operator >> (const Node& node, int& i); friend void operator >> (const Node& node, int& i);
friend void operator >> (const Node& node, unsigned& u); friend void operator >> (const Node& node, unsigned& u);
friend void operator >> (const Node& node, long& l); friend void operator >> (const Node& node, long& l);
friend void operator >> (const Node& node, float& f); friend void operator >> (const Node& node, float& f);
friend void operator >> (const Node& node, double& d); friend void operator >> (const Node& node, double& d);
friend void operator >> (const Node& node, char& c); friend void operator >> (const Node& node, char& c);
// insertion // insertion
friend std::ostream& operator << (std::ostream& out, const Node& node); friend std::ostream& operator << (std::ostream& out, const Node& node);
// ordering // ordering
int Compare(const Node& rhs) const; int Compare(const Node& rhs) const;
friend bool operator < (const Node& n1, const Node& n2); friend bool operator < (const Node& n1, const Node& n2);
private: private:
void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseHeader(Scanner *pScanner, const ParserState& state);
void ParseTag(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state);
void ParseAnchor(Scanner *pScanner, const ParserState& state); void ParseAnchor(Scanner *pScanner, const ParserState& state);
void ParseAlias(Scanner *pScanner, const ParserState& state); void ParseAlias(Scanner *pScanner, const ParserState& state);
private: private:
std::string m_anchor, m_tag; std::string m_anchor, m_tag;
Content *m_pContent; Content *m_pContent;
bool m_alias; bool m_alias;
}; };
} }
#pragma once #pragma once
#include <ios> #include <ios>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include "node.h" #include "node.h"
#include "parserstate.h" #include "parserstate.h"
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
struct Token; struct Token;
class Parser class Parser
{ {
public: public:
Parser(std::istream& in); Parser(std::istream& in);
~Parser(); ~Parser();
operator bool() const; operator bool() const;
void Load(std::istream& in); void Load(std::istream& in);
void GetNextDocument(Node& document); void GetNextDocument(Node& document);
void PrintTokens(std::ostream& out); void PrintTokens(std::ostream& out);
private: private:
void ParseDirectives(); void ParseDirectives();
void HandleDirective(Token *pToken); void HandleDirective(Token *pToken);
void HandleYamlDirective(Token *pToken); void HandleYamlDirective(Token *pToken);
void HandleTagDirective(Token *pToken); void HandleTagDirective(Token *pToken);
private: private:
// can't copy this // can't copy this
Parser(const Parser& rhs) {} Parser(const Parser& rhs) {}
Parser& operator = (const Parser& rhs) { return *this; } Parser& operator = (const Parser& rhs) { return *this; }
private: private:
Scanner *m_pScanner; Scanner *m_pScanner;
ParserState m_state; ParserState m_state;
}; };
} }
#pragma once #pragma once
#include <string> #include <string>
#include <map> #include <map>
namespace YAML namespace YAML
{ {
struct Version { struct Version {
int major, minor; int major, minor;
}; };
struct ParserState struct ParserState
{ {
Version version; Version version;
std::map <std::string, std::string> tags; std::map <std::string, std::string> tags;
void Reset(); void Reset();
std::string TranslateTag(const std::string& handle) const; std::string TranslateTag(const std::string& handle) const;
}; };
} }
#pragma once #pragma once
#include "crt.h" #include "crt.h"
#include "parser.h" #include "parser.h"
#include "node.h" #include "node.h"
#include "iterator.h" #include "iterator.h"
#include "exceptions.h" #include "exceptions.h"
#include "crt.h" #include "crt.h"
#include "content.h" #include "content.h"
namespace YAML namespace YAML
{ {
Content::Content() Content::Content()
{ {
} }
Content::~Content() Content::~Content()
{ {
} }
} }
#pragma once #pragma once
#include <ios> #include <ios>
#include <vector> #include <vector>
#include <map> #include <map>
#include "parserstate.h" #include "parserstate.h"
#include "exceptions.h" #include "exceptions.h"
#include "ltnode.h" #include "ltnode.h"
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
class Parser; class Parser;
class Node; class Node;
class Scalar; class Scalar;
class Sequence; class Sequence;
class Map; class Map;
class Content class Content
{ {
public: public:
Content(); Content();
virtual ~Content(); virtual ~Content();
virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Parse(Scanner *pScanner, const ParserState& state) = 0;
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0;
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const { return false; } virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const { return false; }
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; } virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const { return false; } virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const { return false; }
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; } virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const { return false; }
virtual Node *GetNode(unsigned i) const { return 0; } virtual Node *GetNode(unsigned i) const { return 0; }
virtual unsigned GetSize() const { return 0; } virtual unsigned GetSize() const { return 0; }
virtual bool IsScalar() const { return false; } virtual bool IsScalar() const { return false; }
virtual bool IsMap() const { return false; } virtual bool IsMap() const { return false; }
virtual bool IsSequence() const { return false; } virtual bool IsSequence() const { return false; }
// extraction // extraction
virtual void Read(std::string& s) { throw InvalidScalar(); } virtual void Read(std::string& s) { throw InvalidScalar(); }
virtual void Read(int& i) { throw InvalidScalar(); } virtual void Read(int& i) { throw InvalidScalar(); }
virtual void Read(unsigned& u) { throw InvalidScalar(); } virtual void Read(unsigned& u) { throw InvalidScalar(); }
virtual void Read(long& l) { throw InvalidScalar(); } virtual void Read(long& l) { throw InvalidScalar(); }
virtual void Read(float& f) { throw InvalidScalar(); } virtual void Read(float& f) { throw InvalidScalar(); }
virtual void Read(double& d) { throw InvalidScalar(); } virtual void Read(double& d) { throw InvalidScalar(); }
virtual void Read(char& c) { throw InvalidScalar(); } virtual void Read(char& c) { throw InvalidScalar(); }
// ordering // ordering
virtual int Compare(Content *pContent) { return 0; } virtual int Compare(Content *pContent) { return 0; }
virtual int Compare(Scalar *pScalar) { return 0; } virtual int Compare(Scalar *pScalar) { return 0; }
virtual int Compare(Sequence *pSeq) { return 0; } virtual int Compare(Sequence *pSeq) { return 0; }
virtual int Compare(Map *pMap) { return 0; } virtual int Compare(Map *pMap) { return 0; }
protected: protected:
}; };
} }
#include "crt.h" #include "crt.h"
#include "exp.h" #include "exp.h"
#include "exceptions.h" #include "exceptions.h"
#include <sstream> #include <sstream>
namespace YAML namespace YAML
{ {
namespace Exp namespace Exp
{ {
unsigned ParseHex(const std::string& str, int line, int column) unsigned ParseHex(const std::string& str, int line, int column)
{ {
unsigned value = 0; unsigned value = 0;
for(unsigned i=0;i<str.size();i++) { for(unsigned i=0;i<str.size();i++) {
char ch = str[i]; char ch = str[i];
int digit = 0; int digit = 0;
if('a' <= ch && ch <= 'f') if('a' <= ch && ch <= 'f')
digit = ch - 'a' + 10; digit = ch - 'a' + 10;
else if('A' <= ch && ch <= 'F') else if('A' <= ch && ch <= 'F')
digit = ch - 'A' + 10; digit = ch - 'A' + 10;
else if('0' <= ch && ch <= '9') else if('0' <= ch && ch <= '9')
digit = ch - '0'; digit = ch - '0';
else else
throw ParserException(line, column, ErrorMsg::INVALID_HEX); throw ParserException(line, column, ErrorMsg::INVALID_HEX);
value = (value << 4) + digit; value = (value << 4) + digit;
} }
return value; return value;
} }
std::string Str(char ch) std::string Str(char ch)
{ {
return std::string("") + ch; return std::string("") + ch;
} }
// Escape // Escape
// . Translates the next 'codeLength' characters into a hex number and returns the result. // . Translates the next 'codeLength' characters into a hex number and returns the result.
// . Throws if it's not actually hex. // . Throws if it's not actually hex.
std::string Escape(Stream& in, int codeLength) std::string Escape(Stream& in, int codeLength)
{ {
// grab string // grab string
std::string str; std::string str;
for(int i=0;i<codeLength;i++) for(int i=0;i<codeLength;i++)
str += in.get(); str += in.get();
// get the value // get the value
unsigned value = ParseHex(str, in.line, in.column); unsigned value = ParseHex(str, in.line, in.column);
// legal unicode? // legal unicode?
if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
std::stringstream msg; std::stringstream msg;
msg << ErrorMsg::INVALID_UNICODE << value; msg << ErrorMsg::INVALID_UNICODE << value;
throw ParserException(in.line, in.column, msg.str()); throw ParserException(in.line, in.column, msg.str());
} }
// now break it up into chars // now break it up into chars
if(value <= 0x7F) if(value <= 0x7F)
return Str(value); return Str(value);
else if(value <= 0x7FF) else if(value <= 0x7FF)
return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F));
else if(value <= 0xFFFF) else if(value <= 0xFFFF)
return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
else else
return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) +
Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
} }
// Escape // Escape
// . Escapes the sequence starting 'in' (it must begin with a '\' or single quote) // . Escapes the sequence starting 'in' (it must begin with a '\' or single quote)
// and returns the result. // and returns the result.
// . Throws if it's an unknown escape character. // . Throws if it's an unknown escape character.
std::string Escape(Stream& in) std::string Escape(Stream& in)
{ {
// eat slash // eat slash
char escape = in.get(); char escape = in.get();
// switch on escape character // switch on escape character
char ch = in.get(); char ch = in.get();
// first do single quote, since it's easier // first do single quote, since it's easier
if(escape == '\'' && ch == '\'') if(escape == '\'' && ch == '\'')
return "\'"; return "\'";
// now do the slash (we're not gonna check if it's a slash - you better pass one!) // now do the slash (we're not gonna check if it's a slash - you better pass one!)
switch(ch) { switch(ch) {
case '0': return "\0"; case '0': return "\0";
case 'a': return "\x07"; case 'a': return "\x07";
case 'b': return "\x08"; case 'b': return "\x08";
case 't': case 't':
case '\t': return "\x09"; case '\t': return "\x09";
case 'n': return "\x0A"; case 'n': return "\x0A";
case 'v': return "\x0B"; case 'v': return "\x0B";
case 'f': return "\x0C"; case 'f': return "\x0C";
case 'r': return "\x0D"; case 'r': return "\x0D";
case 'e': return "\x1B"; case 'e': return "\x1B";
case ' ': return "\x20"; case ' ': return "\x20";
case '\"': return "\""; case '\"': return "\"";
case '\'': return "\'"; case '\'': return "\'";
case '\\': return "\\"; case '\\': return "\\";
case 'N': return "\xC2\x85"; // NEL (#x85) case 'N': return "\xC2\x85"; // NEL (#x85)
case '_': return "\xC2\xA0"; // #xA0 case '_': return "\xC2\xA0"; // #xA0
case 'L': return "\xE2\x80\xA8"; // LS (#x2028) case 'L': return "\xE2\x80\xA8"; // LS (#x2028)
case 'P': return "\xE2\x80\xA9"; // PS (#x2029) case 'P': return "\xE2\x80\xA9"; // PS (#x2029)
case 'x': return Escape(in, 2); case 'x': return Escape(in, 2);
case 'u': return Escape(in, 4); case 'u': return Escape(in, 4);
case 'U': return Escape(in, 8); case 'U': return Escape(in, 8);
} }
std::stringstream msg; std::stringstream msg;
throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch); throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch);
} }
} }
} }
#pragma once #pragma once
#include "regex.h" #include "regex.h"
#include <string> #include <string>
#include <ios> #include <ios>
#include "stream.h" #include "stream.h"
namespace YAML namespace YAML
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Here we store a bunch of expressions for matching different parts of the file. // Here we store a bunch of expressions for matching different parts of the file.
namespace Exp namespace Exp
{ {
// misc // misc
const RegEx Blank = RegEx(' ') || RegEx('\t'); const RegEx Blank = RegEx(' ') || RegEx('\t');
const RegEx Break = RegEx('\n') || RegEx("\r\n"); const RegEx Break = RegEx('\n') || RegEx("\r\n");
const RegEx BlankOrBreak = Blank || Break; const RegEx BlankOrBreak = Blank || Break;
const RegEx Digit = RegEx('0', '9'); const RegEx Digit = RegEx('0', '9');
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z');
const RegEx AlphaNumeric = Alpha || Digit; const RegEx AlphaNumeric = Alpha || Digit;
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f');
// actual tags // actual tags
const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx());
const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx());
const RegEx DocIndicator = DocStart || DocEnd; const RegEx DocIndicator = DocStart || DocEnd;
const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF));
const RegEx Key = RegEx('?'), const RegEx Key = RegEx('?'),
KeyInFlow = RegEx('?') + BlankOrBreak; KeyInFlow = RegEx('?') + BlankOrBreak;
const RegEx Value = RegEx(':') + BlankOrBreak, const RegEx Value = RegEx(':') + BlankOrBreak,
ValueInFlow = RegEx(':') + BlankOrBreak; ValueInFlow = RegEx(':') + BlankOrBreak;
const RegEx Comment = RegEx('#'); const RegEx Comment = RegEx('#');
const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak;
// Plain scalar rules: // Plain scalar rules:
// . Cannot start with a blank. // . Cannot start with a blank.
// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ `
// . In the block context - ? : must be not be followed with a space. // . In the block context - ? : must be not be followed with a space.
// . In the flow context ? is illegal and : and - must not be followed with a space. // . In the flow context ? is illegal and : and - must not be followed with a space.
const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)),
PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank));
const RegEx EndScalar = RegEx(':') + BlankOrBreak, const RegEx EndScalar = RegEx(':') + BlankOrBreak,
EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR); EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR);
const RegEx EscSingleQuote = RegEx("\'\'"); const RegEx EscSingleQuote = RegEx("\'\'");
const RegEx EscBreak = RegEx('\\') + Break; const RegEx EscBreak = RegEx('\\') + Break;
const RegEx ChompIndicator = RegEx("+-", REGEX_OR); const RegEx ChompIndicator = RegEx("+-", REGEX_OR);
const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit;
// and some functions // and some functions
std::string Escape(Stream& in); std::string Escape(Stream& in);
} }
namespace Keys namespace Keys
{ {
const char Directive = '%'; const char Directive = '%';
const char FlowSeqStart = '['; const char FlowSeqStart = '[';
const char FlowSeqEnd = ']'; const char FlowSeqEnd = ']';
const char FlowMapStart = '{'; const char FlowMapStart = '{';
const char FlowMapEnd = '}'; const char FlowMapEnd = '}';
const char FlowEntry = ','; const char FlowEntry = ',';
const char Alias = '*'; const char Alias = '*';
const char Anchor = '&'; const char Anchor = '&';
const char Tag = '!'; const char Tag = '!';
const char LiteralScalar = '|'; const char LiteralScalar = '|';
const char FoldedScalar = '>'; const char FoldedScalar = '>';
} }
} }
#include "crt.h" #include "crt.h"
#include "node.h" #include "node.h"
#include "exceptions.h" #include "exceptions.h"
#include "iterpriv.h" #include "iterpriv.h"
namespace YAML namespace YAML
{ {
Iterator::Iterator(): m_pData(0) Iterator::Iterator(): m_pData(0)
{ {
m_pData = new IterPriv; m_pData = new IterPriv;
} }
Iterator::Iterator(IterPriv *pData): m_pData(pData) Iterator::Iterator(IterPriv *pData): m_pData(pData)
{ {
} }
Iterator::Iterator(const Iterator& rhs): m_pData(0) Iterator::Iterator(const Iterator& rhs): m_pData(0)
{ {
m_pData = new IterPriv(*rhs.m_pData); m_pData = new IterPriv(*rhs.m_pData);
} }
Iterator& Iterator::operator = (const Iterator& rhs) Iterator& Iterator::operator = (const Iterator& rhs)
{ {
if(this == &rhs) if(this == &rhs)
return *this; return *this;
delete m_pData; delete m_pData;
m_pData = new IterPriv(*rhs.m_pData); m_pData = new IterPriv(*rhs.m_pData);
return *this; return *this;
} }
Iterator::~Iterator() Iterator::~Iterator()
{ {
delete m_pData; delete m_pData;
} }
Iterator& Iterator::operator ++ () Iterator& Iterator::operator ++ ()
{ {
if(m_pData->type == IterPriv::IT_SEQ) if(m_pData->type == IterPriv::IT_SEQ)
++m_pData->seqIter; ++m_pData->seqIter;
else if(m_pData->type == IterPriv::IT_MAP) else if(m_pData->type == IterPriv::IT_MAP)
++m_pData->mapIter; ++m_pData->mapIter;
return *this; return *this;
} }
Iterator Iterator::operator ++ (int) Iterator Iterator::operator ++ (int)
{ {
Iterator temp = *this; Iterator temp = *this;
if(m_pData->type == IterPriv::IT_SEQ) if(m_pData->type == IterPriv::IT_SEQ)
++m_pData->seqIter; ++m_pData->seqIter;
else if(m_pData->type == IterPriv::IT_MAP) else if(m_pData->type == IterPriv::IT_MAP)
++m_pData->mapIter; ++m_pData->mapIter;
return temp; return temp;
} }
const Node& Iterator::operator * () const 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::operator -> () const 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 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;
throw BadDereference(); throw BadDereference();
} }
const Node& Iterator::second() const 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;
throw BadDereference(); throw BadDereference();
} }
bool operator == (const Iterator& it, const Iterator& jt) bool operator == (const Iterator& it, const Iterator& jt)
{ {
if(it.m_pData->type != jt.m_pData->type) if(it.m_pData->type != jt.m_pData->type)
return false; return false;
if(it.m_pData->type == IterPriv::IT_SEQ) if(it.m_pData->type == IterPriv::IT_SEQ)
return it.m_pData->seqIter == jt.m_pData->seqIter; return it.m_pData->seqIter == jt.m_pData->seqIter;
else if(it.m_pData->type == IterPriv::IT_MAP) else if(it.m_pData->type == IterPriv::IT_MAP)
return it.m_pData->mapIter == jt.m_pData->mapIter; return it.m_pData->mapIter == jt.m_pData->mapIter;
return true; return true;
} }
bool operator != (const Iterator& it, const Iterator& jt) bool operator != (const Iterator& it, const Iterator& jt)
{ {
return !(it == jt); return !(it == jt);
} }
} }
#pragma once #pragma once
#include "ltnode.h" #include "ltnode.h"
#include <vector> #include <vector>
#include <map> #include <map>
namespace YAML namespace YAML
{ {
class Node; class Node;
// IterPriv // IterPriv
// . The implementation for iterators - essentially a union of sequence and map iterators. // . The implementation for iterators - essentially a union of sequence and map iterators.
struct IterPriv struct IterPriv
{ {
IterPriv(): type(IT_NONE) {} IterPriv(): type(IT_NONE) {}
IterPriv(std::vector <Node *>::const_iterator it): type(IT_SEQ), seqIter(it) {} IterPriv(std::vector <Node *>::const_iterator it): type(IT_SEQ), seqIter(it) {}
IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): type(IT_MAP), mapIter(it) {} IterPriv(std::map <Node *, Node *, ltnode>::const_iterator it): type(IT_MAP), mapIter(it) {}
enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP };
ITER_TYPE type; ITER_TYPE type;
std::vector <Node *>::const_iterator seqIter; std::vector <Node *>::const_iterator seqIter;
std::map <Node *, Node *, ltnode>::const_iterator mapIter; std::map <Node *, Node *, ltnode>::const_iterator mapIter;
}; };
} }
#pragma once #pragma once
namespace YAML namespace YAML
{ {
class Node; class Node;
struct ltnode { struct ltnode {
bool operator()(const Node *pNode1, const Node *pNode2) const; bool operator()(const Node *pNode1, const Node *pNode2) const;
}; };
} }
#include "crt.h" #include "crt.h"
#include "map.h" #include "map.h"
#include "node.h" #include "node.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include <iostream> #include <iostream>
namespace YAML namespace YAML
{ {
Map::Map() Map::Map()
{ {
} }
Map::~Map() Map::~Map()
{ {
Clear(); Clear();
} }
void Map::Clear() void Map::Clear()
{ {
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
delete it->first; delete it->first;
delete it->second; delete it->second;
} }
m_data.clear(); m_data.clear();
} }
bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
{ {
it = m_data.begin(); it = m_data.begin();
return true; return true;
} }
bool Map::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const bool Map::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const
{ {
it = m_data.end(); it = m_data.end();
return true; return true;
} }
void Map::Parse(Scanner *pScanner, const ParserState& state) void Map::Parse(Scanner *pScanner, const ParserState& state)
{ {
Clear(); Clear();
// split based on start token // split based on start token
switch(pScanner->peek().type) { switch(pScanner->peek().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;
} }
} }
void Map::ParseBlock(Scanner *pScanner, const ParserState& state) void Map::ParseBlock(Scanner *pScanner, const ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); throw ParserException(-1, -1, ErrorMsg::END_OF_MAP);
Token token = pScanner->peek(); 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->pop(); pScanner->pop();
if(token.type == TT_BLOCK_END) if(token.type == TT_BLOCK_END)
break; break;
Node *pKey = new Node; Node *pKey = new Node;
Node *pValue = new Node; Node *pValue = new Node;
try { try {
// grab key // grab key
pKey->Parse(pScanner, state); pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
pScanner->pop(); pScanner->pop();
pValue->Parse(pScanner, state); pValue->Parse(pScanner, state);
} }
m_data[pKey] = pValue; m_data[pKey] = pValue;
} catch(Exception& e) { } catch(Exception& e) {
delete pKey; delete pKey;
delete pValue; delete pValue;
throw e; throw e;
} }
} }
} }
void Map::ParseFlow(Scanner *pScanner, const ParserState& state) void Map::ParseFlow(Scanner *pScanner, const ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW);
Token& token = pScanner->peek(); 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->pop(); pScanner->pop();
break; break;
} }
// now it better be a key // now it better be a key
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->pop(); pScanner->pop();
Node *pKey = new Node; Node *pKey = new Node;
Node *pValue = new Node; Node *pValue = new Node;
try { try {
// grab key // grab key
pKey->Parse(pScanner, state); pKey->Parse(pScanner, state);
// now grab value (optional) // now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) {
pScanner->pop(); 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->peek(); Token& nextToken = pScanner->peek();
if(nextToken.type == TT_FLOW_ENTRY) if(nextToken.type == TT_FLOW_ENTRY)
pScanner->pop(); 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);
m_data[pKey] = pValue; m_data[pKey] = pValue;
} catch(Exception& e) { } catch(Exception& e) {
// clean up and rethrow // clean up and rethrow
delete pKey; delete pKey;
delete pValue; delete pValue;
throw e; throw e;
} }
} }
} }
void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
{ {
if(startedLine && !onlyOneCharOnLine) if(startedLine && !onlyOneCharOnLine)
out << "\n"; out << "\n";
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) { if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) {
for(int i=0;i<indent;i++) for(int i=0;i<indent;i++)
out << " "; out << " ";
} }
out << "? "; out << "? ";
it->first->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine); it->first->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine);
for(int i=0;i<indent;i++) for(int i=0;i<indent;i++)
out << " "; out << " ";
out << ": "; out << ": ";
it->second->Write(out, indent + 1, true, true); it->second->Write(out, indent + 1, true, true);
} }
if(m_data.empty()) if(m_data.empty())
out << "\n"; out << "\n";
} }
int Map::Compare(Content *pContent) int Map::Compare(Content *pContent)
{ {
return -pContent->Compare(this); return -pContent->Compare(this);
} }
int Map::Compare(Map *pMap) int Map::Compare(Map *pMap)
{ {
node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin(); node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin();
while(1) { while(1) {
if(it == m_data.end()) { if(it == m_data.end()) {
if(jt == pMap->m_data.end()) if(jt == pMap->m_data.end())
return 0; return 0;
else else
return -1; return -1;
} }
if(jt == pMap->m_data.end()) if(jt == pMap->m_data.end())
return 1; return 1;
int cmp = it->first->Compare(*jt->first); int cmp = it->first->Compare(*jt->first);
if(cmp != 0) if(cmp != 0)
return cmp; return cmp;
cmp = it->second->Compare(*jt->second); cmp = it->second->Compare(*jt->second);
if(cmp != 0) if(cmp != 0)
return cmp; return cmp;
} }
return 0; return 0;
} }
} }
#pragma once #pragma once
#include "content.h" #include "content.h"
#include <map> #include <map>
namespace YAML namespace YAML
{ {
class Node; class Node;
class Map: public Content class Map: public Content
{ {
public: public:
Map(); Map();
virtual ~Map(); virtual ~Map();
void Clear(); void Clear();
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const; virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const; virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, const ParserState& state);
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
virtual bool IsMap() const { return true; } virtual bool IsMap() const { return true; }
// ordering // ordering
virtual int Compare(Content *pContent); virtual int Compare(Content *pContent);
virtual int Compare(Scalar *pScalar) { return 1; } virtual int Compare(Scalar *pScalar) { return 1; }
virtual int Compare(Sequence *pSeq) { return 1; } virtual int Compare(Sequence *pSeq) { return 1; }
virtual int Compare(Map *pMap); virtual int Compare(Map *pMap);
private: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, const ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state);
protected: protected:
typedef std::map <Node *, Node *, ltnode> node_map; typedef std::map <Node *, Node *, ltnode> node_map;
node_map m_data; node_map m_data;
}; };
} }
#include "crt.h" #include "crt.h"
#include "node.h" #include "node.h"
#include "token.h" #include "token.h"
#include "scanner.h" #include "scanner.h"
#include "content.h" #include "content.h"
#include "parser.h" #include "parser.h"
#include "scalar.h" #include "scalar.h"
#include "sequence.h" #include "sequence.h"
#include "map.h" #include "map.h"
#include "iterpriv.h" #include "iterpriv.h"
namespace YAML namespace YAML
{ {
// the ordering! // the ordering!
bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const
{ {
return *pNode1 < *pNode2; return *pNode1 < *pNode2;
} }
Node::Node(): m_pContent(0), m_alias(false) Node::Node(): m_pContent(0), m_alias(false)
{ {
} }
Node::~Node() Node::~Node()
{ {
Clear(); Clear();
} }
void Node::Clear() void Node::Clear()
{ {
delete m_pContent; delete m_pContent;
m_pContent = 0; m_pContent = 0;
m_alias = false; m_alias = false;
} }
void Node::Parse(Scanner *pScanner, const ParserState& state) void Node::Parse(Scanner *pScanner, const ParserState& state)
{ {
Clear(); Clear();
ParseHeader(pScanner, state); 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)
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->peek().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);
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, state); 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, state); m_pContent->Parse(pScanner, state);
break; break;
} }
} }
// 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, const ParserState& state) void Node::ParseHeader(Scanner *pScanner, const ParserState& state)
{ {
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
return; return;
switch(pScanner->peek().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;
default: return; default: return;
} }
} }
} }
void Node::ParseTag(Scanner *pScanner, const ParserState& state) void Node::ParseTag(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->peek(); 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);
m_tag = state.TranslateTag(token.value); m_tag = state.TranslateTag(token.value);
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->pop(); pScanner->pop();
} }
void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) void Node::ParseAnchor(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->peek(); 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->pop(); pScanner->pop();
} }
void Node::ParseAlias(Scanner *pScanner, const ParserState& state) void Node::ParseAlias(Scanner *pScanner, const ParserState& state)
{ {
Token& token = pScanner->peek(); 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 != "")
throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT); throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT);
m_anchor = token.value; m_anchor = token.value;
m_alias = true; m_alias = true;
pScanner->pop(); 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
{ {
// write anchor/alias // write anchor/alias
if(m_anchor != "") { if(m_anchor != "") {
if(m_alias) if(m_alias)
out << std::string("*"); out << std::string("*");
else else
out << std::string("&"); out << std::string("&");
out << m_anchor << std::string(" "); out << m_anchor << std::string(" ");
startedLine = true; startedLine = true;
onlyOneCharOnLine = false; onlyOneCharOnLine = false;
} }
// write tag // write tag
if(m_tag != "") { if(m_tag != "") {
out << std::string("!<") << m_tag << std::string("> "); out << std::string("!<") << m_tag << std::string("> ");
startedLine = true; startedLine = true;
onlyOneCharOnLine = false; onlyOneCharOnLine = false;
} }
if(!m_pContent) { if(!m_pContent) {
out << std::string("\n"); out << std::string("\n");
} else { } else {
m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine);
} }
} }
CONTENT_TYPE Node::GetType() const CONTENT_TYPE Node::GetType() const
{ {
if(!m_pContent) if(!m_pContent)
return CT_NONE; return CT_NONE;
if(m_pContent->IsScalar()) if(m_pContent->IsScalar())
return CT_SCALAR; return CT_SCALAR;
else if(m_pContent->IsSequence()) else if(m_pContent->IsSequence())
return CT_SEQUENCE; return CT_SEQUENCE;
else if(m_pContent->IsMap()) else if(m_pContent->IsMap())
return CT_MAP; return CT_MAP;
return CT_NONE; return CT_NONE;
} }
// begin // begin
// Returns an iterator to the beginning of this (sequence or map). // Returns an iterator to the beginning of this (sequence or map).
Iterator Node::begin() const Iterator Node::begin() const
{ {
if(!m_pContent) if(!m_pContent)
return Iterator(); return Iterator();
std::vector <Node *>::const_iterator seqIter; std::vector <Node *>::const_iterator seqIter;
if(m_pContent->GetBegin(seqIter)) if(m_pContent->GetBegin(seqIter))
return Iterator(new IterPriv(seqIter)); return Iterator(new IterPriv(seqIter));
std::map <Node *, Node *, ltnode>::const_iterator mapIter; std::map <Node *, Node *, ltnode>::const_iterator mapIter;
if(m_pContent->GetBegin(mapIter)) if(m_pContent->GetBegin(mapIter))
return Iterator(new IterPriv(mapIter)); return Iterator(new IterPriv(mapIter));
return Iterator(); return Iterator();
} }
// end // end
// . Returns an iterator to the end of this (sequence or map). // . Returns an iterator to the end of this (sequence or map).
Iterator Node::end() const Iterator Node::end() const
{ {
if(!m_pContent) if(!m_pContent)
return Iterator(); return Iterator();
std::vector <Node *>::const_iterator seqIter; std::vector <Node *>::const_iterator seqIter;
if(m_pContent->GetEnd(seqIter)) if(m_pContent->GetEnd(seqIter))
return Iterator(new IterPriv(seqIter)); return Iterator(new IterPriv(seqIter));
std::map <Node *, Node *, ltnode>::const_iterator mapIter; std::map <Node *, Node *, ltnode>::const_iterator mapIter;
if(m_pContent->GetEnd(mapIter)) if(m_pContent->GetEnd(mapIter))
return Iterator(new IterPriv(mapIter)); return Iterator(new IterPriv(mapIter));
return Iterator(); return Iterator();
} }
// size // size
// . Returns the size of this node, if it's a sequence node. // . Returns the size of this node, if it's a sequence node.
// . Otherwise, returns zero. // . Otherwise, returns zero.
unsigned Node::size() const unsigned Node::size() const
{ {
if(!m_pContent) if(!m_pContent)
return 0; return 0;
return m_pContent->GetSize(); return m_pContent->GetSize();
} }
const Node& Node::operator [] (unsigned u) const const Node& Node::operator [] (unsigned u) const
{ {
if(!m_pContent) if(!m_pContent)
throw BadDereference(); throw BadDereference();
Node *pNode = m_pContent->GetNode(u); Node *pNode = m_pContent->GetNode(u);
if(pNode) if(pNode)
return *pNode; return *pNode;
return GetValue(u); return GetValue(u);
} }
const Node& Node::operator [] (int i) const const Node& Node::operator [] (int i) const
{ {
if(!m_pContent) if(!m_pContent)
throw BadDereference(); throw BadDereference();
Node *pNode = m_pContent->GetNode(i); Node *pNode = m_pContent->GetNode(i);
if(pNode) if(pNode)
return *pNode; return *pNode;
return GetValue(i); return GetValue(i);
} }
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// Extraction // Extraction
void operator >> (const Node& node, std::string& s) void operator >> (const Node& node, std::string& s)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(s); node.m_pContent->Read(s);
} }
void operator >> (const Node& node, int& i) void operator >> (const Node& node, int& i)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(i); node.m_pContent->Read(i);
} }
void operator >> (const Node& node, unsigned& u) void operator >> (const Node& node, unsigned& u)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(u); node.m_pContent->Read(u);
} }
void operator >> (const Node& node, long& l) void operator >> (const Node& node, long& l)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(l); node.m_pContent->Read(l);
} }
void operator >> (const Node& node, float& f) void operator >> (const Node& node, float& f)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(f); node.m_pContent->Read(f);
} }
void operator >> (const Node& node, double& d) void operator >> (const Node& node, double& d)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(d); node.m_pContent->Read(d);
} }
void operator >> (const Node& node, char& c) void operator >> (const Node& node, char& c)
{ {
if(!node.m_pContent) if(!node.m_pContent)
throw; throw;
node.m_pContent->Read(c); node.m_pContent->Read(c);
} }
std::ostream& operator << (std::ostream& out, const Node& node) std::ostream& operator << (std::ostream& out, const Node& node)
{ {
node.Write(out, 0, false, false); node.Write(out, 0, false, false);
return out; return out;
} }
int Node::Compare(const Node& rhs) const int Node::Compare(const Node& rhs) const
{ {
// Step 1: no content is the smallest // Step 1: no content is the smallest
if(!m_pContent) { if(!m_pContent) {
if(rhs.m_pContent) if(rhs.m_pContent)
return -1; return -1;
else else
return 0; return 0;
} }
if(!rhs.m_pContent) if(!rhs.m_pContent)
return 1; return 1;
return m_pContent->Compare(rhs.m_pContent); return m_pContent->Compare(rhs.m_pContent);
} }
bool operator < (const Node& n1, const Node& n2) bool operator < (const Node& n1, const Node& n2)
{ {
return n1.Compare(n2) < 0; return n1.Compare(n2) < 0;
} }
} }
#include "crt.h" #include "crt.h"
#include "parser.h" #include "parser.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include <sstream> #include <sstream>
namespace YAML namespace YAML
{ {
Parser::Parser(std::istream& in): m_pScanner(0) Parser::Parser(std::istream& in): m_pScanner(0)
{ {
Load(in); Load(in);
} }
Parser::~Parser() Parser::~Parser()
{ {
delete m_pScanner; delete m_pScanner;
} }
Parser::operator bool() const Parser::operator bool() const
{ {
return !m_pScanner->empty(); return !m_pScanner->empty();
} }
void Parser::Load(std::istream& in) void Parser::Load(std::istream& in)
{ {
delete m_pScanner; delete m_pScanner;
m_pScanner = new Scanner(in); m_pScanner = new Scanner(in);
m_state.Reset(); m_state.Reset();
} }
// GetNextDocument // GetNextDocument
// . Reads the next document in the queue (of tokens). // . Reads the next document in the queue (of tokens).
// . Throws a ParserException on error. // . Throws a ParserException on error.
void Parser::GetNextDocument(Node& document) void Parser::GetNextDocument(Node& document)
{ {
// clear node // clear node
document.Clear(); document.Clear();
// first read directives // first read directives
ParseDirectives(); ParseDirectives();
// we better have some tokens in the queue // we better have some tokens in the queue
if(m_pScanner->empty()) if(m_pScanner->empty())
return; return;
// first eat doc start (optional) // first eat doc start (optional)
if(m_pScanner->peek().type == TT_DOC_START) if(m_pScanner->peek().type == TT_DOC_START)
m_pScanner->pop(); 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->empty() && m_pScanner->peek().type == TT_DOC_END) while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
m_pScanner->pop(); m_pScanner->pop();
} }
// ParseDirectives // ParseDirectives
// . Reads any directives that are next in the queue. // . Reads any directives that are next in the queue.
void Parser::ParseDirectives() void Parser::ParseDirectives()
{ {
bool readDirective = false; bool readDirective = false;
while(1) { while(1) {
if(m_pScanner->empty()) if(m_pScanner->empty())
break; break;
Token& token = m_pScanner->peek(); Token& token = m_pScanner->peek();
if(token.type != TT_DIRECTIVE) if(token.type != TT_DIRECTIVE)
break; break;
// we keep the directives from the last document if none are specified; // we keep the directives from the last document if none are specified;
// but if any directives are specific, then we reset them // but if any directives are specific, then we reset them
if(!readDirective) if(!readDirective)
m_state.Reset(); m_state.Reset();
readDirective = true; readDirective = true;
HandleDirective(&token); HandleDirective(&token);
m_pScanner->pop(); m_pScanner->pop();
} }
} }
void Parser::HandleDirective(Token *pToken) void Parser::HandleDirective(Token *pToken)
{ {
if(pToken->value == "YAML") if(pToken->value == "YAML")
HandleYamlDirective(pToken); HandleYamlDirective(pToken);
else if(pToken->value == "TAG") else if(pToken->value == "TAG")
HandleTagDirective(pToken); HandleTagDirective(pToken);
} }
// HandleYamlDirective // HandleYamlDirective
// . Should be of the form 'major.minor' (like a version number) // . Should be of the form 'major.minor' (like a version number)
void Parser::HandleYamlDirective(Token *pToken) void Parser::HandleYamlDirective(Token *pToken)
{ {
if(pToken->params.size() != 1) if(pToken->params.size() != 1)
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS); throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS);
std::stringstream str(pToken->params[0]); std::stringstream str(pToken->params[0]);
str >> m_state.version.major; str >> m_state.version.major;
str.get(); str.get();
str >> m_state.version.minor; str >> m_state.version.minor;
if(!str || str.peek() != EOF) if(!str || str.peek() != EOF)
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]); throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]);
if(m_state.version.major > 1) if(m_state.version.major > 1)
throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION); throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION);
// TODO: warning on major == 1, minor > 2? // TODO: warning on major == 1, minor > 2?
} }
// HandleTagDirective // HandleTagDirective
// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
void Parser::HandleTagDirective(Token *pToken) void Parser::HandleTagDirective(Token *pToken)
{ {
if(pToken->params.size() != 2) if(pToken->params.size() != 2)
throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS); throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS);
std::string handle = pToken->params[0], prefix = pToken->params[1]; std::string handle = pToken->params[0], prefix = pToken->params[1];
m_state.tags[handle] = prefix; m_state.tags[handle] = prefix;
} }
void Parser::PrintTokens(std::ostream& out) void Parser::PrintTokens(std::ostream& out)
{ {
while(1) { while(1) {
if(m_pScanner->empty()) if(m_pScanner->empty())
break; break;
out << m_pScanner->peek() << "\n"; out << m_pScanner->peek() << "\n";
m_pScanner->pop(); m_pScanner->pop();
} }
} }
} }
#include "crt.h" #include "crt.h"
#include "parserstate.h" #include "parserstate.h"
namespace YAML namespace YAML
{ {
void ParserState::Reset() void ParserState::Reset()
{ {
// version // version
version.major = 1; version.major = 1;
version.minor = 2; version.minor = 2;
// and tags // and tags
tags.clear(); tags.clear();
tags["!"] = "!"; tags["!"] = "!";
tags["!!"] = "tag:yaml.org,2002:"; tags["!!"] = "tag:yaml.org,2002:";
} }
std::string ParserState::TranslateTag(const std::string& handle) const std::string ParserState::TranslateTag(const std::string& handle) const
{ {
std::map <std::string, std::string>::const_iterator it = tags.find(handle); std::map <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end()) if(it == tags.end())
return handle; return handle;
return it->second; return it->second;
} }
} }
#include "crt.h" #include "crt.h"
#include "regex.h" #include "regex.h"
#include "stream.h" #include "stream.h"
#include <iostream> #include <iostream>
namespace YAML namespace YAML
{ {
RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0) RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0)
{ {
SetOp(); SetOp();
} }
RegEx::RegEx(const RegEx& rhs): m_pOp(0) RegEx::RegEx(const RegEx& rhs): m_pOp(0)
{ {
m_op = rhs.m_op; m_op = rhs.m_op;
m_a = rhs.m_a; m_a = rhs.m_a;
m_z = rhs.m_z; m_z = rhs.m_z;
m_params = rhs.m_params; m_params = rhs.m_params;
SetOp(); SetOp();
} }
RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0) RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0)
{ {
SetOp(); SetOp();
} }
RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch) RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch)
{ {
SetOp(); SetOp();
} }
RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z) RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z)
{ {
SetOp(); SetOp();
} }
RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0) RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0)
{ {
for(unsigned i=0;i<str.size();i++) for(unsigned i=0;i<str.size();i++)
m_params.push_back(RegEx(str[i])); m_params.push_back(RegEx(str[i]));
SetOp(); SetOp();
} }
RegEx::~RegEx() RegEx::~RegEx()
{ {
delete m_pOp; delete m_pOp;
} }
RegEx& RegEx::operator = (const RegEx& rhs) RegEx& RegEx::operator = (const RegEx& rhs)
{ {
delete m_pOp; delete m_pOp;
m_pOp = 0; m_pOp = 0;
m_op = rhs.m_op; m_op = rhs.m_op;
m_a = rhs.m_a; m_a = rhs.m_a;
m_z = rhs.m_z; m_z = rhs.m_z;
m_params = rhs.m_params; m_params = rhs.m_params;
SetOp(); SetOp();
return *this; return *this;
} }
void RegEx::SetOp() void RegEx::SetOp()
{ {
delete m_pOp; delete m_pOp;
m_pOp = 0; m_pOp = 0;
switch(m_op) { switch(m_op) {
case REGEX_MATCH: m_pOp = new MatchOperator; break; case REGEX_MATCH: m_pOp = new MatchOperator; break;
case REGEX_RANGE: m_pOp = new RangeOperator; break; case REGEX_RANGE: m_pOp = new RangeOperator; break;
case REGEX_OR: m_pOp = new OrOperator; break; case REGEX_OR: m_pOp = new OrOperator; break;
case REGEX_AND: m_pOp = new AndOperator; break; case REGEX_AND: m_pOp = new AndOperator; break;
case REGEX_NOT: m_pOp = new NotOperator; break; case REGEX_NOT: m_pOp = new NotOperator; break;
case REGEX_SEQ: m_pOp = new SeqOperator; break; case REGEX_SEQ: m_pOp = new SeqOperator; break;
} }
} }
bool RegEx::Matches(char ch) const bool RegEx::Matches(char ch) const
{ {
std::string str; std::string str;
str += ch; str += ch;
return Matches(str); return Matches(str);
} }
bool RegEx::Matches(const std::string& str) const bool RegEx::Matches(const std::string& str) const
{ {
return Match(str) >= 0; return Match(str) >= 0;
} }
bool RegEx::Matches(std::istream& in) const bool RegEx::Matches(std::istream& in) const
{ {
return Match(in) >= 0; return Match(in) >= 0;
} }
bool RegEx::Matches(Stream& in) const bool RegEx::Matches(Stream& in) const
{ {
return Match(in) >= 0; return Match(in) >= 0;
} }
// Match // Match
// . Matches the given string against this regular expression. // . Matches the given string against this regular expression.
// . Returns the number of characters matched. // . Returns the number of characters matched.
// . Returns -1 if no characters were matched (the reason for // . Returns -1 if no characters were matched (the reason for
// not returning zero is that we may have an empty regex // not returning zero is that we may have an empty regex
// which is ALWAYS successful at matching zero characters). // which is ALWAYS successful at matching zero characters).
int RegEx::Match(const std::string& str) const int RegEx::Match(const std::string& str) const
{ {
if(!m_pOp) if(!m_pOp)
return 0; return 0;
return m_pOp->Match(str, *this); return m_pOp->Match(str, *this);
} }
// Match // Match
int RegEx::Match(Stream& in) const int RegEx::Match(Stream& in) const
{ {
return Match(in.stream()); return Match(in.stream());
} }
// Match // Match
// . The stream version does the same thing as the string version; // . The stream version does the same thing as the string version;
// REMEMBER that we only match from the start of the stream! // REMEMBER that we only match from the start of the stream!
// . Note: the istream is not a const reference, but we guarantee // . Note: the istream is not a const reference, but we guarantee
// that the pointer will be in the same spot, and we'll clear its // that the pointer will be in the same spot, and we'll clear its
// flags before we end. // flags before we end.
int RegEx::Match(std::istream& in) const int RegEx::Match(std::istream& in) const
{ {
if(!m_pOp) if(!m_pOp)
return -1; return -1;
int pos = in.tellg(); int pos = in.tellg();
int ret = m_pOp->Match(in, *this); int ret = m_pOp->Match(in, *this);
// reset input stream! // reset input stream!
in.clear(); in.clear();
in.seekg(pos); in.seekg(pos);
return ret; return ret;
} }
RegEx operator ! (const RegEx& ex) RegEx operator ! (const RegEx& ex)
{ {
RegEx ret(REGEX_NOT); RegEx ret(REGEX_NOT);
ret.m_params.push_back(ex); ret.m_params.push_back(ex);
return ret; return ret;
} }
RegEx operator || (const RegEx& ex1, const RegEx& ex2) RegEx operator || (const RegEx& ex1, const RegEx& ex2)
{ {
RegEx ret(REGEX_OR); RegEx ret(REGEX_OR);
ret.m_params.push_back(ex1); ret.m_params.push_back(ex1);
ret.m_params.push_back(ex2); ret.m_params.push_back(ex2);
return ret; return ret;
} }
RegEx operator && (const RegEx& ex1, const RegEx& ex2) RegEx operator && (const RegEx& ex1, const RegEx& ex2)
{ {
RegEx ret(REGEX_AND); RegEx ret(REGEX_AND);
ret.m_params.push_back(ex1); ret.m_params.push_back(ex1);
ret.m_params.push_back(ex2); ret.m_params.push_back(ex2);
return ret; return ret;
} }
RegEx operator + (const RegEx& ex1, const RegEx& ex2) RegEx operator + (const RegEx& ex1, const RegEx& ex2)
{ {
RegEx ret(REGEX_SEQ); RegEx ret(REGEX_SEQ);
ret.m_params.push_back(ex1); ret.m_params.push_back(ex1);
ret.m_params.push_back(ex2); ret.m_params.push_back(ex2);
return ret; return ret;
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Operators // Operators
// MatchOperator // MatchOperator
int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const
{ {
if(str.empty() || str[0] != regex.m_a) if(str.empty() || str[0] != regex.m_a)
return -1; return -1;
return 1; return 1;
} }
int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const
{ {
if(!in || in.peek() != regex.m_a) if(!in || in.peek() != regex.m_a)
return -1; return -1;
return 1; return 1;
} }
// RangeOperator // RangeOperator
int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const
{ {
if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0]) if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0])
return -1; return -1;
return 1; return 1;
} }
int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const
{ {
if(!in || regex.m_a > in.peek() || regex.m_z < in.peek()) if(!in || regex.m_a > in.peek() || regex.m_z < in.peek())
return -1; return -1;
return 1; return 1;
} }
// OrOperator // OrOperator
int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const
{ {
for(unsigned i=0;i<regex.m_params.size();i++) { for(unsigned i=0;i<regex.m_params.size();i++) {
int n = regex.m_params[i].Match(str); int n = regex.m_params[i].Match(str);
if(n >= 0) if(n >= 0)
return n; return n;
} }
return -1; return -1;
} }
int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const
{ {
for(unsigned i=0;i<regex.m_params.size();i++) { for(unsigned i=0;i<regex.m_params.size();i++) {
int n = regex.m_params[i].Match(in); int n = regex.m_params[i].Match(in);
if(n >= 0) if(n >= 0)
return n; return n;
} }
return -1; return -1;
} }
// AndOperator // AndOperator
// Note: 'AND' is a little funny, since we may be required to match things // Note: 'AND' is a little funny, since we may be required to match things
// of different lengths. If we find a match, we return the length of // of different lengths. If we find a match, we return the length of
// the FIRST entry on the list. // the FIRST entry on the list.
int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const
{ {
int first = -1; int first = -1;
for(unsigned i=0;i<regex.m_params.size();i++) { for(unsigned i=0;i<regex.m_params.size();i++) {
int n = regex.m_params[i].Match(str); int n = regex.m_params[i].Match(str);
if(n == -1) if(n == -1)
return -1; return -1;
if(i == 0) if(i == 0)
first = n; first = n;
} }
return first; return first;
} }
int RegEx::AndOperator::Match(std::istream& in, const RegEx& regex) const int RegEx::AndOperator::Match(std::istream& in, const RegEx& regex) const
{ {
int first = -1; int first = -1;
for(unsigned i=0;i<regex.m_params.size();i++) { for(unsigned i=0;i<regex.m_params.size();i++) {
int n = regex.m_params[i].Match(in); int n = regex.m_params[i].Match(in);
if(n == -1) if(n == -1)
return -1; return -1;
if(i == 0) if(i == 0)
first = n; first = n;
} }
return first; return first;
} }
// NotOperator // NotOperator
int RegEx::NotOperator::Match(const std::string& str, const RegEx& regex) const int RegEx::NotOperator::Match(const std::string& str, const RegEx& regex) const
{ {
if(regex.m_params.empty()) if(regex.m_params.empty())
return -1; return -1;
if(regex.m_params[0].Match(str) >= 0) if(regex.m_params[0].Match(str) >= 0)
return -1; return -1;
return 1; return 1;
} }
int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const
{ {
if(regex.m_params.empty()) if(regex.m_params.empty())
return -1; return -1;
if(regex.m_params[0].Match(in) >= 0) if(regex.m_params[0].Match(in) >= 0)
return -1; return -1;
return 1; return 1;
} }
// SeqOperator // SeqOperator
int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const
{ {
int offset = 0; int offset = 0;
for(unsigned i=0;i<regex.m_params.size();i++) { for(unsigned i=0;i<regex.m_params.size();i++) {
int n = regex.m_params[i].Match(str.substr(offset)); int n = regex.m_params[i].Match(str.substr(offset));
if(n == -1) if(n == -1)
return -1; return -1;
offset += n; offset += n;
} }
return offset; return offset;
} }
int RegEx::SeqOperator::Match(std::istream& in, const RegEx& regex) const int RegEx::SeqOperator::Match(std::istream& in, const RegEx& regex) const
{ {
int offset = 0; int offset = 0;
for(unsigned i=0;i<regex.m_params.size();i++) { for(unsigned i=0;i<regex.m_params.size();i++) {
int n = regex.m_params[i].Match(in); int n = regex.m_params[i].Match(in);
if(n == -1) if(n == -1)
return -1; return -1;
offset += n; offset += n;
in.ignore(n); in.ignore(n);
} }
return offset; return offset;
} }
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment