Parsing 减少/减少CUP中的冲突

Parsing 减少/减少CUP中的冲突,parsing,compiler-construction,grammar,shift-reduce-conflict,cup,Parsing,Compiler Construction,Grammar,Shift Reduce Conflict,Cup,我正在使用JavaCup为Java的一个子集实现一个解析器 语法就像 vardecl ::= type ID type ::= ID | INT | FLOAT | ... exp ::= ID | exp LBRACKET exp RBRACKET | ... stmt ::= ID ASSIGN exp SEMI 这很好,但是当我添加 stmt ::= ID ASSIGN exp SEMI |ID LBRACKET exp RBRACKET ASSIGN

我正在使用JavaCup为Java的一个子集实现一个解析器

语法就像

vardecl ::= type ID
type    ::= ID | INT | FLOAT | ...
exp     ::= ID | exp LBRACKET exp RBRACKET | ...
stmt    ::= ID ASSIGN exp SEMI
这很好,但是当我添加

stmt ::= ID ASSIGN exp SEMI
        |ID LBRACKET exp RBRACKET ASSIGN exp SEMI 
杯子不工作,警告如下:

Warning : *** Shift/Reduce conflict found in state #122
  between exp ::= identifier (*) 
  and     statement ::= identifier (*) LBRACKET exp RBRACKET ASSIGN exp SEMI 
  under symbol LBRACKET
  Resolved in favor of shifting.

Warning : *** Reduce/Reduce conflict found in state #42
  between type ::= identifier (*) 
  and     exp ::= identifier (*) 
  under symbols: {}
  Resolved in favor of the first production.

Warning : *** Shift/Reduce conflict found in state #42
  between type ::= identifier (*) 
  and     statement ::= identifier (*) LBRACKET exp RBRACKET ASSIGN exp SEMI 
  under symbol LBRACKET
  Resolved in favor of shifting.

Warning : *** Shift/Reduce conflict found in state #42
  between exp ::= identifier (*) 
  and     statement ::= identifier (*) LBRACKET exp RBRACKET ASSIGN exp SEMI 
  under symbol LBRACKET
  Resolved in favor of shifting.
我认为有两个问题:
1.
type::=ID
exp:=ID
,当解析器看到一个ID时,它想减少它,但不知道减少哪个,
type
exp

  • stmt::=ID LBRACKET exp RBRACKET ASSIGN exp SEMI
    用于分配数组中的元素,例如
    arr[key]=value
    exp::exp LBRACKET exp RBRACKET
    用于表示从数组中获取元素,例如
    arr[key]
  • 因此,在
    arr[key]
    的情况下,当解析器看到
    arr
    时,它知道它是一个ID,但不知道它是否应该移动或减少到
    exp


    但是,我不知道如何解决这个问题,如果有,请给我一些建议,非常感谢。

    您的分析是正确的。语法是LR(2),因为在看到
    ]
    标记之前无法识别声明,该标记将是ID中的第二个下一个标记,可能是类型

    一个简单的解决方案是,当括号显示为连续标记时,破解lexer将
    []
    作为单个标记返回。(lexer可能也应该允许括号之间有空格,所以这不是很简单,但并不复杂。)如果
    [
    后面没有紧跟
    ]
    ,lexer将返回普通的
    [
    ,这使得解析器很容易区分对数组的赋值(将具有
    [
    标记)和数组声明(将具有
    []
    标记)

    重写语法也是可能的,但那真是讨厌

    第二个问题——数组索引赋值与数组索引表达式。通常编程语言允许赋值形式:

    exp [ exp ] = exp
    
    而且不仅仅是
    ID[exp]
    。进行此更改将延迟还原的需要,直到解析器能够识别正确的还原为止。根据语言的不同,此语法可能在语义上没有意义,而是在类型检查(语义)领域进行检查不是语法。但是,如果有某种形式的语法是有意义的,就没有明显的理由禁止它


    一些解析器生成器实现GLR解析器。GLR解析器对此语法没有问题,因为它没有歧义。但CUP不是这样的生成器。

    您的分析是正确的。语法是LR(2),因为只有在
    ]
    将看到令牌,它将是ID中的下一个令牌,可能是一种类型

    一个简单的解决方案是,当括号显示为连续的标记时,破解lexer将
    []
    作为单个标记返回。(lexer可能也应该允许括号之间有空格,所以这不是很简单,但并不复杂。)如果
    [
    后面没有紧跟
    ]
    ,lexer将返回它作为普通的
    [
    。这使得解析器很容易区分对数组的赋值(将有
    [
    标记)和数组的声明(将有
    [
    标记)

    重写语法也是可能的,但那真是讨厌

    第二个问题——数组索引赋值与数组索引表达式。通常编程语言允许赋值形式:

    exp [ exp ] = exp
    
    而且不仅仅是
    ID[exp]
    。进行此更改将延迟还原的需要,直到解析器能够识别正确的还原为止。根据语言的不同,此语法可能在语义上没有意义,而是在类型检查(语义)领域进行检查不是语法。但是,如果有某种形式的语法是有意义的,就没有明显的理由禁止它


    一些语法分析器生成器实现GLR语法分析器。GLR语法分析器不会有问题,因为它没有歧义。但是CUP不是这样的生成器。

    谢谢你的回答。但我认为它不能在我的例子中作为单个标记返回
    []
    ,因为
    [
    ]之间有一个表达式
    在案例
    arr[key]=value
    @jiahao中:如果
    [
    ]
    arr[key]
    之间只有空格,则只能将其作为单个标记返回。是的,但问题是解析器仍然无法区分
    arr[key]
    exp
    stmt
    的一部分。如果
    arr[key]
    arr[key]=value
    的一部分,那么它是
    stmt
    ,并且
    arr
    应该作为
    ID
    进行移位;如果
    arr[key]
    arr[key]的一部分,init()
    ,那么
    arr
    应该减少为
    exp
    。对不起,我想我忘了添加一个规则,它是
    stmt::=exp DOT ID LPAREN参数\u list rpare SEMI
    ,这个规则是用于函数调用的。@jiahao:这是一个不同的问题,它有不同的解决方案。最简单的一个是允许表单
    exp>的赋值[exp]=
    ,这在大多数语言中都是有效的。是的,我同意,非常感谢你的回答,你非常有帮助;)谢谢你的回答。但我认为它不能在我的情况下作为单个标记返回
    []
    ,因为在
    [
    ]
    之间有一个表达式
    key
    =value
    @jiahao:如果
    [
    ]
    之间除了空格之外没有任何东西,那么您只能将其作为单个标记返回
    arr[key]
    仍然是四个标记,但是
    arr[]
    它只有两个。是的,但问题是解析器仍然不能