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