我必须手动修复 Yacc 中的 shift/reduce 个问题吗?
Do I have to fix shift/reduce problems in Yacc manually?
我正在努力解决我语法中的两个 shift/reduce 问题。我无法在任何地方找到解决方案。我看到 Yacc 显然更喜欢这种转变,但如果是这样,那为什么我的不编译呢?我知道其中一个问题是悬而未决的 if-else,但另一个我不知道。我更希望 Yacc 为我处理它。错误消息显示 2 shift reduce conflicts
void yyerror (char *s);
#include <stdio.h>
#include <stdlib.h>
int yylex();
extern int yytext[];
extern FILE *yyin;
%}
%start program
%token LTE GTE BEQUALS NOTEQUALS BEGCOMMENT ENDCOMMENT COMMENT GREATER LESS COMMA PLUS SUB MULT DIV EQUAL LP RP LB RB LC RC SEMICOLON INT FLOAT VOID IF WHILE RETURN ID NUM
%nonassoc IFX
%nonassoc ELSE
%%
program : declaration_list { printf("\nACCEPT\n"); };
declaration_list : declaration_list declaration
| declaration
;
declaration : var_declaration
| fun_declaration
;
var_declaration : type_specifier ID SEMICOLON
| type_specifier ID LB NUM RB SEMICOLON
;
type_specifier : INT
| VOID
;
fun_declaration : type_specifier ID LP params RP compound_stmt ;
params : param_list | VOID ;
param_list : param_list COMMA param
| param
;
param : type_specifier ID
| type_specifier ID LB RB
;
compound_stmt : LC local_declarations statement_list RC
;
local_declarations : local_declarations var_declaration
| /* empty */ ;
statement_list : statement_list statement
| /* empty */ ;
statement : expression_stmt
| compound_stmt
| selection_stmt
| iteration_stmt
| return_stmt ;
expression_stmt : expression SEMICOLON
| SEMICOLON
;
selection_stmt : ifsubroutine statement
| ifsubroutine statement ELSE
;
ifsubroutine : IF LP expression RP
;
iteration_stmt : whilesubroutine LP expression RP statement
;
whilesubroutine : WHILE ;
return_stmt : RETURN SEMICOLON
| RETURN expression SEMICOLON
;
expression : var EQUAL expression
| simple_expression
;
var : ID
| ID LB expression RB
;
simple_expression : additive_expression relop additive_expression
| additive_expression
;
relop : LTE | LESS | GREATER | GTE | EQUAL| NOTEQUALS ;
additive_expression : additive_expression addop term
| term
;
addop : PLUS
| SUB
;
term : term mulop factor
| factor
;
mulop : MULT
| DIV
;
factor : LP expression RP
| var
| call
| NUM
;
call : ID LP args RP
;
args : arg_list | /* empty */ ;
arg_list : arg_list COMMA expression
| expression
;
%%
int main(int argc, char *argv[])
{
yyin = fopen(argv[1], "r");
if (!yyin)
{
printf("no file\n");
exit(0);
}
yyparse();
}
void yyerror(char *s)
{
printf("\nREJECT\n");
// printf("error from yyerror\n");
exit(0);
}
int yywrap()
{
// printf("in yywarp\n");
exit(0);
}```
您的 yywrap()
实现调用 exit()
。这意味着只要扫描器看到文件末尾,应用程序就会终止。所以解析器将无法完成它的工作。
一般来说,您应该在 (f)lex 文件中使用 %option noyywrap
,以避免需要提供 yywrap
。或者使用 -lfl
中的默认实现。但是如果硬要实现的话,应该return1表示没啥可看的了
此外,extern int yytext[];
是不必要的,因为您没有在解析器的任何地方引用 yytext
。而且你不应该在你的解析器中引用 yytext
;这样的用法几乎总是错误的。但是,如果您确实使用了 yytext
,则声明将是错误的:它是指向 char
(而不是 int
)的 指针 (不是数组)。您的 C 编译器可能不会标记该错误。
我正在努力解决我语法中的两个 shift/reduce 问题。我无法在任何地方找到解决方案。我看到 Yacc 显然更喜欢这种转变,但如果是这样,那为什么我的不编译呢?我知道其中一个问题是悬而未决的 if-else,但另一个我不知道。我更希望 Yacc 为我处理它。错误消息显示 2 shift reduce conflicts
void yyerror (char *s);
#include <stdio.h>
#include <stdlib.h>
int yylex();
extern int yytext[];
extern FILE *yyin;
%}
%start program
%token LTE GTE BEQUALS NOTEQUALS BEGCOMMENT ENDCOMMENT COMMENT GREATER LESS COMMA PLUS SUB MULT DIV EQUAL LP RP LB RB LC RC SEMICOLON INT FLOAT VOID IF WHILE RETURN ID NUM
%nonassoc IFX
%nonassoc ELSE
%%
program : declaration_list { printf("\nACCEPT\n"); };
declaration_list : declaration_list declaration
| declaration
;
declaration : var_declaration
| fun_declaration
;
var_declaration : type_specifier ID SEMICOLON
| type_specifier ID LB NUM RB SEMICOLON
;
type_specifier : INT
| VOID
;
fun_declaration : type_specifier ID LP params RP compound_stmt ;
params : param_list | VOID ;
param_list : param_list COMMA param
| param
;
param : type_specifier ID
| type_specifier ID LB RB
;
compound_stmt : LC local_declarations statement_list RC
;
local_declarations : local_declarations var_declaration
| /* empty */ ;
statement_list : statement_list statement
| /* empty */ ;
statement : expression_stmt
| compound_stmt
| selection_stmt
| iteration_stmt
| return_stmt ;
expression_stmt : expression SEMICOLON
| SEMICOLON
;
selection_stmt : ifsubroutine statement
| ifsubroutine statement ELSE
;
ifsubroutine : IF LP expression RP
;
iteration_stmt : whilesubroutine LP expression RP statement
;
whilesubroutine : WHILE ;
return_stmt : RETURN SEMICOLON
| RETURN expression SEMICOLON
;
expression : var EQUAL expression
| simple_expression
;
var : ID
| ID LB expression RB
;
simple_expression : additive_expression relop additive_expression
| additive_expression
;
relop : LTE | LESS | GREATER | GTE | EQUAL| NOTEQUALS ;
additive_expression : additive_expression addop term
| term
;
addop : PLUS
| SUB
;
term : term mulop factor
| factor
;
mulop : MULT
| DIV
;
factor : LP expression RP
| var
| call
| NUM
;
call : ID LP args RP
;
args : arg_list | /* empty */ ;
arg_list : arg_list COMMA expression
| expression
;
%%
int main(int argc, char *argv[])
{
yyin = fopen(argv[1], "r");
if (!yyin)
{
printf("no file\n");
exit(0);
}
yyparse();
}
void yyerror(char *s)
{
printf("\nREJECT\n");
// printf("error from yyerror\n");
exit(0);
}
int yywrap()
{
// printf("in yywarp\n");
exit(0);
}```
您的 yywrap()
实现调用 exit()
。这意味着只要扫描器看到文件末尾,应用程序就会终止。所以解析器将无法完成它的工作。
一般来说,您应该在 (f)lex 文件中使用 %option noyywrap
,以避免需要提供 yywrap
。或者使用 -lfl
中的默认实现。但是如果硬要实现的话,应该return1表示没啥可看的了
此外,extern int yytext[];
是不必要的,因为您没有在解析器的任何地方引用 yytext
。而且你不应该在你的解析器中引用 yytext
;这样的用法几乎总是错误的。但是,如果您确实使用了 yytext
,则声明将是错误的:它是指向 char
(而不是 int
)的 指针 (不是数组)。您的 C 编译器可能不会标记该错误。