Skip to content

Instantly share code, notes, and snippets.

@olegwtf
Last active December 31, 2015 05:29
Show Gist options
  • Save olegwtf/7941326 to your computer and use it in GitHub Desktop.
Save olegwtf/7941326 to your computer and use it in GitHub Desktop.
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