2016-04-14 79 views
1

我正在编写一个简单的Yacc程序,它接收程序代码并返回int和double类型的变量和函数的计数。Yacc - 当存在匹配规则时,一行返回语法错误

我遇到了一个奇怪的问题,即当有一条匹配的规则时,程序返回一个语法错误,但是这条线拾起了一条不同的规则。我带来了显示了这个错误代码的组成部分:(如果你看到未使用的变量,那是因为我删除了不相关的这种错误的其他部分)

YACC代码

%{ 
#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一个),因为该计划似乎选择int变量声明的规则,当它看到“(”令牌,生成语法错误失败。

调试错误消息指出...

.... 
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 
.... 

任何人都可以请指出我做错了什么?谢谢。

+2

难道你不会得到关于转变/减少冲突和无用生产的警告吗?你需要解决这些问题。 – rici

回答

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_KEYWORDDOUBLE_KEYWORD,它不知道它是否需要转移或减少(即它不知道这是否是一个声明或者一个数据类型)。默认情况下,yacc将会改变。

此外,在您的function_declaration_statement中,您首先有一个datatypeyacc会减少它(因为它是唯一的生产规则)。然后它会有像INT_KEYWORD VARIABLE(或DOUBLE_KEYWORD),所以它会认为它是一个int_declaration_statement ...语法错误发生时yacc遇到'('

要解决这个问题,您可以删除function_declaration_statement并在int_declaration_statement(和double)中添加一行。喜欢的东西:

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++;} 
         ; 

,将删除你转移/减少冲突,给你你想要的结果,例如:

--- ~ » ./a.out 
int a; 
int a[3]; 
int a(int a) { 
#int variable=1, #double variable=0#array=1 
#function=1 

希望它能帮助。