in reply to Parse::RecDescent trouble

I hope you don't mind if I go beyond what you asked about. (In fact, I won't even touch that since it's already been addressed.)
use strict; use warnings; use Parse::RecDescent; use Data::Dumper; my $config_parser = Parse::RecDescent->new(<<'__END_OF_GRAMMAR__'); { # These pragmas affect the whole parser. use strict; use warnings; sub check_ip_nums { my ($ip) = @_; return !(grep $_ > 255, split /./, $ip); } sub dequote { my ($s) = @_; for ($s) { s/^"//; s/"\z//; s/\\(.)/$1/sg; return $_; } } } parse : line(s) /\Z/ { $item[1] } line : '' # Skip blank lines. <skip:'[ \\t]*'> # Don't treat newlines as whitespac +e. key_value /\n/ <skip: $item[2]> { $item[3] } key_value : server | key server : IDENT { $item[1] eq 'bind-server' } IP { [@item[0,3]] + } key : IDENT { $item[1] eq 'tsig-key' } filename { [@item[0, +3]] } filename : QSTRING | BAREWORD # Tokens IDENT : /[-\w]+/ QSTRING : /"(?:[^"\\]|\\.)*"/ { dequote($item[1]) } BAREWORD : /[^"\\\s]+/ IP : # This could be done more readably, but # the more is done by the regexp, the # faster it's going to be. A lot faster. /(?:[1-9][0-9]{0,2}|0)\.(?:[1-9][0-9]{0,2}|0)\.(?:[1- +9][0-9]{0,2}|0)\.(?:[1-9][0-9]{0,2}|0)/ { check_ip_nums($item[1]) ? $item[1] : undef } __END_OF_GRAMMAR__ print Dumper $config_parser->parse(<<'__END_OF_CONFIG__'); bind-server 127.0.0.1 tsig-key "/etc/bind/rndc.key" __END_OF_CONFIG__

Replies are listed 'Best First'.
Re^2: Parse::RecDescent trouble
by ribasushi (Pilgrim) on Jan 12, 2007 at 21:32 UTC
    I absolutely don't mind. Actually I am extremely happy I got an answer like this. Thank you a ton, it is full of very helpful advices. Particularly I had no idea I can add a closure to the grammar and use it as part of a virtual main package (I did not find it nowhere in the docs).
    I have an additional question if you do not mind. Can you decipher this:
    line : '' # Skip blank lines. <skip:'[ \t]*'> # Don't treat newlines as whitespace +. key_value /\n/ <skip: $item[2]> { $item[3] }
    for me please? I particularly do not understand the '' construct (it will always match right?) neither do I understand how can you have several tokens in one rule without the | mark (you have '' then a skip pragma then key_value then /\n/ and then another skip pragma)
    Once again thanks a lot for the insights!

      Particularly I had no idea I can add a closure to the grammar and use it as part of a virtual main package

      It's not really a closure. The block is inlined at the start of the generated parser code. You should check out Grammar.pm after executing:

      use Parse::RecDescent my $grammar = ...; Parse::RecDescent->Precompile($grammar, "Grammar");

      That block is documented as Start-up Actions.

      I particularly do not understand the '' construct. it will always match right?

      Yes, but remember that P::RD removes /$skip/ from the input before every terminal in the grammar. The current value of skip is '\\s*', so '' removes all leading whitespace.

      That whole thing allows blank lines between key_value, but not within key_value.