C++ Boost Spirit x3--使用其他解析器参数化解析器
我没有太多的代码要显示,因为我还没有找到任何可以工作的东西,但高层次的问题是,我正在尝试为一系列相关语言创建一系列解析器。我的意思是,这两种语言将共享许多相同的结构,但不会完全重叠。作为一个简单的例子,假设我有一个AST,它由一些(在本例中完全是人为设计的)“叶”类型参数化:C++ Boost Spirit x3--使用其他解析器参数化解析器,c++,parsing,boost,boost-spirit-x3,C++,Parsing,Boost,Boost Spirit X3,我没有太多的代码要显示,因为我还没有找到任何可以工作的东西,但高层次的问题是,我正在尝试为一系列相关语言创建一系列解析器。我的意思是,这两种语言将共享许多相同的结构,但不会完全重叠。作为一个简单的例子,假设我有一个AST,它由一些(在本例中完全是人为设计的)“叶”类型参数化: template <typename t> struct fooT { std::string name; t leaf; }; 模板 结构脚{ std::字符串名; t叶; }; 一种语言可以将t
template <typename t>
struct fooT {
std::string name;
t leaf;
};
模板
结构脚{
std::字符串名;
t叶;
};
一种语言可以将t
实例化为int
,另一种语言可以实例化为double
。我想做的是创建一个模板类或一些我可以用不同的t
和相应的解析器规则实例化的东西,以便生成一系列组合的解析器
在我的真实示例中,我有一组嵌套结构,这些结构在不同的语言中是相同的,但在AST的边缘只有几个小的变化,因此如果我不能以良好的方式组合解析器,我将复制一组解析规则,AST节点,实际上,我没有把它放在一个类中,只是非常仔细地安排了我的头文件和导入,这样我就可以用特殊的名称来组装“悬空”解析器规则。这样做的一个大缺点是,我不能在同一个程序中包含多个不同语言的解析器——正是因为名称冲突
有人知道我如何处理这个问题吗?X3的好处是,您可以像最初定义解析器一样轻松地生成解析器 例如 先进的
对于高级场景(在这些场景中,规则声明和定义在不同的分析单元之间分离,并且/或者需要动态切换),您可以使用
x3::any_rule
holder。我确实将其在不同的翻译单元之间分离,因此我将研究任何_规则。这正是我需要的。我试图融入一个班级,但一切都很糟糕。非常感谢。再次感谢您的回答!我确实设法让我的解析器重构以使用这种风格。不幸的是,编译时间已经过了极限!现在编译解析器大约需要5分钟和10GB内存。这里有人知道有没有好办法解决这个问题吗?我的特定语言有一个很大的递归变体,其中几个组件使用上述模板功能。是的。通常的修复方法是重新引入BOOST_SPIRIT_DEFINE用法。如果没有,上下文类型似乎会被整个解析器表达式所阻塞。这可能会导致不同上下文类型的实例化激增,尤其是递归和/或跳过器更改。如果您以某种方式显示代码,或许我可以尝试将其作为~exocrism~练习。总有一天我要学会穿那根针。我可以试着给你编码。我不确定技术上是否允许我发布它,而且它也被分割成大量文件。我确实在其他帖子中看到了你的一些评论,并尽可能添加了BOOST_SPIRIT_DEFINE调用,但没有太大区别。问题是,对于所有的模板解析器,我不知道如何用BOOST\u-SPIRIT\u-define定义它们。我必须承认我不是一个非常先进的C++开发人员。
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}