使用Flex检测和跳过行注释

时间:2014-08-20 01:02:33

标签: c compiler-construction flex-lexer

如何在Flex中检测到一行注释,如“//”并跳过此行?

另外:

如果使用下面的“/ *”注释即可。它会起作用吗?

   "/*"         { comment(); }
  %%

    comment()
    {
        char c, c1;
    loop:
        while ((c = input()) != '*' && c != 0)
            putchar(c);

        if ((c1 = input()) != '/' && c != 0)
        {
            unput(c1);
            goto loop;
        }

        if (c != 0)
            putchar(c1);
    }

3 个答案:

答案 0 :(得分:15)

为什么不用正则表达式识别注释? lex/flex的重点是避免手动编写词法扫描仪。您提供的代码应该有效(如果您将模式/*放在行的开头),但它有点难看,并且它不会显而易见。

您的问题表示您要跳过评论,但您提供的代码使用putchar()来打印评论,但开头的/*除外。你想做什么?如果您想回复评论,可以使用ECHO操作而不是什么都不做。

以下是正则表达式:

单行评论

这个很容易,因为在lex / flex中,.与换行符不匹配。因此,以下内容将从//匹配到行尾,然后不执行任何操作。

"//".*                                    { /* DO NOTHING */ }

多行评论

这有点棘手,而且 * 是正则表达式字符以及注释标记的关键部分这一事实使得以下正则表达式有点难以阅读。我使用[*]作为识别字符 * 的模式;在flex / lex中,您可以使用"*"代替。使用您认为更具可读性的任何一个。基本上,正则表达式匹配以(字符串) * 结尾的字符序列,直到找到下一个字符为 / 的字符串。换句话说,它具有与C代码相同的逻辑。

[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/]       { /* DO NOTHING */ }

以上要求终止*/;未终止的注释将强制词法分析器返回到注释的开头并接受其他一些令牌,通常是 / 除法运算符。这可能不是你想要的,但是从未经评论的评论中恢复并不容易,因为没有真正好的方法可以知道评论应该在哪里结束。因此,我建议添加错误规则:

[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/]       { /* DO NOTHING */ }
[/][*]                                    { fatal_error("Unterminated comment"); }

答案 1 :(得分:2)

对于//,您可以阅读,直到找到行\nEOF,如果评论位于文件末尾,例如:

static void
skip_single_line_comment(void)
{
  int c;

  /* Read until we find \n or EOF */
  while((c = input()) != '\n' && c != EOF)
    ;

  /* Maybe you want to place back EOF? */
  if(c == EOF)
    unput(c);
}

对于多行评论/* */,您可以阅读,直到看到*并查看下一个字符,如果它是/这意味着这是评论的结束,如果不是跳过任何其他角色。你不应该期望EOF,意思是未公开的评论:

static void
skip_multiple_line_comment(void)
{
  int c;

  for(;;)
  {
    switch(input())
    {
      /* We expect ending the comment first before EOF */
      case EOF:
        fprintf(stderr, "Error unclosed comment, expect */\n");
        exit(-1);
        goto done;
      break;
      /* Is it the end of comment? */
      case '*':
        if((c = input()) == '/')
          goto done;
        unput(c);
        break;
      default:
        /* skip this character */
        break;
    }
  }

done:
  /* exit entry */ ;
}

完整档案:

%{
#include <stdio.h>

static void skip_single_line_comment(void);
static void skip_multiple_line_comment(void);

%}

%option noyywrap

%%
"//"              { puts("short comment was skipped ");
                    skip_single_line_comment();}

"/*"              { puts("long comment begins ");
                    skip_multiple_line_comment();
                    puts("long comment ends");}

" "               { /* empty */ }
[\n|\r\n\t]       { /* empty */ }
.                 { fprintf(stderr, "Tokenizing error: '%c'\n", *yytext);
                    yyterminate(); }
%%

static void
skip_single_line_comment(void)
{
  int c;

  /* Read until we find \n or EOF */
  while((c = input()) != '\n' && c != EOF)
    ;

  /* Maybe you want to place back EOF? */
  if(c == EOF)
    unput(c);
}

static void
skip_multiple_line_comment(void)
{
  int c;

  for(;;)
  {
    switch(input())
    {
      /* We expect ending the comment first before EOF */
      case EOF:
        fprintf(stderr, "Error unclosed comment, expect */\n");
        exit(-1);
        goto done;
      break;
      /* Is it the end of comment? */
      case '*':
        if((c = input()) == '/')
          goto done;
        unput(c);
        break;
      default:
        /* skip this character */
        break;
    }
  }

done:
  /* exit entry */ ;
}

int main(int argc, char **argv)
{
  yylex();
  return 0;
}

答案 2 :(得分:0)

检测单行注释:

^"//"    printf("This is a comment line\n");

这表示任何以//开头的行都将被视为注释行。

检测多行​​注释:

^"/*"[^*]*|[*]*"*/" printf("This is a Multiline Comment\n");

*

说明:

*

^"/*"这说开头应该是/*.

[^*]*包括所有字符,包括\ n但不包括*。

[*]*表示0个或更多星星。

[^*]|[*]* - &#34;或&#34;应用运算符来获取任何字符串。

"*/"指定* /作为结束。

这将在lex中完美运作。

以下是lex文件的完整代码:

%{
#include <stdio.h>
int v=0;
%}
%%
^"//"    printf("This is a comment line\n");
^"/*"[^*]*|[*]*"*/" printf("This is a Multiline Comment\n");
.|\n {}
%%
int yywrap()
{
    return 1;
}
main()
{
    yylex();
}