Allow literal operators in infix expression

This commit is contained in:
yhirose 2021-03-04 19:31:31 -05:00
parent a248d8689e
commit e26a9e88f5
2 changed files with 76 additions and 8 deletions

View File

@ -560,7 +560,7 @@ private:
/* /*
* Semantic action * Semantic action
*/ */
template <typename F, typename... Args> std::any call(F fn, Args &&... args) { template <typename F, typename... Args> std::any call(F fn, Args &&...args) {
using R = decltype(fn(std::forward<Args>(args)...)); using R = decltype(fn(std::forward<Args>(args)...));
if constexpr (std::is_void<R>::value) { if constexpr (std::is_void<R>::value) {
fn(std::forward<Args>(args)...); fn(std::forward<Args>(args)...);
@ -976,7 +976,7 @@ public:
class Sequence : public Ope { class Sequence : public Ope {
public: public:
template <typename... Args> template <typename... Args>
Sequence(const Args &... args) Sequence(const Args &...args)
: opes_{static_cast<std::shared_ptr<Ope>>(args)...} {} : opes_{static_cast<std::shared_ptr<Ope>>(args)...} {}
Sequence(const std::vector<std::shared_ptr<Ope>> &opes) : opes_(opes) {} Sequence(const std::vector<std::shared_ptr<Ope>> &opes) : opes_(opes) {}
Sequence(std::vector<std::shared_ptr<Ope>> &&opes) : opes_(opes) {} Sequence(std::vector<std::shared_ptr<Ope>> &&opes) : opes_(opes) {}
@ -1019,7 +1019,7 @@ public:
class PrioritizedChoice : public Ope { class PrioritizedChoice : public Ope {
public: public:
template <typename... Args> template <typename... Args>
PrioritizedChoice(bool for_label, const Args &... args) PrioritizedChoice(bool for_label, const Args &...args)
: opes_{static_cast<std::shared_ptr<Ope>>(args)...}, : opes_{static_cast<std::shared_ptr<Ope>>(args)...},
for_label_(for_label) {} for_label_(for_label) {}
PrioritizedChoice(const std::vector<std::shared_ptr<Ope>> &opes) PrioritizedChoice(const std::vector<std::shared_ptr<Ope>> &opes)
@ -1577,16 +1577,16 @@ public:
/* /*
* Factories * Factories
*/ */
template <typename... Args> std::shared_ptr<Ope> seq(Args &&... args) { template <typename... Args> std::shared_ptr<Ope> seq(Args &&...args) {
return std::make_shared<Sequence>(static_cast<std::shared_ptr<Ope>>(args)...); return std::make_shared<Sequence>(static_cast<std::shared_ptr<Ope>>(args)...);
} }
template <typename... Args> std::shared_ptr<Ope> cho(Args &&... args) { template <typename... Args> std::shared_ptr<Ope> cho(Args &&...args) {
return std::make_shared<PrioritizedChoice>( return std::make_shared<PrioritizedChoice>(
false, static_cast<std::shared_ptr<Ope>>(args)...); false, static_cast<std::shared_ptr<Ope>>(args)...);
} }
template <typename... Args> std::shared_ptr<Ope> cho4label_(Args &&... args) { template <typename... Args> std::shared_ptr<Ope> cho4label_(Args &&...args) {
return std::make_shared<PrioritizedChoice>( return std::make_shared<PrioritizedChoice>(
true, static_cast<std::shared_ptr<Ope>>(args)...); true, static_cast<std::shared_ptr<Ope>>(args)...);
} }
@ -3184,8 +3184,14 @@ private:
seq(g["PrecedenceAssoc"], seq(g["PrecedenceAssoc"],
oom(seq(ign(g["SpacesOom"]), g["PrecedenceOpe"]))); oom(seq(ign(g["SpacesOom"]), g["PrecedenceOpe"])));
g["PrecedenceOpe"] <= g["PrecedenceOpe"] <=
tok(oom( cho(seq(cls("'"),
seq(npd(cho(g["PrecedenceAssoc"], g["Space"], chr('}'))), dot()))); 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"); g["PrecedenceAssoc"] <= cls("LR");
// Error message instruction // Error message instruction

View File

@ -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<long>(vs[0]);
if (vs.size() > 1) {
auto ope = std::any_cast<std::string>(vs[1]);
auto num = std::any_cast<long>(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<long>(); };
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]") { TEST_CASE("Precedence climbing with macro", "[precedence]") {
// Create a PEG parser // Create a PEG parser
parser parser(R"( parser parser(R"(