C++ 如何使用boost::sprit解析嵌套for循环?

C++ 如何使用boost::sprit解析嵌套for循环?,c++,boost,boost-spirit,C++,Boost,Boost Spirit,我正在尝试分析具有以下语法类型的循环: for(loop = 1:10) { } 在我的语法中,我有以下规则: genericString %= lexeme[+(char_("a-zA-Z"))]; intRule %= int_; commandString %= lexeme[+(char_ - '}')]; forLoop %= string("for") >> '(' >> genericString // variable

我正在尝试分析具有以下语法类型的循环:

for(loop = 1:10) {


}
在我的语法中,我有以下规则:

genericString %= lexeme[+(char_("a-zA-Z"))];
intRule %= int_;
commandString %= lexeme[+(char_ - '}')];
forLoop %= string("for")
        >> '('
        >> genericString // variable e.g. c
        >> '='
        >> (intRule | genericString) // variable e.g. i
        >> ':'
        >> (intRule | genericString) // variable e.g. j
        >> ')' >> '{'
        >> (forLoop | commandString)
        >> '}';
虽然这适用于上面的简单示例,但它无法解析以下嵌套示例:

for(loop = 1:10) {
    for(inner = 1:10) {

    }
}
我猜这是因为解析器“混淆”了大括号的位置。我认为我需要做一些类似于在上所介绍的事情(唉,我发现很难做到)

干杯

编辑1:

我现在认为最好从commandString(下面称为nestedBlock)处理递归,而不是在forLoop中,例如:

forLoop %= string("for")
        >> '('
        >> genericString // variable e.g. c
        >> '='
        >> (intRule | genericString) // variable e.g. i
        >> ':'
        >> (intRule | genericString) // variable e.g. j
        >> ')' 
        >> nestedBlock;

nestedBlock %= lexeme['{' >> -(char_ - '}' - '{')
                          >> -nestedBlock
                          >> -(char_ - '}' - '{')
                          >> '}'];
由于大量boost::spriti错误而失败。这些规则的定义如下:

    qi::rule<Iterator, std::string(), ascii::space_type> nestedBlock;
    qi::rule<Iterator, Function(), ascii::space_type> forLoop;
我声明commandCollection规则如下:

qi::rule<Iterator, boost::fusion::vector<Function>, ascii::space_type> commandCollection;
规则是

qi::rule<Iterator, Function(), ascii::space_type> commandCollection;
qi::规则命令集合;

然后尝试将数据提取为单个函数()结构,效果很好。但我希望它能在某种容器中存储多个命令(即*start)。我还尝试使用std::vector,但也失败了。

您的命令字符串不喜欢内部循环中的空体

通过将
+
更改为
*
来修复此问题:

commandString %= lexeme[*(char_ - '}')];

或者,如果你喜欢匹配一个可选的块,而不是一个潜在的空块,那么考虑一下@ LLONSNMIZ。p> 测试用例:

#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
// #include <boost/spirit/include/phoenix.hpp>

namespace qi    = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

typedef boost::variant<int, std::string> Value;
typedef std::pair<Value, Value> Range;
typedef std::pair<std::string, Range> Iteration;

typedef Iteration attr_t;

template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, attr_t(), Skipper>
{
    parser() : parser::base_type(start)
    {
        using namespace qi;

        genericString %= lexeme[+(char_("a-zA-Z"))];// variable e.g. c
        intRule %= int_;
        commandString %= lexeme[*(char_ - '}')];
        value = intRule | genericString;
        range = value >> ':' >> value;
        forLoop %= lit("for")
                >> '(' >> genericString >> '=' >> range >> ')' 
                >> '{'
                >>      (forLoop | commandString)
                >> '}';

        start = forLoop;

        BOOST_SPIRIT_DEBUG_NODES(
                (start)(intRule)(genericString)(commandString)(forLoop)(value)(range)
                 );
    }

  private:
    qi::rule<It, std::string(), Skipper> genericString, commandString;
    qi::rule<It, int(), Skipper> intRule;
    qi::rule<It, Value(), Skipper> value;
    qi::rule<It, Range(), Skipper> range;
    qi::rule<It, attr_t(), Skipper> forLoop, start;
};

bool doParse(const std::string& input)
{
    typedef std::string::const_iterator It;
    auto f(begin(input)), l(end(input));

    parser<It, qi::space_type> p;
    attr_t data;

    try
    {
        bool ok = qi::phrase_parse(f,l,p,qi::space,data);
        if (ok)   
        {
            std::cout << "parse success\n";
        }
        else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

        if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
        return ok;
    } catch(const qi::expectation_failure<It>& e)
    {
        std::string frag(e.first, e.last);
        std::cerr << e.what() << "'" << frag << "'\n";
    }

    return false;
}

int main()
{
    bool ok = doParse(
            "for(loop = 1:10) {\n"
            "   for(inner = 1:10) {\n"
            "   }\n"
            "}"
            );
    return ok? 0 : 255;
}
#定义BOOST\u SPIRIT\u DEBUG
#包括
#包括
#包括
//#包括
名称空间qi=boost::spirit::qi;
名称空间业力=提升::精神::业力;
名称空间phx=boost::phoenix;
typedef boost::变量值;
typedef std::对范围;
typedef-std::成对迭代;
类型定义迭代属性;
模板
结构分析器:qi::grammar
{
parser():parser::base_类型(开始)
{
使用名称空间qi;
genericString%=lexeme[+(char_uu2;(“a-zA-Z”))];//变量,例如c
intRule%=int_389;;
commandString%=lexeme[*(char_-'}');
value=intRule | genericString;
范围=值>>':'>>值;
forLoop%=点亮(“for”)
>>“('>>常规字符串>>'='>>范围>>”)”
>> '{'
>>(forLoop |命令字符串)
>> '}';
开始=前循环;
BOOST_SPIRIT_DEBUG_节点(
(开始)(intRule)(genericString)(commandString)(forLoop)(值)(范围)
);
}
私人:
qi::rule genericString,commandString;
qi::rule intRule;
qi:规则值;
qi:规则范围;
qi::规则forLoop,开始;
};
bool doParse(常量标准::字符串和输入)
{
typedef std::string::const_迭代器It;
自动f(开始(输入)),l(结束(输入));
语法分析器p;
属性数据;
尝试
{
bool ok=qi::短语解析(f,l,p,qi::空间,数据);
如果(确定)
{

std::cout和问题是什么?对我来说,问题很清楚。@sehe--我只是在Arne的评论之后才澄清了标题中的问题:-)@BenJ空白是预屏蔽的,甚至在你开始commandString规则之前。@BenJ到你的“编辑2”:我觉得你应该提出另一个问题。你能适应展示这个问题吗?(我觉得你只是把
fusion::vector()
std::vector
搞混了。)再次感谢sehe的帮助..我现在正试图将其中一些想法编入我的代码中。干杯:-)对原始帖子进行了另一次编辑(编辑2)。抱歉,我有点扩展了,可能偏离了我最初问题的细节。
commandString %= lexeme[*(char_ - '}')];
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
// #include <boost/spirit/include/phoenix.hpp>

namespace qi    = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

typedef boost::variant<int, std::string> Value;
typedef std::pair<Value, Value> Range;
typedef std::pair<std::string, Range> Iteration;

typedef Iteration attr_t;

template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, attr_t(), Skipper>
{
    parser() : parser::base_type(start)
    {
        using namespace qi;

        genericString %= lexeme[+(char_("a-zA-Z"))];// variable e.g. c
        intRule %= int_;
        commandString %= lexeme[*(char_ - '}')];
        value = intRule | genericString;
        range = value >> ':' >> value;
        forLoop %= lit("for")
                >> '(' >> genericString >> '=' >> range >> ')' 
                >> '{'
                >>      (forLoop | commandString)
                >> '}';

        start = forLoop;

        BOOST_SPIRIT_DEBUG_NODES(
                (start)(intRule)(genericString)(commandString)(forLoop)(value)(range)
                 );
    }

  private:
    qi::rule<It, std::string(), Skipper> genericString, commandString;
    qi::rule<It, int(), Skipper> intRule;
    qi::rule<It, Value(), Skipper> value;
    qi::rule<It, Range(), Skipper> range;
    qi::rule<It, attr_t(), Skipper> forLoop, start;
};

bool doParse(const std::string& input)
{
    typedef std::string::const_iterator It;
    auto f(begin(input)), l(end(input));

    parser<It, qi::space_type> p;
    attr_t data;

    try
    {
        bool ok = qi::phrase_parse(f,l,p,qi::space,data);
        if (ok)   
        {
            std::cout << "parse success\n";
        }
        else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

        if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
        return ok;
    } catch(const qi::expectation_failure<It>& e)
    {
        std::string frag(e.first, e.last);
        std::cerr << e.what() << "'" << frag << "'\n";
    }

    return false;
}

int main()
{
    bool ok = doParse(
            "for(loop = 1:10) {\n"
            "   for(inner = 1:10) {\n"
            "   }\n"
            "}"
            );
    return ok? 0 : 255;
}