in reply to Tricky parsing.

Quite easily

my $grammar = <<'__END_OF_GRAMMAR__'; { use strict; use warnings; sub dequote { local $_ = @_ ? $_[0] : $_; s/^"//; s/"$//; s/\\(.)/$1/sg; return $_; } } parse : '(' item ')' /\z/ { $item[2] } item : value child(s?) { [ $item[1], $item[2] ] } | child(s?) { [ undef, $item[1] ] } child : CHILD_NAME '(' item ')' { [ @item[1,3] ] } value : NUMBER | IDENT | QSTRING NUMBER : /[1-9][0-9]*/ IDENT : /[a-zA-Z][a-zA-Z0-9_]*/ QSTRING : /"(?:[^"\\]|\\.)*"/s { dequote($item[1]) } CHILD_NAME : /:[a-zA-Z][a-zA-Z0-9_]*/ { substr($item[1], 1) } __END_OF_GRAMMAR__

Untested.

Update: I just noticed the "value" is optional. Fixed.

Update: Tested. Found a few bugs. Fixed them.

use Data::Dumper; use Parse::RecDescent (); my $parser = Parse::RecDescent->new($grammar) or die("Bad grammar\n"); my $parse_tree = $parser->parse($text) or die("Bad text\n"); print Dumper $parse_tree;