解决PLY中嵌套函数调用的语法移位/归约冲突
我正在用PLY创建一个解释器的语法。目前,我在尝试将嵌入式函数调用作为表达式来实现,但我遇到了一个问题,就是不太清楚以下规则的冲突出在哪里。
情况是这样的,在这个语言中,有一些针对向量类型对象的“原生”操作,还有一些针对某些数据类型的函数。例如,对于向量,有pop()、push()、join()等函数。
比如说:
vect1.pop()
vect1.join()
所以我有以下规则:
expresion : ID PUNTO POP PAREN_APERTURA PAREN_CIERRE
| ID PUNTO INDEX_OF PAREN_APERTURA expresion PAREN_CIERRE
| ID PUNTO JOIN PAREN_APERTURA PAREN_CIERRE
还有一些函数适用于特定类型的表达式,比如toString()。
例如:
console.log(12.5.toString())
var num1 : number = 20;
console.log(num1.toString())
因此,我添加了以下规则:
expresion : expresion PUNTO funcion_emb PAREN_APERTURA PAREN_CIERRE
funcion_emb : TO_STRING
| TO_UPPER_CASE
| TO_LOWER_CASE
此外,还有其他函数用于转换值,比如:
parseInt("12")
parseFloat("24.5")
对应的规则如下:
expresion: PARSE_INT PAREN_APERTURA expresion PAREN_CIERRE
| PARSE_FLOAT PAREN_APERTURA expresion PAREN_CIERRE
| TYPE_OF expresion
问题是,它产生了一个移位/归约冲突的警告,但并没有告诉我具体是哪个规则引起的。
看着语法,可能是以下规则引起了冲突:
expresion: expresion PUNTO funcion_emb PAREN_APERTURA PAREN_CIERRE
| ID PUNTO POP PAREN_APERTURA PAREN_CIERRE
| ID PUNTO INDEX_OF PAREN_APERTURA expresion PAREN_CIERRE
| ID PUNTO JOIN PAREN_APERTURA PAREN_CIERRE
| PARSE_INT PAREN_APERTURA expresion PAREN_CIERRE
| PARSE_FLOAT PAREN_APERTURA expresion PAREN_CIERRE
| TYPE_OF expresion
这里是表达式和优先级的对应规则:
precedence = (
('left', 'OR'),
('left', 'AND'),
('left', 'IGUAL', 'DIFERENTE'),
('left', 'MENOR_QUE', 'MAYOR_QUE', 'MENOR_IGUAL', 'MAYOR_IGUAL'),
('left', 'MAS', 'MENOS'),
('left', 'MULTI', 'DIV', 'MOD'),
('right', 'NOT', 'UMENOS'),
('nonassoc', 'TYPE_OF'),
)
expresion : expresion MAS expresion
| expresion MENOS expresion
| expresion MULTI expresion
| expresion DIV expresion
| expresion MOD expresion
| expresion IGUAL expresion
| expresion DIFERENTE expresion
| expresion MENOR_QUE expresion
| expresion MAYOR_QUE expresion
| expresion MENOR_IGUAL expresion
| expresion MAYOR_IGUAL expresion
| expresion AND expresion
| expresion OR expresion
| PAREN_APERTURA expresion PAREN_CIERRE
| MENOS expresion %prec UMENOS
| NOT expresion
| expresion PUNTO funcion_emb PAREN_APERTURA PAREN_CIERRE
| ID PUNTO POP PAREN_APERTURA PAREN_CIERRE
| ID PUNTO INDEX_OF PAREN_APERTURA expresion PAREN_CIERRE
| ID PUNTO JOIN PAREN_APERTURA PAREN_CIERRE
| PARSE_INT PAREN_APERTURA expresion PAREN_CIERRE
| PARSE_FLOAT PAREN_APERTURA expresion PAREN_CIERRE
| TYPE_OF expresion
| literal
| ID
funcion_emb : TO_STRING
| TO_UPPER_CASE
| TO_LOWER_CASE
literal : LIT_NUMBER
| LIT_FLOAT
| LIT_CHAR
| LIT_BOOLEAN
| LIT_STRING
有什么建议吗?
更新:
确实,由于ID PUNTO的产生规则存在冲突。现在,我正在添加新的产生规则来访问对象属性。
expresion : acceso_atrib
acceso_atrib : acceso_atrib PUNTO expresion
acceso_atrib : expresion PUNTO expresion
而且,我在语法中已经指定了POINT运算符的优先级和结合性。
precedence = (
('left', 'OR'),
('left', 'AND'),
('left', 'IGUAL', 'DIFERENTE'),
('left', 'MENOR_QUE', 'MAYOR_QUE', 'MENOR_IGUAL', 'MAYOR_IGUAL'),
('left', 'MAS', 'MENOS'),
('left', 'MULTI', 'DIV', 'MOD'),
('right', 'NOT', 'UMENOS'),
('nonassoc', 'TYPE_OF'),
('left', 'PUNTO'), # ADDED
)
然而,在以下规则中仍然发生了冲突:
WARNING: shift/reduce conflict for PUNTO in state 43 resolved as shift
state 43
(74) expresion -> acceso_atrib .
(75) acceso_atrib -> acceso_atrib . PUNTO expresion
! shift/reduce conflict for PUNTO resolved as shift
MAS reduce using rule 74 (expresion -> acceso_atrib .)
MENOS reduce using rule 74 (expresion -> acceso_atrib .)
MULTI reduce using rule 74 (expresion -> acceso_atrib .)
DIV reduce using rule 74 (expresion -> acceso_atrib .)
MOD reduce using rule 74 (expresion -> acceso_atrib .)
IGUAL reduce using rule 74 (expresion -> acceso_atrib .)
DIFERENTE reduce using rule 74 (expresion -> acceso_atrib .)
MENOR_QUE reduce using rule 74 (expresion -> acceso_atrib .)
MAYOR_QUE reduce using rule 74 (expresion -> acceso_atrib .)
MENOR_IGUAL reduce using rule 74 (expresion -> acceso_atrib .)
MAYOR_IGUAL reduce using rule 74 (expresion -> acceso_atrib .)
AND reduce using rule 74 (expresion -> acceso_atrib .)
OR reduce using rule 74 (expresion -> acceso_atrib .)
PUNTO_COMA reduce using rule 74 (expresion -> acceso_atrib .)
PAREN_CIERRE reduce using rule 74 (expresion -> acceso_atrib .)
COMA reduce using rule 74 (expresion -> acceso_atrib .)
CORCHETE_CIERRE reduce using rule 74 (expresion -> acceso_atrib .)
DOS_PUNTOS reduce using rule 74 (expresion -> acceso_atrib .)
PUNTO shift and go to state 87
! PUNTO [ reduce using rule 74 (expresion -> acceso_atrib .) ]
1 个回答
2
调试这些问题的最好方法是调用 yacc.yacc(debug=True)
,然后查看生成的文件 parser.out
。
(18) expresion -> ID . PUNTO POP ( )
(19) expresion -> ID . PUNTO INDEX_OF ( expresion )
(20) expresion -> ID . PUNTO JOIN ( )
(25) expresion -> ID .
你已经读取了一个 ID
,接下来准备读取一个句点(.)。但是语法不确定是应该直接处理这个句点,还是把这个 ID
转换成一个表达式。之所以会有这种不确定,是因为你的语法中有 expression . function_emb ( )
这样的结构。
解决办法是,ID PUNTO ...
这种情况在你的语法中是绝对不应该出现的。所有这些情况都应该是 expression PUNTO ...
,因为 pop()
等操作可以在任何表达式上调用。