如何使用Perl解析C头文件?

Alp*_*neo 6 c python perl parsing header-files

我有一个头文件,其中有一个大型结构.我需要使用一些程序读取这个结构,并对结构的每个成员进行一些操作并将它们写回.

例如,我有一些结构

const BYTE Some_Idx[] = {
4,7,10,15,17,19,24,29,
31,32,35,45,49,51,52,54,
55,58,60,64,65,66,67,69,
70,72,76,77,81,82,83,85,
88,93,94,95,97,99,102,103,
105,106,113,115,122,124,125,126,
129,131,137,139,140,149,151,152,
153,155,158,159,160,163,165,169,
174,175,181,182,183,189,190,193,
197,201,204,206,208,210,211,212,
213,214,215,217,218,219,220,223,
225,228,230,234,236,237,240,241,
242,247,249};
Run Code Online (Sandbox Code Playgroud)

现在,我需要阅读此内容并对每个成员变量应用一些操作,并创建一个具有不同顺序的新结构,如:

const BYTE Some_Idx_Mod_mul_2[] = {
8,14,20, ...
...
484,494,498};
Run Code Online (Sandbox Code Playgroud)

是否有可用于此的Perl库?如果不是Perl,像Python这样的东西也行.

有人可以帮忙!!!

Jam*_*son 9

保持数据位于标题中会使得使用Perl等其他程序变得更加棘手.您可能考虑的另一种方法是将此数据保存在数据库或其他文件中,并根据需要重新生成头文件,甚至可能作为构建系统的一部分.这样做的原因是生成C比解析C容易得多,编写一个解析文本文件并为您创建标题的脚本是微不足道的,甚至可以从您的构建系统调用这样的脚本.

假设您希望将数据保存在C头文件中,则需要以下两种方法之一来解决此问题:

  • 一个快速的一次性脚本,可以准确地(或接近确切地)解析您描述的输入.
  • 一个通用的,编写良好的脚本,可以解析任意C并且通常可以处理许多不同的头文件.

第一种情况似乎比第二种情况更常见,但很难从你的问题中判断出是否可以通过需要解析任意C或需要解析此特定文件的脚本的脚本来解决这个问题.对于适用于您的特定案例的代码,以下内容适用于您的输入:

#!/usr/bin/perl -w

use strict;

open FILE, "<header.h" or die $!;
my @file = <FILE>;
close FILE or die $!;

my $in_block = 0;
my $regex = 'Some_Idx\[\]';
my $byte_line = '';
my @byte_entries;
foreach my $line (@file) {
    chomp $line;

    if ( $line =~ /$regex.*\{(.*)/ ) {
        $in_block = 1;
        my @digits = @{ match_digits($1) };
        push @digits, @byte_entries;
        next;
    }

    if ( $in_block ) {
        my @digits = @{ match_digits($line) };
        push @byte_entries, @digits;
    }

    if ( $line =~ /\}/ ) {
        $in_block = 0;
    }
}

print "const BYTE Some_Idx_Mod_mul_2[] = {\n";
print join ",", map { $_ * 2 } @byte_entries;
print "};\n";

sub match_digits {
    my $text = shift;
    my @digits;
    while ( $text =~ /(\d+),*/g ) {
        push @digits, $1;
    }

    return \@digits;
}
Run Code Online (Sandbox Code Playgroud)

解析任意C有点棘手,对于许多应用程序来说不值得,但也许您需要实际执行此操作.一个技巧是让GCC为你做解析,并使用名为GCC :: TranslationUnit的CPAN模块读入GCC的解析树.这是编译代码的GCC命令,假设您有一个名为test.c的文件:

gcc -fdump-translation-unit -c test.c

这是在解析树中读取的Perl代码:

  use GCC::TranslationUnit;

  # echo '#include <stdio.h>' > stdio.c
  # gcc -fdump-translation-unit -c stdio.c
  $node = GCC::TranslationUnit::Parser->parsefile('stdio.c.tu')->root;

  # list every function/variable name
  while($node) {
    if($node->isa('GCC::Node::function_decl') or
       $node->isa('GCC::Node::var_decl')) {
      printf "%s declared in %s\n",
        $node->name->identifier, $node->source;
    }
  } continue {
    $node = $node->chain;
  }
Run Code Online (Sandbox Code Playgroud)


小智 6

对不起,如果这是一个愚蠢的问题,但为什么要担心解析文件呢?为什么不编写#includes标头的C程序,根据需要处理它,然后吐出修改后的标头的源代码.我确信这比Perl/Python解决方案更简单,并且它会更可靠,因为标头将被C编译器解析器解析.

  • 您还可以编写一个编写C程序的程序. (3认同)