Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

scope issues in Parse::RecDescent

by citromatik (Curate)
on Mar 22, 2011 at 11:42 UTC ( #894775=perlquestion: print w/ replies, xml ) Need Help??
citromatik has asked for the wisdom of the Perl Monks concerning the following question:

Hi all

Another one with Parse::RecDescent:

If you want to get back a list of tokens from a grammar you have to do something like this:

use strict; use warnings; use Data::Dumper use Parse::RecDescent; use vars qw/@tokens/; my $p6 = Parse::RecDescent->new(q( letter : /\w/ character : letter { push @main::tokens, $item{letter}; } Format : character Format )); $p6->Format('abc'); die "Invalid pattern" unless (defined $p6); print Dumper \@tokens;

Is there any way to avoid the use of global variables for achieving this? I would like to feed the grammar with different input strings

Thanks in advance!

citromatik

Comment on scope issues in Parse::RecDescent
Download Code
Re: scope issues in Parse::RecDescent
by Corion (Pope) on Mar 22, 2011 at 12:21 UTC

    As Parse::RecDescent gets its grammar as a string, I see no way to create clever closures or anything that will allow you to use lexical variables. One approach I can think of would be judicious use of local to isolate the effects, but that implies that your parsers won't call each other recursively:

    ... sub do_parse { local $parser_info = { tokens => [], }; my $p6 = Parse::RecDescent->new(q{ { push @{ $parser_info->{tokens} }, $item{letter} } }); }; ...

    That way, you reduce your need for a global variable to one entry point, $parser_info. I think you can also instruct Parse::RecDescent to return you the whole parse tree as an AST instead of having it execute code immediately, by using the <autotree> directive. That wouldn't require any code within your parser, but you have to walk the tree yourself after it has been constructed.

      It seems that you can define "top level" actions and define variables in them. So this would do the trick:

      use strict; use warnings; use Data::Dumper use Parse::RecDescent; ### use vars qw/@tokens/; Avoided using global variables my $p6 = Parse::RecDescent->new(q( {my @tokens} letter : /\w/ character : letter { push @tokens, $item{letter}; } Format : character(s) { \@tokens } )); my $tokens_ref = $p6->Format('abc'); die "Invalid pattern" unless (defined $tokens_ref); print Dumper $tokens_ref;

      Outputs:

      $VAR1 = [ 'a', 'b', 'c' ];

      citromatik

Re: scope issues in Parse::RecDescent
by jethro (Monsignor) on Mar 22, 2011 at 13:36 UTC
    my $p6 = Parse::RecDescent->new(q( letter : /\w/ character : letter Format : character(s) )); my $x= $p6->Format('abc'); die "Invalid pattern" unless (defined $p6); print Dumper $x; #prints $VAR1 = [ 'a', 'b', 'c' ];

    Be careful to specify what a rule returns with $return if more than one production is in a rule (i.e. with a rule like "strangeword: character number character(s)", since only the last production is returned as a default

    With $return you can also return anything you want, i.e. parsed and interpreted commands, hashes, objects ...

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (18)
As of 2014-07-10 19:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (215 votes), past polls