Parse::RecDescent erreichbarkeit von Variablen

Discussion in 'Perl Misc' started by Martin Bley, Jan 5, 2010.

  1. Martin Bley

    Martin Bley Guest

    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, Jan 5, 2010
    #1
    1. Advertising

  2. Martin Bley

    Martin Bley Guest

    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
     
    Martin Bley, Jan 5, 2010
    #2
    1. Advertising

  3. Martin Bley

    sreservoir Guest

    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.
     
    sreservoir, Jan 5, 2010
    #3
  4. Martin Bley

    Martin Bley Guest

    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
     
    Martin Bley, Jan 5, 2010
    #4
  5. Martin Bley

    sreservoir Guest

    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?
     
    sreservoir, Jan 5, 2010
    #5
  6. Martin Bley

    Ted Zlatanov Guest

    On Tue, 5 Jan 2010 05:26:28 -0800 (PST) Martin Bley <> 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/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
     
    Ted Zlatanov, Jan 5, 2010
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jean-gert nesselbosch

    XPath1.0-grammar compatible to Parse::RecDescent

    jean-gert nesselbosch, May 12, 2006, in forum: XML
    Replies:
    0
    Views:
    407
    jean-gert nesselbosch
    May 12, 2006
  2. ccm news
    Replies:
    0
    Views:
    3,078
    ccm news
    Jan 15, 2009
  3. Lex Williams

    Alternative to Parse::RecDescent

    Lex Williams, Aug 26, 2008, in forum: Ruby
    Replies:
    4
    Views:
    198
    James Gray
    Aug 27, 2008
  4. Jon Ericson

    Huffman coding and Parse::RecDescent

    Jon Ericson, Apr 22, 2004, in forum: Perl Misc
    Replies:
    4
    Views:
    171
    Jon Ericson
    Apr 23, 2004
  5. max

    variablen zusammenfassen

    max, Oct 31, 2006, in forum: Javascript
    Replies:
    8
    Views:
    82
    Otto Lang
    Nov 2, 2006
Loading...

Share This Page