Pergunta

Eu tenho um arquivo de cabeçalho no qual há uma grande estrutura. Eu preciso ler esta estrutura usando algum programa e fazer algumas operações em cada membro da estrutura e escrevê-los de volta.

Por exemplo, eu tenho alguma estrutura como

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};

Agora, eu preciso ler este e aplicar alguma operação em cada um a variável de membro e criar uma nova estrutura com ordem diferente, algo como:

const BYTE Some_Idx_Mod_mul_2[] = {
8,14,20, ...
...
484,494,498};

Existe alguma biblioteca Perl já está disponível para isso? Se não Perl, outra coisa, como Python também é OK.

Pode alguém por favor ajuda !!!

Foi útil?

Solução

Manter seus dados em torno de mentir em um cabeçalho torna mais complicado para chegar a usar outros programas como Perl. Outra abordagem que você pode considerar é manter esses dados em um banco de dados ou outro arquivo e regenerar o seu arquivo de cabeçalho conforme a necessidade, talvez até mesmo como parte de seu sistema de compilação. A razão para isto é que a geração C é muito mais fácil do que analisar C, é trivial para escrever um script que analisa um arquivo de texto e faz um cabeçalho para você, e esse script poderia mesmo ser chamado a partir de seu sistema de compilação.

Assumindo que você quiser manter seus dados em um arquivo de cabeçalho C, você terá uma de duas coisas para resolver este problema:

  • um script one-off rápido para analisar exatamente (ou próximo a exatamente) a entrada que você descreve.
  • um script geral, bem escrito que pode analisar C arbitrária e trabalho em geral sobre a lotes de diferentes cabeçalhos.

O primeiro caso parece ser mais comum do que o segundo para mim, mas é difícil dizer de sua pergunta se isso é melhor resolvido por um script que precisa para analisar C arbitrária ou um script que precisa analisar este arquivo específico. Para código que funciona no seu caso específico, as seguintes obras para mim sobre sua entrada:

#!/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;
}

Analisando C arbitrária é um pouco vale a pena complicado e não-lo para muitas aplicações, mas talvez você precisa realmente fazer isso. Um truque é deixar GCC fazer a análise para você e ler na árvore de análise do GCC usando um módulo CPAN chamado GCC :: TranslationUnit . Aqui está o comando GCC para compilar o código, supondo que você tem um único arquivo chamado test.c:

gcc -fdump-tradução-unit -c test.c

Aqui está o código Perl para ler na árvore de análise:

  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;
  }

Outras dicas

Desculpe se isso é uma pergunta estúpida, mas por que se preocupar com a análise do arquivo em tudo? Por que não escrever um programa em C que #includes o cabeçalho, processa-o conforme necessário e, em seguida, cospe para fora a fonte para o cabeçalho modificado. Tenho certeza que isso seria mais simples do que as soluções Perl / Python, e seria muito mais confiável porque o cabeçalho estariam sendo analisados ??pelo analisador compiladores C.

Você realmente não fornecem muita informação sobre como o que deve ser modificado deve ser determinado, mas para resolver o seu exemplo específico:

$ perl -pi.bak -we'if ( /const BYTE Some_Idx/ .. /;/ ) { s/Some_Idx/Some_Idx_Mod_mul_2/g; s/(\d+)/$1 * 2/ge; }' header.h

Quebrando que para baixo, -p diz loop através de arquivos de entrada, colocando cada linha $_, executar o código fornecido, em seguida, imprimir $_. -i.bak permite a edição no local, renomear cada arquivo original com um sufixo bak e imprimir em um novo arquivo chamado qualquer que seja o original. -w habilita advertências. -e '....' fornece o código para ser executado para cada linha de entrada. header.h é o único arquivo de entrada.

No código perl, cheques if ( /const BYTE Some_Idx/ .. /;/ ) que estamos em uma série de linhas que começam com um /const BYTE Some_Idx/ linha de correspondência e terminando com um /;/ linha correspondente. s /.../.../ g faz uma substituição tantas vezes quanto possível. /(\d+)/ corresponde a uma série de dígitos. A / e bandeira diz que o resultado ($1 * 2) é o código que deve ser avaliada para produzir uma cadeia de substituição, em vez de simplesmente uma seqüência de substituição. $ 1 é os dígitos que devem ser substituídos.

Se tudo que você precisa fazer é modificar estruturas, você pode usar diretamente regex para dividir e aplicar alterações a cada valor na struct, olhando para a declaração eo fim}; saber quando parar.

Se você realmente precisa de uma solução mais geral você poderia usar um gerador de analisador, como pyparsing

Existe um módulo Perl chamado Parse :: RecDescent que é uma muito poderosa gerador de analisador descendente recursivo. Ele vem com um monte de exemplos. Um deles é um gramática que pode analisar C .

Agora, eu não acho que isso é importante no seu caso, mas os analisador sintático descendente recursivo usando Parse :: RecDescent são algoritmos mais lenta (O (n ^ 2), eu acho) do que ferramentas como Parse :: Yapp ou Parse :: EYapp . Eu não tenho verificado se Parse :: EYapp vem com um tal exemplo C-parser, mas se assim for, isso é a ferramenta eu recomendo aprendizagem.

solução Python (não completa, apenas uma sugestão;)) Desculpe se quaisquer erros - não testado

import re
text = open('your file.c').read()
patt = r'(?is)(.*?{)(.*?)(}\s*;)'
m = re.search(patt, text)
g1, g2, g3 = m.group(1), m.group(2), m.group(3)
g2 = [int(i) * 2 for i in g2.split(',')
out = open('your file 2.c', 'w')
out.write(g1, ','.join(g2), g3)
out.close()

Existe um módulo Perl realmente útil chamado Convert :: Binary :: C que os arquivos de cabeçalho parses C e converte estruturas de / para estruturas de dados Perl.

Você pode sempre usar pack / unpack , para ler e escrever os dados.

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

my @data;
{
  open( my $file, '<', 'Some_Idx.bin' );

  local $/ = \1; # read one byte at a time

  while( my $byte = <$file> ){
    push @data, unpack('C',$byte);
  }
  close( $file );
}

print join(',', @data), "\n";

{
  open( my $file, '>', 'Some_Idx_Mod_mul_2.bin' );

  # You have two options
  for my $byte( @data ){
    print $file pack 'C', $byte * 2;
  }
  # or
  print $file pack 'C*', map { $_ * 2 } @data;

  close( $file );
}

Para o GCC :: TranslationUnit exemplo ver hparse.pl de http://gist.github.com/395160 que irá fazê-lo em C :: DynaLib, eo Ctypes ainda não escrita também. Este Analisa funções para FFI de e estruturas não descalços contrárias converter :: Binary :: C. hparse só irá adicionar estruturas se usado como args func.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top