为什么我在解析字符串时会出现运行时错误?
Call - CheckDate(obj);
任何其他语法运行良好,但我想解析类似的东西:
template <typename Iterator, typename Skipper>
struct grammar : qi::grammar<Iterator, QVariant(), Skipper>
{
grammar() : grammar::base_type(object)
{
identifier = qi::raw[qi::lexeme[qi::alpha >> *(qi::alnum | '_' | ('-' >> qi::alnum))]];
self = (qi::raw[qi::lexeme["self"]]);
object = (self >> '.' >> identifier)
|(object >> '.' >> identifier); // there is no runtime error without that line
}
}
运行时错误抛出
self.foo.bar2.baz
呼叫。
答案 0 :(得分:0)
在我看来,作为起点的object
规则必须声明为
qi::rule<It, QVariant(), Skipper> object;
虽然我不知道QVariant是什么,但我知道:
要使属性传播起作用,您需要使用内置Qi转换启发式方法来实现属性类型兼容性。
对于第一个分支(self>>'.'>>identifier
),这个/可能/足够简单。我们假设identifier
合成了一个字符串兼容的属性(std::string
或std::vector<char>
,例如),然后生成的属性可以合法地分配为字符串。
作为一个简单的例子,看看这个(我在哪里“模仿”像QVariant
那样的东西):
<强> Live On Coliru 强>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using QVariant = boost::variant<std::string, int>;
template <typename Iterator, typename Skipper>
struct grammar : qi::grammar<Iterator, QVariant(), Skipper>
{
grammar() : grammar::base_type(object)
{
identifier = qi::raw[qi::lexeme[qi::alpha >> *(qi::alnum | '_' | ('-' >> qi::alnum))]];
self = (qi::raw[qi::lexeme["self"]]);
object =
qi::as_string [self >> '.' >> identifier]
//|qi::as_string [object >> '.' >> identifier] // there is no runtime error without that line
;
}
private:
qi::rule<Iterator, QVariant(), Skipper> object;
qi::rule<Iterator, std::string(), Skipper> identifier;
qi::rule<Iterator, std::string(), Skipper> self;
};
int main() {
using It = std::string::const_iterator;
std::string input = "self.foo.bar2.baz";
It f = input.begin(), l = input.end();
QVariant parsed;
bool ok = qi::phrase_parse(f, l, grammar<It, qi::space_type>{}, qi::space, parsed);
if (ok)
std::cout << "Parsed: " << parsed << "\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
印刷:
Parsed: selffoo
Remaining unparsed: '.bar2.baz'
第二个分支
qi::as_string [object >> '.' >> identifier]
必须合成tuple<QVariant, std::string>
才能与其余声明一致。 Spirit无法自动转换它。启发式系统可能会开始抓住吸管,并尝试将绑定属性(请记住,这是神秘的QVariant)视为容器。如果它成功,那么事情就会编译。显然,在运行时,事情会崩溃,因为为QVariant的实际 - 运行时 - 值调用了错误的接口。
这是理论。
查看工作演示,请注意'.'
已被排除。这让我怀疑你实际上不想要任何复杂的对象解引用链接“列表”,而是可能只想将整个匹配的输入视为原始字符串?在这种情况下,最简单的解决方案是提升raw[]
级别,并且可能使用字符串而不是QVariant
。
¹,例如因为QVariant接口有点草率/不安全并直接在变量接口上公开.begin / .end / value_type / insert成员?
答案 1 :(得分:0)
左递归,如&#34; A =(A&gt;&gt; a)| B&#34;在像boost :: spirit这样的LL解析器中是不可靠的。 它们应该转换为LL友好形式: A = bR R = aR | Ë 其中R - 新的非终端和e - epsilon(空终端)。