use strict; use warnings; use List::Util qw( sum ); our %ATOM_WEIGHTS = ( C => 12, O => 16, Pb => 207 ); { our $rv_compound; our $rv_compound_; our $rv_group; our $rv_factor; our $rv_element; # Definitions must not be combined with assignment. my $compound; my $compound_; my $group; my $factor; my $element; $compound = qr/ (??{ $group }) (??{ $compound_ }) # Return value: (?{ local $rv_compound = $rv_group + $rv_compound_; }) /x; $compound_ = qr/ (?: (??{ $group }) (??{ $compound_ }) # Return value (first prod): (?{ local $rv_compound_ = $rv_group + $rv_compound_; }) | # Nothing # Return value (second prod): (?{ local $rv_compound_ = 0; }) ) /x; $group = qr/ (??{ $element }) (??{ $factor }) # Return value: (?{ local $rv_group = $rv_element * $rv_factor; }) /x; $factor = qr/ (?: (\d+) # Return value (first prod): (?{ local $rv_factor = $1 }) | # Nothing # Return value (second prod): (?{ local $rv_factor = 1 }) ) /x; $element = qr/ (?: ([A-Z][a-z]*(?![a-z])) # Return value (first prod): (?{ local $rv_element = $ATOM_WEIGHTS{$1} }) | \( (??{ $compound }) \) # Return value (second prod): (?{ local $rv_element = $rv_compound; }) ) /x; sub weight { local $rv_compound; local $rv_compound_; local $rv_group; local $rv_factor; local $rv_element; my $rv; shift =~ / # To bypass RE bug. () (??{ $compound }) # Return value: (?{ $rv = $rv_compound; }) /x; return $rv; } } print("The weight of $_ is ", weight($_), ".\n") for 'Pb(CO3)2';