2016-04-14 2 views
1

Я пишу простую программу Yacc, которая принимает программный код и возвращает подсчеты int и двойного типа переменных и функций.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_KEYWORD или DOUBLE_KEYWORD, он не знает, нужно ли перенести или уменьшить (т.е. он не знает, если это объявление или просто тип данных). По умолчанию yacc сдвинется.

Кроме того, в вашем function_declaration_statement у вас есть datatype: yacc уменьшит его (поскольку это единственное производственное правило для него). Тогда у него будет что-то вроде 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 

Надеется, что это помогает.