2010-11-10 13 views
9

Sto usando pyparsing per analizzare i file vcd (value change dump). In sostanza, voglio leggere i file, analizzarli in un dizionario interno e manipolare i valori.pyparsing, forward e ricorsiva

Senza entrare nei dettagli sulla struttura, il mio problema si verifica con l'identificazione di categorie annidate.

In file vcd, si dispone di 'ambiti' che includono fili e possibilmente alcuni ambiti più profondi (nidificati). Pensa a loro come livelli.

Così nel mio file, ho:

$scope module toplevel $end 
$scope module midlevel $end 
$var wire a $end 
$var wire b $end 
$upscope $end 
$var wire c $end 
$var wire d $end 
$var wire e $end 
$scope module extralevel $end 
$var wire f $end 
$var wire g $end 
$upscope $end 
$var wire h $end 
$var wire i $end 
$upscope $end 

Così 'primo livello' comprende tutto (A - I), 'midlevel' ha (a - b), 'extralevel' ha (f - g) , ecc

Ecco il mio codice (snippet) per l'analisi di questa sezione:

scope_header = Group(Literal('$scope') + Word(alphas) + Word(alphas) + \ 
        Literal('$end')) 

wire_map = Group(Literal('$var') + Literal('wire') + Word(alphas) + \ 
       Literal('$end')) 

scope_footer = Group(Literal('$upscope') + Literal('$end')) 

scope = Forward() 
scope << (scope_header + ZeroOrMore(wire_map) + ZeroOrMore(scope) + \ 
      ZeroOrMore(wire_map) + scope_footer) 

Ora, quello che ho pensato accade è che in quanto colpisce ogni ambito, sarebbe tenere traccia di ogni 'livello ' e finirei con una struttura che contiene ambiti nidificati. Tuttavia, errori su

$scope module extralevel $end 

dicendo che si aspetta "$ upscope".

Quindi so che non sto utilizzando correttamente la ricorsione. Qualcuno mi può aiutare? Fammi sapere se ho bisogno di fornire maggiori informazioni.

Grazie !!!!

risposta

9

In base alla definizione, un ambito non può contenere un altro ambito, seguito da alcune mappe, seguito da un altro ambito.

Se il parser dispone di una modalità di debug in cui stampa il suo albero di analisi, sarà possibile vederlo immediatamente. Ma in breve, stai dicendo che ci sono zero o più mappe, seguite da zero o più ambiti, seguiti da zero o più mappe, quindi se c'è un ambito, seguito da una mappa, hai già passato il campo dell'ambito, quindi eventuali altri ambiti non sono validi. Se la lingua usata dai supporti pyparsing "o" si potrebbe usare:

scope << (scope_header + ZeroOrMore((wire_map | scope)) + scope_footer) 
+1

Buona intuizione! il pyparsing supporta infatti "o" e con la sintassi esatta che hai indovinato. – PaulMcG

+0

Wow, così semplice !!! Esso funziona magicamente!!!!! Grazie mille! – RaytheonLiszt

+0

È sempre bello quando puoi indovinare la sintassi senza doverla cercare. Tuttavia, il sovraccarico può azzannarti a a $$, prova a eseguire il debug di un programma usando Boost Spirit (l'equivalente di pyparse per C++). È tutto il divertimento del debug di C++, ma ogni chiamata di metodo è di venti operatori sovraccaricati in profondità. –

6

Scegliere @ risposta di ZackBloom come quella corretta, ha intuito bene fuori, senza nemmeno sapere la sintassi di pyparsing.

A pochi commenti/suggerimenti sulla grammatica:

Con la risposta postato sopra, è possibile visualizzare la nidificazione utilizzando pprint e pyparsing del metodo asList() su ParseResults:

res = scope.parseString(vcd) 

from pprint import pprint 
pprint(res.asList()) 

Dare:

[[['$scope', 'module', 'toplevel', '$end'], 
    [['$scope', 'module', 'midlevel', '$end'], 
    ['$var', 'wire', 'a', '$end'], 
    ['$var', 'wire', 'b', '$end'], 
    ['$upscope', '$end']], 
    ['$var', 'wire', 'c', '$end'], 
    ['$var', 'wire', 'd', '$end'], 
    ['$var', 'wire', 'e', '$end'], 
    [['$scope', 'module', 'extralevel', '$end'], 
    ['$var', 'wire', 'f', '$end'], 
    ['$var', 'wire', 'g', '$end'], 
    ['$upscope', '$end']], 
    ['$var', 'wire', 'h', '$end'], 
    ['$var', 'wire', 'i', '$end'], 
    ['$upscope', '$end']]] 

Così ora avete risultati ben strutturati. Ma puoi pulire un po 'le cose. Per prima cosa, ora che hai una struttura, non hai veramente bisogno di tutti quei token $scope, $end, ecc. Puoi certamente scavalcarli mentre navighi tra i risultati analizzati, ma puoi anche fare pyparsing e rilasciarli dall'output analizzato (dato che i risultati sono ora strutturati, non stai davvero perdendo nulla).Cambiarti definizioni parser a:

SCOPE, VAR, UPSCOPE, END = map(Suppress, 
           "$scope $var $upscope $end".split()) 
MODULE, WIRE = map(Literal, "module wire".split()) 

scope_header = Group(SCOPE + MODULE + Word(alphas) + END) 
wire_map = Group(VAR + WIRE + Word(alphas) + END) 
scope_footer = (UPSCOPE + END) 

(Non c'è bisogno di gruppo scope_footer - tutto in quella espressione è soppressa, in modo Group sarebbe solo darvi una lista vuota.)

E ora si può vedere più chiaramente la bit veramente importanti:

[[['module', 'toplevel'], 
    [['module', 'midlevel'], ['wire', 'a'], ['wire', 'b']], 
    ['wire', 'c'], 
    ['wire', 'd'], 
    ['wire', 'e'], 
    [['module', 'extralevel'], ['wire', 'f'], ['wire', 'g']], 
    ['wire', 'h'], 
    ['wire', 'i']]] 

a rischio di troppo raggruppamento, vorrei suggerire anche Group ing il contenuto del tuo scope espressione, in questo modo:

scope << Group(scope_header + 
       Group(ZeroOrMore((wire_map | scope))) + 
       scope_footer) 

che dà questi risultati:

[[['module', 'toplevel'], 
    [[['module', 'midlevel'], [['wire', 'a'], ['wire', 'b']]], 
    ['wire', 'c'], 
    ['wire', 'd'], 
    ['wire', 'e'], 
    [['module', 'extralevel'], [['wire', 'f'], ['wire', 'g']]], 
    ['wire', 'h'], 
    ['wire', 'i']]]] 

Ora ogni risultato portata contiene 2 elementi prevedibili: nell'intestazione del modulo e un elenco di fili o subscopes. Questa prevedibilità renderà molto più facile scrivere il codice ricorsivo che navigare i risultati:

res = scope.parseString(vcd) 
def dumpScope(parsedTokens, indent=''): 
    module,contents = parsedTokens 
    print indent + '- ' + module[1] 
    for item in contents: 
     if item[0]=='wire': 
      print indent + ' wire: ' + item[1] 
     else: 
      dumpScope(item, indent+' ') 
dumpScope(res[0]) 

che viene fuori alla ricerca come:

- toplevel 
    - midlevel 
    wire: a 
    wire: b 
    wire: c 
    wire: d 
    wire: e 
    - extralevel 
    wire: f 
    wire: g 
    wire: h 
    wire: i 

Buona la prima domanda, benvenuto a SO e pyparsing!

+0

Grazie mille per questo Paul !! Questo mi aiuterà davvero a ripulire la grammatica e come uso i risultati, e ora capisco di più di quello che sta succedendo. E devo solo aggiungere che il pyparsing è fantastico! :) – RaytheonLiszt

1

So che questa è una vecchia domanda a cui è già stata data una risposta, ma ho pensato di aggiungere un collegamento utile a un pacchetto di analisi VCD Python in grado di mettere il VCD in una struttura dati Python di base.

Verilog_VCD 1.0

+0

Grazie a @Scott Chin! Sembra utile – RaytheonLiszt