#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. Хорошо, я попробую!