规则永远不会减少,理解为什么

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.