Как описать области в EBNF?

#python #ebnf #cisco-ios #grako #ciscoconfparse

#python #ebnf #cisco-ios #grako #ciscoconfparse

Вопрос:

Я пытаюсь написать анализатор для конфигураций Cisco IOS и ASA, используя Grako и Python. Я пытаюсь выяснить, как представлять ключевые слова с ограниченной областью видимости в EBNF — например, ключевое слово ‘description’ должно отображаться внутри области interface видимости, но существует несколько вариантов interface , и все они являются необязательными (и, я полагаю, порядок может меняться между устройствами):

 interface Vlan1435
 nameif untrust
 description the outside interface for customer X
 bridge-group 1
 security-level 0
  

Ближайший пример, который я нашел, находится в приложении Perl под названием Farly, которое использует модуль perl Parse::Recdescent, который, похоже, похож на Grako.

Оттуда у меня есть этот тип рекурсивного определения:

 @@eol_comments :: /!([^n]*?)n/
@@whitespace :: /[t ] /

start
    =
    file_input $
    ;


file_input
    =
    {NEWLINE | asa_line}
    ;


asa_line
    =
      'names' NEWLINE
    | interface NEWLINE
    ;

interface
    =
    'interface' string NEWLINE interface_options
    ;


interface_options
    =
    if_name | sec_level | if_addr | if_bridgegroup | NEWLINE
    ;


if_bridgegroup
    =
    'bridge-group' digit NEWLINE interface_options
    ;


if_name
    =
    'nameif' string NEWLINE interface_options
    ;


sec_level
    =
    'security-level' digit NEWLINE interface_options
    ;
  

но он создает странный вложенный AST, и он не «сбрасывается» для обнаружения второго интерфейса или чего-либо еще в следующей конфигурации.

Как такого рода области обычно определяются в EBNF? (есть ли полезный учебник и для такого рода вещей? Мой google-fu ничего не нашел для Grako или синтаксических анализаторов в целом)

Ответ №1:

Трюк, который я использую в таких ситуациях, заключается в использовании повторения, даже если параметры могут появиться только один раз:

 interface_options
    =
    { @ :(if_name | sec_level | if_addr | if_bridgegroup)  NEWLINE}*
    ;
  

При необходимости вы можете использовать семантическое действие для проверки того, что параметры не повторяются.

Комментарии:

1. Спасибо! Я думаю, что это в сочетании с заменой класса буфера grako для определения отступов (например, Python) сделает свое дело… просто нужно перейти от однострочного упоминания в документах к функционирующей вещи 🙂

2. Я не думаю, что вам нужен a Buffer для отступа. Вы можете определить отступ как маркер в грамматике и использовать семантическое правило для отслеживания глубины / уровня. Помните, что у вас могут быть «пустые» правила только для активации семантических действий ( unindent = (); в вашем случае).

3. Хорошо, я попробую!