c++ - 如何用boost spirit构建默认值语法?

标签 c++ boost-spirit

我正在分析一些科学文本,其格式类似于

Keyword
{ 1.0  22.2  59.6 'cm' 'yes' }

初学spirit,研究了文档,可以用spirit解决固定格式关键字。

但是对于下面的格式,我不知道如何构建语法。我的问题是: 在我遇到的科学关键字中,某些数据项可以默认为内置默认值。关键字描述指示何时可以应用默认值。有两种方法可以将数量设置为其默认值。首先,通过以斜杠“}”提前结束数据记录,未指定的数量将设置为其默认值。其次,可以通过输入 n* 来默认位于“}”之前的所选数量,其中 n 是要默认的连续数量的数量。例如,3* 会导致关键字数据中接下来的三个数量被赋予它们的默认值。

例如,

Person
{ 'Tom' 188 80 'male' 32 }

假设 'male' 和 '32' 是默认值,其等价物可以是:

Person
{ 'Tom' 188 88 2* }

Person
{ 'Tom' 188 88 'male' 1* }

Person
{ 'Tom' 188 88 }

我搜索了过去的帖子,并且 this给了我一些想法,但我该如何编写 n* 的规则?

最佳答案

您要求的解析器​​非常复杂,因为它必须解决几个任务:

  • 最后处理缺失的元素
  • 处理“2*”语法以替换末尾缺少的元素
  • 不仅正确解析所有有效输入,而且用匹配的值填充给定的数据结构

这里的技巧是以不同的方式利用qi::attr:

  • 为缺少的元素提供默认值:

    qi::int_ | qi::attr(180)
    

    即匹配一个整数或使用默认值 180

  • 为“2*”语法提供所有剩余值(如@vines 建议的那样):

    "2*" >> qi::attr(attr2)
    

    即如果 2* 匹配使用默认值 attr2(这是一个 fusion::vector)。

总的来说,我想出了这个解决方案,它似乎可以很好地解析和返回默认值(即使它看起来很复杂):

#include <string>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/vector.hpp>

int main()
{
    namespace qi = boost::spirit::qi;
    namespace fusion = boost::fusion;

    // the attribute passed to the parser has to match (in structure) the 
    // parser, requiring to create nested fusion::vector's
    typedef fusion::vector<std::string, int>              attribute1_type;
    typedef fusion::vector<int, attribute1_type>          attribute2_type;
    typedef fusion::vector<int, attribute2_type>          attribute3_type;

    // overall attribute type
    typedef fusion::vector<std::string, attribute3_type>  attribute_type;

    // initialize attributes with default values
    attribute1_type attr1("male", 32);
    attribute2_type attr2(80, attr1);
    attribute3_type attr3(180, attr2);

    qi::rule<std::string::iterator, std::string()> quoted_string =
        "'" >> *~qi::char_("'") >> "'";

    qi::rule<std::string::iterator, attribute_type(), qi::space_type> data =
        qi::lit("Person") >> "{" 
            >>  quoted_string 
            >> -(   ("4*" >> qi::attr(attr3))
                |   (qi::int_ | qi::attr(180))
                    >> -(   ("3*" >> qi::attr(attr2))
                        |   (qi::int_ | qi::attr(80))
                            >> -(   ("2*" >> qi::attr(attr1))
                                |   (quoted_string | qi::attr("male"))
                                    >> -(   "1*"  
                                        |   qi::int_ 
                                        |   qi::attr(32)
                                        )
                                )
                        )
                )
        >> "}";

    std::string in1 = "Person\n{ 'Tom' 188 80 'male' 32 }";
    attribute_type fullattr1;
    if (qi::phrase_parse(in1.begin(), in1.end(), data, qi::space, fullattr1))
        std::cout << fullattr1 << std::endl;

    std::string in2 = "Person\n{ 'Tom' 188 80 'male' }";
    attribute_type fullattr2;
    if (qi::phrase_parse(in2.begin(), in2.end(), data, qi::space, fullattr2))
        std::cout << fullattr2 << std::endl;

    std::string in3 = "Person\n{ 'Tom' 188 3* }";
    attribute_type fullattr3;
    if (qi::phrase_parse(in3.begin(), in3.end(), data, qi::space, fullattr3))
        std::cout << fullattr3 << std::endl;

    return 0;
}

将规则拆分为单独的规则(如@vines 建议的那样)需要对输入进行多次解析,这就是我使用这种序列和替代项的嵌套结构的原因。

关于c++ - 如何用boost spirit构建默认值语法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5836993/

相关文章:

c++ - 在 C++ 函数中返回两种不同类型的两个值

c++ - 如何使用 GitHub 进行 C++ 软件的自动发布/夜间发布?

c++ - 分析 "invalid arc tag"(0x00000000)

c++ - 在 Boost Spirit Qi 中,我如何将每个字符匹配到下一个空格(带预跳过)

c++ - Boost Spirit Visual C++ 编译器错误,适用于 GCC

c++ - 语义分析后拦截编译

c++ - 基于堆栈的回文检查器

c++ - Boost::Spirit 简单语法示例

c++ - 如何增加 gcc 可执行堆栈大小?

c++ - Boost spirit 计算器示例运行