如何处理flex中的嵌套注释
how to handle nested comment in flex
我正在为一种支持嵌套注释的语言编写一个flex扫描程序,如下所示:
/*
/**/
*/
我曾经在ocaml/ocamlex上工作,它非常优雅地支持递归调用lex scanner。但我现在正在切换到c++/flex,如何处理这样的嵌套注释?
假设只有注释可以嵌套在注释中,对于一个简单的计数器来说,堆栈是一个非常昂贵的解决方案。例如:
%x SC_COMMENT
%%
int comment_nesting = 0; /* Line 4 */
"/*" { BEGIN(SC_COMMENT); }
<SC_COMMENT>{
"/*" { ++comment_nesting; }
"*"+"/" { if (comment_nesting) --comment_nesting;
else BEGIN(INITIAL); }
"*"+ ; /* Line 11 */
[^/*n]+ ; /* Line 12 */
[/] ; /* Line 13 */
n ; /* Line 14 */
}
一些解释:
第4行:第一条规则之前的缩进行插入yylex
函数的顶部,用于声明和初始化局部变量。我们使用它在每次调用yylex
时将注释嵌套深度初始化为0。必须保持的不变量是comment_nesting
在INITIAL
状态下总是0。
第11-13行:一个更简单的解决方案是单一模式CCD_ 5,但这将导致每个评论字符都被视为一个单独的子标记。即使相应的操作什么都不做,这也会导致扫描循环中断,并对每个字符执行操作切换语句。因此,通常最好尝试同时匹配几个字符。
不过,我们需要小心/和*字符;我们只能忽略那些我们确信不是终止(可能嵌套的)注释的*的星号。因此,第11行和第12行。(第12行不会匹配后面跟着/的星号序列,因为这些星号已经被上面第9行的模式匹配了。)如果后面没有*。因此,第13行。
第14行:然而,匹配过大的代币也可能是次优的。
首先,flex没有针对大型令牌进行优化,并且注释可能非常大。如果flex需要在令牌中间重新填充其缓冲区,它将在新的缓冲区中保留打开的令牌,然后从令牌的开头重新扫描。
其次,柔性扫描仪可以自动跟踪当前的行号,而且相对高效。扫描程序只在与可能匹配换行符的模式匹配的标记中检查换行符。但整个比赛都需要扫描。
我们通过将注释中的换行符作为单独的标记进行匹配来减少这两个问题的影响。(第14行,另请参见第12行)这将yylineno
扫描限制为单个字符,还限制了内部注释标记的预期长度。注释本身可能非常大,但每一行都可能被限制在合理的长度内,从而避免了缓冲区重新填充时潜在的二次重新扫描。
我通过使用yy_push_state、yy_pop_state和启动条件来解决这个问题,如下所示:
%x comment
%%
"/*" {
yy_push_state(comment);
}
<comment>{
"*/" {
yy_pop_state();
}
"/*" {
yy_push_state(comment);
}
}
%%
通过这种方式,我可以处理任何级别的嵌套注释。
- 嵌套在类中时无法设置成员数据
- 无法访问嵌套类.类的使用无效
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 在C++中搜索嵌套多映射值
- 在C++中将矢量转换为嵌套地图
- C++嵌套if语句,基本货币交换
- 在nlohmann json中,如何将嵌套对象的数组转换为嵌套结构的向量
- 嵌套的匿名命名空间
- 了解嵌套循环打印星号图案
- 如何使用boost::具有嵌套结构和最小代码更改的序列化
- 嵌套for循环C++的问题(初学者)
- 从嵌套在std::映射中的std::列表中删除元素的最佳方式
- 用C#中的并集模拟C++嵌套结构
- 部分专业化和嵌套模板
- 嵌套While循环不起作用(C++问题)
- C++-模板嵌套类的引用初始化无效
- 如何处理flex中的嵌套注释
- 在c++中使用嵌套注释来快速(取消)激活代码块是有危险的