Parse::RecDescent erreichbarkeit von Variablen

M

Martin Bley

Hallo NG,

folgendes Problem:

Ich habe ein Package mit dem Namen DhcpParser. In diesem Package gibt
es eine Methode parseFile. Innerhalb der Grammatik möchte ich nun die
geparsten Werte in einen Array schreiben und aus der Methode
via return Anweisung zurückgeben. Leider habe ich außerhalb der
Grammatik keinen Zugriff auf die Variablen
(namentlich @hosts).

In der Doku steht, dass die Variablen im Kontext von Parse::RecDescent
zu sehen sind, wie kann ich
aber darauf aus der Methode parseFile() zugreifen? Da steh ich
wirklich
auf dem Schlauch. Weiss jemand Rat?

Ich habe auch schon versucht, die Variable @hosts mit our ganz oben im
package zu deklarieren, leider auch
ohne Erfolg. Hier meine package (gekürzt)

--Schnipp
package DhcpParser;
[...]
use Parse::RecDescent;
[...]
sub new {
[...]
}

sub parseFile {
my $self = shift;

my %tmp = ();
my @hosts;

my $grammar = <<'EOGRAMMAR';
IDHOST : /[a-zA-Z-0-9]+/
IDMAC : /[a-fA-F0-9:]+/
IDIP : /[0-9.]+/
IDCOMMENT : /.*/

file : host(s?)

host : /^host/ IDHOST
{
$::tmp{'name'} = $item[2];
}
/{/ comment(?) option(s?) terminator(1)

comment : <skip: qr/[ \t]*/> word(s?) newline
word : /#/ IDCOMMENT
{
$::tmp{'comment'} = $item[2];
}
newline : /\n/

option : mac | ip | other

mac : /hardware ethernet/ IDMAC /;/
{
$::tmp{'mac'} = $item[2];
}

ip : /fixed-address/ IDIP /;/
{
$::tmp{'ip'} = $item[2];
}

other : /[^}]/

terminator : /}/
{
push(@::hosts, {
'name' => $::tmp{'name'},
'comment' => $::tmp{'comment'},
'mac' => $::tmp{'mac'},
'ip' => $::tmp{'ip'} }
);
%::tmp = ();
}
EOGRAMMAR

my $parse = new Parse::RecDescent($grammar);

# Datei einlesen
my $text;
open( IN, "<" . $self->{FILENAME} ) or die "Fehler: parseFile: ($!)";
while (<IN>) {
next if ( $_ =~ /^#/ || $_ =~ /^\s+$/ );
$text .= $_;
}
close(IN);

my $tree = $parse->file($text);

if (not $tree) {
exit 1;
} else {
my $cnt= (@hosts); # <-- @hosts ist hier leer (im Kontext der
Grammatik allerdings nicht)
print $cnt, "\n";
}

[...]
}
[...]
1;
--Schnapp

Danke und Gruß,
Martin
 
M

Martin Bley

Hi folks,

sorry for posting in german - I didn't mention the missing 'de' prior
the groupname.

My problem points to variables used inside the grammar in the method
parseFile().
I'm not able to access the variable @hosts outside the grammar and
would like to
know, how to get the data out of the parsed file. Inside the grammar
@hosts is filled
with records, outside it is empty.

Documentation says, all variables are in context of Parse::RecDescent.
So how to
access them in there? Thank for any hints.

Regards,
Martin
 
S

sreservoir

Documentation says, all variables are in context of Parse::RecDescent.
So how to
access them in there? Thank for any hints.

If package-compiiled, then @P::RD::hosts should work; if lexical, then
you're out of luck.

Though usually, it's an input problem and you shouldn't be messing with
module internals.
 
M

Martin Bley

Hi,
If package-compiiled, then @P::RD::hosts should work; if lexical, then
you're out of luck.

Though usually, it's an input problem and you shouldn't be messing with
module internals.
I know, this is not clean code. I just don't get how to use the
parsed
values outside the Parse::RecDescent package. Right now, I declare
hosts
at the beginning of my package DhcpParser with

our @hosts;

This way I can access the variable via @::hosts outside the package.
How is
it done in a "clean" way?

Thanks,
Martin
 
S

sreservoir

Hi,

I know, this is not clean code. I just don't get how to use the
parsed
values outside the Parse::RecDescent package. Right now, I declare
hosts
at the beginning of my package DhcpParser with

our @hosts;

This way I can access the variable via @::hosts outside the package.
How is
it done in a "clean" way?

usually, you write a function to return a ro copy of @hosts. But why
@::hosts if it's in the DhcpParser package? Try @DhcpParser::hosts?
 
T

Ted Zlatanov

MB> I know, this is not clean code. I just don't get how to use the
MB> parsed values outside the Parse::RecDescent package. Right now, I
MB> declare hosts at the beginning of my package DhcpParser with our
MB> @hosts;

MB> This way I can access the variable via @::hosts outside the package.
MB> How is it done in a "clean" way?

This is pretty clean. Do your work inside a package, declare "our
@hosts" and then you'll have a nice clean @DhcpParser::hosts to use.
But I have two comments.

First, have you seen
http://search.cpan.org/~jhthorsen/Net-ISC-DHCPd-0.05/lib/Net/ISC/DHCPd.pm?
It may be useful and handles parsing the leases as well. Your MAC and
IP rules in particular can be improved, perhaps with Regexp::Common.

Generally when I write a P::RD parser I try to keep interaction with
global variables to a minimum. Sometimes it can't be avoided. In your
case, you do (as a summary): match A and set $tmp{A}, then B and set
$tmp{B}, then match a terminal and add the hash ref { A => $tmp{A}, B =>
$tmp{B} } to @hosts. This is not the best way to do it, though it may
work sometimes. What you want is:

# this rule will return an array ref to all the matches
all: match(s)

# this rule will return the hash ref you wanted to build

# you could also return \%item but you'll get unnecessary junk in there

# you could also return { A => $item[1], B => $item[2] } but you'd be
# hard-coding the positions; it may be necessary sometimes

match: A B terminal { $return = { A => $item{A}, B => $item{B} } }

Now, when you call the 'all' rule, you'll get an array ref to all the
matches. The external @hosts and %tmp are not needed.

$return is also nice as a way to indicate rule failure in code--you just
set it to undef. You can call an external function with the just-parsed
arguments, too.

You may also want to look at Hash::Merge to simplify your return values
and the <autotree> P::RD directive to build these hashes automatically
for you. <autotree> can be very verbose, though. I like it for
debugging but usually construct my own data structures in the end.

Ted
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top