Мне кажется, я неправильно понял ваше намерение, когда увидел, что вы устанавливаете outermost
на True
или False
в process_stmt
.Перечитывая ваш вопрос, вы хотели, чтобы код запускался только при самом внешнем вызове рекурсивного синтаксического анализатора .Решение, как я догадался в своем комментарии, - создать внешний контейнер Forward
и прикрепить к нему действие разбора.Вот ваш код со всеми удаленными промежуточными вызовами process_stmt
и одним вызовом на самый внешний уровень в содержащем Forward
:
counter = count(0)
OR_stmt = Forward()
AND_stmt = Group(OneOrMore(Word("XYZ", exact=3)
^ OR_stmt))("AND*")
OR_stmt <<= Group(L_PAR
+ OneOrMore(AND_stmt)
+ R_PAR)("OR*")
outermost = Forward()
outermost <<= AND_stmt
outermost.addParseAction(outermost_true)
data = "(XXXYYY)ZZZ"
outermost.runTests(data)
, который дает:
(XXXYYY)ZZZ
[[[['XXX', 'YYY']], 'ZZZ']]
- AND: [[[['XXX', 'YYY']], 'ZZZ']]
[0]:
[[['XXX', 'YYY']], 'ZZZ']
- OR: [[['XXX', 'YYY']]]
[0]:
[['XXX', 'YYY']]
- AND: [['XXX', 'YYY']]
[0]:
['XXX', 'YYY']
- other: True
- outermost: True
Если вы все еще хотите иметь действие синтаксического анализа, которое вызывается для каждого уровня вашей иерархии, я изменил process_stmt, чтобы он печатал свой прогресс при каждом вызове:
def process_stmt(counter):
"""Closure counts up when nesting occurs"""
def parse_action(tokens):
for t in tokens:
t["count"] = next(counter)
# t["outermost"] = False
t["outermost"] = (False, "used to be {!r}".format(t.outermost))
tokens['outermost'] = True
print(tokens.dump())
print()
return parse_action
Отображение этих промежуточных шагов - лучшев состоянии визуализировать, как каждый вызов сбрасывает внутренний уровень outermost
в Ложь, а его собственный внешний уровень - в Истину
[['XXX', 'YYY']]
- AND: [['XXX', 'YYY']]
[0]:
['XXX', 'YYY']
- count: 0
- outermost: (False, "used to be ''")
- outermost: True
[[['XXX', 'YYY']]]
- OR: [[['XXX', 'YYY']]]
[0]:
[['XXX', 'YYY']]
- AND: [['XXX', 'YYY']]
[0]:
['XXX', 'YYY']
- count: 0
- outermost: (False, "used to be ''")
- count: 1
- outermost: (False, 'used to be True')
- outermost: True
[[[['XXX', 'YYY']], 'ZZZ']]
- AND: [[[['XXX', 'YYY']], 'ZZZ']]
[0]:
[[['XXX', 'YYY']], 'ZZZ']
- OR: [[['XXX', 'YYY']]]
[0]:
[['XXX', 'YYY']]
- AND: [['XXX', 'YYY']]
[0]:
['XXX', 'YYY']
- count: 0
- outermost: (False, "used to be ''")
- count: 1
- outermost: (False, 'used to be True')
- count: 2
- outermost: (False, 'used to be True')
- outermost: True