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__