C++ Boost qi递归规则构建 [英] C++ Boost qi recursive rule construction

查看:27
本文介绍了C++ Boost qi递归规则构建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[看来我的解释和期望都不是很清楚,所以我在帖子末尾添加了我希望如何使用该功能的精确性]

[It seems my explanations and expectations are not clear at all, so I added precision on how I'd like to use the feature at the end of the post]

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

I'm currently working on grammars using boost qi. I had a loop construction for a rule cause I needed to build it from the elements of a vector. I have re-written it with simple types, and it looks like:

#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);
}

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

(Looks like here does not want to be replaced by corresponding hyperlink, so here is the address to find function test_phrase_parser(): http://www.boost.org/doc/libs/1_43_0/libs/spirit/doc/html/spirit/qi/reference/basics.html)

一切都是为了最好的世界……直到我不得不对这条规则提出一个论点.这是新的规则类型:

All was for the best in the best of all worlds... until I had to pass an argument to this rule. Here is the new rule type:

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

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

'int*' type is for example purpose only, my real pointer is adressing a much more complex class... but still a mere pointer.

我相应地更改了我的for"循环,即:

I changed my 'for' loop accordingly, i.e.:

    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 指针的值:

I had to add a new rule because test_phrase_parser() cannot guess which value is to be given to the int pointer:

bqi::rule<Iterator> myInitialRule;

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

And change everything that followed the for loop:

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 ]

-->

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 ]

编译是因为它在语法上完全正确,但是哪个堆栈溢出了,因为它愉快地、漂亮地、递归地调用自己死亡......

Which compiles since it is perfectly syntactically correct, but which magnificently stack overflows coz it happily, nicely, recursively, calls itself to death...

然后我失去了理智并输入:

Then I lost my mind and typed:

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

正如您所料,编译失败.

Which, as you probably expect, has failed to compile.

你想象一下,在写上面的小说之前,我在网上查了一下,但没有发现与复制()和参数同时传递相关的任何内容.有没有人遇到过这个问题?我错过了什么吗?

You imagine that before writing the above novel, I checked out on the web, but didn't find out anything related to copy() and argument passing in the same time. Has anyone already experienced this problem ? Have I missed something ?

请放心,我们将非常感谢您的任何帮助.

Be assured that any help will be really really appreciated.

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

PS: Great thanks to hkaiser who has, without knowing it, answered a lot of my boost::qi problems through google (but this one).

更多信息:

我的解析器的目的是读取用给定语言 L 编写的文件.我的帖子的目的是传播我的上下文"(即:变量定义,特别是常量值,所以我可以计算表达式).

The purpose of my parser is to read files written in a given language L. The purpose of my post is to propagate my "context" (i.e.: variable definitions and especially constant values, so I can compute expressions).

我处理的变量类型数量很少,但肯定会增长,所以我将这些类型保存在一个容器类中.我可以在这些托管类型上循环.

The number of variable types I handle is small, but it's bound to grow, so I keep these types in a container class. I can loop on these managed types.

那么,让我们考虑一个我想要实现的伪算法:

So, let's consider a pseudo-algorithm of what I would like to achive:

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 并能够计算表达式值.

This is done during initialization and then myLoopBuiltRule is used and reused with different LContext*, parsing multiple types. And since some L types can have bounds, which are integer expressions, and that these integer expressions can exhibit constants, I (think that I) need my inherited attribute to take my LContext around and be able to compute expression value.

希望我的意图更清楚.

推荐答案

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

Note I just extended my answer with a few more informational links. In this particular case I have a hunch that you could just get away with the Nabialek trick and replacing the inherited attribute with a corresponding qi::locals<> instead. If I have enough time, I might work out a demonstration later.

请注意,在复制原始表达式树和精神解析器表达式时存在问题,特别是 - 它创建悬空引用,因为内部不应超过包含完整表达式的末尾.在零到2 秒内达到每小时 60 英里!

Please be advised that there are issues when copying proto expression trees and spirit parser expressions in particular - it will create dangling references as the internals are not supposed to live past the end of the containing full expressions. See BOOST_SPIRIT_AUTO on Zero to 60 MPH in 2 seconds!

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

Also see these answers which also concerns themselves with building/composing rules on the fly (at runtime):

  • Generating Spirit parser expressions from a variadic list of alternative parser expressions
  • Can Boost Spirit Rules be parameterized which demonstrates how to return rules from a function using boost::proto::deepcopy (like BOOST_SPIRIT_AUTO does, actually)

总的来说,我强烈建议反对在运行时组合规则.相反,如果您希望在运行时向规则添加替代项",您始终可以使用 qi::symbols<> 代替.诀窍是在符号表中存储规则并使用qi::lazy来调用规则.特别是,这被称为 Nabialek Trick.

In general, I'd very strongly advise against combining rules at runtime. Instead, if you're looking to 'add alternatives' to a rule at runtime, you can always use qi::symbols<> instead. The trick is to store a rule in the symbol-table and use qi::lazy to call the rule. In particular, this is known as the Nabialek Trick.

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

I have a toy command-line arguments parser here that demonstrates how you could use this idiom to match a runtime-defined set of command line arguments:

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

Unfortunately, qi::lazy does not support inherited arguments see e.g.

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

You might be better off writing a custom parser component, as documented here:

稍后我会尝试找一些时间来制定一个示例,用 qi::locals 替换继承的参数.

这篇关于C++ Boost qi递归规则构建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆