Oops, I needed to move the "no strict 'refs'"
from the top of my script into the action. 

But actually I've found a nicer solution, without symbolic refs:

use strict;
use vars qw($parser $text %top %wins %marm %bitmap %resource);
use Data::Dumper;
use Parse::RecDescent;
$RD_WARN  = 1;
$RD_HINT  = 1;
$RD_TRACE = 120;
$parser = Parse::RecDescent->new(q(

mmpfile: chunk(s) /^\Z/
chunk: assignment[$arg[0]] | local | <error>

assignment: keyword <skip: '[ \t]+'> value(s) {
        # a reference to a hash of lists
        my $href = $arg[0] || \%::top;
        push @{$href->{uc $item{keyword}}}, @{$item[3]};
}

local: /START\b/i <skip: '[ \t]+'> ( platform | resource | bitmap )
                <skip: $item[2]> chunk[$item[3]](s?)
       /END\b/i

value:  /VAL\d+\b/i
keyword: /KEY\d+\b/i
platform: /WINS\b/i { \%::wins } | /MARM\b/i { \%::marm }

bitmap: /BITMAP\b/i value {
        # this action would fail if you return undef,
        # so create an empty hash if it doesn't exist yet
        $::bitmap{uc $item[-1]} ||= {};
        $::bitmap{uc $item[-1]};
}
resource: /RESOURCE\b/i value {
        # this action would fail if you return undef,
        # so create an empty hash if it doesn't exist yet
        $::resource{uc $item[-1]} ||= {};
        $::resource{uc $item[-1]};
}

)) or die 'Bad grammar';
$text .= $_ while (<DATA>);
defined $parser->mmpfile($text) or die 'Bad text';
print Data::Dumper->Dump([\%top,
                          \%wins,
                          \%marm,
                          \%bitmap,
                          \%resource],
                          [qw(top wins marm bitmap resource)]);
__DATA__
key1            val1

START BITMAP val2
key2            val3 val4
END

START WINS
key2            val5 val6
END

START RESOURCE  val7
key3            val8
key4            val9
END

> -----Original Message-----
> From: ext Alexander Farber [mailto:[EMAIL PROTECTED]
> 
> I have a text consisting of keyword/value assignments, 
> placed on 1 line (please see the __DATA__ on the bottom).
> Some of the assignments are surrounded by START/END:
> 
> START WINS
> key1  val1 val2
> END
> 
> START MARM
> key1  val1
> END
> 
> I would like to capture all of the assignments into hashes
> of lists. The top-level assignments should go into %hol,
> and the START/END-surrounded assignments should go into
> %wins and %marm. I'm trying to achieve this by passing the
> platform name (the word following START) as an argument to
> the assignment rule and by using that name (lowercased) as 
> a symbolic reference.
> 
> Unfortunately my script listed below dies with the error:
> 
> Can't use string ("::hol") as a HASH ref while "strict refs" 
> in use at (eval 18) line 303, <DATA> line 6.
> 
> Why does it mention "strict refs"? I'm explicitly setting
> "no strict 'refs'" on the top of my script.
> 
> Also, I wonder if there is a nicer way to solve my problem.
> 
> The START/END areas do not nest, they are all 1-level deep.
> 
> Thank you
> Alex
> 
> use strict;
> no strict 'refs';
> use vars qw($parser $text %hol %wins %marm);
> use Data::Dumper;
> use Parse::RecDescent;
> $RD_WARN  = 1;
> $RD_HINT  = 1;
> $RD_TRACE = 120;
> $parser = Parse::RecDescent->new(q(
> 
> mmpfile: chunk(s) /^\Z/
> chunk: assignment[$arg[0]] | local | <error>
> assignment: keyword <skip: '[ \t]+'> value(s) {
>         my $hname = lc $arg[0] || 'hol';
>         push @{${"::$hname"}{uc $item{keyword}}}, @{$item[3]};
> }
> 
> local: /start/i <skip: '[ \t]+'> platform
>                 <skip: $item[2]> chunk[$item[3]](s?)
>        /end/i { print "ITEM3: $item[3]\n" }
> 
> value: /val\d+/i
> keyword: /key\d+/i
> platform: /wins/i || /marm/i
> 
> )) or die 'Bad grammar';
> $text .= $_ while (<DATA>);
> defined $parser->mmpfile($text) or die 'bad text';
> print Data::Dumper->Dump([\%hol,
>                           \%wins,
>                           \%marm],
>                           [qw(hol wins marm)]);
> __DATA__
> 
> key1            val1
> START WINS
> key2            val2 val3
> END
> 
> 

Reply via email to