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

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

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

19
20
21
22
23
	Parser::operator bool() const
	{
		return m_pScanner->PeekNextToken() != 0;
	}

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

31
32
	// GetNextDocument
	// . Reads the next document in the queue (of tokens).
33
	// . Throws (ParserException|ParserException)s on errors.
34
	void Parser::GetNextDocument(Node& document)
35
	{
36
37
38
		// clear node
		document.Clear();

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

42
43
44
45
46
47
48
49
50
		// we better have some tokens in the queue
		if(!m_pScanner->PeekNextToken())
			return;

		// first eat doc start (optional)
		if(m_pScanner->PeekNextToken()->type == TT_DOC_START)
			m_pScanner->EatNextToken();

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

		// and finally eat any doc ends we see
		while(m_pScanner->PeekNextToken() && m_pScanner->PeekNextToken()->type == TT_DOC_END)
			m_pScanner->EatNextToken();
56
57
	}

58
59
	// ParseDirectives
	// . Reads any directives that are next in the queue.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
	void Parser::ParseDirectives()
	{
		bool readDirective = false;

		while(1) {
			Token *pToken = m_pScanner->PeekNextToken();
			if(!pToken || pToken->type != TT_DIRECTIVE)
				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;
75
			HandleDirective(pToken);
76
77
78
79
			m_pScanner->PopNextToken();
		}
	}

80
	void Parser::HandleDirective(Token *pToken)
81
	{
82
83
84
85
		if(pToken->value == "YAML")
			HandleYamlDirective(pToken);
		else if(pToken->value == "TAG")
			HandleTagDirective(pToken);
86
87
88
89
	}

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

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

102
		if(m_state.version.major > 1)
103
			throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION);
104
105

		// TODO: warning on major == 1, minor > 2?
106
107
	}

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

115
		std::string handle = pToken->params[0], prefix = pToken->params[1];
116
		m_state.tags[handle] = prefix;
117
	}
118

119
	void Parser::PrintTokens(std::ostream& out)
120
121
122
123
124
125
	{
		while(1) {
			Token *pToken = m_pScanner->GetNextToken();
			if(!pToken)
				break;

126
			out << *pToken << std::endl;
127
128
		}
	}
129
}