柠檬解析器减少错误

时间:2016-11-07 03:38:09

标签: parsing grammar lemon

我正在尝试编写一个语法来解析英语句子中的数字,我可以成功解析到999.一旦我添加逻辑来支持数千个地方,我得到reduce解析冲突,我很难理解造成它的原因。

我附上了柠檬生成的一部分parser.out文件,我希望有人可以解决这个问题。我还包括了大部分语法,其中线下的所有内容都可以自行运行,但是一旦我在线上添加了数千个逻辑,我就开始遇到问题。

我的想法是我遇到类似“悬空其他”的问题,但是我的分隔符。但是,这通常表现为shift-reduce错误,而看起来我只有reduce错误。 Lemon文档有点稀疏,我不确定如何阅读parser.out文件的内容。例如,在HYPHEN reduce 15 ** Parsing conflict **行中,15甚至引用了什么?

非常感谢任何帮助!

我的语法文件的部分:

final_number(A) ::= one_to_999999(B).
final_number(A) ::= ZERO.

one_to_999999(A) ::= thousands(B) separator one_to_999(C).
one_to_999999(A) ::= thousands(B).
one_to_999999(A) ::= one_to_999(B).

thousands(A) ::= one_to_999(B) separator THOUSAND.
thousands(A) ::= THOUSAND.

/* -------------------------------------- */

one_to_999(A) ::= hundreds(B) separator one_to_99(C).
one_to_999(A) ::= hundreds(B).
one_to_999(A) ::= one_to_99(B).

one_to_99(A) ::= tens(B) separator one_to_9(C).
one_to_99(A) ::= tens(B).
one_to_99(A) ::= ten_to_19(B).
one_to_99(A) ::= one_to_9(B).

hundreds(A) ::= one_to_9(B) separator HUNDRED.
hundreds(A) ::= HUNDRED.

separator ::= WHITESPACE.
separator ::= HYPHEN.
separator ::= .

parser.out的部分错误:

State 5:
          one_to_99 ::= tens * separator one_to_9
     (15) one_to_99 ::= tens *
          separator ::= * WHITESPACE
          separator ::= * HYPHEN
     (65) separator ::= *

                             $ reduce       15     one_to_99 ::= tens
                      THOUSAND reduce       15     one_to_99 ::= tens
                    WHITESPACE shift-reduce 63     separator ::= WHITESPACE
                    WHITESPACE reduce       15      ** Parsing conflict **
                        HYPHEN shift-reduce 64     separator ::= HYPHEN
                        HYPHEN reduce       15      ** Parsing conflict **
                     separator shift        4      
                     {default} reduce       65     separator ::=

1 个答案:

答案 0 :(得分:1)

这里没有足够的信息来诊断完整的问题,但我想我可以填补空白。

指出的问题是问题是解析器识别出tens的状态(那将是"二十","三十",... 。,"九十",对吧?)它现在需要separator(可能是可选的)。如果前瞻标记是实际的分隔符,则必须决定是否立即将tens缩减为one_to_99(作为完成one_to_999而没有尾随数字的前奏)或移位{{1 } {}}或WHITESPACE字符,以HYPHENtens扩展separator

解析器实际上无法仅仅查看分隔符令牌来做出决定。它需要知道接下来的内容(例如,可能是one_to_9THOUSAND,以及其他可能性)。

在向语法中添加数千之前不会发生这种情况,因为没有ONE的可能性,如果数字末尾没有单个数字,则{{1}后面没有分隔符令牌也是。因此,如果有明确的分隔符,那么必须有一个数字,因此需要移位。添加THOUSAND选项后,分隔符令牌的存在不再是一个充分的指南。

尝试在解析器中显式匹配空格类似于通常所说的"无扫描器解析",尽管这并非严格意义上的情况,因为您可能确实有扫描器。但是,扫描仪没有正常工作;它没有丢弃没有句法价值的令牌。虽然有些人喜欢无扫描解析,但人们普遍认为它往往会增加前瞻性要求。 [注1]由于你无法增加柠檬解析器的前瞻(也没有增加许多其他基于yacc的解析器生成器),因此无扫描器解析对于这些工具来说是个问题。

在这种情况下,通过强制解析器处理分隔符很难看出你可能获得什么,很明显你丢失了什么(LALR(1)可解析性),所以我建议你只需在扫描仪的地板上删除空格和连字符,然后将其从解析器中删除即可。您可能会认为这样做会导致tens之类的错误句子。这是真的,但您当前的语法允许THOUSAND(这在我见过的任何风格指南中都不正确),并且可能会禁止three hundred forty---two,具体取决于扫描仪的模式用于识别连字符。

如果您希望"连字符正确",请务必从扫描仪返回连字符(但不是空白),然后仅在有用的地方接受它们:

three hundred-forty two

不会产生任何转移/减少冲突。

注释

  1. 我不是喜欢无扫描解析的人之一,所以我甚至不想尝试解释为什么它被认为是个好主意。