柠檬解析器减少错误



我正在尝试编写一个语法来解析英语句子中的数字,并且我可以成功地解析多达999。一旦我添加了支持千位的逻辑,我就会得到一个reduce解析冲突,并且我很难理解是什么导致了它。

我附加了解析器的一部分。我的文件是由柠檬生成的,我希望有人能解释一下这个问题。我还包括了很大一部分语法,其中行以下的所有内容都可以独立工作,但是一旦我在行以上添加了数千的逻辑,我就开始遇到问题了。

我的想法是,我遇到了一个类似于"悬空else"的问题,但有我的分隔符。然而,这通常表现为shift-reduce错误,而看起来我只有reduce错误。Lemon文档有点稀疏,我不确定如何阅读解析器。输出文件的内容。例如,在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 ::= .

解析器部分。输出错误:

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 ::=

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

所指示的是问题是解析器已经识别出tens的状态(即"二十","三十",……),"90",对吧?),现在需要一个separator(可能是可选的)。如果前瞻标记是一个实际的分隔符,它必须决定是否立即将tens减少到one_to_99(作为不带末尾数字完成one_to_999的前奏)或移动WHITESPACEHYPHEN字符以便用separator和单个数字(one_to_9)扩展tens

解析器真的不能仅仅看分隔符标记就做出决定。它需要知道后面的内容(例如,可能是THOUSANDONE,以及其他可能性)。

在您向语法中添加千位之前不会发生这种情况,因为没有THOUSAND的可能性,如果数字末尾没有单个数字,那么tens标记后面也没有分隔符。因此,如果有一个显式分隔符,那么必须有一个数字,因此需要移位。一旦添加了THOUSAND选项,分隔符令牌的存在就不再是一个足够的指南了。

尝试在解析器中显式匹配空白类似于通常所说的"无扫描器解析",尽管这里严格来说不是这样,因为您可能确实有一个扫描程序。然而,扫描仪没有正常工作;它无法删除没有语法值的令牌。虽然有些人喜欢无扫描程序解析,但人们普遍认为它倾向于增加前瞻性需求。[注1]由于您不能为lemon解析器(也不能为许多其他基于yacc的解析器生成器)增加前瞻性,因此此类工具的无扫描程序解析存在问题。

在这种情况下,很难看出强制解析器处理分隔符可能会获得什么,而且很明显您失去了什么(LALR(1)可解析性),因此我建议您在扫描器中删除空白和连字符,并将它们从解析器中删除。你可能会说这样做会导致错误的句子出现,比如three hundred forty---two。这是真的,但是你当前的语法允许three hundred-forty two(这在我见过的任何风格指南中都是不正确的),并且可能禁止forty - two,这取决于你的扫描仪使用什么模式来识别连字符。

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

one_to_99 ::= tens
            | tens one_to_9
            | tens HYPHEN one_to_9
            ;

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

指出

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

相关内容

  • 没有找到相关文章

最新更新