Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用Flex检测和跳过行注释_C_Compiler Construction_Flex Lexer - Fatal编程技术网

C 使用Flex检测和跳过行注释

C 使用Flex检测和跳过行注释,c,compiler-construction,flex-lexer,C,Compiler Construction,Flex Lexer,如何在Flex中检测像/这样的单行注释并跳过这些行 另外,对于/*注释,以下代码片段是否足够 "/*" { comment(); } %% comment() { char c, c1; loop: while ((c = input()) != '*' && c != 0) putchar(c); if ((c1 = input()) != '/' &a

如何在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);
    }

对于
/
,您可以一直阅读,直到找到
\n
EOF
行的结尾,如果注释位于文件末尾,例如:

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;
}
%{
#包括
静态无效跳过单行注释(无效);
静态无效跳过多行注释(无效);
%}
%选项No yywrap
%%
“/”{puts(“跳过简短评论”);
跳过单行注释()}
“/*”{puts(“长评论开始”);
跳过多行注释();
puts(“长注释结束”);}
“”{/*空*/}
[\n |\r\n\t]{/*空*/}
.                 {fprintf(stderr,“标记化错误:'%c'\n',*yytext”);
yyterminate();}
%%
静态空隙
跳过单行注释(无效)
{
INTC;
/*阅读直到找到\n或EOF*/
而((c=input())!='\n'和&c!=EOF)
;
/*也许你想把EOF放回去*/
如果(c==EOF)
取消打印(c);
}
静态空隙
跳过多行注释(无效)
{
INTC;
对于(;;)
{
开关(输入())
{
/*我们希望在EOF之前先结束评论*/
案例EOF:
fprintf(标准,“错误未关闭注释,预期*/\n”);
出口(-1);
去做;
打破
/*这是评论的结尾吗*/
案例“*”:
如果((c=input())=='/'))
去做;
取消打印(c);
打破
违约:
/*跳过此字符*/
打破
}
}
完成:
/*出入境*/;
}
int main(int argc,字符**argv)
{
yylex();
返回0;
}

为什么不使用正则表达式来识别注释呢?
lex/flex
的全部目的是避免您必须手工编写词汇扫描程序。您提供的代码应该可以工作(如果您将模式
/*
放在行的开头),但是它有点难看,而且不明显它是否可以工作

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

以下是正则表达式:

单行评论

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

"//".*                                    { /* DO NOTHING */ }
多行评论

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

[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/]       { /* DO NOTHING */ }
上述要求终止
*/
;未终止的注释将强制lexer备份到注释的开头,并接受其他标记,通常是/division运算符。这可能不是你想要的,但要从一条未终止的评论中恢复过来并不容易,因为没有真正好的方法知道该评论应该在哪里结束。因此,我建议添加一个错误规则:

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

要检测单行注释:

^"//"    printf("This is a comment line\n");
^"/*"[^*]*|[*]*"*/" printf("This is a Multiline Comment\n");
这表示任何以//开头的行都将被视为注释行

要检测多行注释:

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

说明:

*

^”/*“
这说明开头应该是/*

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

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

[^*]|[*]*
-“或”运算符用于获取任何字符串

“*/”
将*/指定为结束

这在莱克斯身上非常有效

以下是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();
}
%{
#包括
int v=0;
%}
%%
^“//”printf(“这是注释行\n”);
^“/*”[^*]*|[*]*“*/”printf(“这是一个多行注释\n”);
.|\n{}
%%
int yywrap()
{
返回1;
}
main()
{
yylex();
}

您的多行注释解决方案简单而伟大,但我仍然有一个问题。。。我需要为每行注释增加一个行计数器,所以我需要考虑\n的内部注释…是否有可能保持您的正则表达式解决方案的主要思想?Thanksflex会帮你数台词。参见YYLINENOhmm。。真奇怪。Flex为我的输入返回了错误的行。。。它只计算带有初始注释符号的行。我刚刚提出了另一个问题来讨论这一点@达诺:不对。线路拼接可能发生在初始的
/
之间。此外,如果您支持Trigraph,则可以将线拼接拼写为
??/
。此处的多行注释显然不起作用。考虑:/*富吧**/