parser.cpp 3.88 KB
Newer Older
1
#include "parser.h"
2
3
4
5
6
7
#include "directives.h"
#include "eventhandler.h"
#include "exceptions.h"
#include "graphbuilderadapter.h"
#include "node.h"
#include "nodebuilder.h"
8
#include "scanner.h"
9
10
#include "singledocparser.h"
#include "tag.h"
11
12
#include "token.h"
#include <sstream>
13
#include <cstdio>
14
15
16

namespace YAML
{
17
18
19
20
21
	Parser::Parser()
	{
	}
	
	Parser::Parser(std::istream& in)
22
23
24
25
26
27
28
29
30
31
	{
		Load(in);
	}

	Parser::~Parser()
	{
	}

	Parser::operator bool() const
	{
32
		return m_pScanner.get() && !m_pScanner->empty();
33
34
35
36
	}

	void Parser::Load(std::istream& in)
	{
37
		m_pScanner.reset(new Scanner(in));
38
		m_pDirectives.reset(new Directives);
39
40
	}

41
42
	// HandleNextDocument
	// . Handles the next document
43
	// . Throws a ParserException on error.
44
45
	// . Returns false if there are no more documents
	bool Parser::HandleNextDocument(EventHandler& eventHandler)
46
	{
jbeder's avatar
jbeder committed
47
48
		if(!m_pScanner.get())
			return false;
49
50
51

		ParseDirectives();
		if(m_pScanner->empty())
52
53
			return false;
		
54
55
		SingleDocParser sdp(*m_pScanner, *m_pDirectives);
		sdp.HandleDocument(eventHandler);
56
		return true;
57
	}
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
	
	// BuildNextDocumentGraph
	// . Builds a graph of the next document
	// . Returns NULL if there are no more documents
	void *Parser::BuildNextDocumentGraph(GraphBuilderInterface& graphBuilder)
	{
		GraphBuilderAdapter eventHandler(graphBuilder);
		if (HandleNextDocument(eventHandler)) {
			return eventHandler.RootNode();
		} else {
			return NULL;
		}
	}

	// GetNextDocument
	// . Reads the next document in the queue (of tokens).
	// . Throws a ParserException on error.
	bool Parser::GetNextDocument(Node& document)
	{
		NodeBuilder builder(document);
78
		return BuildNextDocumentGraph(builder);
79
	}
80
81
82
83
84
85
86
87
88
89
90
91

	// ParseDirectives
	// . Reads any directives that are next in the queue.
	void Parser::ParseDirectives()
	{
		bool readDirective = false;

		while(1) {
			if(m_pScanner->empty())
				break;

			Token& token = m_pScanner->peek();
jbeder's avatar
jbeder committed
92
			if(token.type != Token::DIRECTIVE)
93
94
95
96
97
				break;

			// we keep the directives from the last document if none are specified;
			// but if any directives are specific, then we reset them
			if(!readDirective)
98
				m_pDirectives.reset(new Directives);
99
100

			readDirective = true;
101
			HandleDirective(token);
102
103
104
105
			m_pScanner->pop();
		}
	}

106
	void Parser::HandleDirective(const Token& token)
107
	{
108
109
110
111
		if(token.value == "YAML")
			HandleYamlDirective(token);
		else if(token.value == "TAG")
			HandleTagDirective(token);
112
113
114
115
	}

	// HandleYamlDirective
	// . Should be of the form 'major.minor' (like a version number)
116
	void Parser::HandleYamlDirective(const Token& token)
117
	{
118
119
120
		if(token.params.size() != 1)
			throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
		
121
		if(!m_pDirectives->version.isDefault)
122
			throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
123

124
		std::stringstream str(token.params[0]);
125
		str >> m_pDirectives->version.major;
126
		str.get();
127
		str >> m_pDirectives->version.minor;
128
		if(!str || str.peek() != EOF)
129
			throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]);
130

131
		if(m_pDirectives->version.major > 1)
132
			throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
133

134
		m_pDirectives->version.isDefault = false;
135
136
137
138
139
		// TODO: warning on major == 1, minor > 2?
	}

	// HandleTagDirective
	// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
140
	void Parser::HandleTagDirective(const Token& token)
141
	{
142
143
		if(token.params.size() != 2)
			throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS);
144

145
146
		const std::string& handle = token.params[0];
		const std::string& prefix = token.params[1];
147
		if(m_pDirectives->tags.find(handle) != m_pDirectives->tags.end())
148
149
			throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
		
150
		m_pDirectives->tags[handle] = prefix;
151
152
153
154
	}

	void Parser::PrintTokens(std::ostream& out)
	{
jbeder's avatar
jbeder committed
155
156
157
		if(!m_pScanner.get())
			return;
		
158
159
160
161
162
163
164
165
166
		while(1) {
			if(m_pScanner->empty())
				break;

			out << m_pScanner->peek() << "\n";
			m_pScanner->pop();
		}
	}
}