use warnings; use strict; use 5.010; # required for Regexp::Grammars my $parser = do { use Regexp::Grammars; qr{ <[Block]>* \{ <[BlockItem]>* \} (?{ $MATCH = { $MATCH{BlockName} => $MATCH{BlockItem} } }) (?: | ) (?{ $MATCH = $MATCH{KeyValue} || $MATCH{Block} }) (?: | \[ <[Value=Word]>* % \s+ \] ) \; (?{ $MATCH = { $MATCH{Key} => $MATCH{Value} } }) [\w-]+ } }; my $input = do { open my $fh, '<', '1112435.txt' or die $!; local $/; <$fh> }; $input =~ $parser or die "Failed to parse input"; use Data::Dump 'pp'; say pp $/{Block};