【问题标题】:Figuring out Flex (lexer) yy_push_state弄清楚 Flex (lexer) yy_push_state
【发布时间】:2017-08-30 15:21:57
【问题描述】:

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

\/\*(\*|\!)[^*]       { 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-lexer


    【解决方案1】:

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

    Rust 是臭名昭著的糟糕文档,注释语法属于这一类。 rust book 在syntax index 中提到了block cmets,但未能在引用的comments section 中记录精确的语法。我也找不到 rustdoc 理解的语法的任何准确描述。

    我已经对您引用的 flex 摘录中的语法进行了逆向工程,但请谨慎对待;它可能与rustcrustdoc 所接受的实际语法有一些相似之处:

    1. Rust 块 cmets 与 C 或 C++ 块 cmets 不同,可以嵌套。这使它们成为不规则的括号语法;他们需要一个下推自动机来解析。所以没有正则表达式可以描述Rust block cmets,需要借助flex state stack来识别它们。

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

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

      不被视为文档注释。

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

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

    1. “我不明白为什么第一行需要 [^*]”

      这是为了避免匹配 box cmets,如上所述。

    2. “在这种情况下匹配的顺序是什么。”

      在所有情况下,flex 在输入中的任意点选择最长的匹配,如果有多个规则匹配相同的最长字符串,它会选择文件中的第一个规则。这就是所谓的“最大咀嚼”规则。所以考虑到这两条规则(我写的没有倾斜的木材森林,因为我觉得它不可读):

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

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

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

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

    4. “再往前两行,它也匹配正常的块注释。为什么它也在文档注释中匹配?”

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

    【讨论】:

    猜你喜欢
    • 2019-05-27
    • 2013-05-19
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    相关资源
    最近更新 更多