转移/减少CUP中的冲突

时间:2017-06-04 02:34:43

标签: parsing compiler-construction grammar shift-reduce-conflict cup

我正在尝试使用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:语法要复杂得多,但我认为如果我看到这些转移/减少问题是如何解决的,我将能够解决其余问题。

感谢您的回答。

1 个答案:

答案 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中的一首歌而言,没有什么是文化特定的参考。