弄清楚 Flex(词法分析器)yy_push_state

Figuring out Flex (lexer) yy_push_state

以下 Flex 结构的 Regex 等价物是什么?我正在尝试为一个项目重新创建 Rusts 语法,但现在我被困在这块上了?这是 inner/outer 文档注释的语法(Rust 有六种类型的注释)。它应该匹配 /** *//*! */ 之类的注释,但是例如我不明白为什么第一行需要 [^*] 以及在这种情况下匹配的顺序是什么。

\/\*(\*|\!)[^*]       { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); }
<doc_block>\/\*       { yy_push_state(doc_block); yymore(); }
<doc_block>\*\/       {
    yy_pop_state();
    if (yy_top_state() == doc_block) {
        yymore();
    } else {
        return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT);
    }
}
<doc_block>(.|\n)     { yymore(); }

据我了解:第 1 行匹配开始 /**/*!;第 2 行,匹配块注释(出于某种原因?);第 3 行,匹配结尾 */;第 11 行,匹配任何字符或换行符(为什么?)。

另外两行它也匹配普通的块注释。为什么它也在文档评论中匹配它?

\/\*                  { yy_push_state(blockcomment); }
<blockcomment>\/\*    { yy_push_state(blockcomment); }
<blockcomment>\*\/    { yy_pop_state(); }
<blockcomment>(.|\n)   { }

flex 状态堆栈允许对不能用正则表达式描述的字符串进行词法分析,因此没有与该 flex 规范等效的正则表达式。有关状态堆栈的文档,包括编写状态条件规则的语法,请参阅 flex manual.

Rust 的文档记录很糟糕,注释语法属于这一类。 Rust book 在 syntax index but fails to document the precise syntax in the referenced comments section 中提到了块注释。我也找不到 rustdoc 理解的语法的任何精确描述。

我已经对您引用的 flex 摘录中的语法进行了逆向工程,但请对它持保留态度;它可能仅与 rustcrustdoc:

接受的实际语法有一些相似之处
  1. Rust 块注释与 C 或 C++ 块注释不同,可以嵌套。这使它们成为不规则的括号语法;他们需要一个下推自动机来解析。所以没有正则表达式可以描述Rust块注释,需要借助flex状态栈来识别。

  2. Rust 文档块注释必须以斜线和恰好两颗星(或一颗星和一个感叹号)开头。文件箱:

    /*************************************
     *        START OF SECTION           *
     *************************************\
    

    不被视为文档注释。

    (我怀疑不识别以 `/!' 开头的内部块注释是一个疏忽,但谁知道呢。)

如果以上正确,可以回答你的问题:

  1. "I don't understand why [^*] is needed on the first line"

    这是为了避免匹配框注释,如上所述。

  2. "what the order of matching is in this case."

    在所有情况下,flex 都会选择输入中任意点的最长可能匹配项,如果有多个规则匹配相同的最长字符串,它会选择文件中的第一个规则。这就是所谓的"maximal munch"规则。因此,鉴于这两个规则(我写的时候没有倾斜木材的森林,因为我觉得它不可读):

    "/*"[*!][^*]     {  DocComment(); }
    "/*"             {  BlockComment(); }
    

    第二条规则将应用于输入 /* Comment/****,匹配两个字符,而第一条规则将应用于 /** Documentation comment,匹配四个字符。 (它也会错误地应用于 /**/,恕我直言,应该将其分析为空块注释而不是文档注释的开头。)

  3. " 第 11 行,匹配任何字符或换行符(为什么?)"

    是的,确实如此。如果它不匹配任何字符,则该字符将不会被任何规则匹配,这是不正确的。

  4. "Two lines further it also matches for the normal block comment. Why is it also matching for it inside the doc comment?"

    因为文档注释中的匹配只适用于文档注释中。不在文档注释中的块注释也需要匹配。但是,这里肯定可以进行一些重构,这可以简化词法描述。