我正在编写一个简单的Yacc程序,它接受程序代码并返回int和double类型的变量和函数的计数。
我遇到了一个奇怪的问题,即如果该行有匹配规则,程序会返回语法错误,但该行会选择不同的规则。我带来了显示此错误的代码组件:(如果您看到未使用的变量,那是因为我删除了与此错误无关的其他部分)
yacc code
%{
#define YYDEBUG 1
#include <stdio.h>
#include <stdlib.h>
int func_count=0;
int int_count=0;
int char_count=0;
int double_count=0;
int float_count=0;
int pointer_count=0;
int array_count=0;
int condition_count=0;
int for_count=0;
int return_count=0;
int numeric_count=0;
%}
%token INT_KEYWORD DOUBLE_KEYWORD CHAR_KEYWORD RETURN_KEYWORD FLOAT_KEYWORD IF_KEYWORD VARIABLE OPERATOR COMPARE DIGIT FOR_KEYWORD POINTER_VARIABLE
%start program
%%
program:
program statement '\n'
|
;
statement:
declaration_statement |
function_declaration_statement {func_count++;}
;
function_declaration_statement:
datatype VARIABLE '(' datatype VARIABLE ')' '{'
;
declaration_statement:
int_declaration_statement |
double_declaration_statement
;
int_declaration_statement:
INT_KEYWORD VARIABLE '[' DIGIT ']' ';'{array_count++;}
|
INT_KEYWORD VARIABLE ';' {int_count++;}
|
INT_KEYWORD VARIABLE '=' DIGIT ';' {int_count++;}
double_declaration_statement:
DOUBLE_KEYWORD VARIABLE '[' DIGIT ']' ';' {array_count++;}
|
DOUBLE_KEYWORD VARIABLE ';' {double_count++;}
|
DOUBLE_KEYWORD VARIABLE '=' DIGIT ';' {double_count++;}
datatype:
INT_KEYWORD
|
DOUBLE_KEYWORD
|
CHAR_KEYWORD
|
FLOAT_KEYWORD
;
%%
int yyerror(char *s){
fprintf(stderr,"%s\n",s);
return 0;
}
int main (void){
yydebug=1;
yyparse();
printf("#int variable=%d, #double variable=%d",int_count,double_count);
printf("#array=%d\n",array_count);
printf("#function=%d\n",func_count);
}
法
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
void yyerror(char *);
%}
%%
"int" {return INT_KEYWORD;}
"double" {return DOUBLE_KEYWORD;}
"char" {return CHAR_KEYWORD;}
"float" {return FLOAT_KEYWORD;}
"if" {return IF_KEYWORD;}
"for" {return FOR_KEYWORD;}
"return" {return RETURN_KEYWORD;}
"==" {return COMPARE;}
">" {return COMPARE;}
"<" {return COMPARE;}
">=" {return COMPARE;}
"<=" {return COMPARE;}
"+" {return OPERATOR;}
"-" {return OPERATOR;}
"/" {return OPERATOR;}
"*" {return OPERATOR;}
"%" {return OPERATOR;}
[0-9]+ {return DIGIT;}
[a-z]+ {return VARIABLE;}
"*"" "?[a-zA-Z]+ {return POINTER_VARIABLE;}
"[" {return *yytext;}
"=" {return *yytext;}
"]" {return *yytext;}
[;\n(){}] {return *yytext;}
[ \t] ;
. {printf("%s\n",yytext); yyerror("invalid charactor");}
%%
int yywrap(void){
return 1;
}
测试文件:
int a;
int a[3];
int a(int a) {
预期输出
#int variable=1, #double variable=0 #array=1
#function=1
但是它在第三行失败了,int a(int a),因为程序似乎选择了int变量声明规则,当它看到&#39;(&#39;令牌,生成语法时失败)错误。
调试错误消息显示......
....
Reading a token: Next token is token INT_KEYWORD ()
Shifting token INT_KEYWORD ()
Entering state 3
Reading a token: Next token is token VARIABLE ()
Shifting token VARIABLE ()
Entering state 13
Reading a token: Next token is token '(' ()
syntax error
....
有谁可以请指出我做错了什么?谢谢。
答案 0 :(得分:1)
你的语法中有两个转移/减少冲突。您可以看到yacc
生成的输出文件中的位置:
State 3
8 int_declaration_statement: INT_KEYWORD . VARIABLE '[' DIGIT ']' ';'
9 | INT_KEYWORD . VARIABLE ';'
10 | INT_KEYWORD . VARIABLE '=' DIGIT ';'
14 datatype: INT_KEYWORD .
VARIABLE shift, and go to state 13
VARIABLE [reduce using rule 14 (datatype)]
State 4
11 double_declaration_statement: DOUBLE_KEYWORD . VARIABLE '[' DIGIT ']' ';'
12 | DOUBLE_KEYWORD . VARIABLE ';'
13 | DOUBLE_KEYWORD . VARIABLE '=' DIGIT ';'
15 datatype: DOUBLE_KEYWORD .
VARIABLE shift, and go to state 14
VARIABLE [reduce using rule 15 (datatype)]
此处,当yacc
遇到INT_KEYWORD
或DOUBLE_KEYWORD
时,它不知道是否需要转移或减少(即它不知道它是否是声明或只是一种数据类型)。默认情况下,yacc
会移动。
此外,在您的function_declaration_statement
中,您首先拥有datatype
:yacc
会减少它(因为它是唯一的生产规则)。然后它会有类似INT_KEYWORD VARIABLE
(或DOUBLE_KEYWORD
)的内容,因此会认为它是int_declaration_statement
...当yacc
遇到{{1}时会发生语法错误}}
要解决此问题,您可以移除'('
并在function_declaration_statement
上添加一行(并加倍)。类似的东西:
int_declaration_statement
这将删除您转移/减少冲突并为您提供所需的结果,例如:
statement: int_declaration_statement
| double_declaration_statement
;
int_declaration_statement: INT_KEYWORD VARIABLE '[' DIGIT ']' ';'{array_count++;}
| INT_KEYWORD VARIABLE ';' {int_count++;}
| INT_KEYWORD VARIABLE '=' DIGIT ';' {int_count++;}
| INT_KEYWORD VARIABLE '(' datatype VARIABLE ')' '{' {func_count++;}
;
希望它有所帮助。