我有这个yacc文件
%error-verbose
%token END
%token ID
%token INT
%token IF
%token ELSE
%token WHILE
%token FOR
%token BREAK
%token CONTINUE
%token RETURN
%token SEM
%token LPAR
%token RPAR
%token PLUS
%token MINUS
%token MULT
%token DIV
%token MOD
%token GT
%token LT
%token GTE /* >= */
%token LTE /* <= */
%token EQUAL /* == */
%token NEQUAL /* != */
%token AND
%token OR
%token EQ
%token COM
%token PRINT
%token READ
%token FLOAT
%token LABR
%token RABR
%token NUM
%token STR
/*
* precedentce tabLTE
*/
%right EQ PE ME TE DE RE
%left OR
%left AND
%left EQUAL NEQUAL
%left LT GT GTE LTE
%left PLUS MINUS
%left MULT DIV MOD
%right PP MM
%{
#include<stdio.h>
extern char *yyname;
extern char *yytext;
extern int yylineno;
void yyerror(char const *msg)
{
fprintf(stderr,"%s:%d:%s\n", yyname,yylineno,msg);
}
%}
%%
program
: definitions
;
definitions
: definition
| definitions definition
;
definition:
| declaration
;
declarations
: /* null */
| declarations declaration
;
declaration
: INT declarator_list SEM
;
declarator_list
: ID
| declarator_list COM ID
;
statements
: /* null */
| statements statement
;
statement
: expression SEM
| SEM /* null statement */
| if_prefix statement
| if_prefix statement ELSE statement
| loop_prefix statement
;
if_prefix
: IF LPAR expression RPAR
;
loop_prefix
: WHILE LPAR expression RPAR
;
expression
: binary
| expression COM binary
;
binary
: ID
| LPAR expression RPAR
| ID LPAR optional_argument_list RPAR
| binary PLUS binary
| binary MINUS binary
| binary MULT binary
| binary DIV binary
| binary MOD binary
| binary GT binary
| binary LT binary
| binary GTE binary
| binary LTE binary
| binary EQUAL binary
| binary NEQUAL binary
| binary AND binary
| binary OR binary
| ID EQ binary
| ID PE binary
| ID ME binary
| ID TE binary
| ID DE binary
| ID RE binary
;
optional_argument_list
: /* no actual arguments */
| argument_list
;
argument_list
: binary
| argument_list COM binary
;
%%
#include <stdlib.h>
extern FILE *yyin;
int main(int argc, char **argv)
{
int ok;
if (argc != 2) {
fprintf(stderr, "%s: Wrong arguments\n", argv[0]);
return EXIT_FAILURE;
}
yyname = argv[1];
if ((yyin = fopen(yyname, "r")) == NULL) {
fprintf(stderr, "%s: %s: Invalid file\n", argv[0], argv[1]);
return EXIT_FAILURE;
}
return (yyparse() ? EXIT_SUCCESS : EXIT_FAILURE);
}
输入时 int x; 一切正常,但输入的内容不是“INT” 让我们说FOR它会抛出一个错误: 意外的期待INT或$结束 所以它实际上只是从规则集中读取第一条规则。 此外,当应用野牛命令时,它会不断显示无用的非终端和终端警告。
这个yacc文件出了什么问题?
答案 0 :(得分:2)
问题在于规则:
program
: definitions
;
definitions
: definition
| definitions definition
;
definition:
| declaration
;
declarations
: /* null */
| declarations declaration
;
declaration
: INT declarator_list SEM
;
只允许声明;什么都不允许statements
作为program
的一部分。你的FOR不是声明,所以语法拒绝它。
“无用的非终端”警告试图告诉你:
你有很大的时间;你的语法有一个错误。你曾尝试为某些制作编写规则,但你永远不会让它被识别,所以没有必要添加它。
或者左右......
也许你需要:
program
: definitions statements
;
或许您也需要允许函数作为定义,然后FOR语句将成为函数体的一部分。
答案 1 :(得分:0)
向我的LL oracle询问你修改后的语法:
Out of 15 non-terminals, 14 are reachable, 1 are unreachable:
'declarations'
Circular symbols:
definitions
definitions
关于圆形符号的投诉意味着“定义”可以衍生出来。例如,'定义'可以产生'定义',但'定义'是可空的,因此'定义'只能产生自身,kinduva无限循环,很少有解析器生成器能够以任何合理的方式处理。换句话说,你已经将'定义'定义为可以为空的符号列表,那么你想要匹配多少个epsilons?无穷大怎么样? : - )
即使语法存在问题,这也是yacc / bison风格尝试生成某些解析器的缺点;如果你确切知道自己在做什么,那就很方便了,但其他方面却很困惑。
但是,关于如何处理语法循环的狭隘观点,它给你一个非常无用的(但是通过口香糖可编辑!)解析器。你怎么能让“定义”可以为空而不是“定义”? IOW:
definitions : | definitions definition ;
definition : declaration ;
尝试不在可空性之上叠加可空性。所以当你以后改为:
definition : declarations ;
不要让'声明'可以为空(这已经由'定义'处理为可空)。相反,将其更改为:
declarations : declaration | declarations declaration ;
这应该可以让你解决眼前的问题和一些新问题: - )