00001 #include "yaml-cpp-pm/parser.h" 00002 #include "yaml-cpp-pm/eventhandler.h" 00003 #include "yaml-cpp-pm/exceptions.h" 00004 #include "yaml-cpp-pm/node.h" 00005 #include "directives.h" 00006 #include "nodebuilder.h" 00007 #include "scanner.h" 00008 #include "singledocparser.h" 00009 #include "tag.h" 00010 #include "token.h" 00011 #include <sstream> 00012 #include <cstdio> 00013 00014 namespace YAML_PM 00015 { 00016 Parser::Parser() 00017 { 00018 } 00019 00020 Parser::Parser(std::istream& in) 00021 { 00022 Load(in); 00023 } 00024 00025 Parser::~Parser() 00026 { 00027 } 00028 00029 Parser::operator bool() const 00030 { 00031 return m_pScanner.get() && !m_pScanner->empty(); 00032 } 00033 00034 void Parser::Load(std::istream& in) 00035 { 00036 m_pScanner.reset(new Scanner(in)); 00037 m_pDirectives.reset(new Directives); 00038 } 00039 00040 // HandleNextDocument 00041 // . Handles the next document 00042 // . Throws a ParserException on error. 00043 // . Returns false if there are no more documents 00044 bool Parser::HandleNextDocument(EventHandler& eventHandler) 00045 { 00046 if(!m_pScanner.get()) 00047 return false; 00048 00049 ParseDirectives(); 00050 if(m_pScanner->empty()) 00051 return false; 00052 00053 SingleDocParser sdp(*m_pScanner, *m_pDirectives); 00054 sdp.HandleDocument(eventHandler); 00055 return true; 00056 } 00057 00058 // GetNextDocument 00059 // . Reads the next document in the queue (of tokens). 00060 // . Throws a ParserException on error. 00061 bool Parser::GetNextDocument(Node& document) 00062 { 00063 NodeBuilder builder(document); 00064 return HandleNextDocument(builder); 00065 } 00066 00067 // ParseDirectives 00068 // . Reads any directives that are next in the queue. 00069 void Parser::ParseDirectives() 00070 { 00071 bool readDirective = false; 00072 00073 while(1) { 00074 if(m_pScanner->empty()) 00075 break; 00076 00077 Token& token = m_pScanner->peek(); 00078 if(token.type != Token::DIRECTIVE) 00079 break; 00080 00081 // we keep the directives from the last document if none are specified; 00082 // but if any directives are specific, then we reset them 00083 if(!readDirective) 00084 m_pDirectives.reset(new Directives); 00085 00086 readDirective = true; 00087 HandleDirective(token); 00088 m_pScanner->pop(); 00089 } 00090 } 00091 00092 void Parser::HandleDirective(const Token& token) 00093 { 00094 if(token.value == "YAML") 00095 HandleYamlDirective(token); 00096 else if(token.value == "TAG") 00097 HandleTagDirective(token); 00098 } 00099 00100 // HandleYamlDirective 00101 // . Should be of the form 'major.minor' (like a version number) 00102 void Parser::HandleYamlDirective(const Token& token) 00103 { 00104 if(token.params.size() != 1) 00105 throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); 00106 00107 if(!m_pDirectives->version.isDefault) 00108 throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); 00109 00110 std::stringstream str(token.params[0]); 00111 str >> m_pDirectives->version.major; 00112 str.get(); 00113 str >> m_pDirectives->version.minor; 00114 if(!str || str.peek() != EOF) 00115 throw ParserException(token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]); 00116 00117 if(m_pDirectives->version.major > 1) 00118 throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); 00119 00120 m_pDirectives->version.isDefault = false; 00121 // TODO: warning on major == 1, minor > 2? 00122 } 00123 00124 // HandleTagDirective 00125 // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. 00126 void Parser::HandleTagDirective(const Token& token) 00127 { 00128 if(token.params.size() != 2) 00129 throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS); 00130 00131 const std::string& handle = token.params[0]; 00132 const std::string& prefix = token.params[1]; 00133 if(m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) 00134 throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); 00135 00136 m_pDirectives->tags[handle] = prefix; 00137 } 00138 00139 void Parser::PrintTokens(std::ostream& out) 00140 { 00141 if(!m_pScanner.get()) 00142 return; 00143 00144 while(1) { 00145 if(m_pScanner->empty()) 00146 break; 00147 00148 out << m_pScanner->peek() << "\n"; 00149 m_pScanner->pop(); 00150 } 00151 } 00152 }