Местоположение
Россия, Приморский край, Владивосток

Лучшие ответы пользователя

Все ответы (1)
  • Yargy-парсер | Как задать интерпретацию рекурсивного правила вывода для извлечения неизвестного числа терминалов в качестве repeatable-атрибута факта?

    @namorum Автор вопроса
    Студент IT-шного направления подготовки
    Пока что придумал только такое решение.
    Описал интерпретацию правила через комментарии, чтобы много места здесь не занимало.
    SECTION = or_(
        rule(SECTION_NAME, FEATURE, FEATURE, FEATURE, FEATURE, FEATURE, FEATURE),
        rule(SECTION_NAME, FEATURE, FEATURE, FEATURE, FEATURE, FEATURE),
        rule(SECTION_NAME, FEATURE, FEATURE, FEATURE, FEATURE),
        rule(SECTION_NAME, FEATURE, FEATURE, FEATURE),
        rule(SECTION_NAME, FEATURE, FEATURE),
        rule(SECTION_NAME, FEATURE)
    )
    
    # На SECTION используется interpretation(Node)
    # SECTION_NAME - interpretation(Node.name)
    # FEATURE -  interpretation(Node.successors).repeatable()


    В моём случае это более-менее работающее решение, поскольку у меня в одной секции почти не встречается больше шести свойств. Однако оно, конечно, не подойдёт для более неопределённых случаев.

    P. S. Ближе к концу написания этого комментария вспомнил, что в cookbook'е yargy-парсера встречал упоминание генераторов правил вывода. Постараюсь разобраться с этими генераторами, и в редакции этого ответа приведу вариант с генератором.

    UPD (25 апр.)

    Написал функцию, с помощью которой правила, подобные указанному выше, описываются в несколько строк.

    '''
    Генерирует интерпретированную правую часть правил конечной рекурсии следующего вида.
    left -> right + sep + left | right
    
    right – повторяющееся в правой части правило.
    right_interpretation – интерпретация для right.
    sep – правило-разделитель последовательности из правил вида right.
    max_recursion_depth – глубина рекурсии.
    '''
    def get_recursive_interpreted_right_part(right, right_interpretation=None, sep=None, max_recursion_depth=10):
        if right_interpretation is not None:
            right = rule(right.interpretation(right_interpretation).repeatable())
        
        list_of_right_rules = []
        for cur_len in reversed(range(1, max_recursion_depth+1)):
            if sep is None:
                right_rule_args = [right] * cur_len
            else:
                right_rule_args = [right, sep] * (cur_len - 1)
                right_rule_args.append(right)
            list_of_right_rules.append(rule(*right_rule_args))
        
        return or_(*list_of_right_rules)


    К примеру, вместо того, чтобы писать это:
    FEATURE_BLOCK = or_(
        rule(
             FEATURE.interpretation(Node.successors).repeatable()
        ),
        rule(
             FEATURE.interpretation(Node.successors).repeatable(), EOL, FEATURE.interpretation(Node.successors).repeatable()
        ),
        rule(
             FEATURE.interpretation(Node.successors).repeatable(), EOL, FEATURE.interpretation(Node.successors).repeatable(), EOL, FEATURE.interpretation(Node.successors).repeatable()
        )
    )

    Можно написать это:
    FEATURE_BLOCK = get_recursive_interpreted_right_part(FEATURE, Node.successors, EOL, 3)


    Это гораздо более удобный вариант, хотя всё ещё рассчитанный на известное максимальное количество повторений правой части. Для моей задачи этого более-менее достаточно.

    Но я по-прежнему надеюсь, что просто пропустил какую-либо из возможностей yargy-парсера, с помощью которой можно провернуть такое из коробки. Буду рад увидеть такой вариант в ответах.
    Также буду рад, если кто-то посчитает, что описанную мною функцию можно описать более лаконично без потери читаемости, и предложит более качественное её описание.
    Ответ написан
    Комментировать

Лучшие вопросы пользователя

Все вопросы (1)