使用状态的 flex 中的注释模式匹配

Comment pattern match in flex using states

我正在尝试匹配 flex 中的单行注释模式。评论的模式可以是:

//this is a single /(some random stuff) line comment

或者可以这样:

// this is also a comment\
continuation of the comment from previous line

从示例中可以看出,我也必须处理多行情况。

现在我的方法是使用状态。这是我目前所拥有的:

"//"                    {
                            yymore();
                            BEGIN (SINGLE_COMMENT); 
                        }

<SINGLE_COMMENT>([^{NEWLINE}]|\[(.){NEWLINE}]) {
                                                    yymore();
                                                }           

<SINGLE_COMMENT>([^{NEWLINE}]|[^\]{NEWLINE})   {
                                                    logout << "Line no " << line_count << ": TOKEN <COMMENT> Lexeme " << string(yytext) << "\nfound\n\n";
                                                    BEGIN (INITIAL);
                                                }

NEWLINE 声明为:

 NEWLINE \r?\n

我的申报单位:

%option noyywrap

%x SINGLE_COMMENT

int line_count = 1;
const int bucketSize = 10; // change if necessary

ofstream logout;
ofstream tokenout;

SymbolTable symbolTable(bucketSize);

NEWLINE 的操作:

{NEWLINE}    {
                line_count++;
             }

如果我 运行 它具有以下输入:

// hello\
int main

这是我的日志文件:

Line no 1: TOKEN <COMMENT> Lexeme // hello\

found

Line no 1: TOKEN <INT> Lexeme int found

Line no 1: TOKEN <ID> Lexeme main found


 ScopeTable # 1

 6 --> < main , ID > 

所以,它没有捕捉到多行评论。 line_count 也不会递增。它保持不变。谁能帮我弄清楚我做错了什么?

Link to code

在 (f)lex 中,与在大多数正则表达式引擎中一样,[] 包含一个 character class 描述。一个字符 class 是一组单独的字符,它总是与该组中的一个字符完全匹配。还有否定字符 classes,它们的写法相同,只是它们以 [^ 开头,并且恰好匹配一个不属于集合成员的字符。

字符 class 与字符序列不同:

  • ab 匹配 a 后跟 b
  • [ab] 匹配 ab

由于字符class只是字符的集合,class中的单个字符重复或可选等是没有意义的。因此,几乎没有正则表达式运算符(*+? 等)在字符 class 中是有意义的。如果将其中之一放在字符 class 表达式中,它会像处理普通字符一样处理:

  • a* 匹配 0 个或多个 as
  • [a*] 匹配 a*

flex 提供的功能之一是大多数其他正则表达式系统不提供的功能是宏扩展,形式为 {name}。这里的 {} 表示定义的宏的扩展,其名称包含在大括号之间。这些字符在字符 class:

中也不特殊
  • {identifier} 匹配名为 identifier 的扩展宏所匹配的任何内容。
  • [{identifier}] 匹配 {} 或字母 definrt
  • 之一的单个字符

宏定义似乎被初学者过度使用了。我的建议总是避免它们,从而避免它们造成的混乱。

还值得注意的是 (f)lex 没有否定子模式的运算符。只能取反字符classes;没有简单的方法来写 "match anything other than foo"。但是,您通常可以依靠 first longest-match rule 来有效地实现否定:如果某些模式 p 执行,则不会有任何模式匹配超过 p。因此,可能没有必要明确地写出否定。

例如,在您的评论检测器中,唯一真正的问题是处理回车 return (\r) 后面没有换行符的字符,您可以使用 (f)lex 的模式匹配算法对你有利:

<SINGLE_COMMENT>{
  [^\\r\n]+          ;
  \\r?\n             { ++line_count; }
  \.                 ; /* only matches if the above rule doesn't */
  \r?\n               { ++line_count; BEGIN(INITIAL); }
  \r                  ; /* only matches if the above rule doesn't */
}

顺便说一下,提供 %option yylineno 通常比尝试手动跟踪换行要容易得多。