Below is a refactoring that avoids using stuff from main. Using stuff from main prevents you from precompiling your grammar into a module. Also, using stuff from main makes the script incompatible with mod_perl. (I also lined up the productions.)
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
I was planning on doing P::RD solution for the OP, but I abandonned the idea when others pointed to existing specialized modules. Thanks for filling in the gap.
Update: The common start of both group productions is very innefficient. Fix:
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] }
In reply to Re^2: Regular Expressions and atomic weights
by ikegami
in thread Regular Expressions and atomic weights
by hokie
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |