9

pyparsingを使用してvcd(値変更ダンプ)ファイルを解析しています。基本的に、ファイルを読み込み、内部辞書に解析して、値を操作したいと思います。

構造の詳細に立ち入ることなく、ネストされたカテゴリを識別する際に問題が発生します。

vcdファイルには、ワイヤと、場合によってはより深い(ネストされた)スコープを含む「スコープ」があります。それらをレベルのように考えてください。

したがって、私のファイルには、次のものがあります。

$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

したがって、「トップレベル」にはすべて(a-i)が含まれ、「ミッドレベル」には(a-b)が含まれ、「エクストラレベル」には(f-g)が含まれます。

このセクションを解析するための私のコード(スニペット)は次のとおりです。

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)

さて、私が思ったことは、それが各スコープに到達すると、各「レベル」を追跡し、ネストされたスコープを含む構造になってしまうということです。ただし、エラーが発生します

$scope module extralevel $end

'$upscope'を期待していると言っています。

したがって、再帰を正しく使用していないことがわかります。誰かが私を助けることができますか?さらに情報を提供する必要がある場合はお知らせください。

ありがとう!!!!

4

2 に答える 2

9

定義によれば、スコープに別のスコープ、その後にいくつかのマップ、その後に別のスコープを含めることはできません。

パーサーに解析ツリーを出力するデバッグモードがある場合は、これをすぐに確認できます。ただし、要するに、0個以上のマップ、0個以上のスコープ、0個以上のマップがあるということです。したがって、スコープがあり、その後にマップがある場合は、すでにスコープフィールドを通過しています。これ以上のスコープは無効です。pyparsingで使用される言語が「または」をサポートしている場合は、次を使用できます。

scope << (scope_header + ZeroOrMore((wire_map | scope)) + scope_footer)
于 2010-11-10T03:46:15.503 に答える
6

@ZackBloomの答えを正しいものとして選択してください。彼は、pyparsingの構文さえ知らなくても、すぐにそれを直感的に理解しました。

あなたの文法に関するほんの少しのコメント/提案:

上記の回答を使用すると、ParseResultsでpprintとpyparsingのasList()メソッドを使用してネストを視覚化できます。

res = scope.parseString(vcd)

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

与える:

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

これで、適切に構造化された結果が得られました。しかし、あなたは物事を少しきれいにすることができます。一つには、構造ができたので、これらすべての、、などのトークンは実際には必要ありませ$scope$end。解析された結果をナビゲートするときに、確かにそれらをステップオーバーすることができますが、解析された出力からそれらをドロップするだけでpyparsingを実行することもできます(結果が構造化されているため、実際には何も失われていません)。パーサー定義を次のように変更します。

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) 

(グループ化する必要はありませんscope_footer。その式のすべてが抑制されているためGroup、空のリストが表示されます。)

そして今、あなたは本当に重要な部分をより明確に見ることができます:

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

グループ化が多すぎるリスクがあるので、次のように表現Groupの内容も使用することをお勧めします。scope

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

これらの結果が得られます。

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

これで、すべてのスコープ結果に2つの予測可能な要素が含まれます。モジュールヘッダーと、ワイヤーまたはサブスコープのリストです。この予測可能性により、結果をナビゲートする再帰コードの記述がはるかに簡単になります。

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

これは次のようになります:

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

良い最初の質問、SOとpyparsingへようこそ!

于 2010-11-10T08:16:26.770 に答える