boost ::精神递归命令c 语法:boost_fusion_adapt_struct失败
boost::spirit recursive imperative c++ grammar: BOOST_FUSION_ADAPT_STRUCT fails
我一直在使用C 中的语法来解析命令语句(如果/else/do/while/for/switch等)。所有其他陈述都保留为字符串。我目前仅对IF/else进行测试(尽管其他语句应在变体中类似)。不幸的是,我会收到编译时间错误:
错误1错误c2440:'return':不能从'std :: vector&lt转换; someseqnode,std ::分配器< ty>>'to'boost :: fusion :: fusion :: vector< someseqnode,boost :: fusion :: void ,boost :: fusion :: void_, boost :: fusion :: void_,boost :: fusion :: void_,boost :: fusion :: void_, boost :: fusion :: void_,boost :: fusion :: void_,boost :: fusion :: void_, boost :: fusion :: void_>&'
在第80行上
我唯一发现的有关BOOST_FUSION_ADAPT_STRUCT和属性传播的编译问题的问题是在适应性结构和规则之间的构件上只有一个成员或其他不兼容的属性。
似乎未能适应ifelsStruct.ifcontent,但我不明白为什么。解决TypEdef,它确实只是向量<变体<ifelsStruct,字符串>>。
递归是问题吗?如果是这样,我该如何解决?
#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#pragma region INCLUDE_STUFF
#include <vector>
#include <string>
#include <iostream>
//boost includes for parser and some collection types (e.g. tuple)
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/fusion.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/spirit/include/qi_raw.hpp>
#include <boost/variant.hpp>
#include "vectorStreamOp.h"//overload stream operator << for std::vector -> for BOOST_SPIRIT_DEBUG
#pragma endregion INCLUDE_STUFF
#pragma region NAMESPACE_STUFF
//to shorten calls fruther down
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
using std::string;
using std::cout;
using std::endl;
using std::vector;
using boost::spirit::qi::parse;
using boost::optional;
using phx::ref;
using phx::at_c;
using qi::char_;
using qi::lexeme;
using qi::_1;
using qi::lit;
using qi::alnum;
using qi::alpha;
using qi::space;
using qi::raw;
using qi::as_string;
#pragma endregion NAMESPACE_STUFF
#pragma region STRUCT_STUFF
/*later make this variant with all impStatementVariants -> either make this a vector to have sequences on all levels or make imperativeCpp derive from this
-> typedef variant<
recursive_wrapper<ifElseStruct>,
recursive_wrapper<switchStruct>,
recursive_wrapper<forStruct>,
recursive_wrapper<whileStruct>,
recursive_wrapper<doWhileStruct>
*/
struct ifElseStruct;
typedef boost::variant<ifElseStruct, string> someSeqNode;
struct ifElseStruct
{
string ifCond;
vector<someSeqNode> ifContent;
optional<vector<someSeqNode>> elseContent;
//for BOOST DEBUG
friend std::ostream& operator<< (std::ostream& stream, const ifElseStruct& var) {
stream << "ifCond: " << var.ifCond << " ifContent: " << var.ifContent << endl << "elseContent:" << var.elseContent;
return stream;
}
};
BOOST_FUSION_ADAPT_STRUCT(
ifElseStruct,
(string, ifCond)
(vector<someSeqNode>, ifContent)
(optional<vector<someSeqNode>>, elseContent)
)
#pragma endregion STRUCT_STUFF
#pragma region GRAMMAR_STUFF
//GRAMMAR for flowcontrol (branching and looping)
template<typename Iterator, typename Skipper> struct imperativeGrammar :qi::grammar<Iterator, vector<someSeqNode>(), Skipper>
{
imperativeGrammar() : imperativeGrammar::base_type(startRule)
{
startRule = *(recursiveImpCpp | nestedSomething); //vector<variant<ifElseStruct(), string>>
recursiveImpCpp = ifElseNormalRule.alias() /*| switchRule | whileRule | forRule ...*/;
//attr: ifElseStruct containing-> string, vector<someSeqNode>, optional<vector<someSeqNode>>
ifElseNormalRule = lit("if")>> '(' >> condition >> ')' >> ifElseContent >> -(lit("else") >> ifElseContent);
condition = *~char_(")");//TODO: replace with nestedSomething rule
ifElseContent = ('{' >> startRule >> '}') /*| singleStatement*/;
singleStatement = !recursiveImpCpp >> (qi::as_string[*~char_(";")] >> qi::as_string[char_(';')]);
nestedSomething = !recursiveImpCpp >> qi::as_string[*~char_("(){}")]
>> -(raw['(' >> nestedSomething >> ')']) >> -(raw['{' >> nestedSomething >> '}'])
>> !recursiveImpCpp >> qi::as_string[*~char_("(){}")];
BOOST_SPIRIT_DEBUG_NODES((startRule)(ifElseNormalRule)(ifElseContent))
}
qi::rule<Iterator, vector<someSeqNode>(), Skipper> startRule;
qi::rule<Iterator, ifElseStruct(), Skipper> recursiveImpCpp;
qi::rule<Iterator, ifElseStruct(), Skipper> ifElseNormalRule;
qi::rule<Iterator, string(), Skipper> condition;
qi::rule<Iterator, vector<someSeqNode>(), Skipper> ifElseContent;
qi::rule<Iterator, std::string(), Skipper> nestedSomething;
qi::rule<Iterator, std::string(), Skipper> singleStatement;
/*qi::rule<Iterator, Skipper> forRule;
qi::rule<Iterator, Skipper> switchCaseBreakRule;
qi::rule<Iterator, Skipper> whileRule;
qi::rule<Iterator, Skipper> doWhileRule;*/
};
#pragma endregion GRAMMAR_STUFF
有许多问题。
- 就像评论所说的那样,不要使用领导剂;他们让你陷入困境
-
如果您要在
nestedSomething
中加入所有源字符串,则只需将其全部包装在raw[]
中(或as_string[raw[...]]
,但这甚至不是必需的),例如,nestedSomething = !recursiveImpCpp >> qi::raw[*~char_("(){}") >> -('(' >> nestedSomething >> ')') >> -('{' >> nestedSomething >> '}') >> !recursiveImpCpp >> *~char_("(){}")];
-
,该规则将符合一个空字符串的意义。这使得语法永无止境(它将与"无限"数量的空
nestedSomething
匹配)。您将不得不决定一些非选项部分。这是一个蛮力的修复:qi::raw[...] [ qi::_pass = px::size(qi::_1) > 0 ];
即使语法陷入了无限程序的无限循环中(尝试使用自己的来源)。以下内容应该清除一点:
identifier_soup = !recursiveImpCpp >> +~qi::char_("(){}"); parenthesized = '(' >> -nestedSomething >> ')'; bracketed = '{' >> -nestedSomething >> '}'; nestedSomething %= qi::raw[ -identifier_soup >> -parenthesized >> -bracketed >> -identifier_soup] [ qi::_pass = px::size(qi::_1) > 0 ];
但这仍然不会解析,例如
int main() { if(true) { std::cout << "Yesn"; } else { std::cout << "Non"; } }
)。原因是main(<parenthesized>){<bracketed>}
在括号内仅接受nestedSomething
。这明确禁止if-else
构造...让我们将
ifElseContent
重命名为适当的东西(例如statement
)block = '{' >> startRule >> '}'; statement = block | singleStatement;
并使用它代替
bracketed
:nestedSomething %= qi::raw[ -identifier_soup >> -parenthesized >> -block >> -identifier_soup] [ qi::_pass = boost::phoenix::size(qi::_1) > 0 ];
一般各种注释
- 您可以简化包含,而不是将它们包裹在区域中
- 您也可以简化其余的(请参阅我的演示)
- 语法对所有负面的外观都将非常低效。考虑引导化或使用更细化的关键字检测方案(使用QI存储库中的期望点和或
distinct()[]
)
部分演示
应用上述注释:
活在coliru
#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/adapted.hpp>
#include <boost/optional/optional_io.hpp>
#ifdef BOOST_SPIRIT_DEBUG
namespace std {
template <typename... T, typename... V>
auto& operator<<(basic_ostream<T...>& os, vector<V...> const& v) {
os << "{";
for (auto& el : v) os << el << " ";
return os;
}
}
#endif
namespace qi = boost::spirit::qi;
/* later make this variant with all impStatementVariants -> either make this a
* vector to have sequences on all levels or make imperativeCpp derive from
* this
-> typedef variant<
recursive_wrapper<ifElseStruct>,
recursive_wrapper<switchStruct>,
recursive_wrapper<forStruct>,
recursive_wrapper<whileStruct>,
recursive_wrapper<doWhileStruct>
*
*/
struct ifElseStruct;
typedef boost::variant<ifElseStruct, std::string> someSeqNode;
struct ifElseStruct
{
std::string ifCond;
std::vector<someSeqNode> ifContent;
boost::optional<std::vector<someSeqNode>> elseContent;
friend std::ostream& operator<< (std::ostream& stream, const ifElseStruct& var) {
stream << "ifCond: " << var.ifCond << " ifContent: " << var.ifContent << std::endl << "elseContent:" << var.elseContent;
return stream;
}
};
BOOST_FUSION_ADAPT_STRUCT(ifElseStruct, ifCond, ifContent, elseContent)
//GRAMMAR for flowcontrol (branching and looping)
template<typename Iterator, typename Skipper> struct imperativeGrammar :qi::grammar<Iterator, std::vector<someSeqNode>(), Skipper>
{
imperativeGrammar() : imperativeGrammar::base_type(startRule)
{
startRule = *(recursiveImpCpp | nestedSomething); //vector<variant<ifElseStruct(), string>>
recursiveImpCpp = ifElseNormalRule.alias() /*| switchRule | whileRule | forRule ...*/;
//attr: ifElseStruct containing-> string, vector<someSeqNode>, optional<vector<someSeqNode>>
ifElseNormalRule = qi::lit("if") >> '(' >> condition >> ')' >> statement >> -("else" >> statement);
condition = *~qi::char_(")");//TODO: replace with nestedSomething rule
block = '{' >> startRule >> '}';
statement = block | singleStatement;
identifier_soup = !recursiveImpCpp >> +~qi::char_("(){}");
parenthesized = '(' >> -nestedSomething >> ')';
bracketed = '{' >> -nestedSomething >> '}';
nestedSomething %= qi::raw[ -identifier_soup
>> -parenthesized
>> -block
>> -identifier_soup] [ qi::_pass = boost::phoenix::size(qi::_1) > 0 ];
singleStatement = !recursiveImpCpp >> qi::raw[*~qi::char_(';') >> ';'];
BOOST_SPIRIT_DEBUG_NODES((startRule)(ifElseNormalRule)(statement)(block)(nestedSomething)(identifier_soup)(parenthesized)(bracketed)(singleStatement))
}
qi::rule<Iterator, std::vector<someSeqNode>(), Skipper> startRule;
qi::rule<Iterator, ifElseStruct(), Skipper> recursiveImpCpp;
qi::rule<Iterator, ifElseStruct(), Skipper> ifElseNormalRule;
qi::rule<Iterator, std::string(), Skipper> condition;
qi::rule<Iterator, std::vector<someSeqNode>(), Skipper> block, statement;
qi::rule<Iterator, std::string(), Skipper> nestedSomething;
qi::rule<Iterator, std::string(), Skipper> singleStatement;
qi::rule<Iterator, Skipper> identifier_soup, parenthesized, bracketed;
/*qi::rule<Iterator, Skipper> forRule;
qi::rule<Iterator, Skipper> switchCaseBreakRule;
qi::rule<Iterator, Skipper> whileRule;
qi::rule<Iterator, Skipper> doWhileRule;*/
};
#include <fstream>
int main() {
//std::string const input = { std::istreambuf_iterator<char>(std::ifstream("main.cpp").rdbuf()), {} };
std::string const input = "int main() { if(true) { std::cout << "Yes\n"; } else { std::cout << "No\n"; } }";
using It = std::string::const_iterator;
It f(input.begin()), l(input.end());
imperativeGrammar<It, qi::space_type> p;
std::vector<someSeqNode> rep;
bool ok = phrase_parse(f, l, p, qi::space, rep);
if (ok) {
std::cout << "Parse success: " << rep << "n";
}
else
std::cout << "Parse failuren";
if (f!=l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'n";
}
打印:
Parse success: {int main() { if(true) { std::cout << "Yesn"; } else { std::cout << "Non"; } }
带有调试信息
<startRule>
<try>int main() { if(true</try>
<ifElseNormalRule>
<try>int main() { if(true</try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try>int main() { if(true</try>
<identifier_soup>
<try>int main() { if(true</try>
<ifElseNormalRule>
<try>int main() { if(true</try>
<fail/>
</ifElseNormalRule>
<success>() { if(true) { std:</success>
<attributes>[]</attributes>
</identifier_soup>
<parenthesized>
<try>() { if(true) { std:</try>
<nestedSomething>
<try>) { if(true) { std::</try>
<identifier_soup>
<try>) { if(true) { std::</try>
<ifElseNormalRule>
<try>) { if(true) { std::</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<parenthesized>
<try>) { if(true) { std::</try>
<fail/>
</parenthesized>
<block>
<try>) { if(true) { std::</try>
<fail/>
</block>
<identifier_soup>
<try>) { if(true) { std::</try>
<ifElseNormalRule>
<try>) { if(true) { std::</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<fail/>
</nestedSomething>
<success> { if(true) { std::c</success>
<attributes>[]</attributes>
</parenthesized>
<block>
<try> { if(true) { std::c</try>
<startRule>
<try> if(true) { std::cou</try>
<ifElseNormalRule>
<try> if(true) { std::cou</try>
<statement>
<try> { std::cout << "Yes</try>
<block>
<try> { std::cout << "Yes</try>
<startRule>
<try> std::cout << "Yesn</try>
<ifElseNormalRule>
<try> std::cout << "Yesn</try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try> std::cout << "Yesn</try>
<identifier_soup>
<try>std::cout << "Yesn"</try>
<ifElseNormalRule>
<try>std::cout << "Yesn"</try>
<fail/>
</ifElseNormalRule>
<success>} else { std::cout <</success>
<attributes>[]</attributes>
</identifier_soup>
<parenthesized>
<try>} else { std::cout <</try>
<fail/>
</parenthesized>
<block>
<try>} else { std::cout <</try>
<fail/>
</block>
<identifier_soup>
<try>} else { std::cout <</try>
<ifElseNormalRule>
<try>} else { std::cout <</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<success>} else { std::cout <</success>
<attributes>[[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]]</attributes>
</nestedSomething>
<ifElseNormalRule>
<try>} else { std::cout <</try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try>} else { std::cout <</try>
<identifier_soup>
<try>} else { std::cout <</try>
<ifElseNormalRule>
<try>} else { std::cout <</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<parenthesized>
<try>} else { std::cout <</try>
<fail/>
</parenthesized>
<block>
<try>} else { std::cout <</try>
<fail/>
</block>
<identifier_soup>
<try>} else { std::cout <</try>
<ifElseNormalRule>
<try>} else { std::cout <</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<fail/>
</nestedSomething>
<success>} else { std::cout <</success>
<attributes>[[[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]]]</attributes>
</startRule>
<success> else { std::cout <<</success>
<attributes>[[[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]]]</attributes>
</block>
<success> else { std::cout <<</success>
<attributes>[[[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]]]</attributes>
</statement>
<statement>
<try> { std::cout << "No</try>
<block>
<try> { std::cout << "No</try>
<startRule>
<try> std::cout << "Non"</try>
<ifElseNormalRule>
<try> std::cout << "Non"</try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try> std::cout << "Non"</try>
<identifier_soup>
<try>std::cout << "Non";</try>
<ifElseNormalRule>
<try>std::cout << "Non";</try>
<fail/>
</ifElseNormalRule>
<success>} }</success>
<attributes>[]</attributes>
</identifier_soup>
<parenthesized>
<try>} }</try>
<fail/>
</parenthesized>
<block>
<try>} }</try>
<fail/>
</block>
<identifier_soup>
<try>} }</try>
<ifElseNormalRule>
<try>} }</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<success>} }</success>
<attributes>[[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]</attributes>
</nestedSomething>
<ifElseNormalRule>
<try>} }</try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try>} }</try>
<identifier_soup>
<try>} }</try>
<ifElseNormalRule>
<try>} }</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<parenthesized>
<try>} }</try>
<fail/>
</parenthesized>
<block>
<try>} }</try>
<fail/>
</block>
<identifier_soup>
<try>} }</try>
<ifElseNormalRule>
<try>} }</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<fail/>
</nestedSomething>
<success>} }</success>
<attributes>[[[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]]</attributes>
</startRule>
<success> }</success>
<attributes>[[[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]]</attributes>
</block>
<success> }</success>
<attributes>[[[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]]</attributes>
</statement>
<success> }</success>
<attributes>[[[t, r, u, e], [[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]], [[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]]]</attributes>
</ifElseNormalRule>
<ifElseNormalRule>
<try> }</try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try> }</try>
<identifier_soup>
<try>}</try>
<ifElseNormalRule>
<try>}</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<parenthesized>
<try>}</try>
<fail/>
</parenthesized>
<block>
<try>}</try>
<fail/>
</block>
<identifier_soup>
<try>}</try>
<ifElseNormalRule>
<try>}</try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<fail/>
</nestedSomething>
<success> }</success>
<attributes>[[[[t, r, u, e], [[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]], [[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]]]]</attributes>
</startRule>
<success></success>
<attributes>[[[[t, r, u, e], [[s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, ]], [[s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, ]]]]]</attributes>
</block>
<identifier_soup>
<try></try>
<ifElseNormalRule>
<try></try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<success></success>
<attributes>[[i, n, t, , m, a, i, n, (, ), , {, , i, f, (, t, r, u, e, ), , {, , s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, , }, , e, l, s, e, , {, , s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, , }, , }]]</attributes>
</nestedSomething>
<ifElseNormalRule>
<try></try>
<fail/>
</ifElseNormalRule>
<nestedSomething>
<try></try>
<identifier_soup>
<try></try>
<ifElseNormalRule>
<try></try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<parenthesized>
<try></try>
<fail/>
</parenthesized>
<block>
<try></try>
<fail/>
</block>
<identifier_soup>
<try></try>
<ifElseNormalRule>
<try></try>
<fail/>
</ifElseNormalRule>
<fail/>
</identifier_soup>
<fail/>
</nestedSomething>
<success></success>
<attributes>[[[i, n, t, , m, a, i, n, (, ), , {, , i, f, (, t, r, u, e, ), , {, , s, t, d, :, :, c, o, u, t, , <, <, , ", Y, e, s, , n, ", ;, , }, , e, l, s, e, , {, , s, t, d, :, :, c, o, u, t, , <, <, , ", N, o, , n, ", ;, , }, , }]]]</attributes>
</startRule>
摘要/建议
如果您在其自身的来源上运行上述示例,您会注意到它在第9行的名称空间上保释。尽管程序完成而不是崩溃是很不错的,但这并不令人鼓舞。
您需要适当的语法。您需要考虑什么是陈述,什么是块,什么是关键字以及它们之间的关系是什么。您的混乱的一部分似乎来自将表达式与语句。。
我非常考虑提出一种语法,即您1.可以工作2.您知道为什么它会起作用,而不是……似乎只是尝试通过解析编程语言来欺骗自己的方式。p>您是否考虑过如何解析std::cout << "int main() { return 0; }";
?
您是否考虑过带有线路接头的宏?
- 将"boost::tuple "转换为"boost::fusion::tuple&quo
- 造成致命错误:boost/fusion/iterator/equal_to.hpp 没有这样的文件或目录
- Boost.Spirit.Qi 语法,用于 Boost.Fusion 自适应结构中的默认值
- 可变参数宏:重用可变参数(Boost.Fusion)
- Boost.Fusion define struct array member
- 传递向量或论点以bubost :: process(boost :: fusion)
- Casting boost::fusion::vector
- 需要使用 boost::fusion::filter_if 元函数的示例
- 如何在运行时填充Boost :: Fusion ::向量
- boost::spirit解析器和boost::fusion支持哪些容器类型
- 传入一个函数,该函数递增 boost::fusion:vector 的元素
- Boost.Hana中是否有类似Boost.Fusion的View概念
- C++使用boost-fusion-adapt_struct迭代到嵌套结构字段中
- 如何实例化没有默认构造函数的类型的 boost::fusion::vector 成员变量
- boost::fusion::zip function vs boost::fusion::zip_view
- 如何在运行时在boost::fusion::vector中查找元素
- 编译时与使用boost::fusion的运行时
- 在使用 boost::fusion 迭代时将漂亮的打印机绑定到 boost::p hoenix actor
- 使用 boost::fusion 进行迭代时指向类成员的指针
- Boost Fusion invoke and SFINAE