2017-02-13 17 views
0

Я пытаюсь разобрать набор арифметических выражений из .txt-файла. (по одному в каждой строке). Я могу получить правильную логику для первой строки, но парсер дает 0 для второго выражения. Более того, я хочу напечатать всю строку на выходе, но путаюсь с того, с чего начать.Yacc не разбирает второе выражение в txt-файле

Lex

%{ 
#include <stdio.h> 
#include "y.tab.h" 
int yylval; /*declared extern by yacc code. used to pass info to yacc*/ 
%} 

letter [A-Za-z] 
digit ([0-9])* 
op  "+"|"*"|"("|")"|"/"|"-" 
ws  [ \t\n\r]+$ 
other . 

%% 

{ws} { /*Nothing*/ } 
{digit} { yylval = atoi(yytext); return NUM;} 
{op} { return yytext[0];} 
{other} { printf("bad %c bad %d \n",*yytext,*yytext); return '?'; } 

%% 

Yacc

%{ 
#include <stdio.h> 
#include <string.h> 
#define YYSTYPE int /* the attribute type for Yacc's stack */ 
extern int yylval;  /* defined by lex, holds attrib of cur token */ 
extern char yytext[]; /* defined by lex and holds most recent token */ 
extern FILE * yyin; /* defined by lex; lex reads from this file */ 
%} 

%token NUM 

%% 
Calc : Expr   {printf(" = %d\n",$1);} 
    | Calc Expr   {printf(" = %d\n",$1);} 
    ; 
Expr : Expr '+' Expr { $$ = $1 + $3; } 
    | Expr '-' Expr  { $$ = $1 - $3; } 
    | Expr '*' Expr  { $$ = $1 * $3; } 
    | Expr '/' Expr  { if($3==0) 
          yyerror("Divide by Zero Encountered."); 
         else 
          $$ = $1/$3;  
         } 
    | '-' Expr   { $$ = -$2;  } 
    | Fact    { $$=$1;   } 
    ;  
Fact : '(' Expr ')' { $$ = $2;  } 
    | Id     { $$ = $1;  } 
    ; 
Id : NUM   { $$ = yylval; } 
    ; 

%% 

void yyerror(char *mesg); /* this one is required by YACC */ 

main(int argc, char* *argv){ 
char ch,c; 
FILE *f;  
if(argc != 2) {printf("useage: calc filename \n"); exit(1);} 
if(!(yyin = fopen(argv[1],"r"))){ 
     printf("cannot open file\n");exit(1); 
} 
yyparse(); 
} 

void yyerror(char *mesg){ 
printf("Bad Expression : %s\n", mesg); 
} 

Текстовый файл

4+3-2*(-7) 
65*+/abc 
9/3-2*(-5) 

Out поставил

=21 
Bad Expression : syntax error 

Ожидаемый выход

4+3-2*(-7)=21 
65*+/abc=Bad Expression : syntax error 
9/3-2*(-5)=13 

Даже если удалить плохое выражение из 2-й линии INT текст файла анализатор дает результата

=21 
=0 

вместо

=21  
=13 

Я попытался прочитать данные и сохранить их в переменной & отображение арифметического выражения с использованием функции обработки файлов во время цикла и использования yyparse() в цикле для сканирования по строкам. Я не могу отследить проблему, поскольку исходный код немного сложный, и я начал изучать эту вещь всего за 20 дней.

Выполнение кода с помощью команд

yacc -v -t -d calc.yacc (I am getting 22 shift/reduce conflicts.) 
lex calc.lex 
gcc y.tab.c lex.yy.c -lm -ll -o calc 
./calc calc.txt 
+0

Части вашей проблемы может заключаться в определении 'Calc'. Вы печатаете '$ 1' оба раза. –

+1

У вас нет правила ошибки, что затрудняет восстановление ошибок. –

ответ

1

Yacc не разбор второго выражения

Да это. Вот откуда исходит синтаксическая ошибка. Если он не разобрал его, он не смог бы дать синтаксическую ошибку для него.

Ожидаемый результат

Там нет ничего, что печатает выражение ввода, так что нет никаких оснований для этого ожидания.

У нас нет исправления ошибок, поэтому нет возможности выполнить редукцию, которая печатает =, если есть синтаксическая ошибка.

Правило для Calc : Calc Expr должно печатать $2, а не $1.

Правило

| '-' Expr   { $$ = -$2;  } 

следует читать

| '-' Fact   { $$ = -$2;  } 

И, наконец, вам нужно сделать что-то о приоритете операций. Мне интересно, откуда у вас эта странная грамматика выражения. Есть много правильных примеров. Что-то вроде этого:

expression 
    : term 
    | expression '+' term 
    | expression '-' term 
    ; 
term 
    : factor 
    | term '*' factor 
    | term '/' factor 
    ; 
factor 
    : primary 
    | '-' primary 
    ; 
primary 
    : ID 
    | NUM 
    | '(' expression ')' 
    ; 

Ошибки и пропуски исключены.

+0

, но все же после размещения парсера $ 2 выдается вывод следующего действительного выражения = 0 –

+1

@NikulVyas вы не проверяете ошибки, вы не обрабатываете приоритет оператора, и я думаю, что ваша обработка унарного минуса является одной из причин для 22 сдвиг/сокращение конфликтов. (у этого комментария должно быть достаточно ключевых слов для Google, чтобы найти решения) – deamentiaemundi

+0

@deamentiaemundi моя идея снизу вверх. Вот почему я прохожу + & - before * &/ –

0

Код прекрасно работает с улучшениями, поэтому для редактирования нужно использовать YACC.

%{ 
#include <stdio.h> 
#include <string.h> 
#define YYSTYPE int /* the attribute type for Yacc's stack */ 
extern int yylval;  /* defined by lex, holds attrib of cur token */ 
extern char yytext[]; /* defined by lex and holds most recent token */ 
extern FILE * yyin; /* defined by lex; lex reads from this file */ 
%} 

%token NUM 

%% 

Calc : Expr    {printf(" = %d\n",$1);} 
    | Calc Expr   {printf(" = %d\n",$2);} 
    | Calc error   {yyerror("\n");} 
    ; 
Expr : Term    { $$ = $1;   } 
    | Expr '+' Term  { $$ = $1 + $3; } 
    | Expr '-' Term  { $$ = $1 - $3; } 
    ; 
Term : Fact    { $$ = $1;   } 
    | Term '*' Fact  { $$ = $1 * $3; } 
    | Term '/' Fact  { if($3==0){ 
       yyerror("Divide by Zero Encountered."); 
          break;} 
       else 
       $$ = $1/$3;  
        } 
    ; 
Fact : Prim    { $$ = $1;  } 
    | '-' Prim   { $$ = -$2;  } 
    ;  
Prim : '(' Expr ')'  { $$ = $2;  } 
    | Id     { $$ = $1;  } 
    ; 
Id :NUM     { $$ = yylval; } 
    ; 
%% 

void yyerror(char *mesg); /* this one is required by YACC */ 

main(int argc, char* *argv){ 
char ch,c; 
FILE *f;  
if(argc != 2) {printf("useage: calc filename \n"); exit(1);} 
if(!(yyin = fopen(argv[1],"r"))){ 
     printf("cannot open file\n");exit(1); 
} 
/* 
f=fopen(argv[1],"r"); 
if(f!=NULL){ 
char line[1000]; 
while(fgets(line,sizeof(line),f)!=NULL) 
    { 
      fprintf(stdout,"%s",line); 
     yyparse(); 
    } 

} 
*/ 
yyparse(); 
} 

void yyerror(char *mesg){ 
printf("\n%s", mesg); 
} 

Я попытался напечатать выражение, но это не представляется возможным с чтением файла построчно & вызова yyparse() в то время цикла. Но вычисления & работают нормально.

1

Проблема заключается в том, что если вы не укажете приоритет с правилами приоритета (или, переписывая грамматику, как предложили другие), yacc разрешает сдвиг-сокращение конфликтов по сдвигу, что означает, что он делает такие взаимно-рекурсивные правила правильными, ассоциативно. Таким образом, выражение

9/3-2*(-5) 

обрабатывается как

9/(3-(2*(-5))) 

с целочисленной арифметикой, что окончательный разрыв заканчивается время 9/13, которое 0.

+0

Можете ли вы предложить мне способ показать арифметическое выражение текстового файла до результата вывода. Например: 9/3-2 * (- 5) = 13 –