Spirit Qi序列解析问题

时间:2012-07-05 08:17:10

标签: c++ parsing boost boost-spirit lookahead

我在使用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编译,但在较旧的设置上也应该没问题。)

1 个答案:

答案 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)];