parser.cpp 2.78 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "parser.h"
#include "node.h"

namespace YAML
{
	Parser::Parser(std::istream& in): INPUT(in), m_ok(true)
	{
		m_state.push(State(C_BLOCK, -1, true));

		// read header
		std::string token = ReadNextToken();
		if(token != DocStart)
			m_ok = false;
	}

	Parser::~Parser()
	{
	}

	Parser::operator bool() const
	{
		return m_ok;
	}

	bool Parser::operator !() const
	{
		return !m_ok;
	}

	bool Parser::IsWhitespace(char ch)
	{
		return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
	}

	void Parser::Putback(const std::string& str)
	{
		for(int i=str.size()-1;i>=0;i--)
			INPUT.putback(str[i]);
	}

	// StringWhitespace
	// . Strips up to n whitespace characters (or as many
	//   as there are, if n is -1)
	void Parser::StripWhitespace(int n)
	{
		while(--n >= 0 && IsWhitespace(INPUT.peek()))
			INPUT.get();
	}

	int Parser::GetNumOfSpaces()
	{
		// get 'em out
		int n = 0;
		while(INPUT.peek() == ' ') {
			INPUT.get();
			n++;
		}

		// put 'em back
		for(int i=0;i<n;i++)
			INPUT.putback(' ');

		return n;
	}

	// SeqContinues
	// . Returns true if the next item to be read is a continuation of the current sequence.
	bool Parser::SeqContinues()
	{
		const State& state = m_state.top();
		if(state.context != C_BLOCK)
			return false;

		int n = GetNumOfSpaces();
		return (n == state.indent);
	}

	// ReadNextNode
	// . Reads and returns the next node from the current input (to be used recursively).
	// . The caller is responsible for cleanup!
	Node *Parser::ReadNextNode()
	{
		if(!INPUT)
			return 0;

		std::string token = ReadNextToken();
		if(token == DocStart || token == DocEnd)
			return 0;	// TODO: putback DocStart?

		Node *pNode = new Node;
		pNode->Read(this, token);
		return pNode;
	}

	// ReadNextToken
	// . Reads:
	//   . If the first character is non-whitespace, non-special token, then until
	//     the end of this scalar.
	std::string Parser::ReadNextToken()
	{
		const State& state = m_state.top();

		if(state.startingNewLine) {
			int n = GetNumOfSpaces();
			StripWhitespace(n);
			if(n > state.indent) {
				m_state.push(State(C_BLOCK, n, true));
			};

			while(m_state.top().startingNewLine && n < m_state.top().indent)
				m_state.pop();
		}

		char ch = INPUT.peek();
		if(IsWhitespace(ch))
			return "";	// TODO

		if(ch == SeqToken) {
			// grab token
			INPUT.get();

			// is next token whitespace?
			if(!IsWhitespace(INPUT.peek())) {
				// read entire line
				std::string line;
				std::getline(INPUT, line);
				return ch + line;
			}

			// if so, strip whitespace and go
			StripWhitespace();

			return std::string("") + SeqToken;
		}

		// read until end-of-line
		std::string line;
		std::getline(INPUT, line);
		return line;
	}
}