flex-bison 忽略空格

flex-bison ignore whitespace

我正在尝试使用 flex-bison 实现一个简单的词法分析器和解析器。

我只想解析这些:

只是一个用逗号分隔的序列,可能包含也可能不包含 space。 所以这是我的语法:

KEY_SET             : KEY
                      {
                        printf("keyset 1");
                      }
                      | KEY COMMA KEY_SET
                      {
                        printf("keyset 2");
                      };

声明KEYCOMMAtoken.//%token

但每当我按回车键或任何白色space。

时,它都会给我 语法错误

所以我什至在 flex 中声明了 IGNORE [ \t\n]。 在解析器中我添加了一个新规则:

IGNORE_BLOCK        : IGNORE
                      {
                        printf("\n...ignoring...\n")
                      };

但这甚至没有发挥作用。

它让我一直报语法错误。

我该如何解决?

词法分析器:

%{
    #include "y.tab.h"
%}
%option noyywrap
COMMA                   [,]
KEY                     [[:alpha:][:alnum:]*]
IGNORE                  [ \t\n]
%%
{COMMA}                 {return COMMA;}
{KEY}                   {return KEY;}
{IGNORE}                {return IGNORE;}
.                       {printf("Exiting...\n");exit(0);}
%%

解析器:

%{
    #include<stdio.h>
    void yyerror (char const *s);
    int yywrap();
    //int extern yylex();
%}
%token      COMMA
%token      KEY
%token      IGNORE
%%
KEY_SET             : KEY
                      {
                        printf("keyset 1");
                      }
                      | KEY COMMA KEY_SET
                      {
                        printf("keyset 2");
                      };

IGNORE_BLOCK        : IGNORE
                      {
                        printf("\n...ignoring...\n")
                      };

%%
int main(int argc, char **argv)
{
    while(1)
    {
      printf("****************\n");
      yyparse();
      char ign;
      scanf("%c",&ign);
    }
    return 0;
}
int yywrap()
{
   return 1;
}
void yyerror (char const *s) {
   fprintf (stderr, "%s\n", s);
}

我用来构建的命令:

flex test.l
bison -dy test.y
gcc lex.yy.c y.tab.c -o test.exe

您的 flex 文件包含一系列规则,每个规则由一个模式和一个动作组成。与流行的看法相反,您不需要在使用模式之前“声明”它们。

如果你想在你的词法分析器中忽略空格,你需要一个什么都不做的规则。

您的按键模式有误,我已修复;您的模式不会接受超过一个字母的键。此外,在您的扫描仪中调用 exit 是非常糟糕的风格。让解析器处理错误。

%{
    #include "y.tab.h"
%}
%option noyywrap
%%
   /* Removed the COMMA rule. See text below. */
   /* ","               {return COMMA;} */
   /* Compare this pattern with the one you used */
[[:alpha:]][[:alnum:]]* {return KEY;}
   /* Recognise and ignore whitespace. */
[[:space:]]+            ; /* Do nothing */
   /* Send unrecognised input to the parser. */
.                       {return *yytext;}

您的解析器不需要 IGNORE,这毫无意义,因为语法不会生成它。 Bison 可能警告过你。

您可以通过其他方式简化解析器:

  • yywrap 是不需要的,因为你的词法分析器有 %option noyywrap.
  • 如果您只是从词法分析器中删除 "," 模式(因为后备规则
    .  { return *yytext; }
    
    将对任何 single-character 文字正确工作。

对于测试,您可能希望一次解析一行而不是忽略语法错误。

我还建议您在调用 bison 时不要使用“遗留”标志 -y;该标志只能用于旧的现有 yacc 语法文件,因为它可能会干扰现代 bison 功能。如果没有-y,bison会将生成的C代码写入<i>filename</i>.tab.c,生成的header到 <i>文件名</i>.tab.h。如果你不喜欢那些名字,你可以使用 -o 标志来指定生成的 C 代码的名称(并且 header 将具有相同的名称,扩展名更改为 .h).

这可能会产生这样的结果:

(请注意,我将 KEY_SET 更改为 key_set,因为语法中通常的风格是 ALL_CAPS 是标记,而 non-terminals 是 lower-case。我还将它从 right-recursive 更改为 left-recursive 以避免如果您的生产操作打印 KEY 标记的值时您会注意到的问题,假设您的词法分析器已给它一个值。)

文件parser.y

%{
    #include<stdio.h>
    void yyerror (char const *s);
    int yylex(void);
    /* Defined in the flex file */
    void set_input(const char* input);
%}
%token  KEY
%%
key_set : KEY             { printf("keyset 1\n"); }
        | key_set ',' KEY { printf("keyset 2\n"); };
%%
int main(int argc, char **argv)
{
    char buffer[BUFSIZ];
    while (1)
    {
      printf("****************\n");
      char* input = fgets(buffer, sizeof buffer, stdin);
      if (buffer == NULL) break;
      set_input(input);
      yyparse();
    }
    return 0;
}

void yyerror (char const *s) {
   fprintf (stderr, "%s\n", s);
}

文件lexer.l

%{
    #include "parser.tab.h"
%}
%option noinput nounput nodefault yylineno
%option noyywrap
%%
[[:alpha:]][[:alnum:]]* {return KEY;}
[[:space:]]+            ; /* Do nothing */
.                       {return *yytext;}
%%
static YY_BUFFER_STATE flex_buffer;
void set_input(const char* input) {
  yy_delete_buffer(flex_buffer);
  flex_buffer = yy_scan_string(input);
}

构建过程:

flex lexer.l
bison -d parser.y
gcc lex.yy.c parser.tab.c -o parser.exe

你的语法不允许空输入,但没关系。但是,出于测试目的,您可能希望在循环中添加一个测试,该循环读取输入行以仅在该行不为空时调用解析器。