我使用spirit::qi 语法来构造并返回非平凡对象作为其合成属性。问题是我希望语法递归地相互依赖。使用递归很简单rules,但我想要递归grammars.
这是一些示例代码。请注意“循环引用”的注释。显然,如果我取消注释这些行,则无法编译,因为 FooGrammar 和 BarGrammar 对象相互包含。
我可以想到两种方法来达到预期的效果,但我似乎无法让它们与 qi 一起工作:
让 BarGrammar 保存一个指向 FooGrammar 的(智能)指针。它需要将 FooGrammar 构造为 lit("start_bar") 上的语义操作。但我不知道 qi 的内部结构来知道这是否安全——我是否需要维护自己的显式 FooGrammars 堆栈?什么时候才能安全销毁它们?
BarGrammar 可以将 FooGrammar 作为其 qi::locals 之一。但由于某种原因,如果我尝试将 qi::locals 中的语法传递为继承属性,则无法编译它。
有没有规范的方法来制作递归语法?
.
#include <boost/fusion/include/std_pair.hpp>
#include <boost/optional.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
namespace phoenix = boost::phoenix;
namespace spirit = boost::spirit;
namespace ascii = spirit::ascii;
namespace qi = spirit::qi;
using ascii::space_type;
using phoenix::ref;
using qi::grammar;
using qi::lit;
using qi::_r1;
using qi::_val;
using qi::lit;
using qi::omit;
using qi::rule;
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
typedef int Reffy;
struct Foo {
int foo;
};
struct Bar {
int bar;
};
template <typename Iterator>
struct BarGrammar;
template <typename Iterator>
struct FooGrammar : grammar<Iterator, Foo(Reffy&), space_type> {
FooGrammar() : FooGrammar::base_type(foo_) {
foo_ = lit("start_foo")[_val = phoenix::construct<Foo>()]
> -bar_(_r1)
> lit("end_foo");
;
}
BarGrammar<Iterator> bar_;
rule<Iterator, Foo(Reffy&), space_type> foo_;
};
template <typename Iterator>
struct BarGrammar : grammar<Iterator, Bar(Reffy&), space_type> {
BarGrammar() : BarGrammar::base_type(bar_) {
bar_ = lit("start_bar")[_val = phoenix::construct<Bar>()]
//> -foo_(_r1) // CIRCULAR REFERENCE
> lit("end_bar");
}
//FooGrammar<Iterator> foo_; // CIRCULAR REFERENCE
rule<Iterator, Bar(Reffy&), space_type> bar_;
};
int main(int argc, char *argv[]) {
Reffy reffy(0);
FooGrammar<string::iterator> foog;
rule<string::iterator, space_type> top_rule = omit[ foog(ref(reffy)) ];
string input("start_foo start_bar end_bar end_foo");
string::iterator begin = input.begin();
string::iterator end = input.end();
if(qi::phrase_parse(begin, end, top_rule, ascii::space)) {
cout << "passed" << endl;
} else {
cout << "failed" << endl;
}
return 0;
}
提前致谢!!
我在 qi 中实现 SQL 解析器时遇到了同样的问题。我对语句、字段、表等有单独的语法,但例如,字段和表有时也可以是语句(子查询)。就我而言,我是这样解决问题的:
顶层语法(您总是开始解析的语法)持有指向所有子语法的共享指针。顶部语法的构造函数将创建所有子语法的实例,并将它们彼此的实例传递为弱指针。这样,每个语法只创建一个实例。没有圆形的shared_ptr
谢谢weak_ptr
。所以基本上,顶层语法拥有所有子语法,并且只是相互传递指针。
所以在你的情况下,我会创建一个TopGrammar
类,有自己的FooGrammar
and BarGrammar
。一旦它们被构造出来,就将它们互相传递指针。并且在TopGrammar
的开始规则只是调用FooGrammar
.
Since TopGrammar
拥有所有子语法,你确信它们的寿命足够。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)