Пожалуйста, выберите правильный ответ @ ZackBloom, он сразу его интуитивно понял, даже не зная синтаксиса pyparsing.
Всего несколько комментариев / предложений по вашей грамматике:
С ответом, опубликованным выше, вы можете визуализировать вложение, используя pprint и метод pyparsing asList()
в ParseResults:
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
и т. Д. Конечно, вы можете просто перешагнуть через них при навигации по проанализированным результатам, но вы также можете использовать пиапарсинг, просто отбросив их из проанализированного вывода (поскольку результаты теперь структурированы, вы ничего не теряете). Измените определения вашего синтаксического анализатора на:
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!