diff --git a/peglib.h b/peglib.h index a9cc9e9..712b812 100644 --- a/peglib.h +++ b/peglib.h @@ -560,7 +560,7 @@ private: /* * Semantic action */ -template std::any call(F fn, Args &&... args) { +template std::any call(F fn, Args &&...args) { using R = decltype(fn(std::forward(args)...)); if constexpr (std::is_void::value) { fn(std::forward(args)...); @@ -976,7 +976,7 @@ public: class Sequence : public Ope { public: template - Sequence(const Args &... args) + Sequence(const Args &...args) : opes_{static_cast>(args)...} {} Sequence(const std::vector> &opes) : opes_(opes) {} Sequence(std::vector> &&opes) : opes_(opes) {} @@ -1019,7 +1019,7 @@ public: class PrioritizedChoice : public Ope { public: template - PrioritizedChoice(bool for_label, const Args &... args) + PrioritizedChoice(bool for_label, const Args &...args) : opes_{static_cast>(args)...}, for_label_(for_label) {} PrioritizedChoice(const std::vector> &opes) @@ -1577,16 +1577,16 @@ public: /* * Factories */ -template std::shared_ptr seq(Args &&... args) { +template std::shared_ptr seq(Args &&...args) { return std::make_shared(static_cast>(args)...); } -template std::shared_ptr cho(Args &&... args) { +template std::shared_ptr cho(Args &&...args) { return std::make_shared( false, static_cast>(args)...); } -template std::shared_ptr cho4label_(Args &&... args) { +template std::shared_ptr cho4label_(Args &&...args) { return std::make_shared( true, static_cast>(args)...); } @@ -3184,8 +3184,14 @@ private: seq(g["PrecedenceAssoc"], oom(seq(ign(g["SpacesOom"]), g["PrecedenceOpe"]))); g["PrecedenceOpe"] <= - tok(oom( - seq(npd(cho(g["PrecedenceAssoc"], g["Space"], chr('}'))), dot()))); + cho(seq(cls("'"), + tok(zom(seq(npd(cho(g["Space"], cls("'"))), g["Char"]))), + cls("'")), + seq(cls("\""), + tok(zom(seq(npd(cho(g["Space"], cls("\""))), g["Char"]))), + cls("\"")), + tok(oom(seq(npd(cho(g["PrecedenceAssoc"], g["Space"], chr('}'))), + dot())))); g["PrecedenceAssoc"] <= cls("LR"); // Error message instruction diff --git a/test/test2.cc b/test/test2.cc index 875f739..8d07ee9 100644 --- a/test/test2.cc +++ b/test/test2.cc @@ -300,6 +300,68 @@ TEST_CASE("Precedence climbing", "[precedence]") { } } +TEST_CASE("Precedence climbing with literal operator", "[precedence]") { + parser parser(R"( + START <- _ EXPRESSION + EXPRESSION <- ATOM (OPERATOR ATOM)* { + precedence + L '#plus#' - # weaker + L '#multiply#' / # stronger + } + ATOM <- NUMBER / T('(') EXPRESSION T(')') + OPERATOR <- T('#plus#' / '#multiply#' / [-/]) + NUMBER <- T('-'? [0-9]+) + ~_ <- [ \t]* + T(S) <- < S > _ + )"); + + REQUIRE(!!parser); // OK + + parser.enable_packrat_parsing(); + + // Setup actions + parser["EXPRESSION"] = [](const SemanticValues &vs) -> long { + auto result = std::any_cast(vs[0]); + if (vs.size() > 1) { + auto ope = std::any_cast(vs[1]); + auto num = std::any_cast(vs[2]); + if (ope == "#plus#") { + result += num; + } else if (ope == "-") { + result -= num; + } else if (ope == "#multiply#") { + result *= num; + } else if (ope == "/") { + result /= num; + } + } + return result; + }; + parser["OPERATOR"] = [](const SemanticValues &vs) { return vs.token_to_string(); }; + parser["NUMBER"] = [](const SemanticValues &vs) { return vs.token_to_number(); }; + + bool ret = parser; + REQUIRE(ret == true); + + { + auto expr = " 1 #plus# 2 #multiply# 3 #multiply# (4 - 5 #plus# 6) / 7 - 8 "; + long val = 0; + ret = parser.parse(expr, val); + + REQUIRE(ret == true); + REQUIRE(val == -3); + } + + { + auto expr = "-1#plus#-2--3"; // -1 + -2 - -3 = 0 + long val = 0; + ret = parser.parse(expr, val); + + REQUIRE(ret == true); + REQUIRE(val == 0); + } +} + TEST_CASE("Precedence climbing with macro", "[precedence]") { // Create a PEG parser parser parser(R"(