Spirit qi用lexer寻找n个字符

时间:2014-12-13 18:37:49

标签: c++ pdf boost-spirit

我正在使用boost spirit lexer和grammar编写PDF文件格式的读者。

问题是,这种语法是一种上下文敏感的语法。 实际上,有一个名为Stream dictionary的对象,它具有以下结构:

<< - begin
*( - zero or more times
/NAME - being the key of dictionary
VALUE - being the value of the key in dictionary
)
>> - end
stream - keyword
DATA
endstream - keyword

因此,流中的数据具有字典中定义的大小,例如:

<</LENGTH 4>>
stream
aaaaendstream

现在问题。我需要告诉语法,跳过n个字符。 以下是解析此类对象的规则。

stream_object %=
    dictionary_object
    >> whitespaces
    >> lexer.stream_begin
    > eol
    > qi::repeat(159)["a-z"]
    > lexer.stream_end;

据我所知,这个语法中的每个操作都使用定义的输入词法分析器,并且'qi :: repeat(159)[“az”]'行期望一个字符完全失败,因为词法分析器不知道这样的序列。

我有多个想法,但都错了。

Lexer州

例如,在遇到“stream”标记后更改词法分析器状态。

this->self += stream_begin[lex::_state = "STREAM_BEGIN"];
this->self("STREAM_BEGIN") = stream_end[lex::_state = initial_state()] | character;

这在某种程度上有效,除非数据 AND 中有“endstream”标记,它还会尝试匹配数据内部每个字符序列的endstream,这会大大减慢解析速度。

ABANDON LEXER

接下来的方法是彻底放弃词法分析器。

stream_object %=
    dictionary_object
    >> whitespaces
    >> lit("stream")
    > lit("\r?\n")
    > qi::repeat(159)["a-z"]
    > lit("endstream");

这样可行,但我不喜欢仅针对单个愚蠢规则放弃词法分析器的想法。此外,由于令牌backtracking,我在阅读使用lit而不是lexer时的性能下降。

另一名参与者

最后一种方法是忽略这样的对象,并只解析字典部分。成功解析字典对象后检查后续标记,并在没有标记化器的情况下读取其余数据,如第二种方法所示。

问题

我真的很想看到某种“向前搜索”或“暂时忽略lexer”指令,能够跳过部分输入,而不会将解析过程分成多个位置,或者引入强迫性开销。 有这样的事吗?对每种方法的思考都表示赞赏。

Lexer Code

typedef boost::spirit::istream_iterator base_iterator_type;
typedef boost::spirit::classic::position_iterator2<base_iterator_type> pos_iterator_type;
typedef boost::spirit::lex::lexertl::token<pos_iterator_type> token_type;
typedef boost::spirit::lex::lexertl::actor_lexer<token_type> lexer_type;

class SpiritLexer : public boost::spirit::lex::lexer<lexer_type> {...}

语法代码

struct SpiritGrammar : qi::grammar<pos_iterator_type> {...}

用法

SpiritLexer lexer;
SpiritGrammar grammar(lexer);
auto result = lex::tokenize_and_parse(input_begin_pos, input_end_pos, lexer, grammar, obj);

2 个答案:

答案 0 :(得分:1)

你能考虑通过移动寻求外部解析/ lexing的流来简化它吗?

当你正在考虑它时,重新考虑对词法分析者的需求? (啊,我明白了,你已经考虑过了。我会说,在这个部门很好,除非你知道你需要它的东西)。

  • 暂时禁用词法分析器(显然)是不可能的。您只需从不同的点/状态重新启动lexing即可。我甚至得出结论,一些基本的指令(无证件,AFAIR)将Lexer状态转换为Parser语义动作,如果有的话,就不能有效地工作

  • 避免使用词法分析器可以使用 spirit::repository::qi 中的指令,这些指令似乎与您所寻找的相近:

从概念上讲,对我而言,您似乎很清楚,您正在混合解析和方向解析。这表明它们应该处于不同的抽象层次。

答案 1 :(得分:1)

这是对您的任务的更多评论

  

使用boost spirit lexer和grammar为PDF文件格式编写阅读器。

而不是对具体问题的回答。但是,这对评论来说太大了。

如果您的任务确实要解析通用PDF文件(而不仅仅是由一组受控制的PDF生成器生成的文件,那么您的方法可能会因多种原因而注定失败,特别是间接对象的规范起始位置列在交叉引用中表格或流。主交叉引用表/流在文档的末尾引用。此外,交叉引用流可以被压缩,需要在完成解析之前进行选择性解压缩。

如果忽略这些表并尝试通过前后解析识别间接对象(这是我理解的方法),您可能会感到惊讶。特别是如果有多个具有相同ID的对象,则无法确定哪个是实际的,哪些被忽略。

此外,引用间接对象的可能性会让您陷入困境。

E.g。你的例子:

<</LENGTH 4>>
stream
aaaaendstream

也可能如下所示:

<</LENGTH 5 0 R>>
stream
aaaaendstream
...
5 0 obj
    4
endobj

因此,您必须预先知道您的信息流有多长。