cisco.grammar: refactored to use indentation markers fro proper in-section parsing; more controller, interface properties
author"Tomas Zeman <tzeman@volny.cz>"
Sun, 15 Nov 2009 22:52:18 +0100
changeset 11 c170b1da9b6e
parent 10 91148603fd70
child 12 0b509f26f4d3
cisco.grammar: refactored to use indentation markers fro proper in-section parsing; more controller, interface properties
cisco.grammar
--- 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"]