我在使用Spirit :: Qi 2.4编写解析器时遇到了一些问题。
我有一系列键值对要按以下格式<key name>=<value>
进行解析。
密钥名称可以是[a-zA-Z0-9]
,后面跟着=
符号,密钥名称和{{1}之间没有空格} 标志。 密钥名称也始终至少有一个空格。
Value 几乎可以是任何C表达式(也可以是空格),但包含=
char和代码块=
的表达式除外。
在键值对序列的末尾有一个{ }
符号。
我为这个表达式编写解析器而苦苦挣扎。由于密钥名称前面总是至少有一个空格,后跟{
,并且不包含空格我将其定义为
=
值几乎可以是任何值,但它不能包含 KeyName %= [+char_("a-zA-Z0-9_") >> lit("=")] ;
或=
个字符,因此我将其定义为:
{
我想过使用这样的前瞻来捕捉价值:
Value %= +(char_ - char_("{=")) ;
但是由于某种原因它不会起作用(似乎ValueExpression
%= (
Value
>> *space
>> &(KeyName | lit("{"))
)
;
贪婪地上升到ValueExpression
标志并且“不知道”从那里做什么)。我对LL解析器的知识有限,所以我不确定这里有什么做法。还有其他方法可以解决这种序列吗?
以下是示例系列:
=
附加信息,因为这是一个更大的语法的一部分,我无法通过Spirit.Qi解析器以任何其他方式解决此问题(如通过'='拆分并执行一些自定义解析或类似的东西)。
修改
我在这里创建了最小的工作示例:http://ideone.com/kgYD8
(在VS 2012下使用boost 1.50编译,但在较旧的设置上也应该没问题。)
答案 0 :(得分:3)
我建议您查看文章Parsing a List of Key-Value Pairs Using Spirit.Qi。
我非常简化了您的代码,而
在这里,没有进一步的麻烦:
#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
namespace qi = boost::spirit::qi;
namespace fusion = boost::fusion;
typedef std::map<std::string, std::string> data_t;
template <typename It, typename Skipper>
struct grammar : qi::grammar<It, data_t(), Skipper>
{
grammar() : grammar::base_type(Sequence)
{
using namespace qi;
KeyName = +char_("a-zA-Z0-9_") >> '=';
Value = qi::no_skip [+(~char_("={") - KeyName)];
Sequence = +(KeyName > Value);
BOOST_SPIRIT_DEBUG_NODE(KeyName);
BOOST_SPIRIT_DEBUG_NODE(Value);
BOOST_SPIRIT_DEBUG_NODE(Sequence);
}
private:
qi::rule<It, data_t(), Skipper> Sequence;
qi::rule<It, std::string()> KeyName; // no skipper, removes need for qi::lexeme
qi::rule<It, std::string(), Skipper> Value;
};
template <typename Iterator>
data_t parse (Iterator begin, Iterator end)
{
grammar<Iterator, qi::space_type> p;
data_t data;
if (qi::phrase_parse(begin, end, p, qi::space, data)) {
std::cout << "parse ok\n";
if (begin!=end) {
std::cout << "remaining: " << std::string(begin,end) << '\n';
}
} else {
std::cout << "failed: " << std::string(begin,end) << '\n';
}
return data;
}
int main ()
{
std::string test(" ARG=Test still in first ARG ARG2=Zombie cat EXP2=FunctionCall(A, B C) {" );
auto data = parse(test.begin(), test.end());
for (auto& e : data)
std::cout << e.first << "=" << e.second << '\n';
}
输出将是:
parse ok
remaining: {
ARG=Test still in first ARG
ARG2=Zombie cat
EXP2=FunctionCall(A, B C)
如果您真的希望'{'成为最后一个值的一部分,请更改此行:
Value = qi::no_skip [+(char_ - KeyName)];