我正在尝试编写一个语法来解析英语句子中的数字,我可以成功解析到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 ::=
答案 0 :(得分:1)
这里没有足够的信息来诊断完整的问题,但我想我可以填补空白。
指出的问题是问题是解析器识别出tens
的状态(那将是"二十","三十",... 。,"九十",对吧?)它现在需要separator
(可能是可选的)。如果前瞻标记是实际的分隔符,则必须决定是否立即将tens
缩减为one_to_99
(作为完成one_to_999
而没有尾随数字的前奏)或移位{{1 } {}}或WHITESPACE
字符,以HYPHEN
和tens
扩展separator
。
解析器实际上无法仅仅查看分隔符令牌来做出决定。它需要知道接下来的内容(例如,可能是one_to_9
或THOUSAND
,以及其他可能性)。
在向语法中添加数千之前不会发生这种情况,因为没有ONE
的可能性,如果数字末尾没有单个数字,则{{1}后面没有分隔符令牌也是。因此,如果有明确的分隔符,那么必须有一个数字,因此需要移位。添加THOUSAND
选项后,分隔符令牌的存在不再是一个充分的指南。
尝试在解析器中显式匹配空格类似于通常所说的"无扫描器解析",尽管这并非严格意义上的情况,因为您可能确实有扫描器。但是,扫描仪没有正常工作;它没有丢弃没有句法价值的令牌。虽然有些人喜欢无扫描解析,但人们普遍认为它往往会增加前瞻性要求。 [注1]由于你无法增加柠檬解析器的前瞻(也没有增加许多其他基于yacc的解析器生成器),因此无扫描器解析对于这些工具来说是个问题。
在这种情况下,通过强制解析器处理分隔符很难看出你可能获得什么,很明显你丢失了什么(LALR(1)可解析性),所以我建议你只需在扫描仪的地板上删除空格和连字符,然后将其从解析器中删除即可。您可能会认为这样做会导致tens
之类的错误句子。这是真的,但您当前的语法允许THOUSAND
(这在我见过的任何风格指南中都不正确),并且可能会禁止three hundred forty---two
,具体取决于扫描仪的模式用于识别连字符。
如果您希望"连字符正确",请务必从扫描仪返回连字符(但不是空白),然后仅在有用的地方接受它们:
three hundred-forty two
不会产生任何转移/减少冲突。