[英]Yacc reading only the first grammar rule
我有这个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它会抛出一个错误:意外的FOR期待INT或$ end所以它实际上只读取规则集中的第一条规则..此外,它一直显示当应用野牛命令时,无用的非终端和终端警告。
这个yacc文件有什么问题?
麻烦的是规则:
program
: definitions
;
definitions
: definition
| definitions definition
;
definition:
| declaration
;
declarations
: /* null */
| declarations declaration
;
declaration
: INT declarator_list SEM
;
只允许声明; 什么都不允许statements
作为program
一部分。 你的FOR不是声明,所以语法拒绝它。
“无用的非终端”警告试图告诉你:
你有很大的时间; 你的语法有一个错误。 您曾尝试为某些制作编写规则,但您永远不会让它被识别,因此添加它没有意义。
或者左右......
也许你需要:
program
: definitions statements
;
或许你也需要允许函数作为定义,然后FOR语句将成为函数体的一部分。
向我的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 ;
这应该让你超越眼前的问题和一些新的问题:-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.