Domanda

Ho un file di intestazione in cui v'è un grande struct. Ho bisogno di leggere questa struttura usando qualche programma e fare alcune operazioni su ogni membro della struttura e di scrivere di nuovo.

Per esempio io ho qualche struttura come

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

Ora, ho bisogno di leggere questo e applicare un po 'il funzionamento su ciascuna delle variabile membro e creare una nuova struttura con ordine diverso, qualcosa di simile:

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

C'è qualche libreria Perl già disponibili per questo? In caso contrario Perl, qualcos'altro come Python è anche OK.

Qualcuno può aiutare !!!

È stato utile?

Soluzione

Come mantenere i dati in giro in un colpo di testa rende più difficile per arrivare a utilizzare altri programmi come Perl. Un altro approccio che si potrebbe prendere in considerazione è quello di mantenere questi dati in un database o un altro file e rigenerare il file di intestazione quando necessario, forse anche come parte del sistema di compilazione. La ragione di questo è che la generazione di C è molto più facile di effettuare il parsing C, è banale per scrivere uno script che analizza un file di testo e fa un colpo di testa per te, e uno di questi script potrebbe anche essere richiamato dal sistema di compilazione.

Supponendo che si desidera conservare i dati in un file di intestazione C, avrete bisogno di una delle due cose per risolvere questo problema:

  • uno script una tantum veloce per analizzare esattamente (o quasi esattamente) l'ingresso che descrivi.
  • un generale, sceneggiatura ben scritta in grado di analizzare arbitraria C e lavorare generalmente a un sacco di diverse intestazioni.

Il primo caso sembra più comune di quanto la seconda a me, ma è difficile dire dalla tua domanda se questo è meglio risolto da uno script che ha bisogno di analizzare C arbitraria o uno script che ha bisogno di analizzare questo file specifico. Per il codice che funziona sul vostro caso specifico, i seguenti lavori per me sul vostro ingresso:

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

Analisi arbitraria C è un po 'complicato e non vale la pena per molte applicazioni, ma forse è necessario fare in realtà questo. Un trucco è lasciare GCC fare il parsing per voi e leggere in albero sintattico di GCC utilizzando un modulo CPAN denominato GCC :: TranslationUnit . Ecco il comando GCC per compilare il codice, a patto di avere un singolo file denominato test.c:

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

Ecco il codice Perl per leggere l'albero di analisi:

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

Altri suggerimenti

Scusate se questa è una domanda stupida, ma perché preoccuparsi di analisi del file a tutti? Perché non scrivere un programma C che #includes l'intestazione, elabora come richiesto e poi sputa la fonte per l'intestazione modificata. Sono sicuro che questo sarebbe più semplice rispetto alle soluzioni Perl / Python, e sarebbe molto più affidabile perché l'intestazione sarebbe essere analizzato dal parser compilatori C.

In realtà non fornire molte informazioni su come ciò che deve essere modificato deve essere determinato, ma per rispondere alle vostre esempio specifico:

$ 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

Rottura che verso il basso, -p dice ciclo attraverso i file di input, mettendo ogni riga $_, l'esecuzione del codice in dotazione, quindi stampare $_. -i.bak consente l'editing in-place, rinominare ogni file originale con un suffisso .bak e la stampa in un nuovo file chiamato tutto ciò che era l'originale. -w consente avvertimenti. -e '....' fornisce il codice da eseguire per ogni linea di ingresso. header.h è l'unico file di input.

Nel codice Perl, controlli if ( /const BYTE Some_Idx/ .. /;/ ) che siamo in una gamma di linee che iniziano con un /const BYTE Some_Idx/ linea di corrispondenza e che termina con un /;/ linea di corrispondenza. s /.../.../ g fa un cambio tante volte quanto possibile. /(\d+)/ corrisponde a una serie di cifre. La bandiera / e dice che il risultato ($1 * 2) è il codice che deve essere valutato per produrre una stringa di sostituzione, invece di limitarsi a una stringa di sostituzione. $ 1 è le cifre che dovrebbero essere sostituiti.

Se tutto quello che dovete fare è modificare le strutture, è possibile utilizzare direttamente regex per dividere e applicare le modifiche a ogni valore nella struct, cercando la dichiarazione e il finale}; per sapere quando fermarsi.

Se si ha realmente bisogno di una soluzione più generale si può utilizzare un generatore di parser, come PyParsing

C'è un modulo Perl chiamato Parse :: RecDescent che è molto potente ricorsiva generatore discesa parser. Viene fornito con una serie di esempi. Uno di loro è un grammatica in grado di analizzare C .

Ora, non credo che questo importa nel tuo caso, ma i parser ricorsivo discesa utilizzando Parse :: RecDescent sono algoritmicamente più lento (O (n ^ 2), credo) di strumenti come Parse :: Yapp o Parse :: EYapp. Non ho controllato se Parse :: EYapp viene fornito con un tale esempio C-parser, ma se è così, questo è lo strumento mi consiglia di apprendimento.

soluzione Python (non completa, solo un accenno;)) Scusate se eventuali errori - non testati

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()

Non è un modulo molto utile Perl chiamato Convertire :: :: Binary C che analizza i file header C e converte le strutture da / per strutture di dati Perl.

Si può sempre utilizzare pack / unpack , a leggere, e scrivere i dati.

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

Per l'esempio GCC :: TranslationUnit vedere hparse.pl da http://gist.github.com/395160 che renderà in C :: DynaLib, e il ctypes non ancora scritto anche. Questo analizza funzioni per FFI di, e le strutture non nude contrarie ai Convertire :: :: Binary C. hparse solo aggiungere le struct se utilizzato come args Funz.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top