简体   繁体   English

boost :: spirit递归命令式C ++语法:BOOST_FUSION_ADAPT_STRUCT失败

[英]boost::spirit recursive imperative c++ grammar: BOOST_FUSION_ADAPT_STRUCT fails

I've been working on a grammar to parse imperative statements (if/else/do/while/for/switch etc.) in c++. 我一直在研究语法来解析C ++中的命令式语句(if / else / do / while / for / switch等)。 All other statements are kept as strings. 所有其他语句保留为字符串。 I'm currently only testing with if/else (though other statements should work analogous in a variant). 我目前仅使用if / else进行测试(尽管其他语句应该在变体中类似地工作)。 Unfortunately I get a compile time error: 不幸的是,我得到一个编译时错误:

Error 1 error C2440: 'return' : cannot convert from 'std::vector< someSeqNode,std::allocator< Ty>>' to 'boost::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_> &' 错误1错误C2440:'返回':无法从'std :: vector <someSeqNode,std :: allocator < Ty >>'转换为'boost :: 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 ::融合::: void_,增强::: fusion :: void_>&'

on line 80 (closing bracket of BOOST_FUSION_ADAPT_STRUCT for ifElseStruct) 在第80行上(ifElseStruct的BOOST_FUSION_ADAPT_STRUCT的右括号)

The only other questions I found regarding compile issues with BOOST_FUSION_ADAPT_STRUCT and attribute propagation were on structs with only one member or otherwise incompatible attributes between adapted struct and a rule. 我发现的关于BOOST_FUSION_ADAPT_STRUCT的编译问题和属性传播的其他唯一问题是在只有一个成员的结构上,或者在适应的结构和规则之间存在不兼容的属性。

It seems to fail on adapting ifElseStruct.ifContent but I don't get why. 它似乎无法适应ifElseStruct.ifContent,但我不明白为什么。 Resolving the typedef it really is just vector< variant< ifElseStruct, string>>. 解决typedef实际上只是vector <variant <ifElseStruct,string >>。

Is the recursion the problem? 递归是问题吗? If so, how do I solve this? 如果是这样,我该如何解决?

#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

There's a number of issues. 有很多问题。

  1. Like the comment said, don't use using-directives ; 就像评论说的那样,不要使用using指令 they land you in trouble 他们让你陷入困境
  2. if all you want to concatenate all source strings in nestedSomething then, just wrap it all in a raw[] (or as_string[raw[...]] but that's not even necessary), eg 如果您想将所有源字符串都连接到nestedSomething则只需将其全部包装在raw[] (或as_string[raw[...]]但这不是必需的),例如

     nestedSomething = !recursiveImpCpp >> qi::raw[*~char_("(){}") >> -('(' >> nestedSomething >> ')') >> -('{' >> nestedSomething >> '}') >> !recursiveImpCpp >> *~char_("(){}")]; 
  3. that rule is broken in the sense that it will match an empty string. 该规则在匹配空字符串的意义上被打破。 This makes the grammar never end (it will match an "infinite" amount of empty nestedSomething ). 这使语法永无止境(它将匹配“无数”数量的空nestedSomething )。 You will have to decide on some non-optional part. 您将不得不决定一些非可选部分。 Here's a brute-force fix: 这是一个蛮力修复程序:

     qi::raw[...] [ qi::_pass = px::size(qi::_1) > 0 ]; 

    Even with that the grammar gets stuck in an infinite loop for non-trivial programs (try it with its own source). 即使这样,对于非平凡的程序,语法也会陷入无限循环中(尝试使用其自己的源代码)。 The following should clear things up a little: 以下内容应该可以使事情变得简单:

     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 ]; 

    But that will still not parse eg int main() { if(true) { std::cout << "Yes\\n"; } else { std::cout << "No\\n"; } } 但这仍然不会解析,例如int main() { if(true) { std::cout << "Yes\\n"; } else { std::cout << "No\\n"; } } int main() { if(true) { std::cout << "Yes\\n"; } else { std::cout << "No\\n"; } } int main() { if(true) { std::cout << "Yes\\n"; } else { std::cout << "No\\n"; } } ). int main() { if(true) { std::cout << "Yes\\n"; } else { std::cout << "No\\n"; } } )。 The reason is that main(<parenthesized>){<bracketed>} does only accept nestedSomething inside the brackets; 原因是main(<parenthesized>){<bracketed>} nestedSomething main(<parenthesized>){<bracketed>}只接受nestedSomething内的nestedSomething that expressly prohibits the if-else construct... 明确禁止if-else构造...

    Let's rename ifElseContent to something proper (like statement ) 让我们将ifElseContent重命名为适当的名称(例如statement

     block = '{' >> startRule >> '}'; statement = block | singleStatement; 

    and use it instead of the bracketed : 并使用它代替bracketed

     nestedSomething %= qi::raw[ -identifier_soup >> -parenthesized >> -block >> -identifier_soup] [ qi::_pass = boost::phoenix::size(qi::_1) > 0 ]; 

General various notes 一般各种注意事项

  • you can simplify the includes, instead of wrapping them in regions to hide them 您可以简化包含,而不是将它们包装在区域中以隐藏它们
  • you can simplify the rest too (see my demo) 您也可以简化其余部分(请参阅我的演示)
  • the grammar is going to be quite inefficient with all the negative look-aheads. 在所有否定的预见下,语法将变得非常低效。 Consider tokenizing or using a much more finegrained keyword detection scheme (using expectation points and or distinct()[] from the Qi Repository) 考虑标记化或使用更细粒度的关键字检测方案(使用Qi存储库中的期望点和/或distinct()[]

Partial Demo 部分演示

Applying the notes above: 应用以上注意事项:

Live On Coliru 生活在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 failure\n";

    if (f!=l)
        std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}

Prints: 打印:

Parse success: {int main() { if(true) { std::cout << "Yes\n"; } else { std::cout << "No\n"; } } 

With debug info 带有调试信息

<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 << "Yes\n</try>
                <ifElseNormalRule>
                  <try> std::cout << "Yes\n</try>
                  <fail/>
                </ifElseNormalRule>
                <nestedSomething>
                  <try> std::cout << "Yes\n</try>
                  <identifier_soup>
                    <try>std::cout << "Yes\n"</try>
                    <ifElseNormalRule>
                      <try>std::cout << "Yes\n"</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 << "No\n"</try>
                <ifElseNormalRule>
                  <try> std::cout << "No\n"</try>
                  <fail/>
                </ifElseNormalRule>
                <nestedSomething>
                  <try> std::cout << "No\n"</try>
                  <identifier_soup>
                    <try>std::cout << "No\n";</try>
                    <ifElseNormalRule>
                      <try>std::cout << "No\n";</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>

Summary/advice 摘要/咨询

If you ran the above sample on its own source you'll notice it bails on the namespace in line 9. Though it's nice that the program completes, rather than crashing, that's not encouraging. 如果您在自己的源代码上运行上述示例则会注意到它在第9行的命名空间中失效。尽管程序完成而不是崩溃很不错,但这并不令人鼓舞。

You need a proper grammar . 您需要适当的语法 You need to THINK about what is a statement, what is a block, what is a keyword and what is the relationship between them. 您需要考虑什么是语句,什么是块,什么是关键字以及它们之间的关系。 Part of your confusion seems to come from conflating expressions with statements . 您的部分困惑似乎来自表达式语句的合并。

I'd very much consider coming up with a grammar that you 1. can work 2. you know why it will work instead of ... seemingly just trying some things to cheat your way through parsing a programming language. 我非常想想出一种语法,您可以1.可以工作2.您知道为什么它可以工作,而不是...似乎只是尝试通过解析某种编程语言来作弊。

Have you even considered how you'd parse std::cout << "int main() { return 0; }"; 您甚至考虑过如何解析std::cout << "int main() { return 0; }"; yet? 然而?

Have you thought about macros with line-continuations? 您是否考虑过带有行连续的宏?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM