连接转移 - 减少冲突

时间:2016-03-15 20:31:05

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

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

语法:

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 second隐藏second ::= | LPAREN RPAREN;等标识符,但我无法使其正常工作。

2 个答案:

答案 0 :(得分:1)

这似乎出现的背景是像

这样的表达式
x + x()

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

x + [x()]

[x + x]()

我认为你可以通过添加一个优先规则来解决这个问题,该规则给出了在这个特定上下文中的开括号优先于加法的优先级。这样,当解析器在这种状态下看到移位并减少动作时,它知道转移到一个打开的括号而不是减少。

答案 1 :(得分:0)

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,而标识符后跟空格或除之外的任何符号(标记为{{ 1}}。

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