Boost Spirit x3 -- 使用其他解析器参数化解析器



我没有很多代码可以显示,因为我还没有设法让任何东西工作,但高级问题是我正在尝试为一系列相关语言创建一系列解析器。 我的意思是,这些语言将共享许多相同的结构,但不会完全重叠。 举个简单的例子,假设我有一个 AST,它由一些(在本例中完全人为)"叶"类型参数化:

template <typename t>
struct fooT {
std::string name;
t leaf;
};

一种语言可能t实例化为int,另一种语言实例化为double。 我想做的是创建一个模板化类或我可以使用不同的t和相应的解析器规则实例化的东西,以便我可以生成一系列组合解析器。

在我的真实示例中,我有一堆嵌套结构,它们在语言中是相同的,但在 AST 的最边缘只有几个小的变化,所以如果我不能以一种好的方式编写解析器,我最终会复制一堆解析规则、AST 节点、 等。 我实际上已经通过将其放在类中而非常仔细地排列我的头文件和导入来使其工作,以便我可以拥有具有可以组装的特殊名称的"悬空"解析器规则。 这样做的一大缺点是我不能在同一程序中包含多种不同语言的解析器——正是因为出现了名称冲突。

有人对我如何处理这个问题有任何想法吗?

X3 的好处是,您可以像最初定义解析器一样轻松地生成解析器。

例如

template <typename T> struct AstNode {
std::string name;
T leaf;
};

现在让我们定义一个通用解析器制作器:

namespace Generic {
template <typename T> auto leaf = x3::eps(false);
template <> auto leaf<int>
= "0x" >> x3::int_parser<uintmax_t, 16>{};
template <> auto leaf<std::string>
= x3::lexeme['"' >> *~x3::char_('"') >> '"'];
auto no_comment = x3::space;
auto hash_comments = x3::space |
x3::lexeme['#' >> *(x3::char_ - x3::eol)] >> (x3::eol | x3::eoi);
auto c_style_comments = x3::space |
"/*" >> x3::lexeme[*(x3::char_ - "*/")] >> "*/";
auto cxx_style_comments = c_style_comments |
x3::lexeme["//" >> *(x3::char_ - x3::eol)] >> (x3::eol | x3::eoi);
auto name = leaf<std::string>;
template <typename T> auto parseNode(auto heading, auto skipper) {
return x3::skip(skipper)[
x3::as_parser(heading) >> name >> ":" >> leaf<T>
];
}
}

这使我们能够使用各种叶子类型和船长样式编写各种语法:

namespace Language1 {
static auto const grammar =
Generic::parseNode<int>("value", Generic::no_comment);
}
namespace Language2 {
static auto const grammar =
Generic::parseNode<std::string>("line", Generic::cxx_style_comments);
}

让我们演示一下:

住在科里鲁

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
#include <iomanip>
namespace x3 = boost::spirit::x3;
template <typename T> struct AstNode {
std::string name;
T leaf;
};
BOOST_FUSION_ADAPT_TPL_STRUCT((T), (AstNode)(T), name, leaf)
namespace Generic {
template <typename T> auto leaf = x3::eps(false);
template <> auto leaf<int>
= "0x" >> x3::uint_parser<uintmax_t, 16>{};
template <> auto leaf<std::string>
= x3::lexeme['"' >> *~x3::char_('"') >> '"'];
auto no_comment = x3::space;
auto hash_comments = x3::space |
x3::lexeme['#' >> *(x3::char_ - x3::eol)] >> (x3::eol | x3::eoi);
auto c_style_comments = x3::space |
"/*" >> x3::lexeme[*(x3::char_ - "*/")] >> "*/";
auto cxx_style_comments = c_style_comments |
x3::lexeme["//" >> *(x3::char_ - x3::eol)] >> (x3::eol | x3::eoi);
auto name = leaf<std::string>;
template <typename T> auto parseNode(auto heading, auto skipper) {
return x3::skip(skipper)[
x3::as_parser(heading) >> name >> ":" >> leaf<T>
];
}
}
namespace Language1 {
static auto const grammar =
Generic::parseNode<int>("value", Generic::no_comment);
}
namespace Language2 {
static auto const grammar =
Generic::parseNode<std::string>("line", Generic::cxx_style_comments);
}
void test(auto const& grammar, std::string_view text, auto ast) {
auto f = text.begin(), l = text.end();
std::cout << "nParsing: " << std::quoted(text, ''') << "n";
if (parse(f, l, grammar, ast)) {
std::cout << " -> {name:" << ast.name << ",value:" << ast.leaf << "}n";
} else {
std::cout << " -- Failed " << std::quoted(text, ''') << "n";
}
}
int main() {
test(Language1::grammar, R"(value "one": 0x01)", AstNode<int>{});
test(
Language2::grammar,
R"(line "Hamlet": "There is nothing either good or bad, but thinking makes it so.")",
AstNode<std::string>{});
test(
Language2::grammar,
R"(line // rejected: "Hamlet": "To be ..."
"King Lear": /*hopefully less trite:*/"As flies to wanton boys are we to the gods")",
AstNode<std::string>{});
}

指纹

Parsing: 'value "one": 0x01'
-> {name:one,value:1}
Parsing: 'line "Hamlet": "There is nothing either good or bad, but thinking makes it so."'
-> {name:Hamlet,value:There is nothing either good or bad, but thinking makes it so.}
Parsing: 'line // rejected: "Hamlet": "To be ..."
"King Lear": /*hopefully less trite:*/"As flies to wanton boys are we to the gods"'
-> {name:King Lear,value:As flies to wanton boys are we to the gods}

高深

对于高级方案(跨 trnalation 单元分离规则声明和定义和/或需要动态切换),可以使用x3::any_rule<>持有者。

最新更新