【问题标题】:difficulty getting c-style comments in flex/lex难以在 flex/lex 中获得 c 风格的注释
【发布时间】:2011-01-08 23:05:03
【问题描述】:

我想在 flex 中制定一个规则来使用像 /* */ 这样的 c 风格的注释

我有以下

c_comment "/*"[\n.]*"*/"

但它永远不会匹配。知道为什么吗?如果您需要更多我的代码,请告诉我,我将提交整个内容。感谢所有回复的人。

【问题讨论】:

  • 我不知道为什么你在那里没有匹配,但你的表达式会吃掉文件中第一个“/*”和最后一个“*/”之间的所有内容。与评论内容匹配的表达式必须排除“*/”被使用。一种方法:flex.sourceforge.net/manual/…
  • 谢谢,该网站很有帮助

标签: flex-lexer


【解决方案1】:

另一个例子:

"/*"([^*]*|(\*+[^/]))*"*/"

【讨论】:

    【解决方案2】:

    我建议你改用start conditions

    %x C_COMMENT
    
    "/*"            { BEGIN(C_COMMENT); }
    <C_COMMENT>"*/" { BEGIN(INITIAL); }
    <C_COMMENT>\n   { }
    <C_COMMENT>.    { }
    

    请注意,&lt;condition&gt; 和规则之间不得有任何空格。

    %x C_COMMENT 定义 C_COMMENT 状态,并且规则 /* 启动它。一旦它开始,*/ 将让它回到初始状态(INITIAL 是预定义的),并且所有其他字符都将被消耗而无需任何特定操作。当两条规则匹配时,Flex 会通过匹配最长的一条来消除歧义,因此点规则不会阻止 */ 匹配。 \n 规则是必要的,因为 a dot matches everything except a newline

    %x 定义使 C_COMMENT 成为独占状态,这意味着词法分析器将仅匹配“标记”&lt;C_COMMENT&gt; 的规则一旦进入该状态。

    这是一个tiny example lexer,它通过打印除/* comments */ 中的内容之外的所有内容来实现此答案。

    【讨论】:

    • 我知道我来晚了,但是这个正则表达式会错误地将/* rubbish */ */ 识别为完整的块注释(从/* 到第二个*/),而不是C样式块 cmets,其中开头的 /* 被最近的关闭 */ 终止,而另一个 */ 在程序中被标识为杂散字符。以下正则表达式(用于 flex/lex)也处理这种情况 "/*"((("*"[^/])?)|[^*])*"*/" Source - [link] (stackoverflow.com/questions/16160190/…)
    • 这里的问题出在&lt;C_COMMENT&gt;. { },如果@zneak 使用了follopwing,它就会解决&lt;C_COMMENT&gt;[^*\n]*&lt;C_COMMENT&gt;"*"+[^*/\n]*。它会吃掉除了 * 后跟 / 之外的所有内容。所以在这种情况下,它会以第一个 * 后跟 / 结束。所以/* rubbish */ foolosh */,它会评论/* rubbish */,并关注foolish */的下一个标记
    • @NitinTripathi,你确定这是必要的吗?我在这里无权访问 flex,但documentation 声明当多个规则匹配时,选择最长的匹配。在我看来,. 规则永远不应该与结束评论的 * 匹配,因为结束评论比任何字符之一长。
    • @NitinTripathi, this very simple flex lexer 没有遇到您(和@Shobhit)描述的/* rubbish */ foolosh */ 问题。
    • 我将示例“tiny example lexer”编译到 a.out 中,然后运行:echo "/* this is a multiline comment */abc" | ./a.out,其中注释块有四个换行符,结果是四个换行符后跟“abc”。我认为这是不正确的——应该忽略整个注释块,因此注释块中的换行符不应该影响输出。
    【解决方案3】:

    the Flex manual 中有一个工作示例,它可以正确处理粗糙的边缘情况:

    <INITIAL>"/*"         BEGIN(IN_COMMENT);
    <IN_COMMENT>"*/"      BEGIN(INITIAL);
    <IN_COMMENT>[^*\n]+   // eat comment in chunks
    <IN_COMMENT>"*"       // eat the lone star
    <IN_COMMENT>\n        yylineno++;
    

    【讨论】:

      【解决方案4】:

      工作示例是:

      \/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/
      

      ostermiller.org中找到

      【讨论】:

      • 在 Flex 中,[^*] 包括 \r\n(以及除 * 之外的所有其他 8 位代码),因此 |[\r\n] 是不必要的。 (就像链接文章中的大多数其他正则表达式环境一样,nedit 除外。)
      【解决方案5】:

      我已经尝试了几种建议的解决方案,结果如下。

      • 我无法得到 C_COMMENT 解决方案,它拥有最多的投票并且看起来很棒,在实践中根本无法工作(其中一个 cmets 至少解释了一个原因)。它应该被否决,当然不应该是投票最高的解决方案
      • Mugen 的解决方案似乎适用于我运行它的所有代码
      • 无法从 Andrey 获得解决方案,甚至无法在 lex 中进行编译。我查看了引用的网站并使用那里的模式没有帮助
      • paxdiablo 的答案很有效,并且具有易于阅读的优点。我进一步修改如下:

        "/*" { int c1 = 0, c2 = input(); 为了(;;) { 如果(c2 == EOF)中断; 如果(c1 == '*' && c2 == '/') 休息; c1 = c2; c2 = 输入(); } }

      【讨论】:

      • 我并不完全清楚为什么我的答案中的解决方案不适合您。如果两个弹性规则匹配,最长的规则优先。这意味着. 规则永远不应该使用*/ 令牌的*This lexer 没有遇到您描述的问题:输入 /* hello */world */ 按预期产生输出 world */
      • 我在您的回答中添加了一条评论,解释了我遇到的问题,这与评论块中嵌入的换行符有关
      【解决方案6】:

      我相信这个解决方案更简单:

      "/*"((\*+[^/*])|([^*]))*\**"*/"
      

      【讨论】:

      【解决方案7】:

      这是一个示例,以防万一有人对如何使用 zneak 的答案感到困惑:

      (基本上,您将“%x C_COMMENT”放在第一部分,其余部分放在第二部分,正如他的有用链接所解释的那样)

      foo.l
      
      %{
      // c code..
      %}
      %x C_COMMENT
      
      %%
      "/*"            { BEGIN(C_COMMENT); }
      <C_COMMENT>"*/" { BEGIN(INITIAL); }
      <C_COMMENT>.    { }
      
      %%
      // c code..
      

      希望对某人有所帮助! 蒂夫

      【讨论】:

        【解决方案8】:

        不知道为什么它没有被选中,但我知道这种模式会产生大量的词汇元素。只检测开始注释标记并将所有内容都扔进 bitbucket 直到找到结束标记会更有效。

        This site 有代码可以做到这一点:

        "/*" {
            for (;;) {
                while ((c = input()) != '*' && c != EOF)
                    ; /* eat up text of comment */
                if (c == '*') {
                    while ((c = input()) == '*')
                        ;
                    if (c == '/')
                        break; /* found the end */
                }
                if (c == EOF) {
                    error ("EOF in comment");
                    break;
                }
            }
        }
        

        【讨论】:

        • 我不确定以这种方式使用输入是否真的很好。 =/ 这不是多虑吗?
        • 我通常倾向于实用主义而不是教条主义:-)
        • 我在这里只看到一个问题,那就是吃掉评论,以便您可以继续对真实令牌进行词法分析。但是,您可能会争辩说,此示例没有利用 flex 提供的抽象机制来使您所做的事情更加清晰。
        • @Nate,我不怀疑有更好的方法来做到这一点,我只提供一种解决方案。我的经验是使用 lex/yacc,我从来没有使用过 flex/bison,因为它们在我需要开发的平台上不可用。这是很久以前的事了,在那些日子里,编译器甚至从未见过 cmets - 它们被预处理器剥离出来,然后是我们开发环境中的一个单独程序:AT&T 3B2 年份,这应该可以表明我的年龄:-)
        • IMO 这是解决此特定问题的最佳方法。 C 风格的 cmets 不能在 lex/flex 框架中非常清晰地表达,所以您不妨编写一些代码来处理它,就像您所做的那样。这样做的好处是不需要 lex 状态,我觉得这使语法更难遵循。我的评论更多是对 zneak 的回应:只要这里的代码严格进行词法分析(确实如此),我觉得它在正确的位置并且不会出现关注点分离的问题。
        猜你喜欢
        • 2010-12-17
        • 2010-10-26
        • 2018-09-06
        • 1970-01-01
        • 2011-02-02
        • 2013-05-23
        • 1970-01-01
        • 2011-11-15
        • 1970-01-01
        相关资源
        最近更新 更多