Lex - 显示语法错误的 yacc 程序

Lex - yacc program showing syntax error

下面的两段代码是为了对输入进行算术运算而写的,但是一直给我语法错误 这是 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 { $$ = +;}
 | expr '-' expr { $$ = -;}
 | expr '*' expr { $$ = *;}
 | expr '/' expr { $$ = /;}
 | '(' expr ')' {$$ = ;}
 ;
 %%
 int main()
 {
     yyparse();
 }

输出:

 2+3

 2+3
 Syntax error

可能是什么问题?

存在三个问题

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

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

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

第二个问题是您的扫描仪实际上并没有将换行符识别为 END 标记:

'\n'  {return END;}

' 不是 (f)lex 的特殊字符。 (有关可接受的模式字符的完整列表,请参阅 Flex manual。)所以该规则正在查找三个字符:一个撇号、一个换行符和另一个撇号。如果您提供该输入,您将获得 "expected" 输出:

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

你想写的是

\n    { return END; }

但这可能也不理想。那将 return 紧接在单个表达式之后。一个更有趣的语法将允许任意数量的表达式:

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",); }
 | S '\n'
expr: ID
 | expr '+' expr { $$ = +;}
 | expr '-' expr { $$ = -;}
 | expr '*' expr { $$ = *;}
 | expr '/' expr { $$ = /;}
 | '(' expr ')' {$$ = ;}
 ;
 %%
 int main()
 {
     yyparse();
 }

改动:

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

最后,您尝试在开始制作时明确识别 END 令牌。这可能有效,但不推荐这样做。

Yacc/bison 通过添加一个看起来与您的规则 S 完全一样的外部规则来自动扩充您的语法:它识别开头 non-terminal 后跟 END。所以不需要添加你自己的作品。