-
Notifications
You must be signed in to change notification settings - Fork 1
/
parser.cpp
121 lines (110 loc) · 2.77 KB
/
parser.cpp
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
/* `parser.cpp`
* By: Ivan Rubinson (c) 2016
* Licensed under the Lesser GNU Public License v3.
*/
#include "clauparse.h"
#include "Clauparse/tokenizer.h"
#include <fstream>
#include <string>
#include <stdexcept>
namespace ClauParse
{
/* `makeNode`
* tokens[i].type must be Tokens::LABEL
*
* TODO:
* Make more checks to improve `ParsingException` messages.
*/
Data::Node makeNode(std::vector<Token> tokens, unsigned int i, Data::Node* parent)
{
Data::Node node;
if (i < tokens.size() && tokens.size() != 0)
{
node.parent = parent;
if (tokens[i].type == Token::LABEL)
{
node.name = tokens[i].value;
}
else
{
throw(ParsingException("Expected LABEL"));
}
if (i + 2 < tokens.size()) // enough space for an EQUALS + LABEL/BLOCK
{
if (tokens[i + 1].type == Token::EQUALS)
{
unsigned int blocks;
switch (tokens[i + 2].type) // What should `node` equal to?
{
case(Token::LABEL) :
node.children.push_back(Data::Node(&node, tokens[i + 2].value));
break;
case(Token::BLOCK_OPEN) :
blocks = 1;
for (unsigned int j = i + 3; j < tokens.size() && blocks > 0; ++j)
// j is set to right after BLOCK_OPEN,
// runs until matching BLOCK_CLOSE, or there are no more tokens.
{
if (blocks == 1 && tokens[j].type == Token::LABEL && tokens[j-1].type != Token::EQUALS)
// If tokens[j] is `node`s child, and isn't after an EQUALS.
{
node.children.push_back(makeNode(tokens, j, &node));
}
else
// If tokens[j] isn't `node`'s child.
{
if (tokens[j].type == Token::BLOCK_OPEN)
{
++blocks;
}
else if (tokens[j].type == Token::BLOCK_CLOSE)
{
--blocks;
}
}
}
if (blocks > 0)
{
throw(ParsingException("A block was opened but not closed"));
}
break;
default:
throw(ParsingException("LABEL EQUALS something unexpected"));
break;
}
}
else
{
node.children.push_back(Data::Node(&node, L""));
}
}
}
return node;
}
Data::Node makeNode(std::vector<Token> tokens)
{
return makeNode(tokens, 0, nullptr);
}
Data parseFile(const char* path)
{
std::wifstream fin(path);
if (fin.is_open() && fin.good()) // TODO: More checks on fin?
{
std::vector<Token> tokens;
tokens.reserve(1024);
// Read file line by line, tokenize each line, and concate all in `tokens`.
std::wstring str;
while (std::getline(fin, str))
{
auto line_tokens = tokenizeLine(str);
tokens.insert(std::end(tokens), std::begin(line_tokens), std::end(line_tokens));
}
return Data(makeNode(tokens));
}
else
{
throw(std::runtime_error(std::string("Can't read from file: ") + path));
}
return Data();
}
}