How to describe scopes in EBNF?
<p>I'm trying to write a parser for Cisco IOS and ASA configurations, using Grako and Python. I'm trying to figure out how to represent 'scoped' keywords in EBNF - for example, the 'description' keyword must appear inside an <code>interface</code> scope, but there are multiple options for <code>interface</code> and they are all optional (and the order can change between devices, I believe):</p>

<pre><code>interface Vlan1435
 nameif untrust
 description the outside interface for customer X
 bridge-group 1
 security-level 0
</code></pre>

<p>The nearest I have found to an example is in a Perl application called Farly that uses the perl Parse::Recdescent module, which appears to be similar to Grako.</p>

<p>From there I have this type of recursive definition:</p>

<pre><code>@@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
    ;
</code></pre>

<p>but it produces a strange nested AST, and it doesn't "reset" to detect the second interface or anything else in the configuration that follows.</p>

<p>How are these kind of scopes normally defined in EBNF?
(is there a useful tutorial for this type of thing, too? My google-fu did not turn up anything for Grako or parsers generally)</p>

<p>A trick I use in these situations is to use repetition even if the options can appear only once:</p>

<pre><code>interface_options
    =
    { @+:(if_name | sec_level | if_addr | if_bridgegroup)  NEWLINE}*
    ;
</code></pre>

<p>If necessary, you can use a semantic action to validate that options are not repeated.</p>

python ebnf cisco-ios grako ciscoconfparse