我正在尝试使用JFlex和Cup为javascript-ish语言编写解析器,但是我遇到了一些致命的转移/减少问题以及减少/减少问题的问题。
我已经彻底搜索并找到了大量的例子,但是我无法将这些例子推断到我的语法中。到目前为止,我的理解是这些问题是因为解析器无法决定采用哪种方式,因为它无法区分。
我的语法如下: 从INPUT开始;
INPUT::= PROGRAM;
PROGRAM::= FUNCTION NEWLINE PROGRAM
| NEWLINE PROGRAM;
FUNCTION ::= function OPTIONAL id p_izq ARG p_der NEWLINE l_izq NEWLINE BODY l_der;
OPTIONAL ::=
| TYPE;
TYPE::= integer
| boolean
ARG ::=
| TYPE id MORE_ARGS;
MORE_ARGS ::=
| colon TYPE id MORE_ARGS;
NEWLINE ::= salto NEWLINE
| ;
BODY ::= ;
我遇到了几个冲突,但这两个只是一个例子:
Warning : *** Shift/Reduce conflict found in state #5
between NEWLINE ::= (*)
and NEWLINE ::= (*) salto NEWLINE
under symbol salto
Resolved in favor of shifting.
Warning : *** Shift/Reduce conflict found in state #0
between NEWLINE ::= (*)
and FUNCTION ::= (*) function OPTIONAL id p_izq ARG p_der NEWLINE l_izq NEWLINE BODY l_der
under symbol function
Resolved in favor of shifting.
PS:语法要复杂得多,但我认为如果我看到这些转移/减少问题是如何解决的,我将能够解决其余问题。
感谢您的回答。
答案 0 :(得分:3)
PROGRAM
无用(in the technical sense)。也就是说,它不会产生任何句子,因为在
PROGRAM::= FUNCTION NEWLINE PROGRAM
| NEWLINE PROGRAM;
PROGRAM
的两个作品都是递归的。对于非终端有用,它需要能够最终生成一些终端串,并且为此,它必须至少有一个非递归生产;否则,递归永远不会终止。我很惊讶CUP没有向你提这个。或许它确实如此,你选择忽略警告。
这是一个问题 - 无用的非终端实际上无法匹配任何东西,因此它们最终会导致解析错误 - 但这不是您报告的解析冲突。冲突来自同一制作的另一个特征,这与你不能除以0的事实有关。
无所谓的是,任何数量的事情仍然没有。因此,如果你有很多事情并且有人出现并且问你究竟有多少没有,那你就会遇到一些问题,因为要从“0 *很多”得到“充足”,你必须要计算“0/0”,这不是一个定义明确的值。 (如果你有很多两个,有人问你有多少两个,那就不会有问题:假设有很多两个可以达到40;你可以很容易地计算出40/2 = 20,这就算了完美是因为20 * 2 = 40。)
所以这里我们没有算术,我们有符号串。不幸的是,不包含符号的字符串实际上是不可见的,就像0代表所有那些千年来一样,直到一些阿拉伯数学家注意到能够不写任何东西的价值。
这就是你所拥有的
PROGRAM::= ... something ...
| NEWLINE PROGRAM;
但NEWLINE
被允许不产生任何东西。
NEWLINE ::= salto NEWLINE
| ;
因此PROGRAM
的第二次递归生成可能不会增加任何内容。它可能会添加很多次,因为生产是递归的。但是解析器需要是确定性的:它需要确切地知道存在多少个nothings,这样它就可以将每个没有任何东西减少到NEWLINE
非终端,然后减少一个新的PROGRAM
非终端。而且它真的不知道要添加多少内容。
简而言之,可选的无意义和重复的无意义是模棱两可的。如果你要在你的语言中插入任何东西,你需要确保有一个固定的有限数量的nothings,因为这是解析器可以明确地解剖虚无的唯一方法。
现在,因为该特定递归的唯一要点(据我所见)是允许空的换行终止语句(由于换行而可见,但什么都不做)。你可以通过改变递归来避免任何事情:
PROGRAM ::= ...
| salto PROGRAM;
虽然它与你当前的问题无关,但我觉得有必要提一下,CUP是一个LALR解析器生成器以及你可能在互联网上学习或阅读的有关递归下降解析器无法处理左递归的所有内容不适用。 (我删除了关于解析技术教学方式的咆哮,所以你必须尝试从我留下的提示中恢复它。)自下而上的解析器生成器,如CUP和yacc / bison 爱左递归。当然,他们也可以处理正确的递归,但不情愿,因为他们需要为每次递归浪费堆栈空间而不是左递归。因此,没有必要扭曲你的语法来处理缺陷;只是自然地写出语法并且快乐。 (所以你很少需要非终端代表“剩下的”东西。)
PD:对于1934年歌剧Porgy and Bess中的一首歌而言,没有什么是文化特定的参考。