perl -we 'use Data::Dumper; $s = \%p; @s = (); while (<>) { our $f++ or $_ = ": " . $_; while (/\G\s*(?:([-\w.]+|"[^"]*")|:([-\w.]*)\s*\(|(\)))/gc) { if (defined($1)) { defined($$s{""}) and die "parse error: two"; $$s{"@"} = $1; } elsif (defined($2)) { push @s, $s; $s = $$s{$2} = {}; } elsif (defined($3)) { @s or die "parse error: close"; $s = pop @s; } } /(\S.*)/g and die "parse error: junk: $1"; } $! and die "read error"; $s == \%p or die "parse error: open"; print Dumper(\%p);'