我正在尝试了解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
$
答案 0 :(得分:1)
Flex不会决定扫描仪何时返回(默认EOF规则除外)。它构建的扫描程序会循环执行词汇操作,直到返回某些操作为止。因此,如何构造扫描仪完全取决于您。
但是,经典的yyparse / yylex处理模型由每次需要新令牌时调用yylex()
的解析器组成。因此,它期望yylex()
一旦找到令牌就立即返回。
在您的第一个代码示例中,没有解析器,并且扫描器操作仅限于打印令牌。尽管该示例完全正确,但依赖于扫描器循环重复执行操作,即使您不打算添加解析器,我也希望使用第二种模型,因为这样可以更轻松地将令牌处理与令牌生成。
但这并不意味着每个词法操作都将包含一个return语句。一些词法模式对应于非令牌(例如,注释和空格),并且相应的动作很可能什么都不做(除了可能记录输入位置),以便扫描程序将继续搜索令牌以返回。>
(F)lex扫描仪不容易制成协程,因此,如果确实需要协程(例如,逐步解析异步输入),则可能会首选其他工具。
Bison确实提供了生成“推送解析器”的可能性,扫描器在每次找到令牌时都会在其中调用,而不是返回解析器。但是“推”和传统的“拉”模型都与协程无关,恕我直言,用这个词来描述解析器/扫描器的交互使我感到不精确和无用(尽管我非常尊重作者,您可能会引用。)