在编译yacc文件时,出现移位/减少冲突。我似乎无法解决,那么如何找到它?错误指向第73行,这是auxVartSpec
生产定义的行,特别是第二生产auxVarSpec COMMA ID
的行,但是我已经为这些令牌设置了优先级。
%
%token <value> SEMICOLON BLANKID PACKAGE RETURN AND ASSIGN STAR COMMA DIV EQ GE GT LBRACE LE LPAR LSQ LT MINUS MOD NE NOT OR PLUS RBRACE RPAR RSQ ELSE FOR IF VAR INT FLOAT32 BOOL STRING PRINT PARSEINT FUNC CMDARGS RESERVED ID INTLIT REALLIT STRLIT
%type <node> Program Declarations VarDeclaration VarSpec Type FuncDeclaration FuncHeader Parameters FuncBody VarsAndStatements Statement ParseArgs FuncInvocation Expr auxDeclarations auxVarSpec auxParameters auxStatement auxFuncInvocation opcType opcParameters opcExpr opcFuncInvocation
%nonassoc IFX
%nonassoc ELSE
%left COMMA
%right ASSIGN
%left OR
%left AND
%left EQ NEQ
%left LT GT LEQ GEQ
%left PLUS MINUS
%left STAR DIV MOD
%right NOT
%%
Program: PACKAGE ID SEMICOLON Declarations
;
Declarations: auxDeclarations
auxDeclarations: %empty
| auxDeclarations VarDeclaration SEMICOLON
| auxDeclarations FuncDeclaration SEMICOLON
;
VarDeclaration: VAR VarSpec
| ID auxVarSpec Type
;
VarSpec: ID auxVarSpec Type
;
auxVarSpec: %empty
| auxVarSpec COMMA ID
;
Type: INT
| FLOAT32
| BOOL
| STRING
;
FuncDeclaration: FUNC FuncHeader FuncBody
;
FuncHeader: ID LPAR opcParameters RPAR opcType
;
opcType: %empty
| Type
;
Parameters: ID Type auxParameters
opcParameters: %empty
| Parameters
;
auxParameters: %empty
| auxParameters COMMA ID Type
;
FuncBody: LBRACE VarsAndStatements RBRACE
VarsAndStatements: VarsAndStatements SEMICOLON
| VarsAndStatements VarDeclaration SEMICOLON
| VarsAndStatements Statement SEMICOLON
| %empty
;
Statement: ID ASSIGN Expr
| LBRACE auxStatement RBRACE
| IF Expr LBRACE auxStatement RBRACE %prec IFX
| IF Expr LBRACE auxStatement RBRACE ELSE LBRACE auxStatement RBRACE
| FOR opcExpr LBRACE auxStatement RBRACE
| RETURN opcExpr
| FuncInvocation
| ParseArgs
| PRINT LPAR Expr RPAR
| PRINT LPAR STRLIT RPAR
;
opcExpr: %empty
| Expr
;
auxStatement: %empty
| auxStatement Statement SEMICOLON
;
ParseArgs: ID COMMA BLANKID ASSIGN PARSEINT LPAR CMDARGS LSQ Expr RSQ RPAR
FuncInvocation: ID LPAR opcFuncInvocation RPAR
auxFuncInvocation: %empty
| COMMA Expr
;
opcFuncInvocation: %empty
| Expr auxFuncInvocation
;
Expr: Expr OR Expr
| Expr AND Expr
| Expr LT Expr
| Expr GT Expr
| Expr EQ Expr
| Expr NE Expr
| Expr LE Expr
| Expr GE Expr
| Expr PLUS Expr
| Expr MINUS Expr
| Expr DIV Expr
| Expr MOD Expr
| NOT Expr
| MINUS Expr
| PLUS Expr
| INTLIT
| REALLIT
| ID
| FuncInvocation
| LPAR Expr RPAR
%%
答案 0 :(得分:2)
您看到的错误消息表示文件中存在73个移位/减少冲突,而不是在第73行存在移位/减少冲突。(移位/减少冲突对应于解析器状态,而不是行号。您可以通过使用-v
命令行选项生成报告文件来查看冲突的位置。)
在这些冲突中,有72个是简单拼写错误的结果。您的语法在NE
的生产中使用标记名称GE
,LE
和Expr
,但是您的优先声明是针对标记NEQ
,{{1}的}和GEQ
。这将产生有关未使用令牌的警告。 (LEQ
和STAR
也未使用。我想您不小心忽略了RESERVED
乘法规则。)
剩余的冲突位于状态45中,其项目为(来自报告文件):
Expr
(每个产品所附的数字是产品编号,而不是生产线编号。产品编号位于报告文件的顶部,但是由于也列出了产品,因此它们在这里没有太大区别。每个作品中的State 45
7 VarDeclaration: ID . auxVarSpec Type
29 Statement: ID . ASSIGN Expr
43 ParseArgs: ID . COMMA BLANKID ASSIGN PARSEINT LPAR CMDARGS LSQ Expr RSQ RPAR
44 FuncInvocation: ID . LPAR opcFuncInvocation RPAR
表示前瞻点。除非您指定.
)
冲突与前瞻--report=itemset
:
COMMA
因此,在这种状态下,可以移动逗号以继续生产43。或者可以使用规则9(COMMA shift, and go to state 68
COMMA [reduce using rule 9 (auxVarSpec)]
)触发减少。这种减少是可能的,因为存在一个以auxVarSpec: %empty
作为下一个非终结符的项目,如果auxVarSpec
不为空,则以逗号开头。
更明确地说,问题在于列表auxVarSpec
中可能有一个VarsAndStatements
(这是一个声明),但也可能有一个VarDeclaration
(这是一个声明一份声明)。因此ParseArgs
和ParseArgs
都是可能的,并且它们都可以以VarDeclaration
开头,但是其中之一需要减少ID COMMA
和ID
之间的空白右侧。 COMMA
。
没有额外的先行标记就无法解决该冲突:如果逗号后跟另一个ID
,则解析器将查看VarDeclaration
,而如果逗号后跟{ {1}}(无论是什么),那么它必须是BLANKID
。
尽管不能按书面方式解决冲突,但可以通过推迟移位/减少决策的常规技术来避免冲突。特别是,有必要区分三种情况:
ParseArgs
一种方法是添加一个明显多余的产品:
ID Type /* VarDeclaration */
ID COMMA ID ... /* VarDeclaration */
ID COMMA BLANKID ... /* ParseArgs */