Last active
December 31, 2015 05:29
-
-
Save olegwtf/7941326 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use strict; | |
package JUNOS::Config::Parser; | |
sub new { | |
my ($class, %cb) = @_; | |
bless \%cb, $class; | |
} | |
sub parse { | |
my ($self, $data) = @_; | |
while (pos($data) < length $data) { | |
$self->_parse(\$data); | |
} | |
} | |
sub _parse { | |
my ($self, $data_ref) = @_; | |
$$data_ref =~ /\G\s*/g; # spaces | |
if ($$data_ref =~ /\G\{/gc) { | |
# brace start | |
if (exists $self->{brace_start}) { | |
$self->{brace_start}->(); | |
} | |
} | |
elsif ($$data_ref =~ /\G\}/gc) { | |
# brace end | |
if (exists $self->{brace_end}) { | |
$self->{brace_end}->(); | |
} | |
} | |
elsif ($$data_ref =~ /\G;/gc) { | |
# semicolon | |
if (exists $self->{semicolon}) { | |
$self->{semicolon}->(); | |
} | |
} | |
elsif ($$data_ref =~ /\G"/gc) { | |
# string | |
my $str = $self->_parse_string($data_ref); | |
if (exists $self->{string}) { | |
$self->{string}->($str); | |
} | |
} | |
else { | |
# value | |
my $val = $self->_parse_value($data_ref); | |
if (exists $self->{value}) { | |
$self->{value}->($val); | |
} | |
} | |
} | |
sub _parse_value { | |
my ($self, $data_ref) = @_; | |
$$data_ref =~ /\G([^;}{\s]+)/gc; | |
return $1; | |
} | |
sub _parse_string { | |
my ($self, $data_ref) = @_; | |
$$data_ref =~ /\G([^"]+)"/gc | |
or die "can't find string at offset ", pos($$data_ref); | |
return $1; | |
} | |
package main; | |
my %state; | |
my %parsed; | |
my $parser = JUNOS::Config::Parser->new( | |
brace_start => sub { | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{interfaces}{ge}{unit} && $state{interfaces}{ge}{unit}{family_inet}) { | |
# braces inside family_inet | |
$state{other_braces}++; | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{interfaces}{ge}{unit} && $state{value_was} eq 'family inet') { | |
# family inet started | |
$state{interfaces}{ge}{unit}{family_inet} = {}; | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{value_was} =~ /^unit\s+\d+$/) { | |
# unit started | |
$state{interfaces}{ge}{unit} = {}; | |
$state{unit_val} = $state{value_was}; | |
return; | |
} | |
if ($state{interfaces} && $state{value_was} =~ m!^ge-\d+/\d+/\d+$!) { | |
# ge started | |
$state{interfaces}{ge} = {}; | |
$state{ge_val} = $state{value_was}; | |
return; | |
} | |
if ($state{value_was} eq 'interfaces') { | |
# interfaces started | |
$state{interfaces} = {}; | |
} | |
}, | |
brace_end => sub { | |
if ($state{other_braces} > 0) { | |
# braces inside family_inet | |
$state{other_braces}--; | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{interfaces}{ge}{unit} && $state{interfaces}{ge}{unit}{family_inet}) { | |
# family inet finished | |
delete $state{interfaces}{ge}{unit}{family_inet}; | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{interfaces}{ge}{unit}) { | |
# unit finished | |
delete $state{interfaces}{ge}{unit}; | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge}) { | |
# ge finished | |
delete $state{interfaces}{ge}; | |
return; | |
} | |
if ($state{interfaces}) { | |
# interfaces finished | |
delete $state{interfaces}; | |
} | |
}, | |
value => sub { | |
if ($state{other_braces} > 0) { | |
# ignore all that deeper | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{interfaces}{ge}{unit} && $state{interfaces}{ge}{unit}{family_inet} && $state{value_was} eq 'address') { | |
# here it is | |
$parsed{ $state{ge_val} }{ $state{unit_val} } = $state{value_was} = $_[0]; | |
return; | |
} | |
if ($state{interfaces} && $state{interfaces}{ge} && $state{interfaces}{ge}{unit}) { | |
if ($_[0] eq 'inet' && $state{value_was} eq 'family') { | |
$state{value_was} = "family inet"; | |
return; | |
} | |
} | |
if ($state{interfaces} && $state{interfaces}{ge}) { | |
if ($state{value_was} eq 'unit') { | |
# it is unit maybe | |
$state{value_was} = "unit $_[0]"; | |
return; | |
} | |
} | |
$state{value_was} = $_[0]; | |
} | |
); | |
$parser->parse( | |
my $data = do { | |
local $/; | |
<DATA> | |
} | |
); | |
use Data::Dumper; | |
print Dumper \%parsed; | |
__DATA__ | |
interfaces { | |
apply-groups policer-arp; | |
ge-1/0/0 { | |
description "*** Description ***"; | |
unit 0 { | |
family inet { | |
address 10.100.200.1/24 { | |
arp 10.100.200.2 mac 00:16:d4:e7:9b:de; | |
} | |
} | |
} | |
} | |
ge-1/0/2 { | |
description " Description "; | |
vlan-tagging; | |
unit 101 { | |
description "NODEB_CLUSTER#101"; | |
vlan-id 101; | |
family inet { | |
address 10.187.132.3/27 { | |
vrrp-group 1 { | |
virtual-address 10.187.132.1; | |
priority 190; | |
accept-data; | |
} | |
} | |
} | |
} | |
unit 102 { | |
description "Description"; | |
vlan-id 102; | |
family inet { | |
address 10.187.132.35/27 { | |
vrrp-group 2 { | |
virtual-address 10.187.132.33; | |
priority 200; | |
accept-data; | |
} | |
} | |
} | |
} | |
unit 103 { | |
description "NODEB_CLUSTER#103"; | |
vlan-id 103; | |
family inet { | |
address 10.187.132.67/27 { | |
vrrp-group 3 { | |
virtual-address 10.187.132.65; | |
priority 190; | |
accept-data; | |
} | |
} | |
} | |
} | |
unit 104 { | |
description "NODEB_CLUSTER#104"; | |
vlan-id 104; | |
family inet { | |
address 10.187.132.99/27 { | |
vrrp-group 4 { | |
virtual-address 10.187.132.97; | |
priority 200; | |
accept-data; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment