Boost.Spirit X3 编译时间因递归规则而爆炸
Boost.Spirit X3 compile time explodes with recursive rule
下面的程序需要10秒才能编译。当我更改下面的parenProcess
规则以'(' >> process >> ')'
编译器花费 CPU 但似乎没有完成时。(我尝试制作一个较小的可重现程序 - 通过删除process
和parenProcess
之间的规则,但随后编译时间不再爆炸)。
嵌入process
时如何修复编译(时间)?
(其他小问题:有没有更好的方法来制定规则"x"和"xActual"?
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace wccs_parser {
namespace x3 = boost::spirit::x3;
namespace ascii = x3::ascii;
using x3::long_;
using x3::ulong_;
using x3::lexeme;
//--- Ast structures
struct AstChannel {
std::string label;
bool complement;
};
struct AstAction {
AstChannel channel;
uint32_t weight;
};
struct AstRenaming {
std::string from;
std::string to;
};
struct AstNullProcess;
struct AstActionPrefixProcess;
struct AstChoiceProcess;
struct AstCompositionProcess;
struct AstRestrictionProcess;
struct AstRenamingProcess;
struct AstConstantProcess;
using AstAnyProcess = x3::variant<
x3::forward_ast<AstNullProcess>,
x3::forward_ast<AstActionPrefixProcess>,
x3::forward_ast<AstChoiceProcess>,
x3::forward_ast<AstCompositionProcess>,
x3::forward_ast<AstRestrictionProcess>,
x3::forward_ast<AstRenamingProcess>,
x3::forward_ast<AstConstantProcess>
>;
struct AstNullProcess {};
struct AstActionPrefixProcess {
AstAction action;
AstAnyProcess subProcess;
};
struct AstChoiceProcess {
std::vector<AstAnyProcess> subProcesses;
};
struct AstCompositionProcess {
std::vector<AstAnyProcess> subProcesses;
};
struct AstRestrictionProcess {
AstAnyProcess subProcess;
std::vector<std::string> labels;
};
struct AstRenamingProcess {
AstAnyProcess subProcess;
std::vector<AstRenaming> renamings;
};
struct AstConstantProcess {
std::string processName;
};
} // End namespace
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstChannel, label, complement)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstAction, channel, weight)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstRenaming, from, to)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstActionPrefixProcess, action, subProcess)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstChoiceProcess, subProcesses)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstCompositionProcess, subProcesses)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstRestrictionProcess, subProcess, labels)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstRenamingProcess, subProcess, renamings)
BOOST_FUSION_ADAPT_STRUCT(wccs_parser::AstConstantProcess, processName)
namespace wccs_parser {
//--- Rules
auto const constantName = x3::rule<struct constantRule, std::string> {"constantName"} =
x3::lexeme[ascii::upper >> *(ascii::alnum)];
auto const label = x3::rule<struct labelRule, std::string> {"label"} =
x3::lexeme[ascii::lower >> *(ascii::alnum)];
auto const channel = x3::rule<struct channelRule, AstChannel> {"channel"} =
label >> x3::matches['!'];
auto const action = x3::rule<struct actionRule, AstAction> {"action"} =
'<' >> channel >> ',' >> ulong_ >> '>';
auto renamingPair = x3::rule<struct renamingPairRule, AstRenaming> {"renamingPair"} =
label > "=>" > label;
x3::rule<struct processRule, AstAnyProcess> process{"process"};
auto const nullProcess = x3::rule<struct nullProcessRule, AstNullProcess> {"nullProcess"} = '0' >> x3::attr(AstNullProcess());
auto const constant = x3::rule<struct constantRule, AstConstantProcess> {"constant"} = constantName;
/// HERE:
auto const parenProcess = '(' > nullProcess > ')';
auto const primitive = x3::rule<struct primitiveRule, AstAnyProcess> {"primitive"} =
parenProcess
| nullProcess
| constant;
auto const restrictionActual = x3::rule<struct restrictionActual, AstRestrictionProcess> {"restrictionActual"} =
primitive >> '' >> '{' >> label % ',' >> '}';
auto const restriction = x3::rule<struct restrictionRule, AstAnyProcess> {"restriction"} =
primitive >> !x3::lit('')
| restrictionActual;
auto const renamingActual = x3::rule<struct renamingActualRule, AstRenamingProcess> {"renamingActual"} =
restriction >> '[' >> renamingPair % ',' >> ']';
auto const renaming = x3::rule<struct renamingRule, AstAnyProcess> {"renaming"} =
restriction >> !x3::lit('[')
| renamingActual;
x3::rule<struct actionPrefixingRule, AstAnyProcess> actionPrefix{"actionPrefix"};
auto const actionPrefixActual = x3::rule<struct actionPrefixActualRule, AstActionPrefixProcess> {"actionPrefixActual"} =
action > ('.' > actionPrefix);
auto const actionPrefix_def =
actionPrefixActual
| renaming;
BOOST_SPIRIT_DEFINE(actionPrefix)
auto const compositionActual = x3::rule<struct choiceActualrule, AstCompositionProcess> {"compositionActual"} =
actionPrefix % '|';
auto const composition = x3::rule<struct compositionRule, AstAnyProcess> {"composition"} =
actionPrefix >> !x3::lit('|')
| compositionActual;
auto const choiceActual = x3::rule<struct choiceActualrule, AstChoiceProcess> {"choiceActual"} =
composition % '+';
auto const choice = x3::rule<struct choiceRule, AstAnyProcess> {"choice"} =
composition >> !x3::lit('+')
| choiceActual;
auto const process_def = choice;
BOOST_SPIRIT_DEFINE(process)
auto const entry = x3::skip(ascii::space) [process];
} //End namespace
int main() {
std::string str("0 + (0)");
wccs_parser::AstAnyProcess root;
auto iter = str.begin();
auto end = str.end();
bool r = parse(iter, end, wccs_parser::entry, root);
if (r) {
std::cout << str << std::endl << std::endl << " Parses OK: " << std::endl;
}
else {
std::cout << "Parsing failedn";
}
if (iter != end) std::cout << "Partial match" << std::endl;
return 0;
}
这是一个已知问题。邮件列表中的CppEvans(?)声称对分支有解决方法,但该分支远远落后,并且更改非常具有侵入性,因此我无法对其进行审查/担保。
因此,正确的办法是在邮件列表中发布,以使主要开发人员参与进来,并提高对此问题的认识。
无论如何,在不更改代码行为的情况下,您可以使用速记:
template <typename T> auto rule = [](const char* name = typeid(T).name()) {
struct _{};
return x3::rule<_, T> {name};
};
template <typename T> auto as = [](auto p) { return rule<T>() = p; };
这将使编写重复的 Ast 强制更加方便:
auto constantName = as<std::string>(x3::lexeme[ascii::upper >> *(ascii::alnum)]);
auto label = as<std::string>(x3::lexeme[ascii::lower >> *(ascii::alnum)]);
auto channel = as<AstChannel>(label >> x3::matches['!']);
auto action = as<AstAction>('<' >> channel >> ',' >> x3::ulong_ >> '>');
auto renamingPair = as<AstRenaming>(label > "=>" > label);
auto nullProcess = as<AstNullProcess>(x3::omit['0']);
auto constant = as<AstConstantProcess>(constantName);
auto parenProcess = '(' > nullProcess > ')';
auto primitive = rule<AstAnyProcess> ("primitive")
= parenProcess
| nullProcess
| constant;
auto restrictionActual = as<AstRestrictionProcess>(primitive >> '' >> '{' >> label % ',' >> '}');
auto restriction = rule<AstAnyProcess> ("restriction")
= primitive >> !x3::lit('')
| restrictionActual
;
auto renamingActual = as<AstRenamingProcess>(restriction >> '[' >> renamingPair % ',' >> ']');
auto renaming = rule<AstAnyProcess> ("renaming")
= restriction >> !x3::lit('[')
| renamingActual
;
auto actionPrefixActual = as<AstActionPrefixProcess>(action > ('.' > actionPrefix));
auto actionPrefix_def = actionPrefixActual | renaming;
auto compositionActual = as<AstCompositionProcess>(actionPrefix % '|');
auto composition = rule<AstAnyProcess> ("composition")
= actionPrefix >> !x3::lit('|')
| compositionActual
;
auto choiceActual = as<AstChoiceProcess>(composition % '+');
auto choice = rule<AstAnyProcess> ("choice")
= composition >> !x3::lit('+')
| choiceActual
;
auto process_def = choice;
BOOST_SPIRIT_DEFINE(actionPrefix, process)
auto const entry = x3::skip(ascii::space) [process];
程序仍然以相同的输出运行。
相关文章:
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 递归列出所有目录中的C++与Python与Ruby的性能
- 递归计数给定目录的文件和所有目录
- 如何在BST的这个简单递归实现中消除警告
- C++:正在检查LinkedList中的回文-递归方法-错误
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 递归无序映射
- 这是定义一组递归规则的正确方法吗?
- 精神:不能在其规则定义中使用x3::skip(skipper)[一些递归规则]
- 使用提升精神的递归 BNF 规则
- 如何在VS2017中在提升精神x3中制定递归规则
- Boost.Spirit X3 编译时间因递归规则而爆炸
- Boost.Spirit(X3,Boost 1.64):如何正确实施此递归规则
- 使用 spirit x3 解析递归规则
- 使用递归的霍纳规则 C/C++
- 如何使这个递归规则工作
- c++中重载递归函数的模板推导规则
- 消除spirit x3解析器规则中的左递归