[似乎我的解释和期望根本不明确,所以我在如何使用帖子末尾的功能时添加了精确度]
我目前正在使用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 ]
– >
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并且能够计算表达式值.
希望我的意图更加清晰.
最佳答案 注意我只是通过一些信息链接扩展了我的答案.在这种特殊情况下,我有一种预感,你可以放弃Nabialek技巧并用相应的qi :: locals<>替换继承的属性.代替.如果我有足够的时间,我可能会稍后进行演示.
警告,揭示问题
请注意,特别是复制proto表达式树和精神解析器表达式时会出现问题 – 它会创建悬空引用,因为内部不应该超出包含完整表达式的末尾.请参阅Zero to 60 MPH in 2 seconds!上的BOOST_SPIRIT_AUTO
另请参阅这些答案,这些答案也涉及动态构建/组合规则(在运行时):
> Generating Spirit parser expressions from a variadic list of alternative parser expressions
> Can Boost Spirit Rules be parameterized演示了如何使用boost :: proto :: deepcopy从函数返回规则(实际上就像BOOST_SPIRIT_AUTO一样)
Nabialek Trick
总的来说,我非常强烈建议不要在运行时组合规则.相反,如果您希望在运行时向规则“添加替代”,则可以始终使用qi :: symbols<>代替.诀窍是将规则存储在符号表中,并使用qi :: lazy来调用规则.特别是,这被称为Nabialek Trick.
我在这里有一个玩具命令行参数解析器,演示了如何使用这个习惯用法匹配运行时定义的一组命令行参数:
> https://gist.github.com/sehe/2a556a8231606406fe36
qi :: lazy的局限性,下一步是什么?
不幸的是,qi :: lazy不支持继承参数,例如
> http://boost.2283326.n4.nabble.com/pass-inhertited-attributes-to-nabialek-trick-td2679066.html
您可能最好编写自定义解析器组件,如下所述:
> http://boost-spirit.com/home/articles/qi-example/creating-your-own-parser-component-for-spirit-qi/
我将尝试找一些时间来制定一个样本,以便稍后用qi :: locals替换继承的参数.