Определить внешний вызов рекурсивного парсера - PullRequest
0 голосов
/ 19 сентября 2018

Мне нужно, чтобы какой-то код выполнялся только при самом внешнем вызове рекурсивного синтаксического анализатора, но я не могу придумать, как это сделать с помощью pyparsing.Вот мой код:

from pyparsing import *
from itertools import count

L_PAR, R_PAR, = map(Suppress, '()')


def process_stmt(counter):
    """Closure counts up when nesting occurs"""

    def parse_action(tokens):
        for t in tokens:
            t["count"] = next(counter)
            # if not outermost:
            t["outermost"] = False

            # if outermost:
            #     t["outermost"] = True

    return parse_action


def outermost_true(tokens):
    tokens['outermost'] = True
    tokens['other'] = True


counter = count(0)
OR_stmt = Forward()
AND_stmt = Group(OneOrMore(Word("XYZ", exact=3)
                           ^ OR_stmt))("AND*")
AND_stmt.setParseAction(process_stmt(counter))
OR_stmt <<= Group(L_PAR
                  + OneOrMore(AND_stmt)
                  + R_PAR)("OR*")
OR_stmt.setParseAction(process_stmt(counter))
AND_stmt.addParseAction(outermost_true)

data = "(XXXYYY)ZZZ"

AND_stmt.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']
            - count: 0
            - outermost: False
        - count: 1
        - other: True
        - outermost: False
    - count: 2
    - outermost: False
- other: True
- outermost: True

Как можно установить для внешнего атрибута outermost значение True?

1 Ответ

0 голосов
/ 02 октября 2018

Мне кажется, я неправильно понял ваше намерение, когда увидел, что вы устанавливаете 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
...