我为一种语言创建了一个编译器,它具有以下语法,由ML-Yacc定义(起始符号是“程序”,在底部定义):
%nonassoc FUN VAR ASSIGN PLUSASSIGN MINUSASSIGN TIMESASSIGN DIVIDEASSIGN
%right ELSE
%left OR
%left AND
%nonassoc EQ NEQ GT LT GE LE
%left PLUS MINUS
%left TIMES DIVIDE
%left UNARY
%left LPAREN
%%
const: INT
| FLOAT
| BOOL
| STRING
ty: ID
| FUN LPAREN typeList RPAREN ARROW ty
typeList: typeList'
|
typeList': ty COMMA typeList'
| ty
exp: primaryExp
| callExp
| boolExp
| opExp
| assignExp
assignExp: ID ASSIGN exp
| ID PLUSASSIGN exp
| ID MINUSASSIGN exp
| ID TIMESASSIGN exp
| ID DIVIDEASSIGN exp
tyargs: LT typeList' GT
callExp: exp LPAREN expList RPAREN
boolExp: exp AND exp
| exp OR exp
opExp: ID PLUSPLUS
| ID MINUSMINUS
| PLUSPLUS ID
| MINUSMINUS ID
| exp PLUS exp
| exp MINUS exp
| MINUS exp %prec UNARY
| BANG exp %prec UNARY
| exp TIMES exp
| exp DIVIDE exp
| exp EQ exp
| exp NEQ exp
| exp GT exp
| exp LT exp
| exp GE exp
| exp LE exp
expList: expList'
|
expList': exp COMMA expList'
| exp
primaryExp: ID
| const
| lambdaExp
| LPAREN exp RPAREN
varDecl: ty ID ASSIGN exp
| ty ID
| VAR ID ASSIGN exp
expStat: exp SEMICOLON
| SEMICOLON
statList: stat statList
|
compoundStat: LBRACE statList RBRACE
selectionStat: IF LPAREN exp RPAREN stat ELSE stat
| IF LPAREN exp RPAREN stat
jumpStat: RETURN exp
| RETURN
| BREAK
iterationStat: WHILE LPAREN exp RPAREN stat
| FOR LPAREN SEMICOLON SEMICOLON RPAREN stat
| FOR LPAREN SEMICOLON SEMICOLON exp RPAREN stat
| FOR LPAREN SEMICOLON exp SEMICOLON RPAREN stat
| FOR LPAREN SEMICOLON exp SEMICOLON exp RPAREN stat
| FOR LPAREN varDecl SEMICOLON SEMICOLON RPAREN stat
| FOR LPAREN varDecl SEMICOLON SEMICOLON exp RPAREN stat
| FOR LPAREN varDecl SEMICOLON exp SEMICOLON RPAREN stat
| FOR LPAREN varDecl SEMICOLON exp SEMICOLON exp RPAREN stat
| FOR LPAREN exp SEMICOLON SEMICOLON RPAREN stat
| FOR LPAREN exp SEMICOLON SEMICOLON exp RPAREN stat
| FOR LPAREN exp SEMICOLON exp SEMICOLON RPAREN stat
| FOR LPAREN exp SEMICOLON exp SEMICOLON exp RPAREN stat
stat: expStat
| compoundStat
| selectionStat
| iterationStat
| jumpStat SEMICOLON
| varDecl SEMICOLON
declList: declList'
|
declList': varDecl COMMA declList'
| varDecl
functionDecl: FUN ID LPAREN declList RPAREN ARROW ty compoundStat
lambdaExp: LPAREN declList RPAREN ARROW ty compoundStat
declarations: varDecl SEMICOLON declarations
| functionDecl declarations
|
program: declarations
这个语法很好,但是现在我想引入参数多态,从而将以下产品添加到语法中:
tyargs: LT typeList' GT
ty: ID tyargs
callExp: exp tyargs LPAREN expList RPAREN
idList: ID COMMA idList
| ID
tyvars: LT idList GT
functionDecl: FUN ID tyvars LPAREN declList RPAREN ARROW ty compoundStat
现在我得到以下2个减少/减少冲突,我不知道如何解决
error: state 75: reduce/reduce conflict between rule 46 and rule 5 on GT
error: state 75: reduce/reduce conflict between rule 46 and rule 5 on COMMA
有谁能告诉我如何删除这两个冲突?
编辑:这是mlyacc http://pastebin.com/2w26ytuV的完整.desc输出。不是说这个也显示了2个良性移位/减少错误
答案 0 :(得分:1)
嗯,没有人回答过,但是你的语法格外含糊不清。有两种可能的作品:
LT ID GT
ID LT ID GT
举一些例子:
<a>
b<a>
这些是tyargs
还是tyvars
还是callExp
的开头?你的语法说他们都可以。因此,如果不对语言或您使用的规则进行一些更改,就很难使用ml-yacc等工具进行解析。
您无法使用ml-yacc编译它,而无需再解释语言结构。有人可能会向您展示一种更好的方法来构建语法规则,以保持在这些工具的约束下。
答案 1 :(得分:1)
问题在于,使用新规则,语法需要任意前瞻来区分varDecl
和expStmt
之间的区别。这来自LT
,它既是表达式的二元运算符,又表示参数化类型的tyargs
列表的开头。
一种可能的解决方法是引入一个新关键字来表示参数化类型或函数(如当前用于引入函数类型的FUN
关键字),这将允许解析器事先知道是否要处理a LT
作为运算符或类型参数列表。
所以你宁愿添加新的规则,如:
ty: TYPE ID tyargs
callExpr: CALL ID tyargs LPAREN expList RPAREN
另一种可能性是通过符号表使用词法分析器反馈 - 让词法分析器识别需要类型参数的标识符(通过查找符号表中的名称)并为它们返回不同的标记。
第三种可能性是使用更强大的解析器生成器来处理更多前瞻,例如野牛的%glr-parser
选项或btyacc