boost ::精神递归命令c 语法:boost_fusion_adapt_struct失败

boost::spirit recursive imperative c++ grammar: BOOST_FUSION_ADAPT_STRUCT fails

本文关键字:boost fusion struct 失败 adapt 递归 命令 语法      更新时间:2023-10-16

我一直在使用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

有许多问题。

  1. 就像评论所说的那样,不要使用领导剂;他们让你陷入困境
  2. 如果您要在nestedSomething中加入所有源字符串,则只需将其全部包装在raw[]中(或as_string[raw[...]],但这甚至不是必需的),例如,

    nestedSomething = !recursiveImpCpp >> qi::raw[*~char_("(){}")
        >> -('(' >> nestedSomething >> ')')
        >> -('{' >> nestedSomething >> '}')
        >> !recursiveImpCpp >> *~char_("(){}")];
    
  3. ,该规则将符合一个空字符串的意义。这使得语法永无止境(它将与"无限"数量的空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; }";

您是否考虑过带有线路接头的宏?