C ++ Boost qi递归规则构造

时间:2013-07-01 13:22:08

标签: boost boost-spirit dynamically-generated rule

[看来我的解释和期望一点都不清楚,所以我在帖子末尾加入了如何使用该功能的精确度]

我目前正在使用boost qi编写语法。我有一个规则的循环结构,因为我需要从向量的元素构建它。我用简单的类型重写了它,它看起来像:

#include <string>

// using boost 1.43.0
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_eps.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace bqi = boost::spirit::qi;

typedef const char* Iterator;

// function that you can find [here][1]
template<typename P> void test_phrase_parser(char const* input, P const& p, bool full_match = true);

int main()
{
    // my working rule type:
    bqi::rule<Iterator, std::string()> myLoopBuiltRule;
    std::vector<std::string> v;
    std::vector<std::string>::const_iterator iv;

    v.push_back("abc");
    v.push_back("def");
    v.push_back("ghi");
    v.push_back("jkl");

    myLoopBuiltRule = (! bqi::eps);
    for(iv = v.begin() ; iv != v.end() ; iv++)
    {
        myLoopBuiltRule =
                myLoopBuiltRule.copy()  [ bqi::_val = bqi::_1 ]
                | bqi::string(*iv)      [ bqi::_val = bqi::_1 ]
                ;
    }
    debug(myLoopBuiltRule);

    char s[] = "  abc ";

    test_phrase_parser(s, myLoopBuiltRule);
}

(看起来here不希望被相应的超链接替换,所以这里是找到函数test_phrase_parser()的地址:http://www.boost.org/doc/libs/1_43_0/libs/spirit/doc/html/spirit/qi/reference/basics.html

在所有世界中,所有人都是最好的......直到我不得不向这个规则传递论据。以下是新规则类型:

    // my not-anymore-working rule type:
    bqi::rule<Iterator, std::string(int*)> myLoopBuiltRule;

'int *'类型仅用于示例目的,我的真实指针正在处理一个更复杂的类......但仍然只是一个指针。

我相应地改变了'for'循环,即:

    for(iv = v.begin() ; iv != v.end() ; iv++)
    {
        myLoopBuiltRule =
                myLoopBuiltRule.copy()(bqi::_r1)    [ bqi::_val = bqi::_1 ]
                | bqi::string(*iv)      [ bqi::_val = bqi::_1 ]
                ;
    }

我不得不添加一条新规则,因为test_phrase_parser()无法猜测将哪个值赋给int指针:

bqi::rule<Iterator> myInitialRule;

并更改for循环后面的所有内容:

myInitialRule = myLoopBuiltRule((int*)NULL);

debug(myLoopBuiltRule);

char s[] = "  abc ";

test_phrase_parser(s, myInitialRule);

然后一切都崩溃了:

/home/sylvain.darras/software/repository/software/external/include/boost/boost_1_43_0/boost/spirit/home/qi/nonterminal/rule.hpp:199: error: no matching function for call to ‘assertion_failed(mpl_::failed************ (boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::operator=(const Expr&)

然后我疯了似试:

myLoopBuiltRule =
        myLoopBuiltRule.copy(bqi::_r1)  [ bqi::_val = bqi::_1 ]
        | bqi::string(*iv)      [ bqi::_val = bqi::_1 ]

- &GT;

error: no matching function for call to ‘boost::spirit::qi::rule<const char*, std::string(int*), boost::fusion::unused_type, boost::fusion::unused_type, boost::fusion::unused_type>::copy(const boost::phoenix::actor<boost::spirit::attribute<1> >&)’

然后我生气了并写道:

myLoopBuiltRule =
        myLoopBuiltRule(bqi::_r1)   [ bqi::_val = bqi::_1 ]
        | bqi::string(*iv)      [ bqi::_val = bqi::_1 ]

哪个编译因为它在句法上是完全正确的,但是它的溢出很棒,很好地,很好地,递归地将它自称为死...

然后我失去了理智并打字:

myLoopBuiltRule =
        jf jhsgf jshdg fjsdgh fjsg jhsdg jhg sjfg jsgh df

正如您可能预期的那样,未能编译。

你想象在写上述小说之前,我在网上查了一下,但没有发现任何与copy()和参数传递相关的内容。有没有人经历过这个问题?我错过了什么吗?

请放心,我们真的非常感谢任何帮助。

PS:非常感谢hkaiser,他在不知情的情况下通过google(但是这个)回答了很多我的boost :: qi问题。


更多信息:

我的解析器的目的是读取以给定语言L编写的文件。我的帖子的目的是传播我的“上下文”(即:变量定义,尤其是常量值,因此我可以计算表达式)。

我处理的变量类型的数量很少,但它必然会增长,所以我将这些类型保存在容器类中。我可以循环使用这些托管类型。

所以,让我们考虑一下我想要实现的伪算法:

LTypeList myTypes;
LTypeList::const_iterator iTypes;

bqi::rule<Iterator, LType(LContext*)> myLoopBuiltRule;

myLoopBuiltRule = (! bqi::eps);
for(iTypes = myTypes.begin() ; iTypes != myTypes.end() ; iTypes++)
{
    myLoopBuiltRule =
        myLoopBuiltRule.copy()(bqi::_r1)    [ bqi::_val = bqi::_1 ]
        | iTypes->getRule()(bqi::_r1)           [ bqi::_val = bqi::_1 ]
}

这是在初始化期间完成的,然后使用myLoopBuiltRule并重复使用不同的LContext *,解析多种类型。由于一些L类型可以有边界,它们是整数表达式,并且这些整数表达式可以表现出常量,我(认为我)需要我的继承属性来获取我的LContext并能够计算表达式值。

希望我的意图更加清晰。

1 个答案:

答案 0 :(得分:2)

注意我只是通过更多信息链接扩展了我的答案。在这种特殊情况下,我有一种预感,你可以只是逃脱Nabialek技巧用相应的替换继承属性 qi::locals<> 代替。如果我有足够的时间,我可能会稍后进行演示。

警告,揭示问题

请注意,特别是在复制proto表达式树和精神解析器表达式时会出现问题 - 创建悬空引用,因为内部不应该超出包含完整表达式的结尾。请参阅Zero to 60 MPH in 2 seconds!

上的BOOST_SPIRIT_AUTO

另请参阅这些答案,这些答案也涉及动态构建/编写规则(在运行时):

Nabialek Trick

一般来说,我非常强烈建议反对在运行时组合规则。相反,如果您希望在运行时向规则“添加备选方案”,则可以始终使用qi::symbols<>。诀窍是在符号表中存储规则并使用qi::lazy来调用规则。特别是,这被称为Nabialek Trick

我在这里有一个玩具命令行参数解析器,它演示了如何使用这个习惯用法匹配运行时定义的一组命令行参数:

qi::lazy的限制,下一步是什么?

不幸的是,qi::lazy不支持继承的参数,例如。

您可能最好编写自定义解析器组件,如下所示:

我会试着找一些时间来制作一个样本,以便稍后用qi :: locals替换继承的参数。