use Parse::RecDescent; use List::Util 'sum'; use vars '%weights'; %weights = qw( C 12 O 16 Pb 207 ); my $g = Parse::RecDescent->new(<<'END_GRAMMAR'); weight: compound { $item[1] } compound: group(s) { ::sum( @{$item[1]} ) } group: element /\d+/ { $item[1] * $item[2] } | element { $item[1] } element: /[A-Z][a-z]*/ { $::weights{ $item[1] } } | "(" compound")" { $item[2] } END_GRAMMAR print $g->weight("Pb(CO3)2"), $/; # prints 327