用正则表达式提到c程序注释

    “提取c程序注释”,这是一个典型的状态机问题,但在此我想用正则表达式(regExp)工具来解决。
    perl的正则表达式很强,起初我想到“多行匹配”,将c文件整个读入一个串变量,然后逐个抽取/*块注释*/。这可能需要使用选项 /m /g ,还得考虑行注释和块注释符的混合情况,是个棘手的问题。
初次尝试 发现一个大问题: 匹配最大串还是最小串?
 

# perl 5.12
# // 行注释
# /* */ 块注释
# 识别错误的原因:匹配最大串 /*comment1*//*comment2*/

open(ifp, "comments.txt") || die ("canot open file.");
$/=undef; # 吞噬

$cnt=0;
while($line = <DATA>)
{
    $line =~ /\/\*.*\*\//s;
    printf("line%2d:%s", $cnt++, $&);
}

__DATA__
/*comment1*/
int sum(int a, int b)
{
return a+b;
}
/*comment2*/


对于模式 /\/\*.*\*\//s 我期望它匹配 /*comment1*/ ,但它却匹配了 /*comment1*/ ... /*comment2*/. 有没有一种方法可以成对匹配?

有。模式对 /\/\*/ ... /\*\// 将成对匹配 /* 和 */。
据推测,模式对 /pattern1/.../pattern2/的工作过程大致如下:
bool sw=off;
if(sw==off)
{
 if(line match /pattern1/)
  sw=on;
}
else
{
 do something, like print~
 if(line match /pattern1/)
  sw=off; 
}
if(sw == on)
    do something.

能够识别行注释和块注释的正则式式perl如下:

# // 行释
# /* 块注释 */
# 注:要求代码与注释分行,因为正则以行为单位匹配。
# 可用格式化工具(ArtisticStyle)将代码与注释分行。
# 特点:识别出的注释保持缩进。

use strict;
use warnings;

my $cnt=0;
my $str;
my $bMultiLine=0;

while (<DATA>)
{
    #print "$_";
    $cnt++;
    $str = $_;
    
    # 单行内的注释
    if(!$bMultiLine)
    {
        # 行注释(要求与代码不在同一行,可用格式化工具将代码与注释分行)
        if (/\s*\/\//)
        {
            print "$cnt S:";
            print;
            next; # skip 
        }
        
        if (/\/\*.*\*\//) # 只占一行的块注释    
        {
            print "$cnt B:";
            print;
            next; # skip 
        }
    }
    
    # 跨行的块注释
    if (/\/\*/ ... /\*\//) # /* ... */
    {
        print "$cnt M:";
        print;
        $bMultiLine=1;
    }
    
    if($bMultiLine)
    {
        if(/.*\*\//)
        {
            $bMultiLine = 0;
        }   
    }    
}
__DATA__
行注释
// this is a line comment
 // this is a line /* comment * /

块注释(只占一行)
/* this is a block comment, in one line. */
/* this is a block comment, // in one line. */

块注释(跨行)
/*
this is a block comment, in multi-line.
*/

块注释中的//属于注释内容
/* this is a
block comment, but
// not a line comment */

块注释中的/*属于注释内容
/* this is a
/* block
/* comment */

块注释不能嵌套,如下面是非法的块注释
/*
illegal comment, because
/* nest... */
ing
*/

void SetPwm(unsigned long m) // 这个行注释与代码在同一行,再与块注释符混合 /* 用regExp难以识别它。 */
{
    printf("hi!");
}


它有一点不足:以行匹配。这要求注释与非注释不能在同一行,这个要求不免苛刻。至于是否可用正则的位置变量、预见性匹配等技巧来解决此问题,我没有更多的想法。 “提取c程序注释”的一种更实用和明了的方法是使用状态机思想,见[状态机示例-提取c程序注释]

作者: vivieu   发布时间: 2010-12-23