野牛 yacc yyerror 不起作用

bison yacc yyerror doesn't work

我是 Yacc 编程的初学者,我有一个简单的任务来编写一个程序,它检查输入的文本文件是否 包含一系列正确配对的括号。任何不正确的顺序 应该被标记为 "Syntax error!"。我用bison和flex。

示例正确数据: (()()((())())()) 但 (() 不正确。

我的问题是我认为它应该有效,但 yyerror 似乎无效。也许我做错了什么,请纠正我。 这是我的代码 Yacc代码:

 %{
int yylex();
void yyerror(char* x);
%}
%%
S: S A
 |A
 ;
A: '('S')'
  |'(' ')'
  ;

以及 lex 代码:

%{
#include "y.tab.h"
%}
%%
[\(\)] return(yytext[0]);
. {printf("%c - error!\n",yytext[0]);}

%%
void yyerror(char* x)
{
    printf("syntax error");
    exit(1);
}

所以问题是它不会引发语法错误,不管我写了多少括号。 编辑: 这是我编译它的方式: screen

您需要提供一个 main() 函数(至少)调用 yyparse()。否则,将使用 libfl 中的 main。那main不叫yyparse();相反,它会重复调用 yylex 直到发出 EOF 信号。 (libfl 是 Fl​​ex 的一部分,而不是 bison,因此它不能依赖 yyparse 甚至存在。)

真的没必要link和-lflmain() 定义对你没有用,库中唯一的其他东西是 yywrap() 的虚拟定义。你没有定义yywrap(),所以会调用库函数;但是,您可以简单地添加

而不是依赖于库
%option noyywrap

到您的 flex 代码(就在 %% 之前),然后生成的扫描器将不会调用 yywrap()

调用 bison 时也无需使用 -y 标志。使用 -y 的唯一原因是能够使用 bison 处理遗留的 yacc 文件。我想你正在使用标志,以便生成的解析器被称为 y.tab.c;如果没有标志,它将被称为 z5.tab.c(头文件将是 z5.tab.h);您可以只使用这些名称。 (或者您可以使用 -o 标志告诉 bison 您希望它使用的准确文件名。)

最后,关于您的 lex 文件的两点说明:

  1. 括号的格式可以这样写:

    [()]  { return yytext[0]; }
    

    不需要在字符 class 内对括号进行反斜杠转义,因为除 ]-\ 外,其他字符在字符内没有特殊含义字符 class.

  2. 模式 . 与换行符不匹配,这就是您输入的换行符未产生错误消息的原因。事实上,none 的模式匹配换行符,因此当您键入换行符时,将调用默认规则。默认规则等同于 ECHO,bison 定义如下:

    fputs(yytext, yyout);
    

    (或fprintf(yyout, "%s", yytext);

    这就是为什么当你输入一个换行符时会输出一个额外的换行符。

所以 lex 的正确代码是:

%{
#include "z5.tab.h"
%}

%%
[\(\)] return(yytext[0]);
. {printf("%c - error!\n",yytext[0]);}
\n ;
%%
int main(void)
{
   yyparse();
   return 0;
}

int yywrap(void)
{
   return 0;
}
void yyerror(char* x)
{
    printf("syntax error");
    exit(1);
}

正确的编译方法是:

flex s5.l 
bison -d z5.y 
gcc lex.yy.c z5.tab.c -L"C:\GnuWin32\lib"