问题描述
我正在尝试使用jflex和Cup编写解析器,但是在处理诸如函数调用和具有递归属性访问之类的递归指向符号时,我遇到了一些问题:
var x = obj.property1.functionCall(p1,p2).property2;
以下是相关的解析器定义:
unary_exp ::= postfix_exp
| ADD2 unary_exp
| SUB2 unary_exp
| unary_operator unary_exp;
unary_operator ::= ADD
| SUB
| BIT_NOT
| NOT;
postfix_exp ::= primary_exp
| postfix_exp LPAR_SQ right_value_exp RPAR_SQ
| postfix_exp LPAR optional_postfix_exp_list RPAR
| postfix_exp DOT postfix_exp
| postfix_exp SUB2
| postfix_exp ADD2;
primary_exp ::= BOOL
| STRING
| INTEGER
| NUMBER
| NULL;
我遇到了以下转移/减少冲突:
Warning : *** Shift/Reduce conflict found in state #190
between postfix_exp ::= postfix_exp DOT postfix_exp (*)
and postfix_exp ::= postfix_exp (*) LPAR optional_postfix_exp_list RPAR
under symbol LPAR
Resolved in favor of shifting.
Warning : *** Shift/Reduce conflict found in state #190
between postfix_exp ::= postfix_exp DOT postfix_exp (*)
and postfix_exp ::= postfix_exp (*) LPAR_SQ right_value_exp RPAR_SQ
under symbol LPAR_SQ
Resolved in favor of shifting.
Warning : *** Shift/Reduce conflict found in state #190
between postfix_exp ::= postfix_exp DOT postfix_exp (*)
and postfix_exp ::= postfix_exp (*) DOT postfix_exp
under symbol DOT
Resolved in favor of shifting.
Warning : *** Shift/Reduce conflict found in state #190
between postfix_exp ::= postfix_exp DOT postfix_exp (*)
and postfix_exp ::= postfix_exp (*) ADD2
under symbol ADD2
Resolved in favor of shifting.
Warning : *** Shift/Reduce conflict found in state #190
between postfix_exp ::= postfix_exp DOT postfix_exp (*)
and postfix_exp ::= postfix_exp (*) SUB2
under symbol SUB2
Resolved in favor of shifting.
Error : *** More conflicts encountered than expected -- parser generation aborted
有人可以向我解释如何处理这些冲突,或者在哪里找到使用java cup,yacc或bison的有效示例吗?
解决方法
您的语法包括此产物:
postfix_exp ::= postfix_exp DOT postfix_exp
您认为这是正确的吗? .
的右操作数可以是任意的postfix_exp吗?如果是这样,a.3
是什么意思? x.false
怎么样? (primary_exp
是postfix_exp
,对吗?这就是语法所说的。)
言归正传,a.b++
是什么意思?从某种意义上说,b++
是.
的操作数?当然,b
是a
成员的名称,而不是独立变量。
语法传达含义,即使它们没有实现语义。它们指定表达式的不同部分相互关联的方式。 (“ parse”和“ parts”听起来很相似,因为动词“ parse”来自名词“ part”,如“ to split成parts”。)因此,您应努力使语法与语言结构相对应。
现在,任何时候看到以下作品:
foo ::= foo OPERATOR foo;
您知道语法是模棱两可的。这是模棱两可的,因为它会为OPERATOR
生成左右关联的解析。例如,如果OPERATOR
是-
,则它将(1 - 1) - 1
与foo
混合(假设1
可以产生1 - (1 - 1)
)。语法歧义总是表现为解析表冲突。
解决歧义很重要,因为这两个表达式具有不同的值。这就是为什么我们必须使用表达式类型的层次结构或运算符优先级声明的原因。 (因此,我们知道如何解决关联性问题。)
但是对于.
运算符,我们确实没有未指定关联性的二进制运算符。我们实际上根本没有二进制运算符,这就是为什么此处的生产称为postfix_exp
的原因。运算符是一个字段选择器,我们可以将其视为不同的后缀运算符的集合,每个适当的复合类型的成员名称都使用一个。
所以这是简单的答案。只要我们说字段选择器的格式为DOT IDENTIFIER
,歧义就会消失。