Beefy Boxes and Bandwidth Generously Provided by pair Networks DiBona
Keep It Simple, Stupid
 
PerlMonks  

multiple occurences when using Parse::RecDescent

by hak0983 (Novice)
on Mar 29, 2005 at 14:15 UTC ( #443133=perlquestion: print w/ replies, xml ) Need Help??
hak0983 has asked for the wisdom of the Perl Monks concerning the following question:

Hiya, I was wondering, how i could get multiple occurences of a rule when using parse::RecDescent. For example, my code at the moment allows "print 'text'", but i need it so that it will allow this several times down the textarea and spot an error in any of the occurences. I have tried using /g, but am not sure how to use it properly. Any ideas? Cheers

my $mw = new MainWindow; my $mw2 = $mw->Text()->pack(); my $mw3 = $mw->Button(-text=>"Check brackets", -command => [ \&parser, $mw2 ] )->pack(); MainLoop; sub parser { my $txt = shift; my $grammar = q { startrule: print open text end print: "print" open: "'" text: /([^']*)/ end: "'" }; my $parser = Parse::RecDescent->new($grammar); if ( defined( $parser->startrule( $txt->get( "1.0", "end" )))) { print "NO ERROR\n"; } else { print "TEXT COULD NOT BE PARSED\n"; } }

Comment on multiple occurences when using Parse::RecDescent
Download Code
Re: multiple occurences when using Parse::RecDescent
by tlm (Prior) on Mar 29, 2005 at 14:31 UTC

    You'll get a lot more help if you put posted code between <code></code> tags. Better yet become familiar with the contents of the PM site FAQ, especially Writeup Formatting Tips.

    the lowliest monk

Re: multiple occurences when using Parse::RecDescent
by gjb (Vicar) on Mar 29, 2005 at 14:37 UTC

    If I understand the problem correctly, a grammar along the following lines should do what you want:

    my $grammar = q { startrule: statement (endline statement)(s?) statement: print open text end print: "print" open: "'" text: /([^']*)/ end: "'" endline: /(\n|\r)+/ };
    It tells the parser that there should be one or more statements, separated by endlines.

    Hope this helps, -gjb-

    Update: graff is correct, the above grammar unfortunately doesn't work on closer inspection, his is the solution I came up with after fixing mine with the exception of /^\Z/ as a terminator.
      For some reason, I couldn't get your rule to handle repeated ocurrences of the target pattern. Here's a variation that worked for me (and it includes printing out the "text" that it finds, to prove the result):
      startrule: statement(s) statement: print open text end print: /\s*print\s*/ open: "'" text: /([^']*)/ {print " $item[1] "} end: "'"
      Generally, for a grammar that's supposed to handle one or more of a basic top-level unit, it's easier/clearer to assign a name to that unit and have just that, plus "(s)", as the startrule, then break it down into components in a later rule.

      UPDATE: The OP said: i need it so that it will allow this several times down the textarea and spot an error in any of the occurences.

      To make it work that way, the startrule should be:

      startrule: statement(s) /$/
      which says that after matching one or more patterns that satisfy "statement", the parser should find the end-of-string. Without this, any string that starts with a valid statement will be accepted, regardless of any unmatchable content that follows.
Re: multiple occurences when using Parse::RecDescent
by thekestrel (Friar) on Mar 29, 2005 at 14:42 UTC
    if you look here there is a good post on using Rec::Descent grammer.

    Regards Paul
    Update: Fixed link format as per Roy's Comments
      If you would use [402387|here] instead of [http://www.perlmonks.com/?node_id=402387|here] for your self-labeled links, they would behave better for people who use perlmonks.org instead of perlmonks.com. (And of course use [id://402387] when you want to have PM use the post's title for the label.)

      Caution: Contents may have been coded under pressure.
Re: multiple occurences when using Parse::RecDescent
by graff (Chancellor) on Mar 30, 2005 at 09:27 UTC
    In case it helps speed things up for you, here's a minimalist version of your code that allows for the grammar to be typed/pasted into a separate text box, so you can modify the grammar on the fly without having to re-edit and re-start the script:
    #!/usr/bin/perl use strict; use Tk; use Parse::RecDescent; my $mw = new MainWindow; my $frm = $mw->Frame()->pack(); my $mw1 = $frm->Text()->pack(-side => 'left'); my $mw2 = $frm->Text()->pack(-side => 'left'); my $mw3 = $mw->Button(-text=>"Check brackets", -command => [ \&parser, $mw1, $mw2 ] )->pack(); MainLoop; sub parser { my ($grm,$txt) = @_; my $grammar = $grm->get('1.0','end'); my $parser = Parse::RecDescent->new($grammar); if ( !defined( $parser )) { warn "BAD GRAMMAR\n"; return; } if ( defined( $parser->startrule( $txt->get( "1.0", "end" )))) { print "NO ERROR\n"; } else { print "TEXT COULD NOT BE PARSED\n"; } }
    As you play with that, you'll notice that Parse::RecDescent gives informative messages about problems with the grammar when it's not usable (but you probably know that already).

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://443133]
Approved by gjb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (11)
As of 2014-04-18 14:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (469 votes), past polls