I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

# Chemical Calculator

Chemical Calculator is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a molecule's chemical formula, calculate the   molar mass.

Introduction
• A molecule consists of atoms. E.g. water, H2O, has two hydrogen atoms and one oxygen atom
• The mass of H2O is 1.008 * 2 + 15.999 = 18.015
• An atom name consists of one upper-case letter followed by zero, one or two lower-case letters.
• H       (Hydrogen)
• He     (Helium)
• Uue   (Ununennium)
• The number of atoms is stated behind the atom or atom group
• An atom group is specified using parenthesis. E.g. Butyric acid, (CH3)2CHCOOH, has two CH3 groups
• A group may contain other groups, e.g. COOH(C(CH3)2)3CH3

Background
• The mass is dimensionless,   it is relative to   1/12   of Carbon-12
• Carbon-12   has exactly   6 protons,   6 electrons,   and   6 neutrons
• One mole of   H2O   has the mass 18.015 grams
• One mole is defined as exactly   6.02214076×1023   particles

The above number is known as the   Avogadro constant,   which is named by the International Bureau of Weights and Measures (IBPM);
the initials are taken from   Bureau International des Poids et Mesures,   the official name of the bureau.

Atom masses

A mapping between most recognized element names and atomic mass follows in comma separated value format:

```H,1.008
He,4.002602
Li,6.94
Be,9.0121831
B,10.81
C,12.011
N,14.007
O,15.999
F,18.998403163
Ne,20.1797
Na,22.98976928
Mg,24.305
Al,26.9815385
Si,28.085
P,30.973761998
S,32.06
Cl,35.45
K,39.0983
Ar,39.948
Ca,40.078
Sc,44.955908
Ti,47.867
V,50.9415
Cr,51.9961
Mn,54.938044
Fe,55.845
Ni,58.6934
Co,58.933194
Cu,63.546
Zn,65.38
Ga,69.723
Ge,72.63
As,74.921595
Se,78.971
Br,79.904
Kr,83.798
Rb,85.4678
Sr,87.62
Y,88.90584
Zr,91.224
Nb,92.90637
Mo,95.95
Ru,101.07
Rh,102.9055
Pd,106.42
Ag,107.8682
Cd,112.414
In,114.818
Sn,118.71
Sb,121.76
I,126.90447
Te,127.6
Xe,131.293
Cs,132.90545196
Ba,137.327
La,138.90547
Ce,140.116
Pr,140.90766
Nd,144.242
Pm,145
Sm,150.36
Eu,151.964
Gd,157.25
Tb,158.92535
Dy,162.5
Ho,164.93033
Er,167.259
Tm,168.93422
Yb,173.054
Lu,174.9668
Hf,178.49
Ta,180.94788
W,183.84
Re,186.207
Os,190.23
Ir,192.217
Pt,195.084
Au,196.966569
Hg,200.592
Tl,204.38
Pb,207.2
Bi,208.9804
Po,209
At,210
Rn,222
Fr,223
Ra,226
Ac,227
Pa,231.03588
Th,232.0377
Np,237
U,238.02891
Am,243
Pu,244
Cm,247
Bk,247
Cf,251
Es,252
Fm,257
Ubn,299
Uue,315```

Examples
`assert   1.008 == molar_mass('H')                  # hydrogenassert   2.016 == molar_mass('H2')                 # hydrogen gasassert  18.015 == molar_mass('H2O')                # waterassert  34.014 == molar_mass('H2O2')               # hydrogen peroxideassert  34.014 == molar_mass('(HO)2')              # hydrogen peroxideassert 142.036 == molar_mass('Na2SO4')             # sodium sulfateassert  84.162 == molar_mass('C6H12')              # cyclohexaneassert 186.295 == molar_mass('COOH(C(CH3)2)3CH3')  # butyric or butanoic acid assert 176.124 == molar_mass('C6H4O2(OH)4')        # vitamin Cassert 386.664 == molar_mass('C27H46O')            # cholesterolassert 315     == molar_mass('Uue')                # ununennium`

Reference

## ALGOL W

Algol W has fixed length strings and no regular expressions, this parses the molecule with a simple recursive descent parser.
Some error checking is included.

`begin    % calculates the molar mass of the specified molecule %    real procedure molar_mass ( string(256) value molecule ) ; begin        string(1) c;        integer   chPos, chMax;        logical   hadError;        real      mass;        % reports a syntax error in the molecule starting at position chPos %        procedure syntaxError( string(80) value message ) ; begin            integer mPos;            write( "Syntax error in molecule: " );            mPos := 0;            while mPos < 80 and message( mPos // 1 ) not = "." do begin                writeon( message( mPos // 1 ) );                mPos := mPos + 1            end while_not_end_of_message ;            write( "    " );for i := 0 until chMax     do writeon( molecule( i // 1 ) );            write( "    " );for i := 0 until chPos - 1 do writeon( " " );            writeon( "^" );            % ensure parsing stops %            hadError := true;            chPos    := chMax * 2        end syntaxError ;        % gets the next character from the molecule %        procedure nextChar ; begin            chPos := chPos + 1;            c     := if chPos > chMax then " " else molecule( chPos // 1 )        end nextChar ;        % parses a compound: a sequence of element names and bracketed compounds, each with   %        % an optional trailing repeat count                                                   %        real procedure parseCompound ; begin            real mass, itemMass;            % parses an element symbol from the molecule and returns its mass                 %            real procedure parseAtom ; begin                string(3)       symbol;                reference(Atom) element;                symbol := c;                nextChar;                if c >= "a" and c <= "z" then begin                    symbol( 1 // 1 ) := c;                    nextChar;                    if c >= "a" and c <= "z" then begin                        symbol( 2 // 1 ) := c;                        nextChar                    end if_have_lc_letter                end if_have_lc_letter ;                % find the element in the table %                element := atoms( decode( symbol( 0 // 1 ) ) - decode( "A" ) );                while element not = null and aSymbol(element) not = symbol do element := aNext(element);                if element not = null then % found the element % aMass(element)                else begin % unknown element %                    chPos := chPos - 1;                    syntaxError( "Unrecognised element." );                    0                end            end parseAtom ;            mass := 0;            while not hadError and ( ( c >= "A" and c <= "Z" ) or c = "(" ) do begin                if c >= "A" and c <= "Z" then itemMass := parseAtom                else if c = "(" then begin % bracketed group %                    nextChar;                    itemMass := parseCompound;                    if chPos > chMax or molecule( chPos // 1 ) not = ")" then syntaxError( "Expected "")""." );                    nextChar                end ;                if c >= "0" and c <= "9" then begin % have a repeat count %                    integer count;                    count := 0;                    while not hadError and c >= "0" and c <= "9" do begin                        count := ( count * 10 ) + ( decode( c ) - decode( "0" ) );                        nextChar                    end while_not_end_of_number ;                    itemMass := itemMass * count                end if_have_a_digit ;                mass := mass + itemMass            end while_still_parseing ;            mass        end parseCompound ;        hadError := false;        % find the end of the molecule %        chMax := 255;        while chMax > 0 and molecule( chMax // 1 ) = " " do chMax := chMax - 1;        % parse the molecule %        chPos := -1;        nextChar;        mass := parseCompound;        if chPos <= chMax then syntaxError( "Unexpected text after the molecule." );        mass    end molar_mass ;    % record to hold element symbols and masses %    record Atom( string(3) aSymbol; real aMass; reference(Atom) aNext );    % hash table of atome, hash is the first character of the symbol - "A" %    reference(Atom) array atoms ( 0 :: 25 ); for i := 0 until 25 do atoms( i ) := null;    begin % setup element symbols and masses as specified in the task %        % adds an element and its mass to the atoms table %        procedure A ( string(3) value symbol; real value mass ) ; begin            integer index;            index := decode( symbol( 0 // 1 ) ) - decode( "A" );            atoms( index ) := Atom( symbol, mass, atoms( index ) )        end A ;        procedure Lanthanides ; begin            A("La",138.90547);A("Ce",140.116 );A("Pr",140.90766);A("Nd",144.242  );A("Pm",145     );            A("Sm",150.36   );A("Eu",151.964 );A("Gd",157.25   );A("Tb",158.92535);A("Dy",162.5   );            A("Ho",164.93033);A("Er",167.259 );A("Tm",168.93422);A("Yb",173.054  );A("Lu",174.9668);        end Lanthanides ;        procedure Actinides ; begin            A("Ac",227      );A("Th",232.0377);A("Pa",231.03588);A("U", 238.02891);A("Np",237     );            A("Pu",244      );A("Am",243     );A("Cm",247      );A("Bk",247      );A("Cf",251     );            A("Es",252      );A("Fm",257     ); % Md           % %, No           %  % Lr          %        end Actinides ;        A("Li", 6.94       );A("Na",22.98976928 );A("K", 39.0983  );A("Rb", 85.4678 );A("Cs",132.90545196);A("Fr", 223 );        A("Be", 9.0121831  );A("Mg",24.305      );A("Ca",40.078   );A("Sr", 87.62   );A("Ba",137.327     );A("Ra", 226 );                                                  A("Sc",44.955908);A("Y",  88.90584);   Lanthanides;         Actinides;                                                  A("Ti",47.867   );A("Zr", 91.224  );A("Hf",178.49      ); % Rf       %                                                  A("V", 50.9415  );A("Nb", 92.90637);A("Ta",180.94788   ); % Db       %                                                  A("Cr",51.9961  );A("Mo", 95.95   );A("W", 183.84      ); % Sg       %                                                  A("Mn",54.938044); % Tc           % A("Re",186.207     ); % Bh       %                                                  A("Fe",55.845   );A("Ru",101.07   );A("Os",190.23      ); % Hs       %                                                  A("Co",58.933194);A("Rh",102.9055 );A("Ir",192.217     ); % Mt       %                                                  A("Ni",58.6934  );A("Pd",106.42   );A("Pt",195.084     ); % Ds       %                                                  A("Cu",63.546   );A("Ag",107.8682 );A("Au",196.966569  ); % Rg       %                                                  A("Zn",65.38    );A("Cd",112.414  );A("Hg",200.592     ); % Cn       %        A("B", 10.81       );A("Al",26.9815385  );A("Ga",69.723   );A("In",114.818  );A("Tl",204.38      ); % Nh       %        A("C", 12.011      );A("Si",28.085      );A("Ge",72.63    );A("Sn",118.71   );A("Pb",207.2       ); % Fl       %        A("N", 14.007      );A("P", 30.973761998);A("As",74.921595);A("Sb",121.76   );A("Bi",208.9804    ); % Ms       %        A("O", 15.999      );A("S", 32.06       );A("Se",78.971   );A("Te",127.6    );A("Po",209         ); % Lv       %        A("F", 18.998403163);A("Cl",35.45       );A("Br",79.904   );A("I", 126.90447);A("At",210         ); % Ts       %        A("Ne",20.1797     );A("Ar",39.948      );A("Kr",83.798   );A("Xe",131.293  );A("Rn",222         ); % Og       %        % ---------------- first period elements ---> % A("H",    1.008);A("He",   4.002602);        % --- hypothetical eigth period elements ---> % A("Uue",315    );A("Ubn",299       );    end;    begin % test cases %        procedure test( real value expectedMass; string(256) value molecule ) ; begin            real mass, diff;            mass := molar_mass( molecule );            write( r_format := "A", r_d := 3, r_w := 9                 , molecule( 0 // 20 ), ":", mass                 );            diff := expectedMass - mass;            if diff > 1'-12 or diff < -1'-12 then writeon( r_format := "A", r_d := 2, r_w := 9                                                         , " expected:", expectedMass                                                         )        end text ;                         test( 1.008, "H" ); test( 2.016, "H2" );         test(  18.015, "H2O"   );        test( 142.03553856000002, "Na2SO4"            ); test(  84.162, "C6H12" );        test( 186.29499999999996, "COOH(C(CH3)2)3CH3" ); test( 350.45,  "UueCl" );    endend.`
Output:
```H                   :    1.008
H2                  :    2.016
H2O                 :   18.015
Na2SO4              :  142.035
C6H12               :   84.162
COOH(C(CH3)2)3CH3   :  186.295
UueCl               :  350.450
```

## C

`#include <stdio.h>#include <stdlib.h>#include <string.h> typedef char *string; typedef struct node_t {    string symbol;    double weight;    struct node_t *next;} node; node *make_node(string symbol, double weight) {    node *nptr = malloc(sizeof(node));    if (nptr) {        nptr->symbol = symbol;        nptr->weight = weight;        nptr->next = NULL;        return nptr;    }    return NULL;} void free_node(node *ptr) {    if (ptr) {        free_node(ptr->next);        ptr->next = NULL;        free(ptr);    }} node *insert(string symbol, double weight, node *head) {    node *nptr = make_node(symbol, weight);    nptr->next = head;    return nptr;} node *dic;void init() {    dic = make_node("H", 1.008);    dic = insert("He", 4.002602, dic);    dic = insert("Li", 6.94, dic);    dic = insert("Be", 9.0121831, dic);    dic = insert("B", 10.81, dic);    dic = insert("C", 12.011, dic);    dic = insert("N", 14.007, dic);    dic = insert("O", 15.999, dic);    dic = insert("F", 18.998403163, dic);    dic = insert("Ne", 20.1797, dic);    dic = insert("Na", 22.98976928, dic);    dic = insert("Mg", 24.305, dic);    dic = insert("Al", 26.9815385, dic);    dic = insert("Si", 28.085, dic);    dic = insert("P", 30.973761998, dic);    dic = insert("S", 32.06, dic);    dic = insert("Cl", 35.45, dic);    dic = insert("Ar", 39.948, dic);    dic = insert("K", 39.0983, dic);    dic = insert("Ca", 40.078, dic);    dic = insert("Sc", 44.955908, dic);    dic = insert("Ti", 47.867, dic);    dic = insert("V", 50.9415, dic);    dic = insert("Cr", 51.9961, dic);    dic = insert("Mn", 54.938044, dic);    dic = insert("Fe", 55.845, dic);    dic = insert("Co", 58.933194, dic);    dic = insert("Ni", 58.6934, dic);    dic = insert("Cu", 63.546, dic);    dic = insert("Zn", 65.38, dic);    dic = insert("Ga", 69.723, dic);    dic = insert("Ge", 72.630, dic);    dic = insert("As", 74.921595, dic);    dic = insert("Se", 78.971, dic);    dic = insert("Br", 79.904, dic);    dic = insert("Kr", 83.798, dic);    dic = insert("Rb", 85.4678, dic);    dic = insert("Sr", 87.62, dic);    dic = insert("Y", 88.90584, dic);    dic = insert("Zr", 91.224, dic);    dic = insert("Nb", 92.90637, dic);    dic = insert("Mo", 95.95, dic);    dic = insert("Ru", 101.07, dic);    dic = insert("Rh", 102.90550, dic);    dic = insert("Pd", 106.42, dic);    dic = insert("Ag", 107.8682, dic);    dic = insert("Cd", 112.414, dic);    dic = insert("In", 114.818, dic);    dic = insert("Sn", 118.710, dic);    dic = insert("Sb", 121.760, dic);    dic = insert("Te", 127.60, dic);    dic = insert("I", 126.90447, dic);    dic = insert("Xe", 131.293, dic);    dic = insert("Cs", 132.90545196, dic);    dic = insert("Ba", 137.327, dic);    dic = insert("La", 138.90547, dic);    dic = insert("Ce", 140.116, dic);    dic = insert("Pr", 140.90766, dic);    dic = insert("Nd", 144.242, dic);    dic = insert("Pm", 145, dic);    dic = insert("Sm", 150.36, dic);    dic = insert("Eu", 151.964, dic);    dic = insert("Gd", 157.25, dic);    dic = insert("Tb", 158.92535, dic);    dic = insert("Dy", 162.500, dic);    dic = insert("Ho", 164.93033, dic);    dic = insert("Er", 167.259, dic);    dic = insert("Tm", 168.93422, dic);    dic = insert("Yb", 173.054, dic);    dic = insert("Lu", 174.9668, dic);    dic = insert("Hf", 178.49, dic);    dic = insert("Ta", 180.94788, dic);    dic = insert("W", 183.84, dic);    dic = insert("Re", 186.207, dic);    dic = insert("Os", 190.23, dic);    dic = insert("Ir", 192.217, dic);    dic = insert("Pt", 195.084, dic);    dic = insert("Au", 196.966569, dic);    dic = insert("Hg", 200.592, dic);    dic = insert("Tl", 204.38, dic);    dic = insert("Pb", 207.2, dic);    dic = insert("Bi", 208.98040, dic);    dic = insert("Po", 209, dic);    dic = insert("At", 210, dic);    dic = insert("Rn", 222, dic);    dic = insert("Fr", 223, dic);    dic = insert("Ra", 226, dic);    dic = insert("Ac", 227, dic);    dic = insert("Th", 232.0377, dic);    dic = insert("Pa", 231.03588, dic);    dic = insert("U", 238.02891, dic);    dic = insert("Np", 237, dic);    dic = insert("Pu", 244, dic);    dic = insert("Am", 243, dic);    dic = insert("Cm", 247, dic);    dic = insert("Bk", 247, dic);    dic = insert("Cf", 251, dic);    dic = insert("Es", 252, dic);    dic = insert("Fm", 257, dic);    dic = insert("Uue", 315, dic);    dic = insert("Ubn", 299, dic);} double lookup(string symbol) {    for (node *ptr = dic; ptr; ptr = ptr->next) {        if (strcmp(symbol, ptr->symbol) == 0) {            return ptr->weight;        }    }     printf("symbol not found: %s\n", symbol);    return 0.0;} double total(double mass, int count) {    if (count > 0) {        return mass * count;    }    return mass;} double total_s(string sym, int count) {    double mass = lookup(sym);    return total(mass, count);} double evaluate_c(string expr, size_t *pos, double mass) {    int count = 0;    if (expr[*pos] < '0' || '9' < expr[*pos]) {        printf("expected to find a count, saw the character: %c\n", expr[*pos]);    }    for (; expr[*pos]; (*pos)++) {        char c = expr[*pos];        if ('0' <= c && c <= '9') {            count = count * 10 + c - '0';        } else {            break;        }    }    return total(mass, count);} double evaluate_p(string expr, size_t limit, size_t *pos) {    char sym[4];    int sym_pos = 0;    int count = 0;    double sum = 0.0;     for (; *pos < limit && expr[*pos]; (*pos)++) {        char c = expr[*pos];        if ('A' <= c && c <= 'Z') {            if (sym_pos > 0) {                sum += total_s(sym, count);                sym_pos = 0;                count = 0;            }            sym[sym_pos++] = c;            sym[sym_pos] = 0;        } else if ('a' <= c && c <= 'z') {            sym[sym_pos++] = c;            sym[sym_pos] = 0;        } else if ('0' <= c && c <= '9') {            count = count * 10 + c - '0';        } else if (c == '(') {            if (sym_pos > 0) {                sum += total_s(sym, count);                sym_pos = 0;                count = 0;            }             (*pos)++; // skip past the paren            double mass = evaluate_p(expr, limit, pos);             sum += evaluate_c(expr, pos, mass);            (*pos)--; // neutralize the position increment        } else if (c == ')') {            if (sym_pos > 0) {                sum += total_s(sym, count);                sym_pos = 0;                count = 0;            }             (*pos)++;            return sum;        } else {            printf("Unexpected character encountered: %c\n", c);        }    }     if (sym_pos > 0) {        sum += total_s(sym, count);    }    return sum;} double evaluate(string expr) {    size_t limit = strlen(expr);    size_t pos = 0;    return evaluate_p(expr, limit, &pos);} void test(string expr) {    double mass = evaluate(expr);    printf("%17s -> %7.3f\n", expr, mass);} int main() {    init();     test("H");    test("H2");    test("H2O");    test("H2O2");    test("(HO)2");    test("Na2SO4");    test("C6H12");    test("COOH(C(CH3)2)3CH3");    test("C6H4O2(OH)4");    test("C27H46O");    test("Uue");     free_node(dic);    dic = NULL;    return 0;}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## C#

Translation of: D
`using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace ChemicalCalculator {    class Program {        static Dictionary<string, double> atomicMass = new Dictionary<string, double>() {            {"H",     1.008 },            {"He",    4.002602},            {"Li",    6.94},            {"Be",    9.0121831},            {"B",    10.81},            {"C",    12.011},            {"N",    14.007},            {"O",    15.999},            {"F",    18.998403163},            {"Ne",   20.1797},            {"Na",   22.98976928},            {"Mg",   24.305},            {"Al",   26.9815385},            {"Si",   28.085},            {"P",    30.973761998},            {"S",    32.06},            {"Cl",   35.45},            {"Ar",   39.948},            {"K",    39.0983},            {"Ca",   40.078},            {"Sc",   44.955908},            {"Ti",   47.867},            {"V",    50.9415},            {"Cr",   51.9961},            {"Mn",   54.938044},            {"Fe",   55.845},            {"Co",   58.933194},            {"Ni",   58.6934},            {"Cu",   63.546},            {"Zn",   65.38},            {"Ga",   69.723},            {"Ge",   72.630},            {"As",   74.921595},            {"Se",   78.971},            {"Br",   79.904},            {"Kr",   83.798},            {"Rb",   85.4678},            {"Sr",   87.62},            {"Y",    88.90584},            {"Zr",   91.224},            {"Nb",   92.90637},            {"Mo",   95.95},            {"Ru",  101.07},            {"Rh",  102.90550},            {"Pd",  106.42},            {"Ag",  107.8682},            {"Cd",  112.414},            {"In",  114.818},            {"Sn",  118.710},            {"Sb",  121.760},            {"Te",  127.60},            {"I",   126.90447},            {"Xe",  131.293},            {"Cs",  132.90545196},            {"Ba",  137.327},            {"La",  138.90547},            {"Ce",  140.116},            {"Pr",  140.90766},            {"Nd",  144.242},            {"Pm",  145},            {"Sm",  150.36},            {"Eu",  151.964},            {"Gd",  157.25},            {"Tb",  158.92535},            {"Dy",  162.500},            {"Ho",  164.93033},            {"Er",  167.259},            {"Tm",  168.93422},            {"Yb",  173.054},            {"Lu",  174.9668},            {"Hf",  178.49},            {"Ta",  180.94788},            {"W",   183.84},            {"Re",  186.207},            {"Os",  190.23},            {"Ir",  192.217},            {"Pt",  195.084},            {"Au",  196.966569},            {"Hg",  200.592},            {"Tl",  204.38},            {"Pb",  207.2},            {"Bi",  208.98040},            {"Po",  209},            {"At",  210},            {"Rn",  222},            {"Fr",  223},            {"Ra",  226},            {"Ac",  227},            {"Th",  232.0377},            {"Pa",  231.03588},            {"U",   238.02891},            {"Np",  237},            {"Pu",  244},            {"Am",  243},            {"Cm",  247},            {"Bk",  247},            {"Cf",  251},            {"Es",  252},            {"Fm",  257},            {"Uue", 315},            {"Ubn", 299},        };         static double Evaluate(string s) {            s += "[";            double sum = 0.0;            string symbol = "";            string number = "";            for (int i = 0; i < s.Length; ++i) {                var c = s[i];                if ('@' <= c && c <= '[') {                    // @, A-Z                    int n = 1;                    if (number != "") {                        n = int.Parse(number);                    }                    if (symbol != "") {                        sum += atomicMass[symbol] * n;                    }                    if (c == '[') {                        break;                    }                    symbol = c.ToString();                    number = "";                } else if ('a' <= c && c <= 'z') {                    symbol += c;                } else if ('0' <= c && c <= '9') {                    number += c;                } else {                    throw new Exception(string.Format("Unexpected symbol {0} in molecule", c));                }            }            return sum;        }         // Taken from return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);        static string ReplaceFirst(string text, string search, string replace) {            int pos = text.IndexOf(search);            if (pos < 0) {                return text;            }            return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);        }         static string ReplaceParens(string s) {            char letter = 's';            while (true) {                var start = s.IndexOf('(');                if (start == -1) {                    break;                }                 for (int i = start + 1; i < s.Length; ++i) {                    if (s[i] == ')') {                        var expr = s.Substring(start + 1, i - start - 1);                        var symbol = string.Format("@{0}", letter);                        s = ReplaceFirst(s, s.Substring(start, i + 1 - start), symbol);                        atomicMass[symbol] = Evaluate(expr);                        letter++;                        break;                    }                    if (s[i] == '(') {                        start = i;                        continue;                    }                }            }            return s;        }         static void Main() {            var molecules = new string[]{                "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",                "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"            };            foreach (var molecule in molecules) {                var mass = Evaluate(ReplaceParens(molecule));                Console.WriteLine("{0,17} -> {1,7:0.000}", molecule, mass);            }        }    }}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## C++

Translation of: C#
`#include <iomanip>#include <iostream>#include <map>#include <string>#include <vector> std::map<std::string, double> atomicMass = {    {"H", 1.008},    {"He",    4.002602},    {"Li",    6.94},    {"Be",    9.0121831},    {"B",    10.81},    {"C",    12.011},    {"N",    14.007},    {"O",    15.999},    {"F",    18.998403163},    {"Ne",   20.1797},    {"Na",   22.98976928},    {"Mg",   24.305},    {"Al",   26.9815385},    {"Si",   28.085},    {"P",    30.973761998},    {"S",    32.06},    {"Cl",   35.45},    {"Ar",   39.948},    {"K",    39.0983},    {"Ca",   40.078},    {"Sc",   44.955908},    {"Ti",   47.867},    {"V",    50.9415},    {"Cr",   51.9961},    {"Mn",   54.938044},    {"Fe",   55.845},    {"Co",   58.933194},    {"Ni",   58.6934},    {"Cu",   63.546},    {"Zn",   65.38},    {"Ga",   69.723},    {"Ge",   72.630},    {"As",   74.921595},    {"Se",   78.971},    {"Br",   79.904},    {"Kr",   83.798},    {"Rb",   85.4678},    {"Sr",   87.62},    {"Y",    88.90584},    {"Zr",   91.224},    {"Nb",   92.90637},    {"Mo",   95.95},    {"Ru",  101.07},    {"Rh",  102.90550},    {"Pd",  106.42},    {"Ag",  107.8682},    {"Cd",  112.414},    {"In",  114.818},    {"Sn",  118.710},    {"Sb",  121.760},    {"Te",  127.60},    {"I",   126.90447},    {"Xe",  131.293},    {"Cs",  132.90545196},    {"Ba",  137.327},    {"La",  138.90547},    {"Ce",  140.116},    {"Pr",  140.90766},    {"Nd",  144.242},    {"Pm",  145},    {"Sm",  150.36},    {"Eu",  151.964},    {"Gd",  157.25},    {"Tb",  158.92535},    {"Dy",  162.500},    {"Ho",  164.93033},    {"Er",  167.259},    {"Tm",  168.93422},    {"Yb",  173.054},    {"Lu",  174.9668},    {"Hf",  178.49},    {"Ta",  180.94788},    {"W",   183.84},    {"Re",  186.207},    {"Os",  190.23},    {"Ir",  192.217},    {"Pt",  195.084},    {"Au",  196.966569},    {"Hg",  200.592},    {"Tl",  204.38},    {"Pb",  207.2},    {"Bi",  208.98040},    {"Po",  209},    {"At",  210},    {"Rn",  222},    {"Fr",  223},    {"Ra",  226},    {"Ac",  227},    {"Th",  232.0377},    {"Pa",  231.03588},    {"U",   238.02891},    {"Np",  237},    {"Pu",  244},    {"Am",  243},    {"Cm",  247},    {"Bk",  247},    {"Cf",  251},    {"Es",  252},    {"Fm",  257},    {"Uue", 315},    {"Ubn", 299},}; double evaluate(std::string s) {    s += '[';     double sum = 0.0;    std::string symbol;    std::string number;     for (auto c : s) {        if ('@' <= c && c <= '[') {            // @, A-Z            int n = 1;            if (number != "") {                n = stoi(number);            }            if (symbol != "") {                sum += atomicMass[symbol] * n;            }            if (c == '[') {                break;            }            symbol = c;            number = "";        } else if ('a' <= c && c <= 'z') {            symbol += c;        } else if ('0' <= c && c <= '9') {            number += c;        } else {            std::string msg = "Unexpected symbol ";            msg += c;            msg += " in molecule";            throw std::runtime_error(msg);        }    }     return sum;} std::string replaceFirst(const std::string &text, const std::string &search, const std::string &replace) {    auto pos = text.find(search);    if (pos == std::string::npos) {        return text;    }     auto beg = text.substr(0, pos);    auto end = text.substr(pos + search.length());    return beg + replace + end;} std::string replaceParens(std::string s) {    char letter = 'a';    while (true) {        auto start = s.find("(");        if (start == std::string::npos) {            break;        }         for (size_t i = start + 1; i < s.length(); i++) {            if (s[i] == ')') {                auto expr = s.substr(start + 1, i - start - 1);                std::string symbol = "@";                symbol += letter;                auto search = s.substr(start, i + 1 - start);                s = replaceFirst(s, search, symbol);                atomicMass[symbol] = evaluate(expr);                letter++;                break;            }            if (s[i] == '(') {                start = i;                continue;            }        }    }    return s;} int main() {    std::vector<std::string> molecules = {        "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",        "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"    };    for (auto molecule : molecules) {        auto mass = evaluate(replaceParens(molecule));        std::cout << std::setw(17) << molecule << " -> " << std::setw(7) << std::fixed << std::setprecision(3) << mass << '\n';    }     return 0;}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## CoffeeScript

### No Regular Expression

`ATOMIC_MASS = {H:1.008,C:12.011,O:15.999,Na:22.98976928,S:32.06,Uue:315} molar_mass = (s) ->	result = ''	i = 0	member = (a,c) ->  a <= s[i] <= c	next = ->		i += 1		s[i-1]	while i < s.length		if s[i] == '(' then result += '+' + next()		else if s[i] == ')' then result += next()		else if member '0','9'			result += '*' 			result += next() while member '0','9'		else if member 'A','Z'			name = next()			name += next() while member 'a','z'			result += '+' + ATOMIC_MASS[name]	parseFloat eval(result).toFixed 3 assert 1.008, molar_mass 'H'assert 2.016, molar_mass 'H2'assert 18.015, molar_mass 'H2O'assert 34.014, molar_mass 'H2O2'assert 34.014, molar_mass '(HO)2'assert 142.036, molar_mass 'Na2SO4'assert 84.162, molar_mass 'C6H12'assert 186.295, molar_mass 'COOH(C(CH3)2)3CH3'assert 176.124, molar_mass 'C6H4O2(OH)4' # Vitamin Cassert 386.664, molar_mass 'C27H46O' # Cholesterolassert 315, molar_mass 'Uue'`

### Regular Expression

Translation of: Julia
`ATOMIC_MASS = {H:1.008,C:12.011,O:15.999,Na:22.98976928,S:32.06,Uue:315} mul = (match, p1, offset, string) -> '*' + p1 add = (match, p1, offset, string) -> 	if p1 == '(' then return '+' + p1 	"+#{ATOMIC_MASS[p1]}" molar_mass = (s) ->	s = s.replace /(\d+)/g, mul	s = s.replace /([A-Z][a-z]{0,2}|\()/g, add	parseFloat(eval(s).toFixed(3)) assert 1.008, molar_mass('H')assert 2.016, molar_mass('H2')assert 18.015, molar_mass('H2O')assert 34.014, molar_mass('H2O2')assert 34.014, molar_mass('(HO)2')assert 142.036, molar_mass('Na2SO4')assert 84.162, molar_mass('C6H12')assert 186.295, molar_mass('COOH(C(CH3)2)3CH3')assert 176.124, molar_mass('C6H4O2(OH)4') # Vitamin Cassert 386.664, molar_mass('C27H46O') # Cholesterolassert 315, molar_mass('Uue')`

## D

Translation of: Go
`import std.array;import std.conv;import std.format;import std.stdio;import std.string; double[string] atomicMass;static this() {    atomicMass = [        "H":   1.008,        "He":  4.002602,        "Li":  6.94,        "Be":  9.0121831,        "B":   10.81,        "C":   12.011,        "N":   14.007,        "O":   15.999,        "F":   18.998403163,        "Ne":  20.1797,        "Na":  22.98976928,        "Mg":  24.305,        "Al":  26.9815385,        "Si":  28.085,        "P":   30.973761998,        "S":   32.06,        "Cl":  35.45,        "Ar":  39.948,        "K":   39.0983,        "Ca":  40.078,        "Sc":  44.955908,        "Ti":  47.867,        "V":   50.9415,        "Cr":  51.9961,        "Mn":  54.938044,        "Fe":  55.845,        "Co":  58.933194,        "Ni":  58.6934,        "Cu":  63.546,        "Zn":  65.38,        "Ga":  69.723,        "Ge":  72.630,        "As":  74.921595,        "Se":  78.971,        "Br":  79.904,        "Kr":  83.798,        "Rb":  85.4678,        "Sr":  87.62,        "Y":   88.90584,        "Zr":  91.224,        "Nb":  92.90637,        "Mo":  95.95,        "Ru":  101.07,        "Rh":  102.90550,        "Pd":  106.42,        "Ag":  107.8682,        "Cd":  112.414,        "In":  114.818,        "Sn":  118.710,        "Sb":  121.760,        "Te":  127.60,        "I":   126.90447,        "Xe":  131.293,        "Cs":  132.90545196,        "Ba":  137.327,        "La":  138.90547,        "Ce":  140.116,        "Pr":  140.90766,        "Nd":  144.242,        "Pm":  145,        "Sm":  150.36,        "Eu":  151.964,        "Gd":  157.25,        "Tb":  158.92535,        "Dy":  162.500,        "Ho":  164.93033,        "Er":  167.259,        "Tm":  168.93422,        "Yb":  173.054,        "Lu":  174.9668,        "Hf":  178.49,        "Ta":  180.94788,        "W":   183.84,        "Re":  186.207,        "Os":  190.23,        "Ir":  192.217,        "Pt":  195.084,        "Au":  196.966569,        "Hg":  200.592,        "Tl":  204.38,        "Pb":  207.2,        "Bi":  208.98040,        "Po":  209,        "At":  210,        "Rn":  222,        "Fr":  223,        "Ra":  226,        "Ac":  227,        "Th":  232.0377,        "Pa":  231.03588,        "U":   238.02891,        "Np":  237,        "Pu":  244,        "Am":  243,        "Cm":  247,        "Bk":  247,        "Cf":  251,        "Es":  252,        "Fm":  257,        "Uue": 315,        "Ubn": 299,    ];} double evaluate(string s) {    s ~= "["; // add end of string marker    double sum = 0.0;    string symbol, number;    for (int i = 0; i < s.length; ++i) {        auto c = s[i];        if (c >= '@' && c <= '[') {            // @, A-Z, [            int n = 1;            if (number != "") {                n = to!int(number);            }            if (symbol != "") {                sum += atomicMass[symbol] * n;            }            if (c == '[') {                break;            }            symbol = c.to!string;            number = "";        } else if (c >= 'a' && c <= 'z') {            symbol ~= c;        } else if (c >= '0' && c <= '9') {            number ~= c;        } else {            throw new Exception("Unexpected symbol " ~ c ~ " in molecule");        }    }    return sum;} string replaceParens(string s) {    char letter = 'a';    while (true) {        auto start = s.indexOf('(');        if (start == -1) {            break;        }         restart:        for (auto i = start + 1; i < s.length; ++i) {            if (s[i] == ')') {                auto expr = s[start + 1 .. i];                auto symbol = format("@%c", letter);                s = s.replaceFirst(s[start .. i + 1], symbol);                atomicMass[symbol] = evaluate(expr);                letter++;                break;            }            if (s[i] == '(') {                start = i;                continue restart;            }        }    }    return s;} void main() {    auto molecules = [        "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",        "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"    ];    foreach (molecule; molecules) {        auto mass = evaluate(replaceParens(molecule));        writefln("%17s -> %7.3f", molecule, mass);    }    writeln(atomicMass);}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## Delphi

Translation of: Go
` program ChemicalCalculator; {\$APPTYPE CONSOLE} {\$R *.res} uses  System.SysUtils,  System.Generics.Collections; {\$I AtomicMass.inc } type  TAtomicMass = class(TDictionary<string, Double>)  public    constructor Create(Keys: array of string; Values: array of Double); overload;  end; { TAtomicMass } constructor TAtomicMass.Create(Keys: array of string; Values: array of Double);var  i: Integer;begin  inherited Create;   Assert(length(Keys) = Length(Values), 'Keys and values must have the same size');  if Length(Keys) = 0 then    exit;   for i := 0 to High(Keys) do    Add(Keys[i], Values[i]);end; var  AtomicMassData: TAtomicMass; function Evaluate(s: string): Double;var  sum: Double;  symbol: string;  number: string;  c: char;  i, n: Integer;begin  s := s + '[';  symbol := '';  number := '';   for i := 1 to s.Length do  begin    c := s[i];    if ('@' <= c) and (c <= '[') then    begin      n := 1;      if not number.IsEmpty then        n := StrToInt(number);      if not symbol.IsEmpty then        sum := sum + AtomicMassData[symbol] * n;      if c = '[' then        Break;      symbol := c;      number := '';      Continue;    end;     if ('a' <= c) and (c <= 'z') then    begin      symbol := symbol + c;      Continue;    end;     if ('0' <= c) and (c <= '9') then    begin      number := number + c;      Continue;    end;     raise Exception.Create('Unexpected symbol ' + c + ' in molecule');  end;  Result := sum;end; function ReplaceFirst(text, search, replace: string): string;var  pos: Integer;begin  pos := text.IndexOf(search);  if (pos < 0) then    Exit(text);  Result := text.Substring(0, pos) + replace + text.Substring(pos + search.Length);end; function ReplaceParens(s: string): string;var  letter: Char;  start: Integer;  i: Integer;  expr, symbol: string;begin  letter := 's';  while True do  begin    start := s.IndexOf('(');    if (start = -1) then      Break;     for i := start + 1 to s.Length - 1 do    begin      if s[i + 1] = ')' then      begin        expr := s.Substring(start + 1, i - start - 1);        symbol := '@' + letter;        s := ReplaceFirst(s, s.Substring(start, i + 1 - start), symbol);        if not (AtomicMassData.ContainsKey(symbol)) then          AtomicMassData.Add(symbol, Evaluate(expr))        else          AtomicMassData[symbol] := Evaluate(expr);        inc(letter);        Break;      end;       if (s[i + 1] = '(') then        start := i;    end;  end;  Result := s;end;  var  molecules: array of string;  i: Integer;  mass: Double; begin  molecules := ['H', 'H2', 'H2O', 'H2O2', '(HO)2', 'Na2SO4', 'C6H12',    'COOH(C(CH3)2)3CH3', 'C6H4O2(OH)4', 'C27H46O', 'Uue'];  AtomicMassData := TAtomicMass.Create(ATOMIC_MASS_SYMBOL, ATOMIC_MASS_VALUE);   for i := 0 to 10 do  begin    mass := Evaluate(ReplaceParens(molecules[i]));    Writeln(format('%17s -> %7s', [molecules[i], FormatFloat('####.000',mass)]));  end;   AtomicMassData.Free;  readln;end. `

Include file with Atomic Mass Constants (AtomicMass.inc).

` const  ATOMIC_MASS_SIZE = 101;  ATOMIC_MASS_SYMBOL: array[0..ATOMIC_MASS_SIZE - 1] of string = ('H', 'He',    'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S',    'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu',    'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo',    'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba',    'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm',    'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb',    'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am',    'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Uue', 'Ubn');   ATOMIC_MASS_VALUE: array[0..ATOMIC_MASS_SIZE - 1] of double = (1.008, 4.002602,    6.94, 9.0121831, 10.81, 12.011, 14.007, 15.999, 18.998403163, 20.1797,    22.98976928, 24.305, 26.9815385, 28.085, 30.973761998, 32.06, 35.45, 39.948,    39.0983, 40.078, 44.955908, 47.867, 50.9415, 51.9961, 54.938044, 55.845,    58.933194, 58.6934, 63.546, 65.38, 69.723, 72.630, 74.921595, 78.971, 79.904,    83.798, 85.4678, 87.62, 88.90584, 91.224, 92.90637, 95.95, 101.07, 102.90550,    106.42, 107.8682, 112.414, 114.818, 118.710, 121.760, 127.60, 126.90447,    131.293, 132.90545196, 137.327, 138.90547, 140.116, 140.90766, 144.242, 145,    150.36, 151.964, 157.25, 158.92535, 162.500, 164.93033, 167.259, 168.93422,    173.054, 174.9668, 178.49, 180.94788, 183.84, 186.207, 190.23, 192.217,    195.084, 196.966569, 200.592, 204.38, 207.2, 208.98040, 209, 210, 222, 223,    226, 227, 232.0377, 231.03588, 238.02891, 237, 244, 243, 247, 247, 251, 252,    257, 315, 299); `

## Factor

Works with: Factor version 0.98
`USING: assocs compiler.units definitions grouping infix.parserinfix.private kernel math.functions math.parser multilinepeg.ebnf qw sequences splitting strings words words.constant ;IN: rosetta-code.chemical-calculator <<     ! Do the stuff inside << ... >> at parse time. HEREDOC: ENDH  1.008         He 4.002602      Li 6.94Be 9.0121831     B  10.81         C  12.011N  14.007        O  15.999        F  18.998403163Ne 20.1797       Na 22.98976928   Mg 24.305Al 26.9815385    Si 28.085        P  30.973761998S  32.06         Cl 35.45         Ar 39.948K  39.0983       Ca 40.078        Sc 44.955908Ti 47.867        V  50.9415       Cr 51.9961Mn 54.938044     Fe 55.845        Co 58.933194Ni 58.6934       Cu 63.546        Zn 65.38Ga 69.723        Ge 72.630        As 74.921595Se 78.971        Br 79.904        Kr 83.798Rb 85.4678       Sr 87.62         Y  88.90584Zr 91.224        Nb 92.90637      Mo 95.95Ru 101.07        Rh 102.90550     Pd 106.42Ag 107.8682      Cd 112.414       In 114.818Sn 118.710       Sb 121.760       Te 127.60I  126.90447     Xe 131.293       Cs 132.90545196Ba 137.327       La 138.90547     Ce 140.116Pr 140.90766     Nd 144.242       Pm 145Sm 150.36        Eu 151.964       Gd 157.25Tb 158.92535     Dy 162.500       Ho 164.93033Er 167.259       Tm 168.93422     Yb 173.054Lu 174.9668      Hf 178.49        Ta 180.94788W  183.84        Re 186.207       Os 190.23Ir 192.217       Pt 195.084       Au 196.966569Hg 200.592       Tl 204.38        Pb 207.2Bi 208.98040     Po 209           At 210Rn 222           Fr 223           Ra 226Ac 227           Th 232.0377      Pa 231.03588U  238.02891     Np 237           Pu 244Am 243           Cm 247           Bk 247Cf 251           Es 252           Fm 257END ! Make constants from the pairs in the above string." \n" split harvest 2 <groups> [    first2 [        [ "rosetta-code.chemical-calculator" create-word ] dip        string>number define-constant    ] 2curry with-compilation-unit] each >> ! Evaluate a string like "+C+O+O+H+(+C+(+C+H*3)*2)*3+C+H*3"! Note that the infix vocabulary can work with the constants! defined above.: eval-infix ( seq -- n )    build-infix-ast infix-codegen prepare-operand call( -- x ) ; ! A grammar to put a + before every element/left paren and a *! before every number and then evaluate the expression.EBNF: molar-mass [=[  number = [0-9]+ => [[ "" like "*" prepend ]]  elt = [A-Z] [a-z]? [a-z]? => [[ sift "" like "+" prepend ]]  lparen = "(" => [[ "" like "+" prepend ]]  any = . => [[ 1string ]]  mass = (elt|number|lparen|any)+ => [[ concat eval-infix ]]      ]=] ! assert= doesn't work due to floating point weirdness.ERROR: failed-assertion expected +/- got ;: approx-assert= ( x y epsilon -- )    3dup ~ [ 3drop ] [ swap failed-assertion ] if ; : chemical-calculator-demo ( -- )    {        { 1.008 "H" }        { 2.016 "H2" }        { 18.015 "H2O" }        { 142.03553856 "Na2SO4" }        { 84.16200000000001 "C6H12" }        { 186.295 "COOH(C(CH3)2)3CH3" }    } [ molar-mass 1e-5 approx-assert= ] assoc-each ; MAIN: chemical-calculator-demo`

No assertion errors.

## Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text (more info). Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for transportation effects more than visualization and edition.

The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code.

## Go

This doesn't use regular expressions, RPN or eval (which Go doesn't have). It's just a simple molar mass evaluator written from scratch.

`package main import (    "fmt"    "strconv"    "strings") var atomicMass = map[string]float64{    "H":   1.008,    "He":  4.002602,    "Li":  6.94,    "Be":  9.0121831,    "B":   10.81,    "C":   12.011,    "N":   14.007,    "O":   15.999,    "F":   18.998403163,    "Ne":  20.1797,    "Na":  22.98976928,    "Mg":  24.305,    "Al":  26.9815385,    "Si":  28.085,    "P":   30.973761998,    "S":   32.06,    "Cl":  35.45,    "Ar":  39.948,    "K":   39.0983,    "Ca":  40.078,    "Sc":  44.955908,    "Ti":  47.867,    "V":   50.9415,    "Cr":  51.9961,    "Mn":  54.938044,    "Fe":  55.845,    "Co":  58.933194,    "Ni":  58.6934,    "Cu":  63.546,    "Zn":  65.38,    "Ga":  69.723,    "Ge":  72.630,    "As":  74.921595,    "Se":  78.971,    "Br":  79.904,    "Kr":  83.798,    "Rb":  85.4678,    "Sr":  87.62,    "Y":   88.90584,    "Zr":  91.224,    "Nb":  92.90637,    "Mo":  95.95,    "Ru":  101.07,    "Rh":  102.90550,    "Pd":  106.42,    "Ag":  107.8682,    "Cd":  112.414,    "In":  114.818,    "Sn":  118.710,    "Sb":  121.760,    "Te":  127.60,    "I":   126.90447,    "Xe":  131.293,    "Cs":  132.90545196,    "Ba":  137.327,    "La":  138.90547,    "Ce":  140.116,    "Pr":  140.90766,    "Nd":  144.242,    "Pm":  145,    "Sm":  150.36,    "Eu":  151.964,    "Gd":  157.25,    "Tb":  158.92535,    "Dy":  162.500,    "Ho":  164.93033,    "Er":  167.259,    "Tm":  168.93422,    "Yb":  173.054,    "Lu":  174.9668,    "Hf":  178.49,    "Ta":  180.94788,    "W":   183.84,    "Re":  186.207,    "Os":  190.23,    "Ir":  192.217,    "Pt":  195.084,    "Au":  196.966569,    "Hg":  200.592,    "Tl":  204.38,    "Pb":  207.2,    "Bi":  208.98040,    "Po":  209,    "At":  210,    "Rn":  222,    "Fr":  223,    "Ra":  226,    "Ac":  227,    "Th":  232.0377,    "Pa":  231.03588,    "U":   238.02891,    "Np":  237,    "Pu":  244,    "Am":  243,    "Cm":  247,    "Bk":  247,    "Cf":  251,    "Es":  252,    "Fm":  257,    "Uue": 315,    "Ubn": 299,} func replaceParens(s string) string {    var letter byte = 'a'    for {        start := strings.IndexByte(s, '(')        if start == -1 {            break        }    restart:        for i := start + 1; i < len(s); i++ {            if s[i] == ')' {                expr := s[start+1 : i]                symbol := fmt.Sprintf("@%c", letter)                s = strings.Replace(s, s[start:i+1], symbol, 1)                atomicMass[symbol] = evaluate(expr)                letter++                break            }            if s[i] == '(' {                start = i                goto restart            }        }    }    return s} func evaluate(s string) float64 {    s += string('[') // add end of string marker    var symbol, number string    sum := 0.0    for i := 0; i < len(s); i++ {        c := s[i]        switch {        case c >= '@' && c <= '[': // @, A-Z, [            n := 1            if number != "" {                n, _ = strconv.Atoi(number)            }            if symbol != "" {                sum += atomicMass[symbol] * float64(n)            }            if c == '[' {                break            }            symbol = string(c)            number = ""        case c >= 'a' && c <= 'z':            symbol += string(c)        case c >= '0' && c <= '9':            number += string(c)        default:            panic(fmt.Sprintf("Unexpected symbol %c in molecule", c))        }    }    return sum} func main() {    molecules := []string{        "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3",        "C6H4O2(OH)4", "C27H46O", "Uue",    }    for _, molecule := range molecules {        mass := evaluate(replaceParens(molecule))        fmt.Printf("%17s -> %7.3f\n", molecule, mass)    }}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000
```

## Java

Translation of: Kotlin
`import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.regex.Pattern; public class ChemicalCalculator {    private static final Map<String, Double> atomicMass = new HashMap<>();     static {        atomicMass.put("H", 1.008);        atomicMass.put("He", 4.002602);        atomicMass.put("Li", 6.94);        atomicMass.put("Be", 9.0121831);        atomicMass.put("B", 10.81);        atomicMass.put("C", 12.011);        atomicMass.put("N", 14.007);        atomicMass.put("O", 15.999);        atomicMass.put("F", 18.998403163);        atomicMass.put("Ne", 20.1797);        atomicMass.put("Na", 22.98976928);        atomicMass.put("Mg", 24.305);        atomicMass.put("Al", 26.9815385);        atomicMass.put("Si", 28.085);        atomicMass.put("P", 30.973761998);        atomicMass.put("S", 32.06);        atomicMass.put("Cl", 35.45);        atomicMass.put("Ar", 39.948);        atomicMass.put("K", 39.0983);        atomicMass.put("Ca", 40.078);        atomicMass.put("Sc", 44.955908);        atomicMass.put("Ti", 47.867);        atomicMass.put("V", 50.9415);        atomicMass.put("Cr", 51.9961);        atomicMass.put("Mn", 54.938044);        atomicMass.put("Fe", 55.845);        atomicMass.put("Co", 58.933194);        atomicMass.put("Ni", 58.6934);        atomicMass.put("Cu", 63.546);        atomicMass.put("Zn", 65.38);        atomicMass.put("Ga", 69.723);        atomicMass.put("Ge", 72.630);        atomicMass.put("As", 74.921595);        atomicMass.put("Se", 78.971);        atomicMass.put("Br", 79.904);        atomicMass.put("Kr", 83.798);        atomicMass.put("Rb", 85.4678);        atomicMass.put("Sr", 87.62);        atomicMass.put("Y", 88.90584);        atomicMass.put("Zr", 91.224);        atomicMass.put("Nb", 92.90637);        atomicMass.put("Mo", 95.95);        atomicMass.put("Ru", 101.07);        atomicMass.put("Rh", 102.90550);        atomicMass.put("Pd", 106.42);        atomicMass.put("Ag", 107.8682);        atomicMass.put("Cd", 112.414);        atomicMass.put("In", 114.818);        atomicMass.put("Sn", 118.710);        atomicMass.put("Sb", 121.760);        atomicMass.put("Te", 127.60);        atomicMass.put("I", 126.90447);        atomicMass.put("Xe", 131.293);        atomicMass.put("Cs", 132.90545196);        atomicMass.put("Ba", 137.327);        atomicMass.put("La", 138.90547);        atomicMass.put("Ce", 140.116);        atomicMass.put("Pr", 140.90766);        atomicMass.put("Nd", 144.242);        atomicMass.put("Pm", 145.0);        atomicMass.put("Sm", 150.36);        atomicMass.put("Eu", 151.964);        atomicMass.put("Gd", 157.25);        atomicMass.put("Tb", 158.92535);        atomicMass.put("Dy", 162.500);        atomicMass.put("Ho", 164.93033);        atomicMass.put("Er", 167.259);        atomicMass.put("Tm", 168.93422);        atomicMass.put("Yb", 173.054);        atomicMass.put("Lu", 174.9668);        atomicMass.put("Hf", 178.49);        atomicMass.put("Ta", 180.94788);        atomicMass.put("W", 183.84);        atomicMass.put("Re", 186.207);        atomicMass.put("Os", 190.23);        atomicMass.put("Ir", 192.217);        atomicMass.put("Pt", 195.084);        atomicMass.put("Au", 196.966569);        atomicMass.put("Hg", 200.592);        atomicMass.put("Tl", 204.38);        atomicMass.put("Pb", 207.2);        atomicMass.put("Bi", 208.98040);        atomicMass.put("Po", 209.0);        atomicMass.put("At", 210.0);        atomicMass.put("Rn", 222.0);        atomicMass.put("Fr", 223.0);        atomicMass.put("Ra", 226.0);        atomicMass.put("Ac", 227.0);        atomicMass.put("Th", 232.0377);        atomicMass.put("Pa", 231.03588);        atomicMass.put("U", 238.02891);        atomicMass.put("Np", 237.0);        atomicMass.put("Pu", 244.0);        atomicMass.put("Am", 243.0);        atomicMass.put("Cm", 247.0);        atomicMass.put("Bk", 247.0);        atomicMass.put("Cf", 251.0);        atomicMass.put("Es", 252.0);        atomicMass.put("Fm", 257.0);        atomicMass.put("Uue", 315.0);        atomicMass.put("Ubn", 299.0);    }     private static double evaluate(String s) {        String sym = s + "[";        double sum = 0.0;        StringBuilder symbol = new StringBuilder();        String number = "";        for (int i = 0; i < sym.length(); ++i) {            char c = sym.charAt(i);            if ('@' <= c && c <= '[') {                // @, A-Z, [                int n = 1;                if (!number.isEmpty()) {                    n = Integer.parseInt(number);                }                if (symbol.length() > 0) {                    sum += atomicMass.getOrDefault(symbol.toString(), 0.0) * n;                }                if (c == '[') {                    break;                }                symbol = new StringBuilder(String.valueOf(c));                number = "";            } else if ('a' <= c && c <= 'z') {                symbol.append(c);            } else if ('0' <= c && c <= '9') {                number += c;            } else {                throw new RuntimeException("Unexpected symbol " + c + " in molecule");            }        }        return sum;    }     private static String replaceParens(String s) {        char letter = 'a';        String si = s;        while (true) {            int start = si.indexOf('(');            if (start == -1) {                break;            }             for (int i = start + 1; i < si.length(); ++i) {                if (si.charAt(i) == ')') {                    String expr = si.substring(start + 1, i);                    String symbol = "@" + letter;                    String pattern = Pattern.quote(si.substring(start, i + 1));                    si = si.replaceFirst(pattern, symbol);                    atomicMass.put(symbol, evaluate(expr));                    letter++;                    break;                }                if (si.charAt(i) == '(') {                    start = i;                }            }        }        return si;    }     public static void main(String[] args) {        List<String> molecules = List.of(            "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",            "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"        );        for (String molecule : molecules) {            double mass = evaluate(replaceParens(molecule));            System.out.printf("%17s -> %7.3f\n", molecule, mass);        }    }}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## Julia

Note that Julia's 64-bit floating point gets a slightly different result for one of the assertions, hence a small change in the last example. The function uses Julia's own language parser to evaluate the compound as an arithmetic expression.

`const H = 1.008const He = 4.002602const Li = 6.94const Be = 9.0121831const B =  10.81const C =  12.011const N =  14.007const O =  15.999const F =  18.998403163const Ne = 20.1797const Na = 22.98976928const Mg = 24.305const Al = 26.9815385const Si = 28.085const P =  30.973761998const S =  32.06const Cl = 35.45const Ar = 39.948const K =  39.0983const Ca = 40.078const Sc = 44.955908const Ti = 47.867const V =  50.9415const Cr = 51.9961const Mn = 54.938044const Fe = 55.845const Co = 58.933194const Ni = 58.6934const Cu = 63.546const Zn = 65.38const Ga = 69.723const Ge = 72.630const As = 74.921595const Se = 78.971const Br = 79.904const Kr = 83.798const Rb = 85.4678const Sr = 87.62const Y =  88.90584const Zr = 91.224const Nb = 92.90637const Mo = 95.95const Ru = 101.07const Rh = 102.90550const Pd = 106.42const Ag = 107.8682const Cd = 112.414const In = 114.818const Sn = 118.710const Sb = 121.760const Te = 127.60const I =  126.90447const Xe = 131.293const Cs = 132.90545196const Ba = 137.327const La = 138.90547const Ce = 140.116const Pr = 140.90766const Nd = 144.242const Pm = 145const Sm = 150.36const Eu = 151.964const Gd = 157.25const Tb = 158.92535const Dy = 162.500const Ho = 164.93033const Er = 167.259const Tm = 168.93422const Yb = 173.054const Lu = 174.9668const Hf = 178.49const Ta = 180.94788const W =  183.84const Re = 186.207const Os = 190.23const Ir = 192.217const Pt = 195.084const Au = 196.966569const Hg = 200.592const Tl = 204.38const Pb = 207.2const Bi = 208.98040const Po = 209const At = 210const Rn = 222const Fr = 223const Ra = 226const Ac = 227const Th = 232.0377const Pa = 231.03588const U =  238.02891const Np = 237const Pu = 244const Am = 243const Cm = 247const Bk = 247const Cf = 251const Es = 252const Fm = 257  function molar_mass(s)    s = replace(s, r"\d+" => (x) -> "*" * x)    s = replace(s, r"[A-Z][a-z]{0,2}|\(" => (x) ->"+" * x)    eval(Meta.parse(s))end @assert 1.008 == molar_mass("H")@assert 2.016 == molar_mass("H2")@assert 18.015 == molar_mass("H2O")@assert 142.03553856000002 == molar_mass("Na2SO4")@assert 84.162 == molar_mass("C6H12")@assert 186.29500000000002 == molar_mass("COOH(C(CH3)2)3CH3") `

No assertion errors.

## Kotlin

Translation of: D
`var atomicMass = mutableMapOf(    "H" to 1.008,    "He" to 4.002602,    "Li" to 6.94,    "Be" to 9.0121831,    "B" to 10.81,    "C" to 12.011,    "N" to 14.007,    "O" to 15.999,    "F" to 18.998403163,    "Ne" to 20.1797,    "Na" to 22.98976928,    "Mg" to 24.305,    "Al" to 26.9815385,    "Si" to 28.085,    "P" to 30.973761998,    "S" to 32.06,    "Cl" to 35.45,    "Ar" to 39.948,    "K" to 39.0983,    "Ca" to 40.078,    "Sc" to 44.955908,    "Ti" to 47.867,    "V" to 50.9415,    "Cr" to 51.9961,    "Mn" to 54.938044,    "Fe" to 55.845,    "Co" to 58.933194,    "Ni" to 58.6934,    "Cu" to 63.546,    "Zn" to 65.38,    "Ga" to 69.723,    "Ge" to 72.630,    "As" to 74.921595,    "Se" to 78.971,    "Br" to 79.904,    "Kr" to 83.798,    "Rb" to 85.4678,    "Sr" to 87.62,    "Y" to 88.90584,    "Zr" to 91.224,    "Nb" to 92.90637,    "Mo" to 95.95,    "Ru" to 101.07,    "Rh" to 102.90550,    "Pd" to 106.42,    "Ag" to 107.8682,    "Cd" to 112.414,    "In" to 114.818,    "Sn" to 118.710,    "Sb" to 121.760,    "Te" to 127.60,    "I" to 126.90447,    "Xe" to 131.293,    "Cs" to 132.90545196,    "Ba" to 137.327,    "La" to 138.90547,    "Ce" to 140.116,    "Pr" to 140.90766,    "Nd" to 144.242,    "Pm" to 145.0,    "Sm" to 150.36,    "Eu" to 151.964,    "Gd" to 157.25,    "Tb" to 158.92535,    "Dy" to 162.500,    "Ho" to 164.93033,    "Er" to 167.259,    "Tm" to 168.93422,    "Yb" to 173.054,    "Lu" to 174.9668,    "Hf" to 178.49,    "Ta" to 180.94788,    "W" to 183.84,    "Re" to 186.207,    "Os" to 190.23,    "Ir" to 192.217,    "Pt" to 195.084,    "Au" to 196.966569,    "Hg" to 200.592,    "Tl" to 204.38,    "Pb" to 207.2,    "Bi" to 208.98040,    "Po" to 209.0,    "At" to 210.0,    "Rn" to 222.0,    "Fr" to 223.0,    "Ra" to 226.0,    "Ac" to 227.0,    "Th" to 232.0377,    "Pa" to 231.03588,    "U" to 238.02891,    "Np" to 237.0,    "Pu" to 244.0,    "Am" to 243.0,    "Cm" to 247.0,    "Bk" to 247.0,    "Cf" to 251.0,    "Es" to 252.0,    "Fm" to 257.0,    "Uue" to 315.0,    "Ubn" to 299.0) fun evaluate(s: String): Double {    val sym = "\$s["    var sum = 0.0    var symbol = ""    var number = ""    for (i in 0 until sym.length) {        val c = sym[i]        if (c in '@'..'[') {            // @, A-Z, [            var n = 1            if (number != "") {                n = Integer.parseInt(number)            }            if (symbol != "") {                sum += atomicMass.getOrElse(symbol) { 0.0 } * n            }            if (c == '[') {                break            }            symbol = c.toString()            number = ""        } else if (c in 'a'..'z') {            symbol += c        } else if (c in '0'..'9') {            number += c        } else {            throw RuntimeException("Unexpected symbol \$c in molecule")        }    }    return sum} fun replaceParens(s: String): String {    var letter = 'a'    var si = s    while (true) {        var start = si.indexOf('(')        if (start == -1) {            break        }         for (i in start + 1 until si.length) {            if (si[i] == ')') {                val expr = si.substring(start + 1 until i)                val symbol = "@\$letter"                si = si.replaceFirst(si.substring(start until i + 1), symbol)                atomicMass[symbol] = evaluate(expr)                letter++                break            }            if (si[i] == '(') {                start = i                continue            }        }    }    return si} fun main() {    val molecules = listOf(        "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",        "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"    )    for (molecule in molecules) {        val mass = evaluate(replaceParens(molecule))        val moleStr = "%17s".format(molecule)        val massStr = "%7.3f".format(mass)        println("\$moleStr -> \$massStr")    }}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## Nim

• Nim lacks runtime eval, that's the reason for so much code. (And me being a sloppy programmer)
• Also, seqs can't contain mixed types.
`#? replace(sub = "\t", by = "  ") import tables, strutils, sequtils, math let ATOMIC_MASS = {"H":1.008, "C":12.011, "O":15.999, "Na":22.98976928, "S":32.06, "Uue":315.0}.toTable proc pass1(s:string): seq[string] = # "H2O" => @["H","*","2","+","O"]	result.add "0"	var i = 0	proc member(a:char,c:char): bool = i < s.len and a <= s[i] and s[i] <= c	proc next(): char = 		i += 1		s[i-1]	while i < s.len:		if s[i] == '(':				result = result.concat @["+","("]			discard next()		elif s[i] == ')': result.add \$next()		elif member('0','9'):			var number = ""			result.add "*" 			while member('0','9'): number &= \$next() 			result.add number		elif member('A','Z'):			if i>0 and s[i-1] != '(': result.add "+"			var name = ""			name.add next()			while member('a','z'): name.add next() 			result.add name proc pass2(s:string): seq[string] = # "H2O" => @["H", "2", "*", "O", "+"]	let ops = "+*" 	var tokens = pass1 s	var stack: seq[string]	var op: string 	for token in tokens:		case token		of "(": stack.add token		of ")":			while stack.len > 0:				op = stack.pop()				if op == "(": break				result.add op		else:			if token in ops:				while stack.len > 0:					op = stack[^1]					if not (op in ops): break					if ops.find(token) >= ops.find(op): break					discard stack.pop()					result.add op				stack.add token			else: result.add token 	while stack.len > 0: result.add stack.pop() proc pass3(s:string): Table[string,int] = # "H2O" => { H:2, O:1 }	let rpn: seq[string] = pass2 s	var stack: seq[Table[string,int]] = @[]	for item in rpn:		if item == "+":			let h1:Table[string,int] = stack.pop()			let h2:Table[string,int] = stack.pop()			var res: Table[string,int] = initTable[string,int]()			for key in h1.keys:				if key != "factor":					res[key] = h1[key]			for key in h2.keys:				if key != "factor":					if h1.haskey key:						res[key] = h1[key] + h2[key]					else:						res[key] = h2[key]			stack.add res		elif item == "*":			let top: Table[string,int] = stack.pop() # 			let hash: Table[string,int] = stack.pop()			let factor: int = top["factor"]			var res: Table[string,int] = initTable[string,int]()			for key in hash.keys:				let str : string = key 				let value: int = hash[key]				res[key] = value * factor 			stack.add res		elif ATOMIC_MASS.haskey(item):			let res : Table[string,int] = {item: 1}.toTable			stack.add res		else: # number			let factor : int = parseInt item			let res : Table[string,int] = {"factor": factor}.toTable			stack.add res	return stack.pop() proc pass4(s: string) : float = # "H2O" => 18.015	let atoms: Table[string,int] = pass3 s	for key in atoms.keys:		let count : int = atoms[key]		result += float(count) * ATOMIC_MASS[key] 	round result,3 let molar_mass = pass4 assert 18.015 == molar_mass "H2O"assert 34.014 == molar_mass "H2O2"assert 34.014 == molar_mass "(HO)2"assert 142.036 == molar_mass "Na2SO4"assert 84.162 == molar_mass "C6H12"assert 186.295 == molar_mass "COOH(C(CH3)2)3CH3"assert 176.124 == molar_mass "C6H4O2(OH)4" # Vitamin Cassert 386.664 == molar_mass "C27H46O" # Cholesterolassert 315 == molar_mass "Uue"`

## Perl

### Grammar

`use strict;use warnings;use List::Util;use Parse::RecDescent; my \$g = Parse::RecDescent->new(<<'EOG');  {     my %atomic_weight = <H 1.008 C 12.011 O 15.999 Na 22.99 S 32.06>  }   weight   : compound         { \$item[1] }  compound : group(s)         { List::Util::sum( @{\$item[1]} ) }  group    : element /\d+/    { \$item[1] * \$item[2] }           | element          { \$item[1] }  element  : /[A-Z][a-z]*/    { \$atomic_weight{ \$item[1] } }           | "(" compound ")" { \$item[2] }EOG for (<H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3>) {    printf "%7.3f %s\n", \$g->weight(\$_), \$_}`

### Regular Expression

`use strict;use warnings;my %atomic_weight = < H 1.008 C 12.011 O 15.999 Na 22.99 S 32.06 >; sub molar_mass {    my(\$mf) = @_;    my(%count,\$mass);    my \$mf_orig = \$mf;    my \$mf_std;     # expand repeated groups    \$mf =~ s/(.*)\((.*?)\)(\d*)/\$1 . \$2 x (\$3 ? \$3 : 1) /e while \$mf =~ m/\(/;     # totals for each atom type    \$mf =~ s/([A-Z][a-z]{0,2})(\d*)/ \$count{\$1} += \$2 ? \$2 : 1/eg;     # calculate molar mass and display, along with standardized MF and original MF    \$mass += \$count{\$_}*\$atomic_weight{"\$_"} for sort keys %count;    \$mf_std .= 'C' . \$count{C} if \$count{C};    \$mf_std .= 'H' . \$count{H} if \$count{H};    \$mf_std .= \$_  . \$count{\$_} for grep { \$_ ne 'C' and \$_ ne 'H' } sort keys %count;    \$mf     .= \$count{\$_} * \$atomic_weight{\$_} for sort keys %count;    printf "%7.3f %-9s %s\n", \$mass, \$mf_std, \$mf_orig;} molar_mass(\$_) for <H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3>`
Output:
```  1.008 H1        H
2.016 H2        H2
18.015 H2O1      H2O
142.036 Na2O4S1   Na2SO4
84.162 C6H12     C6H12
186.295 C11H22O2  COOH(C(CH3)2)3CH3```

## Phix

A simple hand-written single-pass formula parser and evaluator in one.
Note the use of string comparison for error checking rather than floats direct, always much safer in general.
Also note that initially it all worked absolutely fine with the default precision (ie "%g" instead of "%.12g"), and that the higher precision expected value for Na2SO4 also works just fine at both printing precisions.

`constant elements = new_dict() -- (eg "H" -> 1.008) function multiplier(string formula, integer fdx)-- check for a trailing number, or return 1    integer n = 1    if fdx<=length(formula) then        integer ch = formula[fdx]        if ch>='1' and ch<='9' then            n = ch-'0'            fdx += 1            while fdx<=length(formula) do                ch = formula[fdx]                if ch<'0' or ch>'9' then exit end if                n = n*10 + ch-'0'                fdx += 1            end while        end if    end if    return {n,fdx}end function procedure molar_mass(string formula, name, atom expected)    sequence stack = {0} -- (for parenthesis handling)    integer sdx = 1, fdx = 1, n    while fdx<=length(formula) do        integer ch = formula[fdx]        if ch>='A' and ch<='Z' then            -- All elements start with capital, rest lower            integer fend = fdx            while fend<length(formula) do                ch = formula[fend+1]                if ch<'a' or ch>'z' then exit end if                fend += 1            end while            string element = formula[fdx..fend]            atom mass = getd(element,elements)            if mass=0 then ?9/0 end if -- missing?            {n,fdx} = multiplier(formula,fend+1)            stack[sdx] += n*mass        elsif ch='(' then            sdx += 1            stack &= 0            fdx += 1        elsif ch=')' then            {n,fdx} = multiplier(formula,fdx+1)            sdx -= 1            stack[sdx] += stack[\$]*n            stack = stack[1..sdx]        else            ?9/0    -- unknown?        end if    end while    if sdx!=1 then ?9/0 end if -- unbalanced brackets?    if name!="" then formula &= " ("&name&")" end if--  string res = sprintf("%g",stack[1]),    -- (still fine)--         e = sprintf("%g",expected)       --     """    string res = sprintf("%.12g",stack[1]),           e = sprintf("%.12g",expected)    if res!=e then res &= " *** ERROR: expected "&e end if    printf(1,"%26s = %s\n",{formula,res})end procedure -- (following clipped for brevity, works fine with whole table from task description pasted in)constant etext = split("""H,1.008C,12.011O,15.999Na,22.98976928S,32.06Cl,35.45Uue,315""","\n")for i=1 to length(etext) do    {{string element,atom mass}} = scanf(etext[i],"%s,%f")    setd(element,mass,elements)end formolar_mass("H","Hydrogen",1.008)molar_mass("H2","Hydrogen gas",2.016)molar_mass("H2O","Water",18.015)molar_mass("H2O2","Hydrogen peroxide",34.014)molar_mass("(HO)2","Hydrogen peroxide",34.014)--molar_mass("Na2SO4","Sodium sulfate",142.036) -- (fine for "%g")molar_mass("Na2SO4","Sodium sulfate",142.03553856)  --   """molar_mass("C6H12","Cyclohexane",84.162)molar_mass("COOH(C(CH3)2)3CH3","",186.295) molar_mass("C6H4O2(OH)4","Vitamin C",176.124)molar_mass("C27H46O","Cholesterol",386.664)molar_mass("Uue","Ununennium",315)molar_mass("UueCl","",350.45)`
Output:
```              H (Hydrogen) = 1.008
H2 (Hydrogen gas) = 2.016
H2O (Water) = 18.015
H2O2 (Hydrogen peroxide) = 34.014
(HO)2 (Hydrogen peroxide) = 34.014
Na2SO4 (Sodium sulfate) = 142.03553856
C6H12 (Cyclohexane) = 84.162
COOH(C(CH3)2)3CH3 = 186.295
C6H4O2(OH)4 (Vitamin C) = 176.124
C27H46O (Cholesterol) = 386.664
Uue (Ununennium) = 315
UueCl = 350.45
```

## Python

Translation of: Julia
`import re ATOMIC_MASS = {"H":1.008, "C":12.011, "O":15.999, "Na":22.98976928, "S":32.06, "Uue":315} mul = lambda x : '*' + x.group(0)def add(x) :    name = x.group(0)    return '+' + name if name == '(' else '+' + str(ATOMIC_MASS[name]) def molar_mass(s):    nazwa = s    s = re.sub(r"\d+", mul, s)    s = re.sub(r"[A-Z][a-z]{0,2}|\(", add, s)    return print("Atomic mass {:17s} {} {:7.3f}".format(nazwa,'\t',round(eval(s),3)))  `
Output:
```Atomic mass H                 	   1.008
Atomic mass H2                	   2.016
Atomic mass H2O               	  18.015
Atomic mass H2O2              	  34.014
Atomic mass (HO)2             	  34.014
Atomic mass Na2SO4            	 142.036
Atomic mass C6H12             	  84.162
Atomic mass COOH(C(CH3)2)3CH3 	 186.295
Atomic mass C6H4O2(OH)4       	 176.124
Atomic mass C27H46O           	 386.664
Atomic mass Uue               	 315.000```

## Racket

`#lang racket (define table '([H 1.008]                [C 12.011]                [O 15.999]                [Na 22.98976928]                [S 32.06]                [Uue 315.0])) (define (lookup s) (first (dict-ref table s))) (define (calc s)  (define toks    (with-input-from-string (regexp-replaces s '([#px"(\\d+)" " \\1"]                                                 [#px"([A-Z])" " \\1"]))      (thunk (sequence->list (in-port)))))   (let loop ([toks toks])    (match toks      ['() 0]      [(list (? list? sub) (? number? n) toks ...) (+ (* (loop sub) n) (loop toks))]      [(list (? list? sub) toks ...) (+ (loop sub) (loop toks))]      [(list sym (? number? n) toks ...) (+ (* (lookup sym) n) (loop toks))]      [(list sym toks ...) (+ (lookup sym) (loop toks))]))) (define tests '("H"                "H2"                "H2O"                "H2O2"                "(HO)2"                "Na2SO4"                "C6H12"                "COOH(C(CH3)2)3CH3"                "C6H4O2(OH)4"                "C27H46O"                "Uue")) (for ([test (in-list tests)])  (printf "~a: ~a\n"          (~a test #:align 'right #:min-width 20)          (~r (calc test) #:precision 3)))`
Output:
```                   H: 1.008
H2: 2.016
H2O: 18.015
H2O2: 34.014
(HO)2: 34.014
Na2SO4: 142.036
C6H12: 84.162
COOH(C(CH3)2)3CH3: 186.295
C6H4O2(OH)4: 176.124
C27H46O: 386.664
Uue: 315
```

## Raku

(formerly Perl 6)

`my %ATOMIC_MASS =    H  =>   1.008       , Fe =>  55.845    , Te => 127.60       , Ir => 192.217    ,    He =>   4.002602    , Co =>  58.933194 , I  => 126.90447    , Pt => 195.084    ,    Li =>   6.94        , Ni =>  58.6934   , Xe => 131.293      , Au => 196.966569 ,    Be =>   9.0121831   , Cu =>  63.546    , Cs => 132.90545196 , Hg => 200.592    ,    B  =>  10.81        , Zn =>  65.38     , Ba => 137.327      , Tl => 204.38     ,    C  =>  12.011       , Ga =>  69.723    , La => 138.90547    , Pb => 207.2      ,    N  =>  14.007       , Ge =>  72.630    , Ce => 140.116      , Bi => 208.98040  ,    O  =>  15.999       , As =>  74.921595 , Pr => 140.90766    , Po => 209        ,    F  =>  18.998403163 , Se =>  78.971    , Nd => 144.242      , At => 210        ,    Ne =>  20.1797      , Br =>  79.904    , Pm => 145          , Rn => 222        ,    Na =>  22.98976928  , Kr =>  83.798    , Sm => 150.36       , Fr => 223        ,    Mg =>  24.305       , Rb =>  85.4678   , Eu => 151.964      , Ra => 226        ,    Al =>  26.9815385   , Sr =>  87.62     , Gd => 157.25       , Ac => 227        ,    Si =>  28.085       , Y  =>  88.90584  , Tb => 158.92535    , Th => 232.0377   ,    P  =>  30.973761998 , Zr =>  91.224    , Dy => 162.500      , Pa => 231.03588  ,    S  =>  32.06        , Nb =>  92.90637  , Ho => 164.93033    , U  => 238.02891  ,    Cl =>  35.45        , Mo =>  95.95     , Er => 167.259      , Np => 237        ,    Ar =>  39.948       , Ru => 101.07     , Tm => 168.93422    , Pu => 244        ,    K  =>  39.0983      , Rh => 102.90550  , Yb => 173.054      , Am => 243        ,    Ca =>  40.078       , Pd => 106.42     , Lu => 174.9668     , Cm => 247        ,    Sc =>  44.955908    , Ag => 107.8682   , Hf => 178.49       , Bk => 247        ,    Ti =>  47.867       , Cd => 112.414    , Ta => 180.94788    , Cf => 251        ,    V  =>  50.9415      , In => 114.818    , W  => 183.84       , Es => 252        ,    Cr =>  51.9961      , Sn => 118.710    , Re => 186.207      , Fm => 257        ,    Mn =>  54.938044    , Sb => 121.760    , Os => 190.23       ,;grammar Chemical_formula {    my @ATOMIC_SYMBOLS = %ATOMIC_MASS.keys.sort;     rule  TOP      { ^ (<lparen>|<rparen>|<element>)+ \$ }    token quantity { \d+ }    token lparen   { '(' }    token rparen   { ')'                    <quantity>? }    token element  { \$<e>=[@ATOMIC_SYMBOLS] <quantity>? }}class Chemical_formula_actions {    has @stack = 0;    method TOP     (\$/) { \$/.make: @stack }    method lparen  (\$/) { push @stack, 0  }    method rparen  (\$/) { my \$m = @stack.pop;                          @stack[*-1] += (\$<quantity> // 1) * \$m }    method element (\$/) { @stack[*-1] += (\$<quantity> // 1) * %ATOMIC_MASS{~\$<e>} }}sub molar_mass ( Str \$formula --> Real ) {    Chemical_formula.parse( \$formula, :actions(Chemical_formula_actions.new) )        orelse die "Chemical formula not recognized: '\$formula'";    return \$/.made.[0];}say .&molar_mass.fmt('%7.3f '), \$_ for <H H2 H2O Na2SO4 C6H12 COOH(C(CH3)2)3CH3>;`
Output:
```  1.008 H
2.016 H2
18.015 H2O
142.036 Na2SO4
84.162 C6H12
186.295 COOH(C(CH3)2)3CH3```

## REXX

This REXX version has some basic error checking to catch malformed chemical formulas.

Also a more precise atomic mass for the (all) known elements is used   (for instance, F).

Some of the elements added for the REXX example are:

```   mendelevium (Md), nobelium (No), lawrencium (Lr), rutherfordium (Rf), dubnium (Db),
seaborgium  (Sg), bohrium (Bh),  hassium (Hs), meitnerium (Mt),  darmstadtium (Ds),
roentgenium (Rg), copernicium (Cn), nihoniym (Nh), flerovium (Fl),  moscovium (Mc),
livermorium (Lv), tennessine (Ts),  and  oganesson (Og)
```
`/*REXX program  calculates the   molar mass   from a specified chemical formula.        */numeric digits 30                                /*ensure enough decimal digits for mass*//*─────────── [↓]  table of known elements (+2 more) with their atomic mass ────────────*/@.=             ;  @.Co= 58.933195 ;  @.H =  1.00794   ;  @.Np=237       ;  @.Se= 78.96                   @.Cr= 51.9961   ;  @.In=114.818     ;  @.N = 14.0067  ;  @.Sg=266@.Ac=227        ;  @.Cs=132.9054519;  @.Ir=192.217     ;  @.Og=294       ;  @.Si= 28.0855@.Ag=107.8682   ;  @.Cu= 63.546    ;  @.I =126.904     ;  @.Os=190.23    ;  @.Sm=150.36@.Al= 26.9815386;  @.C = 12.0107   ;  @.Kr= 83.798     ;  @.O = 15.9994  ;  @.Sn=118.710@.Am=243        ;  @.Db=262        ;  @.K = 39.0983    ;  @.Pa=231.03588 ;  @.Sr= 87.62@.Ar= 39.948    ;  @.Ds=271        ;  @.La=138.90547   ;  @.Pb=207.2     ;  @.S = 32.065@.As= 74.92160  ;  @.Dy=162.500    ;  @.Li=  6.941     ;  @.Pd=106.42    ;  @.Ta=180.94788@.At=210        ;  @.Er=167.259    ;  @.Lr=262         ;  @.Pm=145       ;  @.Tb=158.92535@.Au=196.966569 ;  @.Es=252        ;  @.Lu=174.967     ;  @.Po=210       ;  @.Tc= 98@.Ba=137.327    ;  @.Eu=151.964    ;  @.Lv=292         ;  @.Pr=140.90765 ;  @.Te=127.60@.Be=  9.012182 ;  @.Fe= 55.845    ;  @.Mc=288         ;  @.Pt=195.084   ;  @.Th=232.03806@.Bh=264        ;  @.Fl=289        ;  @.Md=258         ;  @.Pu=244       ;  @.Ti= 47.867@.Bi=208.98040  ;  @.Fm=257        ;  @.Mg= 24.3050    ;  @.P = 30.973762;  @.Tl=204.3833@.Bk=247        ;  @.Fr=223        ;  @.Mn= 54.938045  ;  @.Ra=226       ;  @.Tm=168.93421@.Br= 79.904    ;  @.F = 18.9984032;  @.Mo= 95.94      ;  @.Rb= 85.4678  ;  @.Ts=293@.B = 10.811    ;  @.Ga= 69.723    ;  @.Mt=268         ;  @.Re=186.207   ;  @.U =238.02891@.Ca= 40.078    ;  @.Gd=157.25     ;  @.Na= 22.98976928;  @.Rf=261       ;  @.V = 50.9415@.Cd=112.411    ;  @.Ge= 72.64     ;  @.Nb= 92.906     ;  @.Rg=272       ;  @.W =183.84@.Ce=140.116    ;  @.He=  4.002602 ;  @.Nd=144.242     ;  @.Rh=102.905   ;  @.Xe=131.293@.Cf=251        ;  @.Hf=178.49     ;  @.Ne= 20.1797    ;  @.Rn=220       ;  @.Yb=173.04@.Cl= 35.453    ;  @.Hg=200.59     ;  @.Nh=284         ;  @.Ru=101.07    ;  @.Y = 88.90585@.Cm=247        ;  @.Ho=164.930    ;  @.Ni= 58.6934    ;  @.Sb=121.760   ;  @.Zn= 65.409@.Cn=285        ;  @.Hs=277        ;  @.No=259         ;  @.Sc= 44.955912;  @.Zr= 91.224                                                          @.Ubn=299      ;  @.Uue=315parse arg \$if \$='' | \$=","  then \$= ' H    H2    H2O    H2O2    (HO)2    Na2SO4    C6H12 ' ,                                 " COOH(C(CH3)2)3CH3    C6H4O2(OH)4     C27H46O     Uue"  do j=1  for words(\$);   x= word(\$, j)          /*obtain the formula of the molecule.  */  mm= chemCalc(x)                                /*get the molar mass  "  "      "      */  if mm<0  then iterate                          /*if function had an error, skip output*/  say right('molar mass of ' x, 50)  " is"   mm  /*display the molar mass of a chemical.*/  end   /*j*/exit                                             /*stick a fork in it,  we're all done. *//*──────────────────────────────────────────────────────────────────────────────────────*/chemCalc: procedure expose @.; parse arg z       /*obtain chemical formula of molecule. */          lev= 0                                 /*indicates level of parentheses depth.*/          \$.= 0                                  /*the sum of the molar mass  (so far). */               do k=1  to  length(z);              y= substr(z, k, 1)      /*get a thing*/               if y=='('  then do;  lev= lev + 1;  iterate k;  end               if y==')'  then do;  y= substr(z, k+1, 1)                                    if \datatype(y, 'W')  then do; say "illegal number:" y                                                                   return -1                                                               end                                    n= getNum()                            /*get number.*/                                    \$.lev= \$.lev * n;  \$\$= \$.lev; \$.lev= 0 /*sum level. */                                    lev= lev - 1;      \$.lev= \$.lev + \$\$   /*add to prev*/                                    k= k + length(n)                       /*adjust  K. */                                    iterate   /*k*/                               end                                         /*[↑] get ele*/               e=y;   e= getEle();                     upper e             /* and upper.*/               if   e==.  then do;  say 'missing element: '  e;   return -2;    end               if @.e==.  then do;  say 'invalid element: '  e;   return -3;    end               y= substr(z, k+length(e), 1)               k= k + length(e) - 1                                        /*adjust  K. */               n= getNum()                                                 /*get number.*/               if n\==.  then k= k + length(n)                             /*adjust  K. */                         else n= 1                                         /*no number. */               \$.lev= \$.lev   +   n * @.e                                  /*add product*/               end   /*k*/          return format(\$.lev, max(4, pos(., \$.lev) ) )                    /*align the #*//*──────────────────────────────────────────────────────────────────────────────────────*/getEle:   if \datatype(y, 'U')  then do;  say err "illegal element: "   y;  return .;  end                         do i=1  until \datatype(q, 'L');  q= substr(z, k+i, 1)                         if datatype(q, 'L')  then e= e || q               /*lowercase? */                         end   /*i*/;                         return e/*──────────────────────────────────────────────────────────────────────────────────────*/getNum:   if \datatype(y, 'W')  then return .;             n=                         do i=1  until \datatype(q, 'W');  q= substr(z, k+i, 1)                         if datatype(q, 'W')  then n= n || q               /*is a digit?*/                         end   /*i*/;                         return n`
output   when using the default inputs:
```                                  molar mass of  H  is    1.00794
molar mass of  H2  is    2.01588
molar mass of  H2O  is   18.01528
molar mass of  H2O2  is   34.01468
molar mass of  (HO)2  is   34.01468
molar mass of  Na2SO4  is  142.04213856
molar mass of  C6H12  is   84.15948
molar mass of  COOH(C(CH3)2)3CH3  is  186.29118
molar mass of  C6H4O2(OH)4  is  176.12412
molar mass of  C27H46O  is  386.65354
molar mass of  Uue  is  315
```

## Ruby

Translation of: D
`\$atomicMass = {    "H"   =>  1.008,    "He"  =>  4.002602,    "Li"  =>  6.94,    "Be"  =>  9.0121831,    "B"   =>  10.81,    "C"   =>  12.011,    "N"   =>  14.007,    "O"   =>  15.999,    "F"   =>  18.998403163,    "Ne"  =>  20.1797,    "Na"  =>  22.98976928,    "Mg"  =>  24.305,    "Al"  =>  26.9815385,    "Si"  =>  28.085,    "P"   =>  30.973761998,    "S"   =>  32.06,    "Cl"  =>  35.45,    "Ar"  =>  39.948,    "K"   =>  39.0983,    "Ca"  =>  40.078,    "Sc"  =>  44.955908,    "Ti"  =>  47.867,    "V"   =>  50.9415,    "Cr"  =>  51.9961,    "Mn"  =>  54.938044,    "Fe"  =>  55.845,    "Co"  =>  58.933194,    "Ni"  =>  58.6934,    "Cu"  =>  63.546,    "Zn"  =>  65.38,    "Ga"  =>  69.723,    "Ge"  =>  72.630,    "As"  =>  74.921595,    "Se"  =>  78.971,    "Br"  =>  79.904,    "Kr"  =>  83.798,    "Rb"  =>  85.4678,    "Sr"  =>  87.62,    "Y"   =>  88.90584,    "Zr"  =>  91.224,    "Nb"  =>  92.90637,    "Mo"  =>  95.95,    "Ru"  =>  101.07,    "Rh"  =>  102.90550,    "Pd"  =>  106.42,    "Ag"  =>  107.8682,    "Cd"  =>  112.414,    "In"  =>  114.818,    "Sn"  =>  118.710,    "Sb"  =>  121.760,    "Te"  =>  127.60,    "I"   =>  126.90447,    "Xe"  =>  131.293,    "Cs"  =>  132.90545196,    "Ba"  =>  137.327,    "La"  =>  138.90547,    "Ce"  =>  140.116,    "Pr"  =>  140.90766,    "Nd"  =>  144.242,    "Pm"  =>  145,    "Sm"  =>  150.36,    "Eu"  =>  151.964,    "Gd"  =>  157.25,    "Tb"  =>  158.92535,    "Dy"  =>  162.500,    "Ho"  =>  164.93033,    "Er"  =>  167.259,    "Tm"  =>  168.93422,    "Yb"  =>  173.054,    "Lu"  =>  174.9668,    "Hf"  =>  178.49,    "Ta"  =>  180.94788,    "W"   =>  183.84,    "Re"  =>  186.207,    "Os"  =>  190.23,    "Ir"  =>  192.217,    "Pt"  =>  195.084,    "Au"  =>  196.966569,    "Hg"  =>  200.592,    "Tl"  =>  204.38,    "Pb"  =>  207.2,    "Bi"  =>  208.98040,    "Po"  =>  209,    "At"  =>  210,    "Rn"  =>  222,    "Fr"  =>  223,    "Ra"  =>  226,    "Ac"  =>  227,    "Th"  =>  232.0377,    "Pa"  =>  231.03588,    "U"   =>  238.02891,    "Np"  =>  237,    "Pu"  =>  244,    "Am"  =>  243,    "Cm"  =>  247,    "Bk"  =>  247,    "Cf"  =>  251,    "Es"  =>  252,    "Fm"  =>  257,    "Uue" =>  315,    "Ubn" =>  299,} def evaluate(s)    s += "[" # add end of string marker    sum = 0.0    i = 0    symbol = ""    number = ""    while i < s.length        c = s[i]        if '@' <= c and c <= '[' then            n = 1            if number != "" then                n = number.to_i            end            if symbol != "" then                mass = \$atomicMass[symbol]                sum = sum + mass * n            end            if c == '[' then                break            end            symbol = c.to_s            number = ""        elsif 'a' <= c and c <= 'z' then            symbol = symbol + c        elsif '0' <= c and c <= '9' then            number = number + c        else            raise "Unexpected symbol %c in molecule" % [c]        end        i = i + 1    end    return sumend def replaceParens(s)    letter = 'a'    while true        start = s.index '('        if start == nil then            break        end         i = start + 1        while i < s.length            if s[i] == ')' then                expr = s[start + 1 .. i - 1]                symbol = "@%c" % [letter]                r = s[start .. i + 0]                s = s.sub(r, symbol)                \$atomicMass[symbol] = evaluate(expr)                letter = letter.next                break            end            if s[i] == '(' then                start = i            end             i = i + 1        end    end    return send def main    molecules = [        "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",        "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"    ]    for molecule in molecules        mass = evaluate(replaceParens(molecule))        print "%17s -> %7.3f\n" % [molecule, mass]    endend main()`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## Swift

`import Foundation struct Chem {  struct Molecule {    var formula: String    var parts: [Molecule]    var quantity = 1     var molarMass: Double {      switch parts.count {      case 0:        return Chem.atomicWeights[formula]! * Double(quantity)      case _:        return parts.lazy.map({ \$0.molarMass }).reduce(0, +) * Double(quantity)      }    }     private init(formula: String, parts: [Molecule], quantity: Int) {      self.formula = formula      self.parts = parts      self.quantity = quantity    }     init?(fromString str: String) {      guard let mol = Molecule.parseString(str[...]) else {        return nil      }       self = mol    }     private static func parseString(_ str: Substring) -> Molecule? {      guard !str.isEmpty else {        return nil      }       var parts = [Molecule]()      var workingMol = ""      var idx = str.startIndex       func completeAtom() -> Bool {        guard Chem.atomicWeights.keys.contains(workingMol) else {          return false        }         parts.append(Molecule(formula: workingMol, parts: [], quantity: 1))        workingMol = ""         return true      }       while idx != str.endIndex {        let char = str[idx]         guard char.isASCII else {          return nil        }         if (char.isUppercase || char == "(" || char.isNumber) && !workingMol.isEmpty {          guard completeAtom() else {            return nil          }        }         if char == "(" {          var parenLevel = 1           let subMolStart = str.index(after: idx)          idx = subMolStart           while parenLevel != 0 {            guard idx != str.endIndex else {              return nil            }             if str[idx] == "(" {              parenLevel += 1            } else if str[idx] == ")" {              parenLevel -= 1            }             if parenLevel != 0 {              idx = str.index(after: idx)            }          }           guard let subMol = parseString(str[subMolStart..<idx]) else {            return nil          }           parts.append(subMol)           idx = str.index(after: idx)           continue        } else if char == ")" {          fatalError()        }         workingMol.append(char)         if char.isNumber {          guard !parts.isEmpty else {            return nil          }           var workNum = workingMol           idx = str.index(after: idx)           while idx != str.endIndex && str[idx].isNumber {            workNum.append(str[idx])            idx = str.index(after: idx)          }           parts[parts.count - 1].quantity = Int(workNum)!          workingMol = ""           continue        }         idx = str.index(after: idx)      }       guard workingMol.isEmpty || completeAtom() else {        return nil      }       return Molecule(formula: String(str), parts: parts, quantity: 1)    }  }   static func calculateMolarMass(of chem: String) -> Double? {    guard let mol = Molecule(fromString: chem) else {      return nil    }     return mol.molarMass  }   fileprivate static let atomicWeights = [    "H":  1.008,    "He": 4.002602,    "Li": 6.94,    "Be": 9.0121831,    "B": 10.81,    "C": 12.011,    "N": 14.007,    "O": 15.999,    "F": 18.998403163,    "Ne": 20.1797,    "Na": 22.98976928,    "Mg": 24.305,    "Al": 26.9815385,    "Si": 28.085,    "P": 30.973761998,    "S": 32.06,    "Cl": 35.45,    "K": 39.0983,    "Ar": 39.948,    "Ca": 40.078,    "Sc": 44.955908,    "Ti": 47.867,    "V": 50.9415,    "Cr": 51.9961,    "Mn": 54.938044,    "Fe": 55.845,    "Ni": 58.6934,    "Co": 58.933194,    "Cu": 63.546,    "Zn": 65.38,    "Ga": 69.723,    "Ge": 72.63,    "As": 74.921595,    "Se": 78.971,    "Br": 79.904,    "Kr": 83.798,    "Rb": 85.4678,    "Sr": 87.62,    "Y": 88.90584,    "Zr": 91.224,    "Nb": 92.90637,    "Mo": 95.95,    "Ru": 101.07,    "Rh": 102.9055,    "Pd": 106.42,    "Ag": 107.8682,    "Cd": 112.414,    "In": 114.818,    "Sn": 118.71,    "Sb": 121.76,    "I": 126.90447,    "Te": 127.6,    "Xe": 131.293,    "Cs": 132.90545196,    "Ba": 137.327,    "La": 138.90547,    "Ce": 140.116,    "Pr": 140.90766,    "Nd": 144.242,    "Pm": 145,    "Sm": 150.36,    "Eu": 151.964,    "Gd": 157.25,    "Tb": 158.92535,    "Dy": 162.5,    "Ho": 164.93033,    "Er": 167.259,    "Tm": 168.93422,    "Yb": 173.054,    "Lu": 174.9668,    "Hf": 178.49,    "Ta": 180.94788,    "W": 183.84,    "Re": 186.207,    "Os": 190.23,    "Ir": 192.217,    "Pt": 195.084,    "Au": 196.966569,    "Hg": 200.592,    "Tl": 204.38,    "Pb": 207.2,    "Bi": 208.9804,    "Po": 209,    "At": 210,    "Rn": 222,    "Fr": 223,    "Ra": 226,    "Ac": 227,    "Pa": 231.03588,    "Th": 232.0377,    "Np": 237,    "U": 238.02891,    "Am": 243,    "Pu": 244,    "Cm": 247,    "Bk": 247,    "Cf": 251,    "Es": 252,    "Fm": 257,    "Ubn": 299,    "Uue": 315  ]} let testCases = [  ("H", "1.008"),  ("H2", "2.016"),  ("H2O", "18.015"),  ("H2O2", "34.014"),  ("(HO)2", "34.014"),  ("Na2SO4", "142.036"),  ("C6H12", "84.162"),  ("COOH(C(CH3)2)3CH3", "186.295"),  ("C6H4O2(OH)4", "176.124"),  ("C27H46O", "386.664"),  ("Uue", "315.000")] let fmt = { String(format: "%.3f", \$0) } for (mol, expected) in testCases {  guard let mass = Chem.calculateMolarMass(of: mol) else {    fatalError("Bad formula \(mol)")  }   assert(fmt(mass) == expected, "Incorrect result")   print("\(mol) => \(fmt(mass))")}`
Output:
```H => 1.008
H2 => 2.016
H2O => 18.015
H2O2 => 34.014
(HO)2 => 34.014
Na2SO4 => 142.036
C6H12 => 84.162
COOH(C(CH3)2)3CH3 => 186.295
C6H4O2(OH)4 => 176.124
C27H46O => 386.664
Uue => 315.000```

## VBA

`Option Explicit Enum ParsingStateCode    NORM    GROUP_JUST_ENDEDEnd Enum Dim masses As Collection Sub main()    Dim molecule    For Each molecule In Array("H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3", _    "C6H4O2(OH)4", "C27H46O", "Uue")        Debug.Print molecule; Tab(20); GetMM(molecule)    NextEnd Sub Function GetMM(ByVal f As String) As Double    If masses Is Nothing Then init    f = f & "@"    Dim pos As Long    Dim mass(5) As Double    For pos = 1 To Len(f)        Dim sym\$: sym = Mid(f, pos, 1)        Select Case sym        Case "A" To "Z"            GoSub calc            Dim atom\$: atom = sym        Case "a" To "z"            atom = atom & sym        Case "("            GoSub calc            Dim depth As Long: depth = depth + 1        Case ")"            GoSub calc            Dim parsingState As ParsingStateCode            parsingState = GROUP_JUST_ENDED        Case 0 To 9            Dim nStr As String            nStr = nStr & sym        Case "@"            GoSub calc        End Select    Next    GetMM = mass(0)Exit Function'-------------------------------------------------------------------calc:    Dim n As Long    If nStr = "" Then        n = 1    Else        n = CLng(nStr)    End If    Select Case parsingState    Case NORM        mass(depth) = mass(depth) + masses(atom) * n        atom = ""    Case GROUP_JUST_ENDED        mass(depth) = mass(depth) * n        depth = depth - 1        mass(depth) = mass(depth) + mass(depth + 1)        parsingState = NORM    End Select    'n = 0    nStr = ""ReturnEnd Function Sub init()    Set masses = New Collection    masses.Add 0, ""    masses.Add 1.008, "H"    masses.Add 4.002602, "He"    masses.Add 6.94, "Li"    masses.Add 9.0121831, "Be"    masses.Add 10.81, "B"    masses.Add 12.011, "C"    masses.Add 14.007, "N"    masses.Add 15.999, "O"    masses.Add 18.998403163, "F"    masses.Add 20.1797, "Ne"    masses.Add 22.98976928, "Na"    masses.Add 24.305, "Mg"    masses.Add 26.9815385, "Al"    masses.Add 28.085, "Si"    masses.Add 30.973761998, "P"    masses.Add 32.06, "S"    masses.Add 35.45, "Cl"    masses.Add 39.0983, "K"    masses.Add 39.948, "Ar"    masses.Add 40.078, "Ca"    masses.Add 44.955908, "Sc"    masses.Add 47.867, "Ti"    masses.Add 50.9415, "V"    masses.Add 51.9961, "Cr"    masses.Add 54.938044, "Mn"    masses.Add 55.845, "Fe"    masses.Add 58.6934, "Ni"    masses.Add 58.933194, "Co"    masses.Add 63.546, "Cu"    masses.Add 65.38, "Zn"    masses.Add 69.723, "Ga"    masses.Add 72.63, "Ge"    masses.Add 74.921595, "As"    masses.Add 78.971, "Se"    masses.Add 79.904, "Br"    masses.Add 83.798, "Kr"    masses.Add 85.4678, "Rb"    masses.Add 87.62, "Sr"    masses.Add 88.90584, "Y"    masses.Add 91.224, "Zr"    masses.Add 92.90637, "Nb"    masses.Add 95.95, "Mo"    masses.Add 101.07, "Ru"    masses.Add 102.9055, "Rh"    masses.Add 106.42, "Pd"    masses.Add 107.8682, "Ag"    masses.Add 112.414, "Cd"    masses.Add 114.818, "In"    masses.Add 118.71, "Sn"    masses.Add 121.76, "Sb"    masses.Add 126.90447, "I"    masses.Add 127.6, "Te"    masses.Add 131.293, "Xe"    masses.Add 132.90545196, "Cs"    masses.Add 137.327, "Ba"    masses.Add 138.90547, "La"    masses.Add 140.116, "Ce"    masses.Add 140.90766, "Pr"    masses.Add 144.242, "Nd"    masses.Add 145, "Pm"    masses.Add 150.36, "Sm"    masses.Add 151.964, "Eu"    masses.Add 157.25, "Gd"    masses.Add 158.92535, "Tb"    masses.Add 162.5, "Dy"    masses.Add 164.93033, "Ho"    masses.Add 167.259, "Er"    masses.Add 168.93422, "Tm"    masses.Add 173.054, "Yb"    masses.Add 174.9668, "Lu"    masses.Add 178.49, "Hf"    masses.Add 180.94788, "Ta"    masses.Add 183.84, "W"    masses.Add 186.207, "Re"    masses.Add 190.23, "Os"    masses.Add 192.217, "Ir"    masses.Add 195.084, "Pt"    masses.Add 196.966569, "Au"    masses.Add 200.592, "Hg"    masses.Add 204.38, "Tl"    masses.Add 207.2, "Pb"    masses.Add 208.9804, "Bi"    masses.Add 209, "Po"    masses.Add 210, "At"    masses.Add 222, "Rn"    masses.Add 223, "Fr"    masses.Add 226, "Ra"    masses.Add 227, "Ac"    masses.Add 231.03588, "Pa"    masses.Add 232.0377, "Th"    masses.Add 237, "Np"    masses.Add 238.02891, "U"    masses.Add 243, "Am"    masses.Add 244, "Pu"    masses.Add 247, "Cm"    masses.Add 247, "Bk"    masses.Add 251, "Cf"    masses.Add 252, "Es"    masses.Add 257, "Fm"    masses.Add 299, "Ubn"    masses.Add 315, "Uue"End Sub`
Output:
```H                   1,008
H2                  2,016
H2O                 18,015
H2O2                34,014
(HO)2               34,014
Na2SO4              142,03553856
C6H12               84,162
COOH(C(CH3)2)3CH3   186,295
C6H4O2(OH)4         176,124
C27H46O             386,664
Uue                 315```

## Visual Basic .NET

Translation of: C#
`Module Module1     Dim atomicMass As New Dictionary(Of String, Double) From {        {"H", 1.008},        {"He", 4.002602},        {"Li", 6.94},        {"Be", 9.0121831},        {"B", 10.81},        {"C", 12.011},        {"N", 14.007},        {"O", 15.999},        {"F", 18.998403163},        {"Ne", 20.1797},        {"Na", 22.98976928},        {"Mg", 24.305},        {"Al", 26.9815385},        {"Si", 28.085},        {"P", 30.973761998},        {"S", 32.06},        {"Cl", 35.45},        {"Ar", 39.948},        {"K", 39.0983},        {"Ca", 40.078},        {"Sc", 44.955908},        {"Ti", 47.867},        {"V", 50.9415},        {"Cr", 51.9961},        {"Mn", 54.938044},        {"Fe", 55.845},        {"Co", 58.933194},        {"Ni", 58.6934},        {"Cu", 63.546},        {"Zn", 65.38},        {"Ga", 69.723},        {"Ge", 72.63},        {"As", 74.921595},        {"Se", 78.971},        {"Br", 79.904},        {"Kr", 83.798},        {"Rb", 85.4678},        {"Sr", 87.62},        {"Y", 88.90584},        {"Zr", 91.224},        {"Nb", 92.90637},        {"Mo", 95.95},        {"Ru", 101.07},        {"Rh", 102.9055},        {"Pd", 106.42},        {"Ag", 107.8682},        {"Cd", 112.414},        {"In", 114.818},        {"Sn", 118.71},        {"Sb", 121.76},        {"Te", 127.6},        {"I", 126.90447},        {"Xe", 131.293},        {"Cs", 132.90545196},        {"Ba", 137.327},        {"La", 138.90547},        {"Ce", 140.116},        {"Pr", 140.90766},        {"Nd", 144.242},        {"Pm", 145},        {"Sm", 150.36},        {"Eu", 151.964},        {"Gd", 157.25},        {"Tb", 158.92535},        {"Dy", 162.5},        {"Ho", 164.93033},        {"Er", 167.259},        {"Tm", 168.93422},        {"Yb", 173.054},        {"Lu", 174.9668},        {"Hf", 178.49},        {"Ta", 180.94788},        {"W", 183.84},        {"Re", 186.207},        {"Os", 190.23},        {"Ir", 192.217},        {"Pt", 195.084},        {"Au", 196.966569},        {"Hg", 200.592},        {"Tl", 204.38},        {"Pb", 207.2},        {"Bi", 208.9804},        {"Po", 209},        {"At", 210},        {"Rn", 222},        {"Fr", 223},        {"Ra", 226},        {"Ac", 227},        {"Th", 232.0377},        {"Pa", 231.03588},        {"U", 238.02891},        {"Np", 237},        {"Pu", 244},        {"Am", 243},        {"Cm", 247},        {"Bk", 247},        {"Cf", 251},        {"Es", 252},        {"Fm", 257},        {"Uue", 315},        {"Ubn", 299}    }     Function Evaluate(s As String) As Double        s += "["        Dim sum = 0.0        Dim symbol = ""        Dim number = ""        For i = 1 To s.Length            Dim c = s(i - 1)            If "@" <= c AndAlso c <= "[" Then                ' @,A-Z                Dim n = 1                If number <> "" Then                    n = Integer.Parse(number)                End If                If symbol <> "" Then                    sum += atomicMass(symbol) * n                End If                If c = "[" Then                    Exit For                End If                symbol = c.ToString                number = ""            ElseIf "a" <= c AndAlso c <= "z" Then                symbol += c            ElseIf "0" <= c AndAlso c <= "9" Then                number += c            Else                Throw New Exception(String.Format("Unexpected symbol {0} in molecule", c))            End If        Next        Return sum    End Function     Function ReplaceFirst(text As String, search As String, replace As String) As String        Dim pos = text.IndexOf(search)        If pos < 0 Then            Return text        Else            Return text.Substring(0, pos) + replace + text.Substring(pos + search.Length)        End If    End Function     Function ReplaceParens(s As String) As String        Dim letter = "s"c        While True            Dim start = s.IndexOf("(")            If start = -1 Then                Exit While            End If             For i = start + 1 To s.Length - 1                If s(i) = ")" Then                    Dim expr = s.Substring(start + 1, i - start - 1)                    Dim symbol = String.Format("@{0}", letter)                    s = ReplaceFirst(s, s.Substring(start, i + 1 - start), symbol)                    atomicMass(symbol) = Evaluate(expr)                    letter = Chr(Asc(letter) + 1)                    Exit For                End If                If s(i) = "(" Then                    start = i                    Continue For                End If            Next        End While        Return s    End Function     Sub Main()        Dim molecules() As String = {            "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12",            "COOH(C(CH3)2)3CH3", "C6H4O2(OH)4", "C27H46O", "Uue"        }        For Each molecule In molecules            Dim mass = Evaluate(ReplaceParens(molecule))            Console.WriteLine("{0,17} -> {1,7:0.000}", molecule, mass)        Next    End Sub End Module`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000```

## Wren

Translation of: Go
Library: Wren-fmt
Library: Wren-str
`import "/fmt" for Fmtimport "/str" for Char, Str var atomicMass = {    "H":   1.008,    "He":  4.002602,    "Li":  6.94,    "Be":  9.0121831,    "B":   10.81,    "C":   12.011,    "N":   14.007,    "O":   15.999,    "F":   18.998403163,    "Ne":  20.1797,    "Na":  22.98976928,    "Mg":  24.305,    "Al":  26.9815385,    "Si":  28.085,    "P":   30.973761998,    "S":   32.06,    "Cl":  35.45,    "Ar":  39.948,    "K":   39.0983,    "Ca":  40.078,    "Sc":  44.955908,    "Ti":  47.867,    "V":   50.9415,    "Cr":  51.9961,    "Mn":  54.938044,    "Fe":  55.845,    "Co":  58.933194,    "Ni":  58.6934,    "Cu":  63.546,    "Zn":  65.38,    "Ga":  69.723,    "Ge":  72.630,    "As":  74.921595,    "Se":  78.971,    "Br":  79.904,    "Kr":  83.798,    "Rb":  85.4678,    "Sr":  87.62,    "Y":   88.90584,    "Zr":  91.224,    "Nb":  92.90637,    "Mo":  95.95,    "Ru":  101.07,    "Rh":  102.90550,    "Pd":  106.42,    "Ag":  107.8682,    "Cd":  112.414,    "In":  114.818,    "Sn":  118.710,    "Sb":  121.760,    "Te":  127.60,    "I":   126.90447,    "Xe":  131.293,    "Cs":  132.90545196,    "Ba":  137.327,    "La":  138.90547,    "Ce":  140.116,    "Pr":  140.90766,    "Nd":  144.242,    "Pm":  145,    "Sm":  150.36,    "Eu":  151.964,    "Gd":  157.25,    "Tb":  158.92535,    "Dy":  162.500,    "Ho":  164.93033,    "Er":  167.259,    "Tm":  168.93422,    "Yb":  173.054,    "Lu":  174.9668,    "Hf":  178.49,    "Ta":  180.94788,    "W":   183.84,    "Re":  186.207,    "Os":  190.23,    "Ir":  192.217,    "Pt":  195.084,    "Au":  196.966569,    "Hg":  200.592,    "Tl":  204.38,    "Pb":  207.2,    "Bi":  208.98040,    "Po":  209,    "At":  210,    "Rn":  222,    "Fr":  223,    "Ra":  226,    "Ac":  227,    "Th":  232.0377,    "Pa":  231.03588,    "U":   238.02891,    "Np":  237,    "Pu":  244,    "Am":  243,    "Cm":  247,    "Bk":  247,    "Cf":  251,    "Es":  252,    "Fm":  257,    "Uue": 315,    "Ubn": 299} var evaluate = Fn.new { |s|    s = s + "[" // add end of string marker    var symbol = ""    var number = ""    var sum = 0    for (i in 0...s.count) {        var c = s[i]        if (Str.ge(c, "@") && Str.le(c, "[")) {  // @, A-Z, [            var n = 1            if (number != "") n = Num.fromString(number)            if (symbol != "") sum = sum + atomicMass[symbol] * n            if (c == "[") break            symbol = c            number = ""        } else if (Char.isLower(c)) {            symbol = symbol + c        } else if (Char.isDigit(c)) {            number = number + c        } else {            Fiber.abort("Unexpected symbol '%(c)' in molecule.")        }    }    return sum} var replaceFirst = Fn.new { |s, from, to|    var ix = s.indexOf(from)    if (ix == -1) return s    var tail = (s.count >= ix + from.count) ? s[(ix + from.count)..-1] : ""    return s[0...ix] + to + tail} var replaceParens = Fn.new { |s|    var letter = "a"    while (true) {        var start = s.indexOf("(")        if (start == -1) return s        var restart = true        while (restart) {            var i = start + 1            while (i < s.count) {                if (s[i] == ")") {                    var expr = s[start+1...i]                    var symbol = "@%(letter)"                    s = replaceFirst.call(s, s[start..i], symbol)                    atomicMass[symbol] = evaluate.call(expr)                    letter = String.fromByte(letter.bytes[0] + 1)                    restart = false                    break                }                if (s[i] == "(") {                    start = i                    break                }                i = i + 1            }        }    }    return s} var molecules = [    "H", "H2", "H2O", "H2O2", "(HO)2", "Na2SO4", "C6H12", "COOH(C(CH3)2)3CH3",    "C6H4O2(OH)4", "C27H46O", "Uue"]for (molecule in molecules) {    var mass = evaluate.call(replaceParens.call(molecule))    System.print("%(Fmt.s(17, molecule)) -> %(Fmt.f(7, mass, 3))")}`
Output:
```                H ->   1.008
H2 ->   2.016
H2O ->  18.015
H2O2 ->  34.014
(HO)2 ->  34.014
Na2SO4 -> 142.036
C6H12 ->  84.162
COOH(C(CH3)2)3CH3 -> 186.295
C6H4O2(OH)4 -> 176.124
C27H46O -> 386.664
Uue -> 315.000
```

## zkl

`fcn molarMass(str,mass=0.0){    while(span:=str.span("(",")",False)){  // get inner most () group      group:=str[span.xplode()];	  // (CH3)      str   =str.del(span.xplode());      // nuke (CH3)      w    :=molarMass(group[1,-1],mass); // remove "(" & ")"      i,s2 := span[0], str[i,*];      if(m.search(s2))			  // well crap, (CH3)2         { z:=m.matched[1]; str=str.del(i,z.len()); mass=w*z.toInt() }      else mass=w;   }   ms:=List(mass);	// HO --> (1.008,15.999).sum()   while(str){       if(not atomRE.search(str)) throw(Exception.ValueError);      ns,nm,n := atomRE.matched;      n=(if(n) n.toInt() else 1);	// H2      ms.append(atomicMass[nm]*n);      str=str.del(ns.xplode());		// nuke H or H2   }   ms.reduce('+);}`
`var [const] atomicMass = Dictionary(  "Ac",227.000000, "Ag",107.868200, "Al", 26.981538, "Am",243.000000, "Ar", 39.948000,   "As", 74.921595, "At",210.000000, "Au",196.966569, "B" , 10.810000, "Ba",137.327000,   "Be",  9.012183, "Bi",208.980400, "Bk",247.000000, "Br", 79.904000, "C" , 12.011000,   "Ca", 40.078000, "Cd",112.414000, "Ce",140.116000, "Cf",251.000000, "Cl", 35.450000,   "Cm",247.000000, "Co", 58.933194, "Cr", 51.996100, "Cs",132.905452, "Cu", 63.546000,   "Dy",162.500000, "Er",167.259000, "Es",252.000000, "Eu",151.964000, "F" , 18.998403,   "Fe", 55.845000, "Fm",257.000000, "Fr",223.000000, "Ga", 69.723000, "Gd",157.250000,   "Ge", 72.630000, "H" ,  1.008000, "He",  4.002602, "Hf",178.490000, "Hg",200.592000,   "Ho",164.930330, "I" ,126.904470, "In",114.818000, "Ir",192.217000, "K" , 39.098300,   "Kr", 83.798000, "La",138.905470, "Li",  6.940000, "Lu",174.966800, "Mg", 24.305000,   "Mn", 54.938044, "Mo", 95.950000, "N" , 14.007000, "Na", 22.989769, "Nb", 92.906370,   "Nd",144.242000, "Ne", 20.179700, "Ni", 58.693400, "Np",237.000000, "O" , 15.999000,   "Os",190.230000, "P" , 30.973762, "Pa",231.035880, "Pb",207.200000, "Pd",106.420000,   "Pm",145.000000, "Po",209.000000, "Pr",140.907660, "Pt",195.084000, "Pu",244.000000,   "Ra",226.000000, "Rb", 85.467800, "Re",186.207000, "Rh",102.905500, "Rn",222.000000,   "Ru",101.070000, "S" , 32.060000, "Sb",121.760000, "Sc", 44.955908, "Se", 78.971000,   "Si", 28.085000, "Sm",150.360000, "Sn",118.710000, "Sr", 87.620000, "Ta",180.947880,   "Tb",158.925350, "Te",127.600000, "Th",232.037700, "Ti", 47.867000, "Tl",204.380000,   "Tm",168.934220, "U" ,238.028910, "V" , 50.941500, "W" ,183.840000, "Xe",131.293000,   "Y" , 88.905840, "Yb",173.054000, "Zn", 65.380000, "Zr", 91.224000, ), m=RegExp("([1-9]+)"),   atomRE=fcn{  // sort by name length, build RE: "(Lu|Es|Er..|W|Y)([1-9]*)"	 nms:=atomicMass.keys;	 ( [(nms.apply("len") : (0).max(_)) .. 1, -1].pump(List, // 2..1	    'wrap(n){ nms.filter('wrap(nm){ nm.len()==n }) }).flatten()	   .concat("|","(",")([1-9]*)") )	 : RegExp(_);   }();`
`foreach cstr in (T("H","H2","H2O","Na2SO4","C6H12","COOH(C(CH3)2)3CH3"))   { println(cstr," --> ",molarMass(cstr)) }`
```H --> 1.008