我已经为一种语言创建了一个编译器,该编译器具有以下语法,由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 个良性移位/减少错误
问题是,对于新规则,语法需要任意前瞻才能区分varDecl
和expStmt
。 这是因为LT
既是表达式的二元运算符,又指示参数化类型的tyargs
列表的开始。
一种可能的解决方法是引入一个新关键字来表示参数化类型或函数(如当前用于引入函数类型的FUN
关键字),这将允许解析器提前知道是将LT
视为运算符还是类型参数列表。 因此,您可以改为添加新规则,例如:
ty: TYPE ID tyargs
callExpr: CALL ID tyargs LPAREN expList RPAREN
另一种可能性是通过符号表使用词法分析器反馈 - 让词法分析器识别需要类型参数的标识符(通过在符号表中查找名称)并为它们返回不同的标记。
第三种可能性是使用更强大的解析器生成器,可以处理更多的前瞻,例如 bison 的%glr-parser
选项或 btyacc
好吧,没有人回答,但你使语法光荣地模棱两可。有两种可能的作品:
LT ID GT
ID LT ID GT
举一些例子:
<a>
b<a>
这些是tyargs
还是tyvars
还是callExp
的开始?你的语法说它们可以是两者兼而有之。因此,如果不对所使用的语言或规则进行一些更改,就很难使用 ml-yacc 等工具进行解析。
如果不进一步解释语言结构,您将很难使用 ml-yacc 编译它。有人可能会向您展示一种更好的方法来构建语法规则,以保持在此类工具的约束范围内。