删除C文件中的注释,同时每行读取一行

时间:2015-01-09 09:40:44

标签: perl

我想对与C / C ++注释和预处理器指令兼容的汇编文件进行一些重新分解。

不幸的是我不能使用像Astyle这样的重构工具。我必须手动解析我的文件。

我的重构算法迭代文件的每一行,如下所示:

while(<FH>)
{
   next if isComment($_);

   $count += s/$search/$replace/;   # A refactoring rule
   $count += arithmetic($_);        # R1=R2+3*4;  --> r1 = r2 + 3 * 4;
   ...
   $out .= $_;
}

if($count)
{
   open my $fh ">$filename";
   print $fh $out;
   close $fh;
}

使用这种方法我无法准确检测到评论行。因此,我实施的计数器指向每个/*,并减少每个*/。如果计数器大于0,我忽略该行。

不幸的是,在这种情况下,此方法不起作用:

/*     /* <-- Not allowed      */ /*    */ 

计数器将等于1,而它应该等于0.

所以我正在寻找一种准确的方法来检测注释块并忽略它们。有没有可以帮助我的包裹或模块?

2 个答案:

答案 0 :(得分:1)

您必须更详细地解析代码,因为评论字符可能位于字符串中或#ifdef中。

也许您应该运行预处理器来为您准备代码。对于GCC预处理器,请查看How do I run the GCC preprocessor to get the code after macros like #define are expanded?

您可能希望将预处理的代码输出到stdout并在perl代码中打开一个管道。

要完全正确地执行它,您还必须解析所有包含文件。想象一下以下(非常糟糕但有效)的代码:

inc1.h

/*

inc2.h

*/

的main.c

#include <stdio.h>

int main() {
    #include "inc1.h"
    printf("Ha!\n");
    #include "inc2.h"
}

答案 1 :(得分:0)

最终我发现这个解决方案效果很好。我全局识别所有评论区块,并将其替换为标记/*@@n@@*/,其中n是一个数字。

处理完成后,我可以恢复原始评论。

#!/usr/bin/env perl
use 5.014;
use strict;
use warnings;

# C/C++ Comment detection
my $re = qr{(
   /\*         ##  Start of /* ... */ comment
   [^*]*\*+    ##  Non-* followed by 1-or-more *'s
   (?:
     [^/*][^*]*\*+
   )*
   /
   |//.*      ##  // ... comment
   |"[^"]*"   ##  A souble quoted string
   |'[^"]*'   ##  A simple quoted string
   )}mx;

my $i = 0;
my @comments = ();

while(<$fh>) {
    return unless -f;
    my $filename = $_;

    # Read whole file
    open my $fh, '<', $filename or die "Unable to open $filename";
    $_ = do {local $/ = undef; <$fh>};

    # Store C/C++ comments and replace them with markers
    $i = 0;
    @comments = ();
    s|$re|&store($1)|eg;

    # Do the processing
    ...

    # Restore C comments
    $i = 0;
    for my $comment (@comments) {
       my $s = quotemeta("/*@@".$i++."@@*/");
       s|$s|$comment|g;
    }
}

sub store {
    my $marker = "/*@@".$i."@@*/";
    $comments[$i] = shift;
    $i++;
    $marker;
}