规则永远不会减少,理解为什么
rules are never reduced, understanding why
我正在学习使用YACC,有些错误我真的无法理解。我想知道为什么在尝试使用 .y 文件生成解析器时出现此错误。这是我的 .y 文件,它代表 Pascal 语言的上下文无关语法:
%%
Program : program ident ';' declaration_opc compound_stmt '.'
;
declaration_opc : var declaration_list
|
;
declaration_list : declaration ';' declaration_list
| declaration ';'
;
declaration : id_list ':' type
;
id_list : ident
| ident ',' id_list
;
type : integer
| BOOLEAN
;
proc_dec : proc_header forward ';'
| proc_header declaration_list compound_stmt
| func_header forward ';'
| func_header declaration_list compound_stmt
;
proc_header : procedure ident parametros ';'
;
func_header : function ident parametros : type
;
parametros : '(' param_list ')'
|
;
param_list : arg
| arg ';' param_list
;
arg : id_list ':' type
| var id_list ':' type
;
compound_stmt : begin statement_list end
;
statement_list : statement ';' statement_list
| statement
;
statement : ident attrib expression
| IF expression then statement
| IF expression then statement ELSE statement
| WHILE expression DO statement
| compound_stmt
| readln ident
| writeln print_list
|
;
print_list : literal print_list2
| expression print_list2
;
print_list2 : ',' print_list
|
;
expression : add_expression relop add_expression
| add_expression
;
relop : lessequal
| '<'
| '>'
| moreequal
| '='
| notequal
;
add_expression : add_expression addop term
;
addop : '+'
| '-'
| or
;
term : term mulop unary_exp
| unary_exp
;
mulop : '*'
| div
| mod
| and
;
unary_exp : not unary_exp
| factor
;
factor : '(' expression ')'
| ident
| num
| TRUE
| FALSE
;
%%
我总是这样:
byaccj: 19 rules never reduced
byaccj: 1 shift/reduce conflict.
有什么可能的解决方案?我发现其他人也有同样的错误,但我找不到对我的问题有用的东西。如果需要更多信息,我会提供。我还读到 'Rules never reduced' 错误意味着我的语法中的某些规则从未被使用过,但我无法用我的规则看到这一点。
文件不完整,因为有许多标记从未定义过(例如 BOOLEAN
)。如果完整,我们可以给出更好的答案。
一般来说,未reduced 的规则根本不会(就yacc 可以确定的而言)通过任何一系列步骤连接到开始状态。所以它们是您应该重新设计或移除的碎片。
以下是之前讨论过的几个地方:
- YACC rules not getting reduced
- YACC Rules not reduced
在您的情况下,规则 proc_dec
永远不会出现在任何其他规则的右侧,因此永远无法从您的起始符号 (Program
) 到达它。 Yacc 只是告诉你这个规则(以及它使用的所有规则,没有别的)是不可访问的。
通常,您想使用 -v
选项让 yacc 生成一个 y.output
文件,其中包含有关语法的详细信息。此文件将具体告诉您所有冲突和未使用的规则 -- 它们是什么以及它们是如何产生的 -- 而消息只是为您提供问题的摘要。
在这种情况下,您有两个基本的问题来源。一个是您根本没有在程序的语法中包含过程。你可能会用类似的东西来解决这个问题:
Program : program ident ';' declaration_opc procedures compound_stmt '.'
;
procedures: proc_dec
| procedures ';' proc_dec
;
[自从我写任何 Pascal 以来已经有一段时间了——顺便说一句,我不记得你是否真的需要分号来分隔程序,但如果不需要,删除它是微不足道的。]
第二个问题领域是 add_expression
的语法总是无限递归的:
add_expression : add_expression addop term
;
您没有包含任何内容来停止左侧的递归。你可能想要这样的东西:
add_expression : add_expression addop term
| term addop term
;
对于像 a + b - c
这样的表达式,它将匹配第一个替代项:(a + b)add_expression - addop cterm,第二个选项将用于仅匹配 a + b
部分,如:aterm +addop bterm.
我正在学习使用YACC,有些错误我真的无法理解。我想知道为什么在尝试使用 .y 文件生成解析器时出现此错误。这是我的 .y 文件,它代表 Pascal 语言的上下文无关语法:
%%
Program : program ident ';' declaration_opc compound_stmt '.'
;
declaration_opc : var declaration_list
|
;
declaration_list : declaration ';' declaration_list
| declaration ';'
;
declaration : id_list ':' type
;
id_list : ident
| ident ',' id_list
;
type : integer
| BOOLEAN
;
proc_dec : proc_header forward ';'
| proc_header declaration_list compound_stmt
| func_header forward ';'
| func_header declaration_list compound_stmt
;
proc_header : procedure ident parametros ';'
;
func_header : function ident parametros : type
;
parametros : '(' param_list ')'
|
;
param_list : arg
| arg ';' param_list
;
arg : id_list ':' type
| var id_list ':' type
;
compound_stmt : begin statement_list end
;
statement_list : statement ';' statement_list
| statement
;
statement : ident attrib expression
| IF expression then statement
| IF expression then statement ELSE statement
| WHILE expression DO statement
| compound_stmt
| readln ident
| writeln print_list
|
;
print_list : literal print_list2
| expression print_list2
;
print_list2 : ',' print_list
|
;
expression : add_expression relop add_expression
| add_expression
;
relop : lessequal
| '<'
| '>'
| moreequal
| '='
| notequal
;
add_expression : add_expression addop term
;
addop : '+'
| '-'
| or
;
term : term mulop unary_exp
| unary_exp
;
mulop : '*'
| div
| mod
| and
;
unary_exp : not unary_exp
| factor
;
factor : '(' expression ')'
| ident
| num
| TRUE
| FALSE
;
%%
我总是这样:
byaccj: 19 rules never reduced
byaccj: 1 shift/reduce conflict.
有什么可能的解决方案?我发现其他人也有同样的错误,但我找不到对我的问题有用的东西。如果需要更多信息,我会提供。我还读到 'Rules never reduced' 错误意味着我的语法中的某些规则从未被使用过,但我无法用我的规则看到这一点。
文件不完整,因为有许多标记从未定义过(例如 BOOLEAN
)。如果完整,我们可以给出更好的答案。
一般来说,未reduced 的规则根本不会(就yacc 可以确定的而言)通过任何一系列步骤连接到开始状态。所以它们是您应该重新设计或移除的碎片。
以下是之前讨论过的几个地方:
- YACC rules not getting reduced
- YACC Rules not reduced
在您的情况下,规则 proc_dec
永远不会出现在任何其他规则的右侧,因此永远无法从您的起始符号 (Program
) 到达它。 Yacc 只是告诉你这个规则(以及它使用的所有规则,没有别的)是不可访问的。
通常,您想使用 -v
选项让 yacc 生成一个 y.output
文件,其中包含有关语法的详细信息。此文件将具体告诉您所有冲突和未使用的规则 -- 它们是什么以及它们是如何产生的 -- 而消息只是为您提供问题的摘要。
在这种情况下,您有两个基本的问题来源。一个是您根本没有在程序的语法中包含过程。你可能会用类似的东西来解决这个问题:
Program : program ident ';' declaration_opc procedures compound_stmt '.'
;
procedures: proc_dec
| procedures ';' proc_dec
;
[自从我写任何 Pascal 以来已经有一段时间了——顺便说一句,我不记得你是否真的需要分号来分隔程序,但如果不需要,删除它是微不足道的。]
第二个问题领域是 add_expression
的语法总是无限递归的:
add_expression : add_expression addop term
;
您没有包含任何内容来停止左侧的递归。你可能想要这样的东西:
add_expression : add_expression addop term
| term addop term
;
对于像 a + b - c
这样的表达式,它将匹配第一个替代项:(a + b)add_expression - addop cterm,第二个选项将用于仅匹配 a + b
部分,如:aterm +addop bterm.