b10m has asked for the wisdom of the Perl Monks concerning the following question:

I'm messing with Parse::RecDescent and stumble upon a problem with nesting. Say I have this code for example:

use strict; use Parse::RecDescent; my $parser = Parse::RecDescent->new(q( start: part(s) part : tag { print ">>> $item[1] <<<\n" } | raw tag : stag raw etag { $return = "$item{stag} $item{raw} $item +{etag}" } raw : m{([^<]+)} stag : m{<open>} etag : m{<close>} )); $parser->start(<DATA>); __DATA__ <open> Some content <close> <open> some <open> more content <close> <c +lose>

The result will be that the first (non nested) content is matched, but the other one (nested example) is not.

How to parse such nesting? I can see why it doesn't work, but I can't see the solution. The documentation unfortunately is not clear on this to me :(

--
b10m

All code is usually tested, but rarely trusted.

Replies are listed 'Best First'.
Re: Parse::RecDescent and nesting
by amw1 (Friar) on Jan 14, 2005 at 15:42 UTC
    This may not be exactly what you want but it is probabbly a little closer. I added the numbers after the tags to track which open/close pair I was looking at. Left 'em in.
    + use strict; use Parse::RecDescent; my $parser = Parse::RecDescent->new(q( start: part(s) { print join("\n",@{$item[1 +]}); } part : stag part(s) etag { $return = "$item{stag +} " . join(" ", @{$item[2]}) . " $item{etag}"; } | stag data etag { $return = "$item{stag +} $item{data} $item{etag}"; } | data data : m{([^<]+)} stag : m{<open\d>} etag : m{<close\d>} )); $parser->start(<DATA>); __DATA__ <open1> Some content <close1> <open2> some <open3> more content <close +3> <close2>
    gives the following output
    <open1> Some content <close1> <open2> some <open3> more content <close3> <close2>
    The formatting of the second clause can be twekaed with the join char.
    I am by no means a P::RD master, but I really enjoy playing with it. Let me know if this helps.
Re: Parse::RecDescent and nesting
by hv (Prior) on Jan 14, 2005 at 13:51 UTC

    I don't see anything in your grammar that would permit such nesting. I think you can allow it simply by defining tag as stag part etag.

    Hugo

Parse RecDescent nesting solved (95%)
by tphyahoo (Vicar) on Jan 17, 2005 at 17:03 UTC
    I think you want something like the following.
    use strict; use Parse::RecDescent; my $parser = Parse::RecDescent->new(q( start: chunk(s) chunk: tag | raw tag : stag raw etag { print "tag: $item[1] $item[2] $item[3]\n"; #$return = "$item{stag} $item{raw} $item{etag}" $return = "$item[1] $item[2] $item[3]"; } | stag raw tag(s) raw etag { print "tag: $item[1] $item[2] $item[3] $item[4] $item[5]\n"; #$return = "$item{stag} $item{raw} $item{etag}" $return = "$item[1] $item[2] $item[3] $item[4] $item[5]"; } #outputs: #tag: <open> tag 1 <close> #tag: <open> tag 2 <close> #tag: <open> tag 3 b <close> #tag: <open> tag 3 a ARRAY(0x1a55ad8) tag 3 c <close> #tag: <open> tag 4 b <close> #tag: <open> tag 4 d <close> #tag: <open> tag 4 c # ARRAY(0x1a8f664) tag 4 e # <close> #tag: <open> tag 4 a # ARRAY(0x1a8f670) tag 4 f # <close> raw : m{([^<]*)} stag : m{<open>} etag : m{<close>} )); #slurp mode local $/=''; $parser->start(<DATA>); __DATA__ <open> tag 1 <close> notatag 1 <open> tag 2 <close> notatag 2 <open> tag 3 a <open> tag 3 b <close> tag 3 c <close> notatag 3 <open> tag 4 a <open> tag 4 b <close> <open> tag 4 c <open> tag 4 d <close> tag 4 e <close> tag 4 f <close> notatag 4
    I am 95% happy with this code. If only I wasn't getting those ugly hex refs in the output.

    Maybe some other monk can help with that :)

    thomas. UPDATE: Follow up at Parse RecDescent Nesting (Followup)