cisco.grammar: refactored to use indentation markers fro proper in-section parsing; more controller, interface properties
--- a/cisco.grammar Mon Nov 09 17:48:33 2009 +0100
+++ b/cisco.grammar Sun Nov 15 22:52:18 2009 +0100
@@ -1,6 +1,8 @@
# Grammar for Cisco devices
+# Configuration is expected to be preprocessed via following command:
+# perl -ne '/(^\s*)(\S.*)$/; print length($1)." $2\n"'
-<autotree>
+#<autotree>
{ # perl code follows
$::res = {};
@@ -22,22 +24,22 @@
file: <skip: qr/[^\S\n]*/> # Ignore non-newline whitespace
line(s) eofile
-line: emptyline
- | s_controller
+line: s_controller
| s_interface
- | comment
- | cmdline
+ | indent comment
+ | indent cmdline
+ | indent emptyline
| <error>
emptyline: eol
-comment: /^\!.*/ eol
+comment: /!.*/ eol
cmdline: l_hostname eol
| l_hash eol
| word(s) eol
-word: /[0-9a-zA-Z:\/_\#\"\.,+<>-]+/
+word: /[0-9a-zA-Z:\/_\#\"\.,+<>()&{}-]+/
{ $item[1] }
type: /\w+/
@@ -46,6 +48,9 @@
num: /\d+/
{ $item[1] }
+indent: /\d+/
+ { $item[1] }
+
range: /\d+/"-"/\d+/
{ { from => $item[1], to => $item[3] } }
@@ -74,8 +79,13 @@
section: cmdline(s) "!"
{ print "section\n"; }
+l_section: /[1-9]/ word(s) eol
+ | /[1-9]/ "!" eol
+ | /[1-9]/ eol
+ | <error>
+
# Lines w/ hash (passwd, secret etc)
-l_hash: word(s) /\S+/ words(s)
+l_hash: word(s) /\S+/ word(s)
| word(s) /\S+/
# Hostname
@@ -90,38 +100,53 @@
controller_num: /\d+\/\d+/
{ $item[1] }
-s_controller: "controller" type controller_num s_controller_l[ctx => ctx('controller', $item{controller_num}) ](s) "!" eol
+s_controller: "0" "controller" type controller_num eol s_controller_l[ctx => ctx('controller', $item{controller_num}) ](s) "0" "!" eol
{ $::res->{controller}->{$item{controller_num}}->{type} = $item{type} }
-s_controller_l: l_description[ctx => $arg{ctx}]
+s_controller_l: "1" s_controller_content[ctx => $arg{ctx}] eol
+ | l_section
+
+s_controller_content: l_description[ctx => $arg{ctx}]
| "channel-group" num "timeslots" range
{ $arg{ctx}->{"channel-group"}->{$item{num}}->{ts} = $item{range} }
| "channel-group" num "unframed"
{ $arg{ctx}->{"channel-group"}->{$item{num}}->{unframed} = 1 }
- | cmdline
- | emptyline
- | <error>
+ | "framing" keyword
+ { $arg{ctx}->{framing} = $item{keyword} }
+
+# Vlan range
+vlan_s_range: /\d+/"-"/\d+/
+ {
+ for (my $i = $item[1]; $i <= $item[3]; $i++) {
+ $arg{ctx}->{$arg{key}}->{$i} = 1; }
+ }
+ | /\d+/
+ { $arg{ctx}->{$arg{key}}->{$item[1]} = 1 }
+vlan_range: vlan_s_range","vlan_range
+ | vlan_s_range
# interface section
-iface_name: /\w+\d+(\/\d+)?(:\d+(\.\d+)?)?/
+iface_name: /\w+\d+[0-9\/\.:]*/
{ $item[1] }
-s_interface: "interface" iface_name /\S*/ eol s_interface_l[ctx => ctx("interface", $item{iface_name}) ](s) "!" eol
+s_interface: "0" "interface" iface_name /\S*/ eol s_interface_l[ctx => ctx("interface", $item{iface_name}) ](s) "0" "!" eol
{
- print "interface $item{iface_name}\n";
- $::res->{interface}->{$item{iface_name}}->{type} = $item[3]
- if length($item[3]) > 0
+ $::res->{interface}->{$item{iface_name}}->{type} = $item[4]
+ if length($item[4]) > 0
}
ip: /\d+\.\d+\.\d+\.\d+/
{ $item[1] }
-s_interface_l: l_description
- | /(no)?/ "shutdown" eol
+s_interface_l: "1" s_interface_content[ctx => $arg{ctx}] eol
+ | l_section
+
+s_interface_content: l_description[ctx => $arg{ctx}]
+ | /(no)?/ "shutdown"
{ $arg{ctx}->{shutdown} = ($item[1] eq 'no') ? 0 : 1 }
- | "ip" "address" ip ip eol
- { $arg{ctx}->{ip} = $item[3]; $arg{ctx}->{mask} = $item[4] }
- | "encapsulation" keyword /\S*/ eol
+ | "ip" "address" ip ip
+ { $arg{ctx}->{ip} = $item[3]; $arg{ctx}->{mask} = $item[3] }
+ | "encapsulation" keyword /\S*/
{
$arg{ctx}->{encap} = $item[2];
$arg{ctx}->{encap_param} = $item[3] if length($item[3]) > 0
@@ -129,7 +154,13 @@
| "frame-relay" keyword keyword
{ $arg{ctx}->{"frame-relay"} = {type => $item[2], value => $item[3]} }
| "bandwidth" num
- { $arg{ctx}->{bandwidth} = $item{num}; }
- |cmdline
- | emptyline
- | <error>
+ { $arg{ctx}->{bandwidth} = $item{num} }
+ | "ip" "vrf" "forwarding" word
+ { $arg{ctx}->{"ip-vrf-fwd"} = $item{word} }
+ | "switchport" "mode" /access|trunk/
+ { $arg{ctx}->{"switchport-mode"} = $item[3] }
+ | "switchport" "access" "vlan" num
+ { $arg{ctx}->{vlan} = $item{num} }
+ | "switchport" "trunk" "encapsulation" keyword
+ { $arg{ctx}->{"trunk-encap"} = $item{keyword} }
+ | "switchport" "trunk" "allowed" "vlan" vlan_range[ctx => $arg{ctx}, key => "vlan"]