我正在尝试使用Grako和Python为Cisco IOS和ASA配置编写解析器。我试图弄清楚如何在EBNF中表示“作用域”关键字-例如,“描述”关键字必须出现在interface范围内,但是interface有多个选项,并且它们都是可选的(并且我认为,设备之间的顺序可能会发生变化):

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


我发现最接近的示例是在名为Farly的Perl应用程序中,该应用程序使用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或解析器提供任何服务)

最佳答案

在这些情况下,我使用的一个技巧是使用重复,即使这些选项只能出现一次:

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


如有必要,您可以使用语义操作来验证选项是否重复。

09-28 13:11