#include "bnf.h" #include "cpp.h" #include "lexer.h" #include "grammer.h" #include "minicc.h" #include "debug.h" #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include #include #include #include #include #include #include #include class Test: public ::testing::Test { protected: Test(){ debug = false; } ~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 Terminals{"identifier", "=", ";"}; std::string Code{"a = bc ; c = 123 ; esd = Ff ; "};//1 = XYZ ; "}; std::vector 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}}, #if 0 {"pp-number", "1", { 1, 31}}, {"preprocessing-op-or-punc", "=", { 1, 33}}, {"identifier", "XYZ", { 1, 35}}, {"preprocessing-op-or-punc", ";", { 1, 39}}, #endif }; Lex::Lexer lexer(LexBNF, LexTop); auto tokens = lexer.Lex(Code); ASSERT_EQ(tokens, tokens_reference); #if 0 // TODO: use Debug() interface 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 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(); }