每次调用yylex()都会为输入生成令牌还是所有令牌?

时间:2019-02-07 18:55:31

标签: flex-lexer lex lexer

我正在尝试了解flex在引擎盖下如何工作。

  • 在下面的第一个示例中,似乎main()仅调用一次yylex(),并且yylex()生成了整个输入的所有令牌。

  • 在第二个示例中,似乎main()每个生成的令牌调用一次yylex(),而yylex()每个调用生成一个令牌。

每次调用yylex()都会生成一个令牌还是输入的所有令牌?

为什么在两个示例中yylex()被调用不同的次数?

我听说yylex()就像一个协程,每次调用都会从上次调用留下的其余输入中恢复并生成令牌。从这个意义上讲,第一个示例如何只调用一次yylex()并在输入中生成所有令牌?

谢谢。

/* just like Unix wc */
%{
int chars = 0;
int words = 0;
int lines = 0;
%}
%%
[a-zA-Z]+  { words++; chars += strlen(yytext); }
\n         { chars++; lines++; }
.          { chars++; }
%%
main(int argc, char **argv)
{
  yylex();
  printf("%8d%8d%8d\n", lines, words, chars);
}


$ ./a.out
The boy stood on the burning deck
shelling peanuts by the peck
^D
2 12 63
$

/* recognize tokens for the calculator and print them out */
%{
   enum yytokentype {
     NUMBER = 258,
     ADD = 259,
     SUB = 260,
     MUL = 261,
     DIV = 262,
     ABS = 263,
     EOL = 264
   };
   int yylval;
%}
%%
"+"    { return ADD; }
"-"    { return SUB; }
"*"    { return MUL; }
"/"    { return DIV; }
"|"    { return ABS; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
\n     { return EOL; }
[ \t]  { /* ignore whitespace */ }
.      { printf("Mystery character %c\n", *yytext); }
%%
main(int argc, char **argv)
{
  int tok;
  while(tok = yylex()) {
    printf("%d", tok);
    if(tok == NUMBER) printf(" = %d\n", yylval);
    else printf("\n");
  }
}

$ ./a.out
a / 34 + |45
Mystery character a
262
258 = 34
259
263
258 = 45
264
^D
$

1 个答案:

答案 0 :(得分:1)

Flex不会决定扫描仪何时返回(默认EOF规则除外)。它构建的扫描程序会循环执行词汇操作,直到返回某些操作为止。因此,如何构造扫描仪完全取决于您。

但是,经典的yyparse / yylex处理模型由每次需要新令牌时调用yylex()的解析器组成。因此,它期望yylex()一旦找到令牌就立即返回。

在您的第一个代码示例中,没有解析器,并且扫描器操作仅限于打印令牌。尽管该示例完全正确,但依赖于扫描器循环重复执行操作,即使您不打算添加解析器,我也希望使用第二种模型,因为这样可以更轻松地将令牌处理与令牌生成。

但这并不意味着每个词法操作都将包含一个return语句。一些词法模式对应于非令牌(例如,注释和空格),并且相应的动作很可能什么都不做(除了可能记录输入位置),以便扫描程序将继续搜索令牌以返回。

(F)lex扫描仪不容易制成协程,因此,如果确实需要协程(例如,逐步解析异步输入),则可能会首选其他工具。

Bison确实提供了生成“推送解析器”的可能性,扫描器在每次找到令牌时都会在其中调用,而不是返回解析器。但是“推”和传统的“拉”模型都与协程无关,恕我直言,用这个词来描述解析器/扫描器的交互使我感到不精确和无用(尽管我非常尊重作者,您可能会引用。)