chemical-compounds
Sometimes you want to be able to parse chemical formulas in a normal, user-friendly syntax. For example, water is usually written "H2O". This syntax is good for users, but for Lisp code, you need a different representation. In chemical-compounds, H2O would be represented as ((H 2) O).

A more complicated molecule is glucose, C6H12O6. This is ((C 6) (H 12) (O 6)) in our internal representation. You may have noticed that "C6H12O6" is ugly and hard to read, due to the clunky way that plain text deals with the subscripts. Therefore, in the format used by chemical-compounds, glucose is "C6 H12 O6", with spaces.

Some chemical formulas parenthesize parts of the compound and add a subscript. The formula "(C O2)4 H2" would be parsed as (((C (O 2)) 4) (H 2)).

The home page is http://common-lisp.net/project/chemboy/

Example

(use-package :compounds)

;; Pretty-print water to a string and return it
(with-output-to-string (s) (pprint-compound '((H 2) O) s))
; => "H2 O"

;; Parse some compounds
(parse-compound "C6 H12 O6") ; => ((C 6) (H 12) (O 6))
(parse-compound "(C O2)4 H2") ; => (((C (O 2)) 4) (H 2))

;; Calculate the number of grams per mole of some compounds.
;; This depends on the *(periodic-table) package.
(formula-weight '((C 6) (H 12) (O 6))) ; => 180.15768
(formula-weight (parse-compound "C6 H12 O6")) ; => 180.15768

;; Parse the argument if necessary.
;; This is just a trivial convenience function.
(get-compound "C6 H12 O6") ; => ((C 6) (H 12) (O 6))
(get-compound '((C 6) (H 12) (O 6))) ; => ((C 6) (H 12) (O 6))

It is released under the LLGPL

How it works

On the off-chance that someone is interested in how this library works:

The formula weight finding and pretty-printing are fairly easy to implement recursively, but the parsing is interesting. I had originally entertained crazy thoughts about using cl-ppcre and some regexp lunacy to parse chemical formulas. I quickly abandoned this ridiculous idea. How does one use regular expressions recursively to match things like "(C O2)4 H2"? I don't know, and I don't want to know. Instead, I used META.

META is a parsing technique, not a parser. I ripped some of the basic META code from Henry Baker's paper, and found it underpowered and inconventient. After adding in some heavy macros for a lot of things (the closest I've ever come to making a domain-specific language for parsing), it became very nice. Writing parsers with META really is straightforward with the proper macros. I thank META for my code's great portability; chemical-compounds has been tested successfully on SBCL, LispWorks, Corman Lisp, and ECL.


Science