parser.cpp 3.12 KB
Newer Older
1
#include "crt.h"
2
#include "parser.h"
3
#include "scanner.h"
4
#include "token.h"
Jesse Beder's avatar
Jesse Beder committed
5
#include "exceptions.h"
6
#include <sstream>
7
8
9

namespace YAML
{
10
	Parser::Parser(std::istream& in): m_pScanner(0)
11
	{
12
		Load(in);
13
14
15
16
	}

	Parser::~Parser()
	{
17
		delete m_pScanner;
18
19
	}

20
21
	Parser::operator bool() const
	{
22
		return !m_pScanner->empty();
23
24
	}

25
26
27
28
29
30
31
	void Parser::Load(std::istream& in)
	{
		delete m_pScanner;
		m_pScanner = new Scanner(in);
		m_state.Reset();
	}

32
33
	// GetNextDocument
	// . Reads the next document in the queue (of tokens).
Jesse Beder's avatar
Jesse Beder committed
34
	// . Throws a ParserException on error.
35
	void Parser::GetNextDocument(Node& document)
36
	{
37
38
39
		// clear node
		document.Clear();

40
41
42
		// first read directives
		ParseDirectives();

43
		// we better have some tokens in the queue
44
		if(m_pScanner->empty())
45
46
47
			return;

		// first eat doc start (optional)
48
49
		if(m_pScanner->peek().type == TT_DOC_START)
			m_pScanner->pop();
50
51

		// now parse our root node
52
		document.Parse(m_pScanner, m_state);
53
54

		// and finally eat any doc ends we see
55
56
		while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
			m_pScanner->pop();
57
58
	}

59
60
	// ParseDirectives
	// . Reads any directives that are next in the queue.
61
62
63
64
65
	void Parser::ParseDirectives()
	{
		bool readDirective = false;

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

69
			Token& token = m_pScanner->peek();
70
			if(token.type != TT_DIRECTIVE)
71
72
73
74
75
76
77
78
				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)
				m_state.Reset();

			readDirective = true;
79
			HandleDirective(&token);
80
			m_pScanner->pop();
81
82
83
		}
	}

84
	void Parser::HandleDirective(Token *pToken)
85
	{
86
87
88
89
		if(pToken->value == "YAML")
			HandleYamlDirective(pToken);
		else if(pToken->value == "TAG")
			HandleTagDirective(pToken);
90
91
92
93
	}

	// HandleYamlDirective
	// . Should be of the form 'major.minor' (like a version number)
94
	void Parser::HandleYamlDirective(Token *pToken)
95
	{
96
		if(pToken->params.size() != 1)
97
			throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS);
98

99
		std::stringstream str(pToken->params[0]);
100
101
102
		str >> m_state.version.major;
		str.get();
		str >> m_state.version.minor;
103
		if(!str || str.peek() != EOF)
104
			throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]);
105

106
		if(m_state.version.major > 1)
107
			throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION);
108
109

		// TODO: warning on major == 1, minor > 2?
110
111
	}

112
113
	// HandleTagDirective
	// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
114
	void Parser::HandleTagDirective(Token *pToken)
115
	{
116
		if(pToken->params.size() != 2)
117
			throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS);
118

119
		std::string handle = pToken->params[0], prefix = pToken->params[1];
120
		m_state.tags[handle] = prefix;
121
	}
122

123
	void Parser::PrintTokens(std::ostream& out)
124
125
	{
		while(1) {
126
			if(m_pScanner->empty())
127
128
				break;

129
130
			out << m_pScanner->peek() << std::endl;
			m_pScanner->pop();
131
132
		}
	}
133
}