0

我正在尝试从 .txt 文件中解析一组算术表达式。(每行一个。)我能够为第一行获得正确的逻辑,但解析器为第二个表达式给出 0。此外,我想在输出中打印整个字符串,但从哪里开始感到困惑。

莱克斯

%{
#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  '?'; }

%%

雅克

%{
#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)

输出

=21
Bad Expression : syntax error

预期产出

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

即使我从文本文件的第二行中删除了错误的表达式,解析器也会给出结果

=21 
=0 

代替

=21    
=13

我尝试读取数据并将其存储在变量中并使用 while 循环中的文件处理选项显示算术表达式,并在循环中使用 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
4

3 回答 3

1

问题在于,如果您不使用优先规则指定优先级(或通过重写语法,正如其他人所建议的那样),yacc 通过 shift 解决 shift-reduce 冲突,这意味着它使此类相互递归的规则具有右关联性。所以表达式

9/3-2*(-5)

被解析为

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

使用整数算术,最终除法最终为 9/13,即 0。

于 2017-02-14T01:44:56.480 回答
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 ')'
    ;

错误和遗漏除外。

于 2017-02-13T21:40:26.123 回答
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);
}

我试图打印表达式,但是在 while 循环中逐行读取文件并调用 yyparse() 是不可能的。但是计算和语法工作正常。

于 2017-02-14T00:27:09.850 回答