Lex - yacc程序显示语法错误

时间:2017-02-07 12:15:23

标签: yacc lex

为了对输入执行算术运算,已经编写了以下两个代码,但它始终给出了语法错误 这是lex程序

%{ 
#include "y.tab.h" 
#include <stdlib.h>
%}



%%

[0-9]+ {yylval =  atoi(yytext);return ID;}

[*-+/()] {return yytext[0];}

'\n'  {return END;}


. {return yytext[0];}

%%

这是yacc计划:

 %{
     #include <stdio.h>
     #include <stdlib.h>
     #include "y.tab.h"     
 %}
 %token ID END  
 %%
 S: expr END { printf("Answer is : %d\n",$$);   exit(1);  }   
 expr: ID
 | 
 | expr '+' expr { $$ = $1+$3;}
 | expr '-' expr { $$ = $1-$3;}
 | expr '*' expr { $$ = $1*$3;}
 | expr '/' expr { $$ = $1/$3;}
 | '(' expr ')' {$$ = $2;}
 ;
 %%
 int main()
 {
     yyparse();
 }

输出:

 2+3

 2+3
 Syntax error

问题是什么?

1 个答案:

答案 0 :(得分:0)

有三个问题。

第一个问题是你的语法只能识别一个表达式:

S: expr END { printf("Answer is : %d\n",$$);   exit(1);  }

因此,如果输入两个表达式,则会出现语法错误。

第二个问题是您的扫描程序实际上并未将换行符识别为END令牌:

'\n'  {return END;}

&#39; 不是(f)lex的特殊字符。 (有关已接受模式字符的完整列表,请参阅Flex manual。)因此该规则正在查找三个字符:撇号,换行符和另一个撇号。如果您提供该输入,您将得到&#34;期望&#34;输出:

$ ./badexpr
2+3'
'
Answer is : 5
$

你打算写的是

\n    { return END; }

但这可能也不理想。这将在单个表达式后立即返回。一个更有趣的语法将允许任意数量的表达式:

file.l

%{ 
#include <stdlib.h>
#include "y.tab.h" 
%}

%%

[0-9]+ {yylval =  atoi(yytext);return ID;}
.|\n   {return yytext[0];}

file.y

%{
     #include <stdio.h>
     #include <stdlib.h>
%}
%token ID
%%
S: /* %empty */
 | S expr '\n'   { printf("Answer is : %d\n",$2); }
 | S '\n'
expr: ID
 | expr '+' expr { $$ = $1+$3;}
 | expr '-' expr { $$ = $1-$3;}
 | expr '*' expr { $$ = $1*$3;}
 | expr '/' expr { $$ = $1/$3;}
 | '(' expr ')' {$$ = $2;}
 ;
 %%
 int main()
 {
     yyparse();
 }

的变化:

  • 我从flex输入中删除了所有单字符模式,因为它们都具有相同的效果:返回单个字符读取。这包括换行符,因为有以下更改。
  • 我更改了语法的开始生成,以便它显式查找换行符(而不是END)并接受任意数量的输入行。
  • 我从bison输入中删除了#include "y.tab.h",因为没有必要在解析器文件中包含解析器头。
  • 我将expr的空制作品移到S制作中,以便它不会尝试打印空表达式的值。

最后,您尝试在初始制作中明确识别END令牌。这可能有效,但不建议这样做。

Yacc / bison通过添加外观规则自动增加您的语法,该规则看起来与您的规则S完全相同:它识别起始非终端,后跟END。因此,添加自己的作品是不必要的。