Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

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

by 7stud (Deacon)
on Jan 28, 2013 at 19:55 UTC ( [id://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.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (4)
As of 2024-04-24 19:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found