Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Re^3: Why won't this basic Parse::RecDescent example work?

by 7stud (Deacon)
on Jan 28, 2013 at 19:55 UTC ( #1015752=note: print w/ replies, xml ) Need Help??


in reply to Re^2: Why won't this basic Parse::RecDescent example work?
in thread Why won't this basic Parse::RecDescent example work?

Iím not familiar with Parse::RecDescent,

Then thanks for being brave enough to take a look!

by reference to the docs plus a bit of trial-and-error I got this to work by adjusting the regex and assigning $1 to a local variable.

Nice going! After reading the "Start up Action" section in the docs, I reread the "Action" section, and I noticed this statement:

The results of named subrules are stored in the hash under each subrule's name (including the repetition specifier, if any)

So the key I was using in the %item hash, 'dir', was wrong. The key should be 'dir(s)'. So now I can get this output:

use strict; use warnings; use 5.012; use Parse::RecDescent; $::RD_ERRORS = 1; #Parser dies when it encounters an error $::RD_WARN = 1; #Enable warnings - warn on unused rules &c. $::RD_HINT = 1; # Give out hints to help fix problems. our %HASH; my $grammar = <<'END_OF_GRAMMAR'; startrule : from_clause from_clause : 'from' dir(s) { print "-->@{$item{'dir(s)'}}<-- \n"; $main::HASH{dirs} = @{$item{'dir(s)'}}; } dir : 'hello' END_OF_GRAMMAR my $parser = Parse::RecDescent->new($grammar); $parser->startrule("from hello world"); use Data::Dumper; say Dumper(\%HASH); --output:-- -->hello<-- $VAR1 = { 'dirs' => 1 };

Partial success! Note the dereference of $item{'dir(s)'}. Now, what is that '1'? The return value from print()? But print() isn't the last statement of the action. If I change the dir rule to:

dir : 'hello' | 'world'

I get this output:

-->hello world<-- $VAR1 = { 'dirs' => 2 };

Is 2 the count of the words matched? What is going on? I am using the exact same array in each of these lines:

print "-->@{$item{'dir(s)'}}<-- \n"; $main::HASH{dirs} = @{$item{'dir(s)'}};

...yet I am getting different results 'hello world' v. 2! How is that possible? Argghh, of course! Perl doesn't care about giving you the exact same results for any expression you use--because perl determines the result by the context in which the expression appears. In my case, the print() statement supplies list context for the array, and "$main::... =" provides scalar context for the array--and an array provides its length in scalar context.

So now I can get the expected output:

use strict; use warnings; use 5.012; use Parse::RecDescent; $::RD_ERRORS = 1; #Parser dies when it encounters an error $::RD_WARN = 1; #Enable warnings - warn on unused rules &c. $::RD_HINT = 1; # Give out hints to help fix problems. our %HASH; my $grammar = <<'END_OF_GRAMMAR'; startrule : from_clause from_clause : 'from' dir(s) { print "-->@{$item{'dir(s)'}}<-- \n"; $main::HASH{dirs} = $item{'dir(s)'}; } dir : 'hello' | 'world' END_OF_GRAMMAR my $parser = Parse::RecDescent->new($grammar); $parser->startrule("from hello world hello"); use Data::Dumper; say Dumper(\%HASH); --output:-- -->hello world<-- $VAR1 = { 'dirs' => [ 'hello', 'world' ] };

Next up, the regex problem. This doesn't work:

my $grammar = <<'END_OF_GRAMMAR'; #Start up action(executed in parser namespace): { use 5.012; #So I can use say() } startrule : from_clause from_clause : 'from' dir(s) { say "-->$item[0]<--"; say "-->@{$item[-1]}<--"; } dir : m{/} END_OF_GRAMMAR my $parser = Parse::RecDescent->new($grammar); $parser->startrule("from ./hello"); --output:-- (blank)

Note that I tried using the @item array this time. The first item in @item is the rule name, "from_clause", and the next items should be the matches for the subrules, so $item[2], or equivalently $item[-1], should be the matches for dir(s). But because I am not even seeing the arrows in my print statement, that means the parser isn't finding a match for my rule.

I also notice there are weird rules the parser follows for comments. This does not cause an error:

my $grammar = <<'END_OF_GRAMMAR'; #Start up action(executed in parser namespace): { use 5.012; #So I can use say() } ...

...but this does cause an error:

my $grammar = <<'END_OF_GRAMMAR'; #Start up action(executed in parser namespace): { use 5.012; #So I can use say() } ... --output:-- Unknown starting rule (Parse::RecDescent::namespace000001::startrule) +called at 3.pl line 76.

Back to the regex problem. It seems that Parse::RecDescent takes the regex pattern and adds a ^ to the beginning of the pattern and adds $ to the end of the pattern. In other words, the regex you specify has to match all of the text you are interested in examining.

my $grammar = <<'END_OF_GRAMMAR'; #Start up action(executed in parser namespace): { use 5.012; #So I can use say() } startrule : from_clause from_clause : 'from' dir(s) { say "-->$_<--" for @{ $item{'dir(s)'} }; } dir : m{\S* / \S*}xms END_OF_GRAMMAR my $parser = Parse::RecDescent->new($grammar); $parser->startrule("from ./hello hello/world"); --output:-- -->./hello<-- -->hello/world<--

And reworking my original example:

use strict; use warnings; use 5.012; use Parse::RecDescent; $::RD_ERRORS = 1; #Parser dies when it encounters an error $::RD_WARN = 1; #Enable warnings - warn on unused rules &c. $::RD_HINT = 1; # Give out hints to help fix problems. our %HASH; my $grammar = <<'END_OF_GRAMMAR'; #Start up action(executed in parser namespace): { use 5.012; #So I can use say() } startrule : from_clause from_clause : 'from' dir(s) { say "-->$_<--" for @{ $item{'dir(s)'} }; $main::HASH{target_dirs} = $item{'dir(s)'}; } dir : m{\S* / \S*}xms END_OF_GRAMMAR my $parser = Parse::RecDescent->new($grammar); $parser->startrule("from ./hello hello/world"); use Data::Dumper; say Dumper(\%HASH); --output:-- -->./hello<-- -->hello/world<-- $VAR1 = { 'target_dirs' => [ './hello', 'hello/world' ] };

Success! Thanks.


Comment on Re^3: Why won't this basic Parse::RecDescent example work?
Select or Download Code

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1015752]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (6)
As of 2015-07-03 06:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (48 votes), past polls