代码之家  ›  专栏  ›  技术社区  ›  Tim unnamed eng

对'yylex()'的每个调用是否为输入生成一个令牌或所有令牌?

  •  0
  • Tim unnamed eng  · 技术社区  · 6 年前

    我试图了解软篷下的弹性工作原理。

    • 在下面的第一个示例中,似乎 main() 电话 yylex() 只有一次 yLeX() 为整个输入生成所有标记。

    • 在第二个例子中,似乎 主体() 电话 yLeX() 每个生成的令牌一次,以及 yLeX() 每次调用生成一个令牌。

    每个电话都打给 yLeX() 为输入生成一个令牌还是所有令牌?

    为什么是 yLeX() 在这两个例子中调用了不同的次数?

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

    谢谢。

    /* 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 回复  |  直到 6 年前
        1
  •  1
  •   rici    6 年前

    flex不决定扫描仪何时返回(默认EOF规则除外)。它构建的扫描器在循环中执行词法操作,直到某些操作返回。所以这完全取决于您想要如何构造扫描仪。

    然而,经典的YYParse/YYLEX处理模型由解析器调用组成。 yylex() 每次它需要一个新的令牌。所以它期待 yLeX() 找到令牌后立即返回。

    在第一个代码示例中,没有解析器,扫描器操作仅限于打印出令牌。虽然示例是完全正确的,但是依赖于scanner循环来重复执行操作,我更喜欢第二个模型,即使您(还)不打算添加解析器,因为它将使令牌处理与令牌生成分离更容易。

    但这并不意味着每个词汇操作都将包含一个返回语句。一些词汇模式对应于非标记(例如注释和空白),相应的操作很可能什么也不做(除了可能记录输入位置),这样扫描器将继续搜索要返回的标记。

    (f)lex扫描器不容易生成协程,因此如果确实需要协程(例如,增量解析异步输入),那么可能需要另一个工具。

    Bison确实提供了生成一个“push-parser”的可能性,在这个“push-parser”中,扫描仪 电话 解析器每次找到一个令牌,而不是 回到 解析器。但是无论是“推”还是传统的“拉”模型都与协程、imho没有任何关系,并且使用这个词来描述解析器/扫描器交互对我来说都是不精确和无用的(尽管我很尊重你引用的作者)。