Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Perl Misc (http://www.velocityreviews.com/forums/f67-perl-misc.html)
-   -   Parse::RecDescent erreichbarkeit von Variablen (http://www.velocityreviews.com/forums/t912137-parse-recdescent-erreichbarkeit-von-variablen.html)

Martin Bley 01-05-2010 11:40 AM

Parse::RecDescent erreichbarkeit von Variablen
 
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

Martin Bley 01-05-2010 11:53 AM

Re: Parse::RecDescent erreichbarkeit von Variablen
 
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

sreservoir 01-05-2010 12:53 PM

Re: Parse::RecDescent erreichbarkeit von Variablen
 
On 1/5/2010 7:53 PM, Martin Bley wrote:
> 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.

Martin Bley 01-05-2010 01:26 PM

Re: Parse::RecDescent erreichbarkeit von Variablen
 
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

sreservoir 01-05-2010 02:16 PM

Re: Parse::RecDescent erreichbarkeit von Variablen
 
On 1/5/2010 9:26 PM, Martin Bley wrote:
> 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?


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?

Ted Zlatanov 01-05-2010 02:51 PM

Re: Parse::RecDescent erreichbarkeit von Variablen
 
On Tue, 5 Jan 2010 05:26:28 -0800 (PST) Martin Bley <martinbley@yahoo.de> wrote:

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/Ne.../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


All times are GMT. The time now is 01:58 PM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57