2016-04-14 9 views
1

プログラムコードを受け取り、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); 


} 

のyaccコード(あなたは未使用の変数が表示された場合、私はこのエラーに関係のない他の部分を削除したため、それはだ)LEX

%{ 
#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 a(int a)の3行目で失敗し、 '('トークンが構文エラーを生成しています。

デバッグエラーメッセージが言う...

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

文法には2つのシフト/リダクションの競合があります。 INT_KEYWORDまたはDOUBLE_KEYWORDに遭遇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によって生成された出力ファイルに場所を確認することができます宣言または単なるデータ型)。デフォルトでは、yaccがシフトします。

また、function_declaration_statementには、datatypeyaccがあります(それが唯一の制作ルールであるため)。それでINT_KEYWORD VARIABLE(またはDOUBLE_KEYWORD)のようになるので、それはint_declaration_statementだと思うでしょう... yacc'('に遭遇すると構文エラーが起こります。

これを解決するには、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++;} 
         ; 

:ような何か

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

はそれがお役に立てば幸いです。

関連する問題