Version 1.0; GlobalPList plist1 [option1] [option2] { #base=111 # this is a full line comment Pat n1000000g0000001; # this is a partial line comment Pat n2000000g0000002; #HOT# LocalPList plist2 { Pat n5000000g0000005; GlobalPList plist4 { Pat n8000000g0000008; #KEEP# } } Pat n3000000g0000003; #HOT,COLD# Pat n4000000g0000004; PList plist2; PList file1.plist:plist3; } GlobalPList plist2 [option3] { PList plist1; Pattern n6000000g0000006; Pattern n7000000g0000007; } #### use strict; use warnings; my $file = $ARGV[0]; my $s; if (defined $file) { # parse data from file argument open my $fh, '<', $file or die "Failed to open file ($file):$!\n"; # for processing speed, tossing out full line comments and empty lines now while (<$fh>) { next if /^\s*#.*$/ and !/^\s*#\s*base\s*=/; next if /^\s*$/; $s .= $_ } } else { # parse data from DATA while () { next if /^\s*#.*$/ and !/^\s*#\s*base\s*=/; next if /^\s*$/; $s .= $_ } } close $fh or die "Failed to close file ($file): $!\n"; #print STDERR "DATA :\n$s\n"; use Regexp::Grammars; my $parser = qr/ # # \d+(\.\d+)? GlobalPList|LocalPList PList \w+ \[[\w \.,]*\] \d+ \#[^\n]* Pat|Pattern \w+ \w+ \{ \} [\w\.]+ <[global_plist]>+ Version \; \#\s*base\s*=\s*<[base_number]>+ % ,\s*\n \#<[tag]>+ % ,\# <.global_plist_declare> <[plist_option]>* % \s* <.plist_open> ? (<[data_node]> | <.comment>)+ <.plist_close> | | <.reference_plist_declare> ( : | ) ; <.pat_declare> ; ? /xms; $s =~ $parser; use Data::Dumper; open $fh, '>', 'C:\tmp\tmp' or die "FAILED!\n"; print $fh "RESULTS:".Dumper(\%/); print STDERR "RESULTS:".Dumper(\%/); __DATA__ Version 1.0; # Plist SVN Url: $HeadURL: https://XXXXXX... # Plist SVN Revision: $Id: gt.plist 2555 2014-02-06 16:16:26Z vsgatcha $ # RunDir: /XXXXXX... GlobalPList plist1 [option1] [option2] { #base=111 # this is a full line comment Pat n1000000g0000001; # this is a partial line comment Pat n2000000g0000002; #HOT# LocalPList plist2 { Pat n5000000g0000005; GlobalPList plist4 { Pat n8000000g0000008; #KEEP# } } Pat n3000000g0000003; #HOT,COLD# Pat n4000000g0000004; PList plist2; PList file1:plist3; } GlobalPList plist2 [option3] { PList plist1; Pattern n6000000g0000006; Pattern n7000000g0000007; } #### use strict; use warnings; use Data::Dumper; my $file = $ARGV[0]; my $s; if (defined $file) { # parse data from file if given open my $fh, '<', $file or die "Failed to open file ($file):$!\n"; # for processing speed, tossing out full line comments and empty lines now while (<$fh>) { next if /^\s*#.*$/ and !/^\s*#\s*base\s*=/; next if /^\s*$/; $s .= $_ } close $fh or die "Failed to close file ($file): $!\n"; } else { # parse data from DATA while () { next if /^\s*#.*$/ and !/^\s*#\s*base\s*=/; next if /^\s*$/; $s .= $_ } } #print STDERR "DATA :\n$s\n"; use Marpa::R2; my $grammar_str = <<'END_GRAMMAR'; inaccessible is fatal by default lexeme default = latm => 1 :start ::= plist_file plist_file ::= version_data ows global_plists version_data ::= 'Version' mws float ows ';' global_plists ::= global_plist+ global_plist ::= global_pl_declare mws pl_name ows opt_pl_options ows '{' ows opt_embedded_base ows nodes '}' pl_name ::= [\w]+ opt_pl_options ::= option* option ::= '[' ows option_data ows ']' ows nodes ::= node+ node ::= pattern | comment | global_plist || reference_plist pattern ::= pat_declare mws pat_name ows opt_pat_option ';' ows opt_tag_str ows opt_pat_option ::= option* comment ::= '#' comment_chars newline ows reference_plist ::= 'PList' mws ref_pl_name ows ';' ows ref_pl_name ::= opt_ref_file pl_name opt_ref_file ::= ref_file* ref_file ::= file_name ':' file_name ::= [\w\.]+ opt_tag_str ::= tag_str* tag_str ::= '#' ows tag_list ows '#' tag_list ::= tag* separator => comma opt_embedded_base ::= embedded_base* embedded_base ::= '#' ows 'base' ows '=' ows base_numbers base_numbers ::= base_number+ separator => comma comma ::= ',' pat_name ::= [\w]+ pat_declare ::= 'Pat'|'Pattern' comment_chars ::= [^\n]* newline ::= [\n] int ::= [\d]+ tag ::= [\w]+ global_pl_declare ::= 'GlobalPList'|'LocalPList'|'PatternList' option_data ::= [\w \.,]* base_number ::= [\d]+ float ::= int opt_fractional opt_fractional ::= fractional* fractional ::= '.' int # optional whitespace ows ::= [\s]* # mandatory whitespace mws ::= [\s]+ END_GRAMMAR my $grammar = Marpa::R2::Scanless::G->new({ source => \$grammar_str, }); my $parser = Marpa::R2::Scanless::R->new({ grammar => $grammar, # trace_values => 2, # trace_terminals => 1, }); eval { $parser->read( \$s ); }; if ($@) { print "PARSE ERROR:$@\n"; die "EXITING\n"; # die $parser->show_progress(0, -1); } else { print "SUCCESSFUL PARSE!\n"; ; } print STDERR Dumper( $parser->value ); __DATA__ Version 1.0; # Plist SVN Url: $HeadURL: https://XXXXXX... # Plist SVN Revision: $Id: gt.plist 2555 2014-02-06 16:16:26Z vsgatcha $ # RunDir: /XXXXXX... GlobalPList plist1 [option1] [option2] { #base=111 # this is a full line comment Pat n1000000g0000001; # this is a partial line comment Pat n2000000g0000002; #HOT# LocalPList plist2 { Pat n5000000g0000005; GlobalPList plist4 { Pat n8000000g0000008; #KEEP# } } Pat n3000000g0000003; #HOT,COLD# Pat n4000000g0000004; PList plist2; PList file1.plist:plist3; } GlobalPList plist2 [option3] { PList plist1; Pattern n6000000g0000006; Pattern n7000000g0000007; }