灵气条件解析

Spirit Qi conditional parsing

我正在写一个pdf解析库。

曾几何时,我有一个像这样解析的输入:

1 0 obj
(anything)
endobj

我已经为外部容器创建了解析规则,然后为内部对象创建了单独的规则:

CONTAINER_PARSER %=
number >> number >> "obj" >> OBJECT_PARSER >> "endobj";

OBJECT_PARSER %= number | value | ... 

这没有任何问题。但是,出于各种原因,我不得不重新设计规则,以便两个容器值都属于对象本身。

容器本身只是可选的。意思是,前面的代码和下面的代码表示相同的对象,没有额外的容器信息:

(anything)

我有 2 个想法,如何解决这个问题,但在我看来,这两个想法都不符合 Qi 方法。

替代解析器

我想告诉解析器,要么解析包含在 obj - endobj 中的值,要么只解析该值。

start %=
(
    object_number
    >> generation_number
    >> qi::lit("obj")
    >> object
    > qi::lit("endobj")
) | object;
// I intentionally missed some semantic actions assigning the values to the object,
because it is out of the scope of my problem

我没能成功,因为交替的两个部分具有相同的公开属性,编译器感到困惑。

可选方法

我试图告诉解析器,前一个容器对于解析值来说只是可选的。

start %=
-(
    object_number
    >> generation_number
    >> qi::lit("obj")
)
>> object
> -qi::lit("endobj");

这种方法的问题是,如果第一部分也存在,那么最后一部分 "endobj" 必须存在。

解决方案可能很简单,但我真的无法从代码、文档和 Whosebug 答案中找出答案。

更新评论后:

start = 
    (
        ( object_number >> generation_number 
        | qi::attr(1) > qi::attr(0) // defaults
        ) >> "obj" >> object > "endobj"
    | qi::attr(1) >> qi::attr(0) >> object
    )
    ;

假设您对(可选)数字不感兴趣:

start = 
       -qi::omit [ object_number >> generation_number ]
    >> "obj" >> object > "endobj"
    ;

如果您有兴趣并且有合适的默认值:

start = 
       ( object_number >> generation_number 
       | qi::attr(1) > qi::attr(0) // defaults
       )
    >> "obj" >> object > "endobj"
    ;

当然可以

  • 将收件人类型更改为 object_numbers 的 optional<int>,这样您就可以简单地 -object_number >> -generation_number;这有点草率,因为它还允许 "1 obj (anything) endobj"

  • 将收件人类型更改为变体:

    boost::variant<simple_object, object_contaier>

    在这种情况下,您的 AST 与您问题中的 "alternative" 方法(第一个)相匹配