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.)
- Your parser accepts 127. 0. 0 .1 as a valid ip.
- Your parser accepts 127.newline0.newline0newline.1 as a valid ip.
- Your parser accepts 127.00000000000000.000000000000000.000000001 as a valid ip.
- Your parser accepts "newlineabcnewline" as a valid filename.
- Your parser returns abc for filename " abc ".
- Your parser accepts ip127.0.0.1 and tsig-keyserver.
- Your parser accepts bind-server 127.0.0.1 tsig-key "/etc/bind/rndc.key" all on one line. I'm pretty sure you don't want that.
- Using q{} around your grammar can easily lead to weird problems with slashes. You should double your slashes (yuck and easy to miss one) or use here-docs.
- <reject: do { ... }> can be simplified to <reject: ...>.
- strict and warnings aren't on for your actions and the parser in general.
- The return value for config shouldn't include $item[2].
- It's hard to see alternate rules. I line up the |s with the :s. (I also line up the :s, but that's personal preference.)
- What if the file name contains a "?
- I removed $::RD_AUTOACTION = q { [@item] };. It was causing extra code, not less.
- For the quoteless filename, it would be better if you specified which character *are* allowed.
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__
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.