You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

YACC规则未被归约,出现无用非终结符与无用规则错误求解

YACC中「无用非终结符」与「无用规则」问题排查

问题描述

正在学习使用YACC,遇到了「无用非终结符」和「无用规则」两类错误。查阅资料得知这类错误通常由规则不可达导致,但反复检查后仍未找到问题,看起来所有规则的非终结符都出现在产生式两侧。以下是YACC代码及终端报错信息:

YACC代码

%{

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

extern int nLineas;

void yyerror(const char* msg) {
    fprintf(stderr, "%s\n", msg);
}
int yylex(void);
FILE *yyin;

%}

%start programa

%union {
    int tipo;
    char nombre[30];
}

%token <tipo> NUM
%token CARACTER
%token CADENA
%token <nombre> ID
%token INT
%token DOUBLE
%token CHAR
%token FLOAT
%token IF
%token MAIN
%token ELSE
%token SCANF
%token PRINTF
%token DEFINE
%token INCLUDE
%token FOR
%token WHILE
%token DO
%token IGUAL
%token DIFERENTE
%token MAYOR
%token MENOR
%token ESIGUAL
%token ESDIFERENTE
%token MAYORIGUAL
%token MENORIGUAL
%token '(' ')'

%left '+' '-'
%left '*' '/' '<' '>'
//%left ">=" "<=" "==" "!=" "&&" "||" "!"
%left UNARIO

%%
//PROGRAMA
programa: DECLARACIONCONSTANTES DECLARACIONVARIABLES FUNCIONMAIN {printf("\nTodo correcto numero de lineas %d.\n",nLineas);}
    ;
//SECCIONES DEL PROGRAMA
//Declaracion de constantes
DECLARACIONCONSTANTES:          /*Vacia*/
                            |DECLARACIONCONSTANTE
                            DECLARACIONCONSTANTES
                            ;
DECLARACIONCONSTANTE:           '#' DEFINE ID NUM {printf("\nDeclaracion constante númerica.\n\n");}
                                |'#' DEFINE ID '"' CADENA '"' {printf("\nDeclaracion constante cadena.\n\n");}
                                //'#' DEFINE ID "'"  "'" {printf("Declaracion constante cadena.\n");} Ver como hacer letra sin que lo incluyan en otro tipo
                                ;

//Declaracion de variables
DECLARACIONVARIABLES:           /*Vacia*/
                                |DECLARACIONVARIABLE
                                DECLARACIONVARIABLES
                                ;
DECLARACIONVARIABLE:            INT ID ';' {printf("\nDeclaracion variable int.\n\n");}
                                |FLOAT ID ';' {printf("\nDeclaracion de variable float.\n\n");}
                                |CHAR ID ';' {printf("\nDeclaracion de variable char.\n\n");}
                                |CHAR ID '[' NUM ']' ';' {printf("\nDeclaracion de variable cadena de caracteres.\n\n");}
                                ;

//Funcion Main

FUNCIONMAIN:                    CABECERAMAIN '{' DECLARACIONVARIABLES INSTRUCCIONES '}'
                                ;
            
CABECERAMAIN:                   MAIN '(' ')' {printf("\nCabecera main.\n\n");}
                                ;

INSTRUCCIONES:                  /*Vacio*/
                                |INSTRUCCION
                                INSTRUCCIONES
                                ;
                
INSTRUCCION:                    DECLARACIONVARIABLES
                                |ID '+' '+' ';' {printf("\nInstruccion -> incremento.\n\n");}
                                |ID '-' '-' ';' {printf("\nInstruccion -> decremento.\n\n");}
                                |ASIGNACION
                                |VISUALIZACION
                                |CONDICIONAL
                                |MIENTRAS
                                |LECTURA
                                |EXPRESION
                                ;

CONDICIONAL:                    IF '(' EXPRESION ')' '{' INSTRUCCIONES '}' {printf("\nInstruccion condicional -> estructura if.\n\n");}
                                |IF '(' EXPRESION ')' '{' INSTRUCCIONES '}' ELSE '{' INSTRUCCIONES '}' {printf("\nInstruccion condicional -> estructura if/else.\n\n");}
                                ;
        
MIENTRAS:                       WHILE '(' EXPRESION ')' '{' INSTRUCCIONES '}' {printf("\nInstruccion condicional mientras -> estructura while.\n\n");}

ASIGNACION:                     ID IGUAL NUM ';' {printf("\nInstrucción de asignacion: idVariable ->expresion numerica.\n\n");}
                                |ID IGUAL CADENA ';' {printf("\nInstrucción de asignación: idVariable -> cadena.\n\n");}
                                //|ID '=' '"'  '"' {printf("Instrucción de asignación: idVariable -> cadena\n");} Ver como hacer letra sin que lo incluyan en otro tipo
                                ;
            
VISUALIZACION:                  PRINTF '(' ID ')' ';' {printf("\nInstruccion de visualizacion -> printf de una variable.\n\n");}
                                |PRINTF '(' CADENA ')' ';' {printf("\nInstruccion de visualizacion -> printf de una cadena.\n\n");}
                                ;
                
LECTURA:                        SCANF '(' VARIABLE ')' ';' {printf("\nInstruccion  de lectura -> scanf.\n\n");}

EXPRESION:                      VARIABLE OP_BOOLEANOS VARIABLE {printf("\nExpresion -> booleana.\n\n");}
                                |VARIABLE OP_NUMERICOS VARIABLE {printf("\nExpresion -> numerica.\n\n");}
                                ;

VARIABLE:                       TERM VARIABLE
                                ;

TERM:                           NUM
                                |CADENA
                                |ID
                                |OP_NUMERICOS
                                |OP_BOOLEANOS
                                |',' 
                                |'('
                                |')'
                                ;
    
OP_BOOLEANOS:                   '&&'
                                |'||'
                                |IGUAL
                                |DIFERENTE
                                |MAYOR
                                |MENOR
                                |ESIGUAL
                                |ESDIFERENTE
                                |MAYORIGUAL
                                |MENORIGUAL
                                ;

OP_NUMERICOS:                   '+'
                                |'-'
                                |'*'
                                |'/'
                                ;
                
                            
%%

int main()
{
    yyin = fopen("Pruebas.c", "r");
    if(yyin == NULL){
        printf("ERROR de apertura de fichero.\n");
        return 1;
    }
    yyparse();
    return 0;
}

终端报错信息

yacc.y: warning: 8 useless nonterminals and 33 useless rules
yacc.y:93.1-11: warning: useless nonterminal: CONDICIONAL
yacc.y:97.1-8: warning: useless nonterminal: MIENTRAS
yacc.y:108.1-7: warning: useless nonterminal: LECTURA
yacc.y:93.40-48: warning: useless nonterminal: EXPRESION
yacc.y:108.43-50: warning: useless nonterminal: VARIABLE
yacc.y:114.33-36: warning: useless nonterminal: TERM
yacc.y:110.42-53: warning: useless nonterminal: OP_BOOLEANOS
yacc.y:111.43-54: warning: useless nonterminal: OP_NUMERICOS
yacc.y:93.33-135: warning: useless rule: CONDICIONAL: IF '(' EXPRESION ')' '{' INSTRUCCIONES '}'
yacc.y:94.34-168: warning: useless rule: CONDICIONAL: IF '(' EXPRESION ')' '{' INSTRUCCIONES '}' ELSE '{' INSTRUCCIONES '}'
yacc.y:97.33-150: warning: useless rule: MIENTRAS: WHILE '(' EXPRESION ')' '{' INSTRUCCIONES '}'

问题分析与修复

核心原因

报错的根源是**VARIABLE规则存在无限递归,无法推导到合法的终结符序列**:

VARIABLE: TERM VARIABLE ;

这个规则要求VARIABLE必须是TERM后紧跟另一个VARIABLE,没有终止条件,永远无法生成只包含终结符的串。导致依赖VARIABLE的EXPRESION无法被正确推导,进而所有依赖EXPRESION的规则(如CONDICIONAL、MIENTRAS)以及依赖VARIABLE的LECTURA都变成不可达,被标记为无用。

另外TERM规则中包含了运算符、括号、逗号等非变量元素,不符合语法逻辑,也会影响推导的合法性。

修复步骤

  1. 修正VARIABLE规则,添加终止条件:
VARIABLE: TERM 
        | TERM VARIABLE 
        ;

这样VARIABLE可以是单个TERM,或者TERM后跟VARIABLE,能够正常终止递归推导。

  1. 调整TERM规则,只保留合法的表达式单元:
TERM: NUM 
    | CADENA 
    | ID 
    | '(' EXPRESION ')'  // 支持括号包裹表达式,符合常规语法
    ;

移除运算符、逗号等不属于表达式单元的元素,确保TERM代表合法的变量或值。

  1. 优化EXPRESION规则(可选):
    添加单个VARIABLE作为合法表达式的选项,让语法更健壮:
EXPRESION: VARIABLE OP_BOOLEANOS VARIABLE 
         | VARIABLE OP_NUMERICOS VARIABLE 
         | VARIABLE  // 单个变量/值也是合法表达式
         ;

完成以上修改后,重新编译YACC代码,「无用非终结符」和「无用规则」的警告会消失。

内容的提问来源于stack exchange,提问作者Péritas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:27:13