2010-11-10 9 views
9

Ich benutze pyparsing, um vcd (Wert ändern Dump) Dateien zu analysieren. Im Wesentlichen möchte ich die Dateien einlesen, in ein internes Wörterbuch einlesen und die Werte manipulieren.pyparsing, forward und recursion

Ohne auf Details in der Struktur zu gehen, tritt mein Problem beim Identifizieren verschachtelter Kategorien auf.

In VCD-Dateien haben Sie "Bereiche", die Drähte und möglicherweise einige tiefere (verschachtelte) Bereiche enthalten. Denken Sie an sie wie Ebenen.

Also in meiner Akte, die ich habe:

$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 

So 'Toplevel' umfasst alles (a - i), 'midlevel' hat (a - b) 'extralevel' hat (f - g) usw.

Hier ist mein Code (snippet) zum Parsen dieser Sektion:

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) 

Nun, was ich dachte passiert ist, dass, wie es jeden Bereich trifft, wäre es Spur jedes ‚Niveau halten " und ich würde am Ende eine Struktur mit verschachtelten Bereichen haben. Es ist jedoch auf

$scope module extralevel $end 

Ausspruch es erwartet "$ upscope".

Also weiß ich, dass ich die Rekursion nicht richtig verwende. Kann mir jemand helfen? Lassen Sie mich wissen, wenn ich mehr Informationen zur Verfügung stellen muss.

Danke !!!!

Antwort

9

Gemäß Ihrer Definition darf ein Bereich keinen weiteren Bereich enthalten, gefolgt von einigen Maps gefolgt von einem anderen Bereich.

Wenn der Parser einen Debug-Modus hat, in dem er seinen Syntaxbaum ausgibt, können Sie dies sofort sehen. Kurz gesagt, Sie sagen, dass es null oder mehr Maps gibt, gefolgt von null oder mehr Bereichen, gefolgt von null oder mehr Maps. Wenn also ein Bereich gefolgt von einer Map vorhanden ist, haben Sie das Bereichsfeld bereits überschritten Weitere Bereiche sind ungültig. Wenn die Sprache von pyparsing verwendeten Trägern „oder“ Sie nutzen könnten:

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

Gute Intuition! pyparsing unterstützt tatsächlich "oder" und genau die Syntax, die Sie erraten haben. – PaulMcG

+0

Wow, so einfach !!! Es wirkt wie ein Zauber!!!!! Vielen Dank! – RaytheonLiszt

+0

Es ist immer gut, wenn Sie die Syntax erraten können, ohne nachschlagen zu müssen. Die Überladung kann Sie jedoch im a $$ beißen, versuchen Sie, ein Programm mit Boost Spirit zu debuggen (das Äquivalent von pyparse für C++). Es macht Spaß, C++ zu debuggen, aber jeder Methodenaufruf ist zwanzig überladene Operatoren. –

6

Bitte wählen @ ZackBloom Antwort als die richtigen, Schaute er es rechts ab, ohne auch nur pyparsing Syntax zu kennen.

Nur ein paar Kommentare/Vorschläge auf Ihre Grammatik:

Mit der Antwort oben geschrieben, können Sie die Verschachtelung mit pprint und pyparsing der asList() Methode auf ParseResults visualisieren:

res = scope.parseString(vcd) 

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

Giving:

[[['$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']]] 

Jetzt haben Sie also gut strukturierte Ergebnisse. Aber Sie können die Dinge ein bisschen aufräumen. Für eine Sache, jetzt, da Sie eine Struktur haben, brauchen Sie nicht wirklich all diese $scope, $end usw. Token. Sie können sie sicher überspringen, wenn Sie durch die analysierten Ergebnisse navigieren, aber Sie können Pyparsen auch einfach aus der geparsten Ausgabe entfernen lassen (da die Ergebnisse nun strukturiert sind, verlieren Sie wirklich nichts).Ändern Sie Parser-Definitionen:

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) 

(keine Notwendigkeit zu einer Gruppe scope_footer - alles in diesem Ausdruck unterdrückt wird, so Group würde Ihnen nur eine leere Liste.)

Und jetzt können Sie sehen, deutlicher die wirklich wichtige Bits:

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

Auf die Gefahr von zu viel Gruppierung, würde ich auch Group vorschlagen, den Inhalt Ihrer scope Ausdruck ing, wie folgt aus:

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

, die diese Ergebnisse gibt:

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

Nun jedes Umfang Ergebnis hat 2 vorhersagbaren Elemente: den Modul-Header und eine Liste von Drähten oder subscopes. Diese Vorhersagbarkeit wird es viel einfacher machen den rekursiven Code zu schreiben, die Ergebnisse navigiert:

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

, die herauskommt, die aussehen wie:

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

Gute erste Frage, begrüßen zu SO und pyparsing!

+0

Vielen Dank für diesen Paul !! Das wird mir wirklich helfen, meine Grammatik aufzuräumen und wie ich die Ergebnisse verwende, und jetzt verstehe ich mehr von dem, was vor sich geht. Und ich muss nur hinzufügen, dass Piparsen ist super! :) – RaytheonLiszt

1

Ich weiß, dass dies eine alte Frage ist, die bereits beantwortet wurde, aber ich dachte, ich würde einen nützlichen Link zu einem Python VCD-Parsing-Paket hinzufügen, das Ihre VCD in eine grundlegende Python-Datenstruktur bringen kann.

Verilog_VCD 1.0

+0

Danke @Scott Chin! Sieht nützlich aus. – RaytheonLiszt