我对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;
等标识符,但我无法使其正常工作。
答案 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}}。
另一种可能的解决方案是要求在使用之前声明函数,然后使用符号表和词法反馈(即,将信息从解析器传递回词法分析器;在这种情况下,给定标识符的事实是一个功能)。