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
|
#include "bnf.h"
#include "cpp.h"
#include "lexer.h"
#include "grammer.h"
#include "minicc.h"
#include <boost/algorithm/string.hpp>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <algorithm>
#include <cctype>
#include <deque>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
class Test: public ::testing::Test {
protected:
Test(){}
~Test() override {}
};
TEST_F(Test, BNF) {
std::string LexTop{"preprocessing-token"};
BNF LexBNF{
{"preprocessing-token", {{"identifier"},
{"preprocessing-op-or-punc"},
{"pp-number"}}},
{"identifier", {{"identifier-nondigit"},
{"identifier", "identifier-nondigit"},
{"identifier", "digit"}}},
{"digit", {{"0"}, {"1"}, {"2"}, {"3"}, {"4"}, {"5"}, {"6"}, {"7"}, {"8"}, {"9"} }},
{"identifier-nondigit",
{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}, {"f"}, {"g"}, {"h"}, {"i"}, {"j"}, {"k"}, {"l"}, {"m"},
{"n"}, {"o"}, {"p"}, {"q"}, {"r"}, {"s"}, {"t"}, {"u"}, {"v"}, {"w"}, {"x"}, {"y"}, {"z"},
{"A"}, {"B"}, {"C"}, {"D"}, {"E"}, {"F"}, {"G"}, {"H"}, {"I"}, {"J"}, {"K"}, {"L"}, {"M"},
{"N"}, {"O"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"T"}, {"U"}, {"V"}, {"W"}, {"X"}, {"Y"}, {"Z"}, {"_"}}},
{"preprocessing-op-or-punc", {{";"},
{"="}}},
{"pp-number", {{"digit"},
{"pp-number", "digit"}}}
};
std::string Top{"program"};
BNF bnf{
{"program", {{"statement-list"}}},
{"statement-list", {
{"statement"},
{"statement-list", "statement"},
}},
{"statement", {{"assignment", ";"}}},
{"assignment", {{"identifier", "=", "identifier"},
{"identifier", "=", "pp-number"}}}
};
// implicit?
//std::set<std::string> Terminals{"identifier", "=", ";"};
std::string Code{"a = bc ; c = 123 ; esd = Ff ; 1 = XYZ ; "};
std::vector<Token> tokens_reference{
{"identifier", "a", { 1, 1} },
{"preprocessing-op-or-punc", "=", { 1, 3}},
{"identifier", "bc", { 1, 5}},
{"preprocessing-op-or-punc", ";", { 1, 8}},
{"identifier", "c", { 1, 10}},
{"preprocessing-op-or-punc", "=", { 1, 12}},
{"pp-number", "123", { 1, 14}},
{"preprocessing-op-or-punc", ";", { 1, 18}},
{"identifier", "esd", { 1, 20}},
{"preprocessing-op-or-punc", "=", { 1, 24}},
{"identifier", "Ff", { 1, 26}},
{"preprocessing-op-or-punc", ";", { 1, 29}},
{"pp-number", "1", { 1, 31}},
{"preprocessing-op-or-punc", "=", { 1, 33}},
{"identifier", "XYZ", { 1, 35}},
{"preprocessing-op-or-punc", ";", { 1, 39}},
};
Lex::Lexer lexer(LexBNF, LexTop);
auto tokens = lexer.Lex(Code);
ASSERT_EQ(tokens, tokens_reference);
#if 1
std::cout << "=== Tokens =================================" << std::endl;
for (const auto& i: tokens) {
std::cout << i.type << ": " << i.value << std::endl;
}
#endif
CPP::PreprocessorTokensToTokens(tokens);
Gram::Compiler compiler(bnf, Top);
auto Tree = compiler.compile(tokens);
compiler.DumpTree();
//----------------------------------------------------------------
std::string Code2{"a = bc ; c = 123 ; esd = Ff ; 1 = XYZ "};
std::vector<Token> tokens_reference2{
{"identifier", "a", { 1, 1} },
{"preprocessing-op-or-punc", "=", { 1, 3}},
{"identifier", "bc", { 1, 5}},
{"preprocessing-op-or-punc", ";", { 1, 8}},
{"identifier", "c", { 1, 10}},
{"preprocessing-op-or-punc", "=", { 1, 12}},
{"pp-number", "123", { 1, 14}},
{"preprocessing-op-or-punc", ";", { 1, 18}},
{"identifier", "esd", { 1, 20}},
{"preprocessing-op-or-punc", "=", { 1, 24}},
{"identifier", "Ff", { 1, 26}},
{"preprocessing-op-or-punc", ";", { 1, 29}},
{"pp-number", "1", { 1, 31}},
{"preprocessing-op-or-punc", "=", { 1, 33}},
{"identifier", "XYZ", { 1, 35}},
//{"preprocessing-op-or-punc", ";", { 1, 39}},
};
tokens = lexer.Lex(Code2);
ASSERT_EQ(tokens, tokens_reference2);
CPP::PreprocessorTokensToTokens(tokens);
try {
Tree = compiler.compile(tokens);
FAIL() << "compile() was expected to throw."s;
} catch (const std::runtime_error& ex) {
ASSERT_EQ(std::string{ex.what()}, "Compile error: Invalid program.");
}
}
int main(int argc, char* argv[]) {
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
|