我想在Flex中创建一个规则来匹配C风格的注释,例如 /* */。
我有以下代码:
c_comment "/*"[\n.]*"*/"
但它从未被匹配。 任何想法为什么?如果需要更多我的代码,请告诉我,我会提交全部内容。感谢回复的任何人。
我想在Flex中创建一个规则来匹配C风格的注释,例如 /* */。
我有以下代码:
c_comment "/*"[\n.]*"*/"
但它从未被匹配。 任何想法为什么?如果需要更多我的代码,请告诉我,我会提交全部内容。感谢回复的任何人。
我建议你使用开始条件。
%x C_COMMENT
"/*" { BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { BEGIN(INITIAL); }
<C_COMMENT>\n { }
<C_COMMENT>. { }
请注意,<condition>
和规则之间不能有任何空格。
%x C_COMMENT
定义了C_COMMENT状态,并将规则/*
与它开始联系。一旦开始,*/
将使其返回到初始状态(INITIAL
是预定义的),每个其他字符都将被消耗而没有特定的动作。当两个规则匹配时,Flex通过选择具有最长匹配长度的规则来消除歧义,因此点规则不会阻止*/
匹配。\n
规则是必需的,因为点可匹配除换行符以外的所有字符。
%x
定义使C_COMMENT成为一个独占状态,这意味着词法分析器只会在进入该状态后匹配“标记”<C_COMMENT>
的规则。/* comments */
之外的所有内容实现了此答案。/* rubbish */ */
识别为完整的块注释(从/*
到第二个*/
),而不是C风格的块注释,在这种注释中,开头的/*
由最近的结束符*/
终止,另一个*/
被识别为程序中的杂字符。以下正则表达式(用于flex / lex)也处理了这种情况"/*"((("*"[^/])?)|[^*])*"*/"
来源- [链接](https://dev59.com/BmQo5IYBdhLWcg3wUN7Y) - Shobhit<C_COMMENT>. { }
上,如果 @zneak 使用以下代码,则可以解决问题 <C_COMMENT>[^*\n]*<C_COMMENT>"*"+[^*/\n]*
。它会吞掉除了 * 后跟 / 之外的所有内容。
因此,在这种情况下,它将以第一个 * 后跟 / 结束。所以 /* rubbish */ foolosh */
,它将注释掉 /* rubbish */
并跟随下一个标记 foolish */
。 - Nitin Tripathi。
规则不应该匹配关闭注释的*
,因为关闭注释比任何字符都长。 - zneakecho "/* this is a multiline comment */abc" | ./a.out
其中注释块有四个换行符,结果是四个换行符后跟着'abc'。我认为这不正确 - 整个注释块应该被忽略,因此注释块中的换行符不应影响输出。 - mwag如果有人不清楚如何使用zneak的答案,请看下面的例子:
(基本上,你把“%x C_COMMENT”放在第一部分中,其余内容放在第二部分中,正如他提供的有用链接所解释的那样)
foo.l
%{
// c code..
%}
%x C_COMMENT
%%
"/*" { BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { BEGIN(INITIAL); }
<C_COMMENT>. { }
%%
// c code..
不确定为什么它没有被捕捉到,但我知道这种模式可能会产生大型词汇元素。检测只是开始注释标记并将一切都扔进位桶,直到找到结束标记更有效率。
这个网站有代码可以实现这一点:
"/*" {
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;
}
}
}
"/*"((\*+[^/*])|([^*]))*\**"*/"
yytext
中缓冲。 - wcochran在Flex手册中有一个实例,它可以正确处理棘手的边缘情况:
<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++;
我尝试了几种建议的解决方案,这里是结果。
paxdiablo的答案有效,并且有易读性的优点。我进一步修改如下:
"/*" { int c1 = 0, c2 = input(); for(;;) { if(c2 == EOF) break; if(c1 == '*' && c2 == '/') break; c1 = c2; c2 = input(); } }
"/*"([^*]*|(\*+[^/]))*"*/"
[^*]
包括 \r
和 \n
(以及除 *
之外的每个8位代码),因此 |[\r\n]
是不必要的。(就像链接文章中大多数其他正则表达式环境一样,除了 nedit
。) - rici