perlparse-recdescent

Interpolating variables in a Parse::RecDescent regex


I'm working on a Parse::RecDescent grammar to read a given human-readable set of rules and then spit out a file that is much easier for a computer to read.

One of the tokens is a list of "keywords"; about 26 different keywords. These may change over time, and may be referenced by multiple pieces of code. Consequently, I want to store the keyword-y things in a data file and load them in.

A feature of Parse::RecDescent is the ability to interpolate variables in regexes, and I would like to use it.

I wrote up some code as a proof of concept:

@arr = ("foo", "bar", "frank", "jim");


$data = <<SOMEDATA;
This is some data with the word foo in it
SOMEDATA

$arrstr = join("|", @arr);

if($data =~ /($arrstr)/)
{
    print "Matched $1\n";
}
else
{
    print "Failed to match\n";
}

This worked correctly. When I moved to my main program to implement it, I wrote:

{
    my $myerror = open(FILE, "data.txt") or die("Failed to open data");
    my @data_arr = <FILE>;
    close FILE;
    my $dataarrstr = join("|", @data_arr);

}
#many rules having nothing to do with the data array are here...

event : /($dataarrstr)/
    { $return = $item[1]; }
    | 

And at this point, I received this error from P::RD: ERROR (line 18): Invalid event: Was expecting /($dataarrstr)/.

I don't know why. Does anyone have any ideas that would serve to help me out here?

edit: This is not a scoping issue- I've tried that. I've also tried the m{...} syntax.


Solution

  • After perusing documentation and a very similar question over at http://perlmonks.org/?node_id=384098, I worked out this solution.

    event :/\w+/
        {
            $return = ::is_valid_event($item[1]);
        }
        | <error>
    

    Outside the grammar -

    #This manages the problem of not being able to interpolate the variable 
    #in the grammar action
    sub is_valid_event {
        my $word = shift @_;
        if($word =~ /$::data_str/)
        {
            return $word;
        }
        else
        {
            return undef;
        }
    }