【问题标题】:Concatenation shift-reduce conflict串联移位减少冲突
【发布时间】:2016-03-15 20:31:05
【问题描述】:

我有一个用于识别标识符和字符串连接表达式的 JavaCUP LR(1) 解析器的简单语法。我还想添加一些空函数调用作为可能的串联参数。但是,当我尝试这样做时,会导致 shift/reduce 冲突。

语法:

precedence left PLUS;

e ::= e exp
      | exp;

exp ::= concat
      | literal;

concatenation ::= exp PLUS exp
                | LPAREN exp RPAREN;


literal ::= IDENTIFIER
          | STRING
          | IDENTIFIER LPAREN RPAREN; // THIS PRODUCES THE ERROR

输入:

x + x + (x)            // match
"foo" + x              // match
(("goo") + (((y))))    // match

function_name() + x + "foo" + (other_func())    // what I also want

冲突:

Warning : *** Shift/Reduce conflict found in state #12
between literal ::= IDENTIFIER (*) 
and     literal ::= IDENTIFIER (*) LPAREN RPAREN  
under symbol LPAREN

我尝试了许多不同的方法,例如在文字中隐藏 IDENTIFIER secondsecond ::= | LPAREN RPAREN; 等标识符,但我无法使其工作。

【问题讨论】:

  • 您是否与 JavaCUP 绑定?还是您只需要一种解析简单表达式的方法?
  • 不幸的是只有JavaCUP

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


【解决方案1】:

似乎出现这种情况的上下文是像

这样的表达式
x + x()

解析器在看到x + x 后,无法判断它是否应该将x + x 减少回exp 或移动(。换句话说,它无法判断是否将表达式解释为

x + [x()]

或作为

[x + x]()

我认为您可以通过添加一个优先规则来解决这个问题,该规则使该特定上下文中的左括号具有比加法更高的优先级。这样,当解析器在这种状态下看到 shift 和 reduce 操作时,它就知道在左括号上进行 shift 而不是 reduce。

【讨论】:

  • 其实你需要'('的优先级高于IDENTIFIER,而不是'+'。 (但 '+' 需要声明为左关联,因为产生式 concat: exp '+' exp 不明确)
【解决方案2】:

Bison 处理以下语法,没有移位/归约冲突:

%token IDENTIFIER STRING
%left IDENTIFIER
%left '('
%left '+'
%%

e      : e exp
       | exp

exp    : concat
       | literal

concat : exp '+' exp
       | '(' exp ')'

literal: IDENTIFIER
       | IDENTIFIER '(' ')'
       | STRING

必须为IDENTIFIER 提供优先级声明,以便为literal: IDENTIFIER 产生式提供优先级。

我发现语法有点奇怪,因为它似乎不允许连接括号。但我相信这是有原因的。

只要函数调用没有参数,上述方法就可以正常工作,但它不允许使用参数调用函数,因为那样会模棱两可。 (这可能被认为是不允许使用不可见的串联运算符的一个很好的理由。)对于它的价值,awk 具有函数和没有运算符的串联,它在词法上解决了这种歧义:标识符后面紧跟 ( ,没有插入空格,被标记为FUNC_NAME,而后跟空格或除 ( 之外的任何符号的标识符被标记为NAME

另一种可能的解决方案是要求在使用之前声明函数,然后使用符号表和词法反馈(即,将信息从解析器传递回词法分析器;在这种情况下,给定标识符的事实是一个函数)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多