使用Flex检测和跳过行注释
如何在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); }
为什么不用正则表达式来识别注释? lex/flex
的全部意义在于避免手动编写词法扫描器。 您提供的代码应该可以工作(如果您将模式/*
放在行的开头),但它有点难看,并且它不会显而易见。
您的问题是要跳过注释,但您提供的代码使用putchar()
来打印注释,但开头的/*
除外。 你想做什么? 如果要回显注释,可以使用ECHO
操作而不是什么都不做。
以下是正则表达式:
单行评论
这个很容易,因为在lex / flex中.
将不符合换行符。 因此,以下内容将从//
到行的末尾匹配,然后不执行任何操作。
"//".* { /* DO NOTHING */ }
多行评论
这有点棘手,而且*是正则表达式字符以及注释标记的关键部分这一事实使得以下正则表达式有点难以阅读。 我使用[*]
作为识别字符*的模式; 在flex / lex中,您可以使用"*"
代替。 使用您认为更具可读性的任何一种。 本质上,正则表达式匹配以(字符串) *结尾的字符序列,直到找到下一个字符为/的字符串。 换句话说,它具有与C代码相同的逻辑。
[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] { /* DO NOTHING */ }
以上要求终止*/
; 未终止的注释将强制词法分析器返回到注释的开头并接受一些其他令牌,通常是/ division运算符。 这可能不是你想要的,但是从未经评论的评论中恢复并不容易,因为没有真正好的方法可以知道评论应该在哪里结束。 因此,我建议添加错误规则:
[/][*][^*]*[*]+([^*/][^*]*[*]+)*[/] { /* DO NOTHING */ } [/][*] { fatal_error("Unterminated comment"); }
对于//
您可以阅读,直到找到行尾\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 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; }
要检测单行注释:
^"//" printf("This is a comment line\n");
这表示以//开头的任何行都将被视为注释行。
要检测多行注释:
^"/*"[^*]*|[*]*"*/" printf("This is a Multiline Comment\n");
*
说明:
*
^"/*"
这表示开头应为/ *。
[^*]*
包括所有字符,包括\ n但不包括*。
[*]*
表示0或更多星数。
[^*]|[*]*
– 应用“或”运算符来获取任何字符串。
"*/"
指定* /作为结束。
这将在lex中完美运行。
以下是lex文件的完整代码:
%{ #include int v=0; %} %% ^"//" printf("This is a comment line\n"); ^"/*"[^*]*|[*]*"*/" printf("This is a Multiline Comment\n"); .|\n {} %% int yywrap() { return 1; } main() { yylex(); }