diff --git a/parsers/go/LICENSE b/parsers/go/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/parsers/go/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/parsers/go/Makefile b/parsers/go/Makefile new file mode 100644 index 0000000..ddff40e --- /dev/null +++ b/parsers/go/Makefile @@ -0,0 +1,5 @@ +y.go: smiles.y + go tool yacc -p smiles smiles.y + +fmt: + gofmt -s=true -tabs=false -tabwidth=2 -w=true `find . -name "*.go"` diff --git a/parsers/go/README b/parsers/go/README new file mode 100644 index 0000000..a57e8e0 --- /dev/null +++ b/parsers/go/README @@ -0,0 +1,4 @@ +This is a parser for OpenSMILES chemical formula format. +It uses go tool 'yacc'. + +http://www.opensmiles.org/ diff --git a/parsers/go/elements.go b/parsers/go/elements.go new file mode 100644 index 0000000..2004577 --- /dev/null +++ b/parsers/go/elements.go @@ -0,0 +1,264 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package smiles + +type Element int + +const ( + H = Element(iota + 1) + 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 + Tc + 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 + Md + No + Lr + Rf + Db + Sg + Bh + Hs + Mt + Ds + Rg + Cn + Fl = Element(114) + Lv = Element(116) +) + +var NameToElement = map[string]Element{ + "H": H, + "He": He, + "Li": Li, + "Be": Be, + "B": B, + "C": C, + "N": N, + "O": O, + "F": F, + "Ne": Ne, + "Na": Na, + "Mg": Mg, + "Al": Al, + "Si": Si, + "P": P, + "S": S, + "Cl": Cl, + "Ar": Ar, + "K": K, + "Ca": Ca, + "Sc": Sc, + "Ti": Ti, + "V": V, + "Cr": Cr, + "Mn": Mn, + "Fe": Fe, + "Co": Co, + "Ni": Ni, + "Cu": Cu, + "Zn": Zn, + "Ga": Ga, + "Ge": Ge, + "As": As, + "Se": Se, + "Br": Br, + "Kr": Kr, + "Rb": Rb, + "Sr": Sr, + "Y": Y, + "Zr": Zr, + "Nb": Nb, + "Mo": Mo, + "Tc": Tc, + "Ru": Ru, + "Rh": Rh, + "Pd": Pd, + "Ag": Ag, + "Cd": Cd, + "In": In, + "Sn": Sn, + "Sb": Sb, + "Te": Te, + "I": I, + "Xe": Xe, + "Cs": Cs, + "Ba": Ba, + "La": La, + "Ce": Ce, + "Pr": Pr, + "Nd": Nd, + "Pm": Pm, + "Sm": Sm, + "Eu": Eu, + "Gd": Gd, + "Tb": Tb, + "Dy": Dy, + "Ho": Ho, + "Er": Er, + "Tm": Tm, + "Yb": Yb, + "Lu": Lu, + "Hf": Hf, + "Ta": Ta, + "W": W, + "Re": Re, + "Os": Os, + "Ir": Ir, + "Pt": Pt, + "Au": Au, + "Hg": Hg, + "Tl": Tl, + "Pb": Pb, + "Bi": Bi, + "Po": Po, + "At": At, + "Rn": Rn, + "Fr": Fr, + "Ra": Ra, + "Ac": Ac, + "Th": Th, + "Pa": Pa, + "U": U, + "Np": Np, + "Pu": Pu, + "Am": Am, + "Cm": Cm, + "Bk": Bk, + "Cf": Cf, + "Es": Es, + "Fm": Fm, + "Md": Md, + "No": No, + "Lr": Lr, + "Rf": Rf, + "Db": Db, + "Sg": Sg, + "Bh": Bh, + "Hs": Hs, + "Mt": Mt, + "Ds": Ds, + "Rg": Rg, + "Cn": Cn, + "Fl": Fl, + "Lv": Lv, + + // aromatic + "b": -B, + "c": -C, + "n": -N, + "o": -O, + "p": -P, + "s": -S, + "as": -As, + "se": -Se, +} + +var Weights = []float32{0, 1.007948, 4.002602, 6.941222222, 9.012182333333, 10.811777778, 12.0107888889, 14.0067222222, 15.9994333333, 18.9984032555556, 20.1797666667, 22.98976928222222, 24.3050666667, 26.9815386888889, 28.0855333333, 30.973762222222, 32.065555556, 35.453222222, 39.948111111, 39.0983111111, 40.078444444, 44.955912666667, 47.867111111, 50.9415111111, 51.9961666667, 54.938045555556, 55.845222222, 58.933195555556, 58.6934444444, 63.546333333, 65.38222222, 69.723111111, 72.63111111, 74.92160222222, 78.96333333, 79.904111111, 83.798222222, 85.4678333333, 87.62111111, 88.90585222222, 91.224222222, 92.90638222222, 95.96222222, 98.0, 101.07222222, 102.90550222222, 106.42111111, 107.8682222222, 112.411888889, 114.818333333, 118.710777778, 121.760111111, 127.60333333, 126.90447333333, 131.293666667, 132.9054519222222, 137.327777778, 138.90547777778, 140.116111111, 140.90765222222, 144.242333333, 145.0, 150.36222222, 151.964111111, 157.25333333, 158.92535222222, 162.500111111, 164.93032222222, 167.259333333, 168.93421222222, 173.054555556, 174.9668111111, 178.49222222, 180.94788222222, 183.84111111, 186.207111111, 190.23333333, 192.217333333, 195.085, 196.966569444444, 200.59222222, 204.3833222222, 207.2111111, 208.98040111111, 209.0, 210.0, 222.0, 223.0, 226.0, 227.0, 232.03806222222, 231.03588222222, 238.02891333333, 237.0, 244.0, 243.0, 247.0, 247.0, 251.0, 252.0, 257.0, 258.0, 259.0, 262.0, 267.0, 268.0, 269.0, 270.0, 269.0, 278.0, 281.0, 281.0, 285.0, 286.0, 289.0, 288.0, 293.0, 294.0, 294.0} diff --git a/parsers/go/lexer.go b/parsers/go/lexer.go new file mode 100644 index 0000000..b5608e4 --- /dev/null +++ b/parsers/go/lexer.go @@ -0,0 +1,195 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package smiles + +import ( + "log" + "unicode/utf8" +) + +const eof = 0 + +// The parser uses the type Lex as a lexer. It must provide +// the methods Lex(*SymType) int and Error(string). +type smilesLex struct { + line []byte // Line that is not parsed yet + pending map[int]int // Maps [yet] unclaimed ringbond to index of bond in Molecule.Bonds + Molecule Molecule // Output +} + +// The parser calls this method to get each new token. This +// implementation returns operators and NUM. +func (x *smilesLex) Lex(yylval *smilesSymType) int { + for { + c := x.next() + if c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' { + return x.element(c, yylval) + } + switch c { + case eof: + return eof + case '=', '#', '$', ':', '/', '\\': + return x.bond(c, yylval) + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + yylval.number = int(c - '0') + return digit + case '*': + return wildcard + case '.': + return dot + case '@': + return x.chirality(yylval) + case '+', '(', ')', '[', ']', '%': + return int(c) + case '-': + return minus + default: + return error1 + } + } +} + +// Lex chirality that consists of several bytes +func (x *smilesLex) chirality2(c1, c2, d2 rune, yylval *smilesSymType) int { + var d1 rune = '0' + var max int + switch { + case c1 == 'T' && c2 == 'H': + yylval.chirality = Chirality{Type: CHIRALITY_TH} + max = 2 + case c1 == 'A' && c2 == 'L': + yylval.chirality = Chirality{Type: CHIRALITY_AL} + max = 2 + case c1 == 'S' && c2 == 'P': + yylval.chirality = Chirality{Type: CHIRALITY_SP} + max = 3 + case c1 == 'T' && c2 == 'B': + yylval.chirality = Chirality{Type: CHIRALITY_TB} + d1 = d2 + d2 = x.next() + max = 20 + case c1 == 'O' && c2 == 'H': + yylval.chirality = Chirality{Type: CHIRALITY_OH} + d1 = d2 + d2 = x.next() + max = 30 + default: + return error1 + } + idx := int(d1-'0')*10 + int(d2-'0') + if idx < 1 || idx > max { + return error1 + } + yylval.chirality.Index = idx + return chirality +} + +// Lex chirality +func (x *smilesLex) chirality(yylval *smilesSymType) int { + switch x.peek() { + case 'T', 'A', 'S', 'O': + return x.chirality2(x.next(), x.next(), x.next(), yylval) + case '@': + x.next() + yylval.chirality = Chirality{Type: CHIRALITY_CW} + default: + yylval.chirality = Chirality{Type: CHIRALITY_CCW} + } + return chirality +} + +// Lex an element. +func (x *smilesLex) element(c rune, yylval *smilesSymType) int { + var element Element + var ok bool + if element, ok = NameToElement[string([]rune{c, x.peek()})]; !ok { + if element, ok = NameToElement[string([]rune{c})]; !ok { + return error1 + } + } else { + x.next() + } + switch element { + case H: + yylval.element = element + return hydrogen + case B, C, N, O, S, P, F, Cl, Br, I: + yylval.element = element + return aliphatic_organic + case -B, -C, -N, -O, -S, -P: + yylval.element = -element + return aromatic_organic + case -Se, -As: + yylval.element = -element + return aromatic_other + default: + yylval.element = element + } + return other +} + +// Lex a bond. +func (x *smilesLex) bond(c rune, yylval *smilesSymType) int { + switch c { + case '=': + yylval.bond = BOND_DOUBLE + case '#': + yylval.bond = BOND_TRIPLE + case '$': + yylval.bond = BOND_QUADRUPLE + case ':': + yylval.bond = BOND_AROMATIC + case '/': + yylval.bond = BOND_UP + case '\\': + yylval.bond = BOND_DOWN + } + + // This is a fix for syntax ambiguity - look ahead *in the lexer* + switch x.peek() { + case '%', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return ringbond + } + return chainbond +} + +// Return the next rune but don't advance the read position. +func (x *smilesLex) peek() rune { + if len(x.line) == 0 { + return eof + } + c, _ := utf8.DecodeRune(x.line) + return c +} + +// Return the next rune for the lexer. +func (x *smilesLex) next() rune { + if len(x.line) == 0 { + return eof + } + c, size := utf8.DecodeRune(x.line) + x.line = x.line[size:] + if c == utf8.RuneError { + log.Print("invalid utf8") + return x.next() + } + return c +} + +// The parser calls this method on a parse error. +func (x *smilesLex) Error(s string) { + log.Printf("parse error: %s", s) +} diff --git a/parsers/go/parser.go b/parsers/go/parser.go new file mode 100644 index 0000000..516bc72 --- /dev/null +++ b/parsers/go/parser.go @@ -0,0 +1,164 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package smiles + +import "fmt" + +func NewAtom(lexer smilesLexer, e Element, aromacity, aliphacity bool) int { + molecule := &lexer.(*smilesLex).Molecule + isotope := int(Weights[e] + 0.5) + a := &Atom{Element: e, index: len(molecule.Atoms), aromatic: aromacity, aliphatic: aliphacity, Isotope: isotope} + molecule.Atoms = append(molecule.Atoms, a) + return a.index +} + +func NewChain() Chain { + return Chain{} +} + +func SetChirality(lexer smilesLexer, a int, c Chirality) int { + lexer.(*smilesLex).Molecule.Atoms[a].Chirality = c + return a +} + +func SetHCount(lexer smilesLexer, a int, c int) int { + lexer.(*smilesLex).Molecule.Atoms[a].HCount = c + return a +} + +func SetCharge(lexer smilesLexer, a int, c int) int { + lexer.(*smilesLex).Molecule.Atoms[a].Charge = c + return a +} + +func SetClass(lexer smilesLexer, a int, c int) int { + lexer.(*smilesLex).Molecule.Atoms[a].Class = c + return a +} + +func SetIsotope(lexer smilesLexer, a int, i int) int { + lexer.(*smilesLex).Molecule.Atoms[a].Isotope = i + return a +} + +func GetBondType(a Atom, b BondType) BondType { + if b != BOND_DEFAULT { + return b + } + if a.aromatic { + return BOND_AROMATIC + } + return BOND_SINGLE +} + +func NewBond(m *Molecule, b BondType, a1, a2 int) { + m.Bonds = append(m.Bonds, Bond{GetBondType(*m.Atoms[a1], b), a1, a2}) +} + +func AddRingbond(_lex smilesLexer, a int, b BondType, i int) int { + lexer := _lex.(*smilesLex) + molecule := &lexer.Molecule + + if b1, ok := lexer.pending[i]; ok { + delete(lexer.pending, i) + b = GetBondType(*molecule.Atoms[a], b) + if molecule.Bonds[b1].Type != b { + panic(fmt.Sprintf("Ringbond %v has differnt types: %v vs %v.", i, molecule.Bonds[b1].Type, b)) + } + molecule.Bonds[b1].Atom2 = a + } else { + lexer.pending[i] = len(molecule.Bonds) + NewBond(molecule, b, a, -1) + } + return a +} + +func AppendToChain(lexer smilesLexer, c Chain, a int, b BondType) Chain { + if len(c) > 0 { + NewBond(&lexer.(*smilesLex).Molecule, b, c[len(c)-1], a) + } + c = append(c, a) + return c +} + +func AttachBranch(lexer smilesLexer, a int, c Chain, b BondType) int { + NewBond(&lexer.(*smilesLex).Molecule, b, c[0], a) + return a +} + +func FinalizeMolecule(lexer smilesLexer) { + if len(lexer.(*smilesLex).pending) > 0 { + panic("Some ringbonds are still not claimed.") + } + molecule := &lexer.(*smilesLex).Molecule + perAtom := make(map[int][]BondType) + for _, B := range molecule.Bonds { + perAtom[B.Atom1] = append(perAtom[B.Atom1], B.Type) + perAtom[B.Atom2] = append(perAtom[B.Atom2], B.Type) + if B.Type == BOND_DEFAULT { + panic("Default bond made it through to Finalize(). Not good.") + } + } + for a, A := range molecule.Atoms { + if !A.aliphatic { + continue + } + v := 0 + for _, bt := range perAtom[a] { + switch bt { + case BOND_QUADRUPLE: + v += 4 + case BOND_TRIPLE: + v += 3 + case BOND_DOUBLE: + v += 2 + case BOND_SINGLE, BOND_UP, BOND_DOWN: + v += 1 + default: // BOND_AROMATIC + panic("Aromatic bonds are not supported yet") + } + h := 0 + switch A.Element { + case B: + h = 3 - v + case C: + h = 4 - v + case O: + h = 2 - v + case F, Cl, Br, I: + h = 1 - v + case N, P: + if v > 3 { + h = 5 - v + } else { + h = 3 - v + } + case S: + if v > 4 { + h = 6 - v + } else if v > 2 { + h = 4 - v + } else { + h = 2 - v + } + } + if h < 0 { + panic("Hydrogen count for aliphatic become <0") + } + A.HCount = h + } + } +} diff --git a/parsers/go/smiles.go b/parsers/go/smiles.go new file mode 100644 index 0000000..e1f72c4 --- /dev/null +++ b/parsers/go/smiles.go @@ -0,0 +1,28 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package smiles + +import "errors" + +func Parse(line string) (result *Molecule, err error) { + lexer := &smilesLex{[]byte(line), map[int]int{}, Molecule{}} + if smilesParse(lexer) == 1 { + err = errors.New("an error happened") + } else { + result = &lexer.Molecule + } + return +} diff --git a/parsers/go/smiles.y b/parsers/go/smiles.y new file mode 100644 index 0000000..25d306c --- /dev/null +++ b/parsers/go/smiles.y @@ -0,0 +1,117 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +%{package smiles +%} + +%union { + char rune + number int + bond BondType + chain Chain + chirality Chirality + element Element +} + +%token ringbond chainbond dot +%token chirality +%token hydrogen aliphatic_organic aromatic_organic aromatic_other other wildcard +%token minus error1 +%token digit + +%type ELEMENT_SYMBOLS AROMATIC_SYMBOLS +%type ATOM RINGED_ATOM BRANCHED_ATOM BRACKET_ATOM BRACKET_ATOM0 BRACKET_ATOM1 BRACKET_ATOM2 BRACKET_ATOM3 BRACKET_ATOM4 +%type CHAIN +%type ISOTOPE HCOUNT CLASS NUMBER CHARGE + +%% + +top: CHAIN { FinalizeMolecule(smileslex)}; + +CHAIN : BRANCHED_ATOM { $$ = AppendToChain(smileslex, NewChain(), $1, BOND_DEFAULT)} + | CHAIN BRANCHED_ATOM { $$ = AppendToChain(smileslex, $1, $2, BOND_DEFAULT) } + | CHAIN minus BRANCHED_ATOM { $$ = AppendToChain(smileslex, $1, $3, BOND_SINGLE) } + | CHAIN chainbond BRANCHED_ATOM { $$ = AppendToChain(smileslex, $1, $3, $2) } + | CHAIN dot BRANCHED_ATOM { $$ = AppendToChain(smileslex, $1, $3, $2) } + +BRACKET_ATOM0 : ELEMENT_SYMBOLS { $$ = NewAtom(smileslex, $1, false, false) } + | AROMATIC_SYMBOLS { $$ = NewAtom(smileslex, $1, true, false) } +; + +BRACKET_ATOM1 : "[" BRACKET_ATOM0 { $$ = $2 } + | "[" ISOTOPE BRACKET_ATOM0 { $$ = SetIsotope(smileslex, $3, $2) } +; + +BRACKET_ATOM2 : BRACKET_ATOM1 + | BRACKET_ATOM1 chirality { $$ = SetChirality(smileslex, $1, $2) } +; + +BRACKET_ATOM3 : BRACKET_ATOM2 + | BRACKET_ATOM2 HCOUNT { $$ = SetHCount(smileslex, $1, $2) } +; + +BRACKET_ATOM4 : BRACKET_ATOM3 + | BRACKET_ATOM3 CHARGE { $$ = SetCharge(smileslex, $1, $2) } +; + +BRACKET_ATOM : BRACKET_ATOM4 "]" { $$ = $1 } + | BRACKET_ATOM4 CLASS "]" { $$ = SetClass(smileslex, $1, $2) } +; + +ATOM : BRACKET_ATOM + | aliphatic_organic { $$ = NewAtom(smileslex, $1, false, true) } + | aromatic_organic { $$ = NewAtom(smileslex, $1, true, false) } + | wildcard { $$ = NewAtom(smileslex, $1, false, false) } +; + +RINGED_ATOM : ATOM + | RINGED_ATOM digit { $$ = AddRingbond(smileslex, $1, BOND_DEFAULT, $2) } + | RINGED_ATOM '%' digit digit { $$ = AddRingbond(smileslex, $1, BOND_DEFAULT, $3 * 10 + $4) } + | RINGED_ATOM ringbond digit { $$ = AddRingbond(smileslex, $1, $2, $3) } + | RINGED_ATOM ringbond '%' digit digit { $$ = AddRingbond(smileslex, $1, $2, $4 * 10 + $5) } +; + + +BRANCHED_ATOM : RINGED_ATOM + | BRANCHED_ATOM "(" CHAIN ")" { $$ = AttachBranch(smileslex, $1, $3, BOND_DEFAULT)} + | BRANCHED_ATOM "(" minus CHAIN ")" { $$ = AttachBranch(smileslex, $1, $4, BOND_SINGLE)} + | BRANCHED_ATOM "(" chainbond CHAIN ")" { $$ = AttachBranch(smileslex, $1, $4, $3)} + | BRANCHED_ATOM "(" dot CHAIN ")" { $$ = AttachBranch(smileslex, $1, $4, $3)} +; + +ELEMENT_SYMBOLS : hydrogen | aliphatic_organic | other ; +AROMATIC_SYMBOLS : aromatic_organic | aromatic_other ; + +ISOTOPE : NUMBER ; +HCOUNT : hydrogen { $$ = 1 } + | hydrogen NUMBER { $$ = $2 } +; + +CHARGE : "+" { $$ = 1 } + | "+" "+" { $$ = 2 } + | "+" digit { $$ = int($2) } + | "+" digit digit { $$ = int($2*10+$3) } + | minus { $$ = -1 } + | minus minus { $$ = -2 } + | minus digit digit { $$ = -int($2*10+$3) } +; + +CLASS : NUMBER ; + +NUMBER : digit + | NUMBER digit { $$ = $1 * 10 + $2 } +; + +%% diff --git a/parsers/go/smiles_test.go b/parsers/go/smiles_test.go new file mode 100644 index 0000000..f80e3df --- /dev/null +++ b/parsers/go/smiles_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package smiles_test + +import ( + "fmt" + "code.google.com/p/opensmiles" + "sort" +) + +type Bond struct { + a, b int +} + +type BondSlice []Bond + +func (b BondSlice) Len() int { return len(b) } +func (b BondSlice) Less(i, j int) bool { + if b[i].a == b[j].a { + return b[i].b < b[j].b + } + return b[i].a < b[j].a +} +func (b BondSlice) Swap(i, j int) { b[i], b[j] = b[j], b[i] } + +func ParseAndPrint(src string) { + molecule, err := smiles.Parse(src) + if err != nil { + fmt.Println("Error happened", err) + return + } + var weights []int + var bonds BondSlice + for _, atom := range molecule.Atoms { + weights = append(weights, atom.Isotope) + } + for _, b := range molecule.Bonds { + if b.Atom1 > b.Atom2 { + bonds = append(bonds, Bond{b.Atom2, b.Atom1}) + } else { + bonds = append(bonds, Bond{b.Atom1, b.Atom2}) + } + } + sort.Sort(bonds) + fmt.Println("Weights:", weights) + fmt.Println("Bonds:", bonds) +} + +func ExampleParse() { + src := "C1=CC=CC=C1" + ParseAndPrint(src) + // Output: + // Weights: [12 12 12 12 12 12] + // Bonds: [{0 1} {0 5} {1 2} {2 3} {3 4} {4 5}] +} diff --git a/parsers/go/types.go b/parsers/go/types.go new file mode 100644 index 0000000..8fcc761 --- /dev/null +++ b/parsers/go/types.go @@ -0,0 +1,59 @@ +package smiles + +type BondType int +type ChiralityType int + +const ( + BOND_DEFAULT = BondType(iota) + BOND_SINGLE + BOND_DOUBLE + BOND_TRIPLE + BOND_QUADRUPLE + BOND_UP + BOND_DOWN + BOND_AROMATIC +) + +const ( + CHIRALITY_DEFAULT = ChiralityType(iota) + CHIRALITY_CCW + CHIRALITY_CW + CHIRALITY_TH // Valid indices are 1, 2 + CHIRALITY_AL // Valid indices are 1, 2 + CHIRALITY_SP // Valid indices are 1, 2, 3 + CHIRALITY_TB // Valid indices are 1...20 + CHIRALITY_OH // Valid indices are 1...30 +) + +type Atom struct { + Bonds []Bond + Branches []Chain + Charge int + Chirality Chirality + Class int + Element Element + HCount int + Isotope int + + // used only while parsing SMILES + aliphatic bool + aromatic bool + index int +} + +type Bond struct { + Type BondType + Atom1, Atom2 int // <0 are the ringbonds that are still unresolved +} + +type Chain []int + +type Chirality struct { + Type ChiralityType + Index int +} + +type Molecule struct { + Atoms []*Atom + Bonds []Bond +} diff --git a/parsers/go/y.go b/parsers/go/y.go new file mode 100644 index 0000000..8bf84cd --- /dev/null +++ b/parsers/go/y.go @@ -0,0 +1,527 @@ + +//line smiles.y:16 +package smiles +import __yyfmt__ "fmt" +//line smiles.y:17 + +//line smiles.y:19 +type smilesSymType struct { + yys int + char rune + number int + bond BondType + chain Chain + chirality Chirality + element Element +} + +const ringbond = 57346 +const chainbond = 57347 +const dot = 57348 +const chirality = 57349 +const hydrogen = 57350 +const aliphatic_organic = 57351 +const aromatic_organic = 57352 +const aromatic_other = 57353 +const other = 57354 +const wildcard = 57355 +const minus = 57356 +const error1 = 57357 +const digit = 57358 + +var smilesToknames = []string{ + "ringbond", + "chainbond", + "dot", + "chirality", + "hydrogen", + "aliphatic_organic", + "aromatic_organic", + "aromatic_other", + "other", + "wildcard", + "minus", + "error1", + "digit", +} +var smilesStatenames = []string{} + +const smilesEofCode = 1 +const smilesErrCode = 2 +const smilesMaxDepth = 200 + +//line smiles.y:117 + + +//line yacctab:1 +var smilesExca = []int{ + -1, 1, + 1, -1, + -2, 0, +} + +const smilesNprod = 51 +const smilesPrivate = 57344 + +var smilesTokenNames []string +var smilesStates []string + +const smilesLast = 119 + +var smilesAct = []int{ + + 3, 2, 33, 15, 17, 18, 29, 25, 7, 8, + 19, 53, 9, 16, 28, 32, 14, 43, 44, 45, + 71, 46, 37, 72, 17, 18, 17, 18, 7, 8, + 7, 8, 9, 16, 9, 16, 14, 60, 14, 59, + 70, 51, 69, 26, 52, 23, 56, 15, 54, 62, + 63, 64, 55, 38, 39, 41, 42, 40, 57, 68, + 58, 26, 67, 15, 15, 15, 17, 18, 48, 49, + 7, 8, 7, 8, 9, 16, 9, 47, 14, 31, + 14, 22, 61, 17, 18, 66, 65, 7, 8, 26, + 50, 9, 16, 20, 1, 14, 21, 7, 8, 27, + 24, 9, 30, 34, 10, 14, 38, 39, 41, 42, + 40, 11, 12, 13, 6, 4, 5, 36, 35, +} +var smilesPact = []int{ + + 88, -1000, 78, -10, 77, -1000, -1000, -1000, -1000, -1000, + 27, -8, 71, 8, 45, -10, 88, 88, 88, 63, + -1000, 74, 25, -1000, -7, 32, -1000, -1000, 30, 44, + -1000, 73, -1000, -1000, 98, -1000, -1000, 32, -1000, -1000, + -1000, -1000, -1000, -10, -10, -10, 61, 88, 88, 88, + 70, -1000, 69, -1000, -1000, -1000, 46, -1000, 43, 32, + -1000, -1000, 21, 19, -1, -1000, 7, -1000, -1000, -1000, + -1000, -1000, -1000, +} +var smilesPgo = []int{ + + 0, 118, 117, 116, 115, 0, 114, 2, 113, 112, + 111, 104, 1, 103, 102, 100, 7, 99, 94, +} +var smilesR1 = []int{ + + 0, 18, 12, 12, 12, 12, 12, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 6, 6, 3, + 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 1, 1, 1, 2, 2, 13, 14, + 14, 17, 17, 17, 17, 17, 17, 17, 15, 16, + 16, +} +var smilesR2 = []int{ + + 0, 1, 1, 2, 3, 3, 3, 1, 1, 2, + 3, 1, 2, 1, 2, 1, 2, 2, 3, 1, + 1, 1, 1, 1, 2, 4, 3, 5, 1, 4, + 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 2, 2, 3, 1, 2, 3, 1, 1, + 2, +} +var smilesChk = []int{ + + -1000, -18, -12, -5, -4, -3, -6, 9, 10, 13, + -11, -10, -9, -8, 17, -5, 14, 5, 6, 20, + 16, 19, 4, 18, -15, -16, 16, -17, 22, 14, + -14, 8, 7, -7, -13, -1, -2, -16, 8, 9, + 12, 10, 11, -5, -5, -5, -12, 14, 5, 6, + 16, 16, 19, 18, 16, 22, 16, 14, 16, -16, + -7, 21, -12, -12, -12, 16, 16, 16, 16, 21, + 21, 21, 16, +} +var smilesDef = []int{ + + 0, -2, 1, 2, 28, 23, 19, 20, 21, 22, + 0, 15, 13, 11, 0, 3, 0, 0, 0, 0, + 24, 0, 0, 17, 0, 48, 49, 16, 41, 45, + 14, 39, 12, 9, 0, 7, 8, 38, 33, 34, + 35, 36, 37, 4, 5, 6, 0, 0, 0, 0, + 0, 26, 0, 18, 50, 42, 43, 46, 0, 40, + 10, 29, 0, 0, 0, 25, 0, 44, 47, 30, + 31, 32, 27, +} +var smilesTok1 = []int{ + + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 19, 3, 3, + 20, 21, 3, 22, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 17, 3, 18, +} +var smilesTok2 = []int{ + + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, +} +var smilesTok3 = []int{ + 0, +} + +//line yaccpar:1 + +/* parser for yacc output */ + +var smilesDebug = 0 + +type smilesLexer interface { + Lex(lval *smilesSymType) int + Error(s string) +} + +const smilesFlag = -1000 + +func smilesTokname(c int) string { + // 4 is TOKSTART above + if c >= 4 && c-4 < len(smilesToknames) { + if smilesToknames[c-4] != "" { + return smilesToknames[c-4] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func smilesStatname(s int) string { + if s >= 0 && s < len(smilesStatenames) { + if smilesStatenames[s] != "" { + return smilesStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func smileslex1(lex smilesLexer, lval *smilesSymType) int { + c := 0 + char := lex.Lex(lval) + if char <= 0 { + c = smilesTok1[0] + goto out + } + if char < len(smilesTok1) { + c = smilesTok1[char] + goto out + } + if char >= smilesPrivate { + if char < smilesPrivate+len(smilesTok2) { + c = smilesTok2[char-smilesPrivate] + goto out + } + } + for i := 0; i < len(smilesTok3); i += 2 { + c = smilesTok3[i+0] + if c == char { + c = smilesTok3[i+1] + goto out + } + } + +out: + if c == 0 { + c = smilesTok2[1] /* unknown char */ + } + if smilesDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", smilesTokname(c), uint(char)) + } + return c +} + +func smilesParse(smileslex smilesLexer) int { + var smilesn int + var smileslval smilesSymType + var smilesVAL smilesSymType + smilesS := make([]smilesSymType, smilesMaxDepth) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + smilesstate := 0 + smileschar := -1 + smilesp := -1 + goto smilesstack + +ret0: + return 0 + +ret1: + return 1 + +smilesstack: + /* put a state and value onto the stack */ + if smilesDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", smilesTokname(smileschar), smilesStatname(smilesstate)) + } + + smilesp++ + if smilesp >= len(smilesS) { + nyys := make([]smilesSymType, len(smilesS)*2) + copy(nyys, smilesS) + smilesS = nyys + } + smilesS[smilesp] = smilesVAL + smilesS[smilesp].yys = smilesstate + +smilesnewstate: + smilesn = smilesPact[smilesstate] + if smilesn <= smilesFlag { + goto smilesdefault /* simple state */ + } + if smileschar < 0 { + smileschar = smileslex1(smileslex, &smileslval) + } + smilesn += smileschar + if smilesn < 0 || smilesn >= smilesLast { + goto smilesdefault + } + smilesn = smilesAct[smilesn] + if smilesChk[smilesn] == smileschar { /* valid shift */ + smileschar = -1 + smilesVAL = smileslval + smilesstate = smilesn + if Errflag > 0 { + Errflag-- + } + goto smilesstack + } + +smilesdefault: + /* default state action */ + smilesn = smilesDef[smilesstate] + if smilesn == -2 { + if smileschar < 0 { + smileschar = smileslex1(smileslex, &smileslval) + } + + /* look through exception table */ + xi := 0 + for { + if smilesExca[xi+0] == -1 && smilesExca[xi+1] == smilesstate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + smilesn = smilesExca[xi+0] + if smilesn < 0 || smilesn == smileschar { + break + } + } + smilesn = smilesExca[xi+1] + if smilesn < 0 { + goto ret0 + } + } + if smilesn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + smileslex.Error("syntax error") + Nerrs++ + if smilesDebug >= 1 { + __yyfmt__.Printf("%s", smilesStatname(smilesstate)) + __yyfmt__.Printf(" saw %s\n", smilesTokname(smileschar)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for smilesp >= 0 { + smilesn = smilesPact[smilesS[smilesp].yys] + smilesErrCode + if smilesn >= 0 && smilesn < smilesLast { + smilesstate = smilesAct[smilesn] /* simulate a shift of "error" */ + if smilesChk[smilesstate] == smilesErrCode { + goto smilesstack + } + } + + /* the current p has no shift on "error", pop stack */ + if smilesDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", smilesS[smilesp].yys) + } + smilesp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if smilesDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", smilesTokname(smileschar)) + } + if smileschar == smilesEofCode { + goto ret1 + } + smileschar = -1 + goto smilesnewstate /* try again in the same state */ + } + } + + /* reduction by production smilesn */ + if smilesDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", smilesn, smilesStatname(smilesstate)) + } + + smilesnt := smilesn + smilespt := smilesp + _ = smilespt // guard against "declared and not used" + + smilesp -= smilesR2[smilesn] + smilesVAL = smilesS[smilesp+1] + + /* consult goto table to find next state */ + smilesn = smilesR1[smilesn] + smilesg := smilesPgo[smilesn] + smilesj := smilesg + smilesS[smilesp].yys + 1 + + if smilesj >= smilesLast { + smilesstate = smilesAct[smilesg] + } else { + smilesstate = smilesAct[smilesj] + if smilesChk[smilesstate] != -smilesn { + smilesstate = smilesAct[smilesg] + } + } + // dummy call; replaced with literal code + switch smilesnt { + + case 1: + //line smiles.y:41 + { FinalizeMolecule(smileslex)} + case 2: + //line smiles.y:43 + { smilesVAL.chain = AppendToChain(smileslex, NewChain(), smilesS[smilespt-0].number, BOND_DEFAULT)} + case 3: + //line smiles.y:44 + { smilesVAL.chain = AppendToChain(smileslex, smilesS[smilespt-1].chain, smilesS[smilespt-0].number, BOND_DEFAULT) } + case 4: + //line smiles.y:45 + { smilesVAL.chain = AppendToChain(smileslex, smilesS[smilespt-2].chain, smilesS[smilespt-0].number, BOND_SINGLE) } + case 5: + //line smiles.y:46 + { smilesVAL.chain = AppendToChain(smileslex, smilesS[smilespt-2].chain, smilesS[smilespt-0].number, smilesS[smilespt-1].bond) } + case 6: + //line smiles.y:47 + { smilesVAL.chain = AppendToChain(smileslex, smilesS[smilespt-2].chain, smilesS[smilespt-0].number, smilesS[smilespt-1].bond) } + case 7: + //line smiles.y:49 + { smilesVAL.number = NewAtom(smileslex, smilesS[smilespt-0].element, false, false) } + case 8: + //line smiles.y:50 + { smilesVAL.number = NewAtom(smileslex, smilesS[smilespt-0].element, true, false) } + case 9: + //line smiles.y:53 + { smilesVAL.number = smilesS[smilespt-0].number } + case 10: + //line smiles.y:54 + { smilesVAL.number = SetIsotope(smileslex, smilesS[smilespt-0].number, smilesS[smilespt-1].number) } + case 11: + smilesVAL.number = smilesS[smilespt-0].number + case 12: + //line smiles.y:58 + { smilesVAL.number = SetChirality(smileslex, smilesS[smilespt-1].number, smilesS[smilespt-0].chirality) } + case 13: + smilesVAL.number = smilesS[smilespt-0].number + case 14: + //line smiles.y:62 + { smilesVAL.number = SetHCount(smileslex, smilesS[smilespt-1].number, smilesS[smilespt-0].number) } + case 15: + smilesVAL.number = smilesS[smilespt-0].number + case 16: + //line smiles.y:66 + { smilesVAL.number = SetCharge(smileslex, smilesS[smilespt-1].number, smilesS[smilespt-0].number) } + case 17: + //line smiles.y:69 + { smilesVAL.number = smilesS[smilespt-1].number } + case 18: + //line smiles.y:70 + { smilesVAL.number = SetClass(smileslex, smilesS[smilespt-2].number, smilesS[smilespt-1].number) } + case 19: + smilesVAL.number = smilesS[smilespt-0].number + case 20: + //line smiles.y:74 + { smilesVAL.number = NewAtom(smileslex, smilesS[smilespt-0].element, false, true) } + case 21: + //line smiles.y:75 + { smilesVAL.number = NewAtom(smileslex, smilesS[smilespt-0].element, true, false) } + case 22: + //line smiles.y:76 + { smilesVAL.number = NewAtom(smileslex, smilesS[smilespt-0].element, false, false) } + case 23: + smilesVAL.number = smilesS[smilespt-0].number + case 24: + //line smiles.y:80 + { smilesVAL.number = AddRingbond(smileslex, smilesS[smilespt-1].number, BOND_DEFAULT, smilesS[smilespt-0].number) } + case 25: + //line smiles.y:81 + { smilesVAL.number = AddRingbond(smileslex, smilesS[smilespt-3].number, BOND_DEFAULT, smilesS[smilespt-1].number * 10 + smilesS[smilespt-0].number) } + case 26: + //line smiles.y:82 + { smilesVAL.number = AddRingbond(smileslex, smilesS[smilespt-2].number, smilesS[smilespt-1].bond, smilesS[smilespt-0].number) } + case 27: + //line smiles.y:83 + { smilesVAL.number = AddRingbond(smileslex, smilesS[smilespt-4].number, smilesS[smilespt-3].bond, smilesS[smilespt-1].number * 10 + smilesS[smilespt-0].number) } + case 28: + smilesVAL.number = smilesS[smilespt-0].number + case 29: + //line smiles.y:88 + { smilesVAL.number = AttachBranch(smileslex, smilesS[smilespt-3].number, smilesS[smilespt-1].chain, BOND_DEFAULT)} + case 30: + //line smiles.y:89 + { smilesVAL.number = AttachBranch(smileslex, smilesS[smilespt-4].number, smilesS[smilespt-1].chain, BOND_SINGLE)} + case 31: + //line smiles.y:90 + { smilesVAL.number = AttachBranch(smileslex, smilesS[smilespt-4].number, smilesS[smilespt-1].chain, smilesS[smilespt-2].bond)} + case 32: + //line smiles.y:91 + { smilesVAL.number = AttachBranch(smileslex, smilesS[smilespt-4].number, smilesS[smilespt-1].chain, smilesS[smilespt-2].bond)} + case 33: + smilesVAL.element = smilesS[smilespt-0].element + case 34: + smilesVAL.element = smilesS[smilespt-0].element + case 35: + smilesVAL.element = smilesS[smilespt-0].element + case 36: + smilesVAL.element = smilesS[smilespt-0].element + case 37: + smilesVAL.element = smilesS[smilespt-0].element + case 38: + smilesVAL.number = smilesS[smilespt-0].number + case 39: + //line smiles.y:98 + { smilesVAL.number = 1 } + case 40: + //line smiles.y:99 + { smilesVAL.number = smilesS[smilespt-0].number } + case 41: + //line smiles.y:102 + { smilesVAL.number = 1 } + case 42: + //line smiles.y:103 + { smilesVAL.number = 2 } + case 43: + //line smiles.y:104 + { smilesVAL.number = int(smilesS[smilespt-0].number) } + case 44: + //line smiles.y:105 + { smilesVAL.number = int(smilesS[smilespt-1].number*10+smilesS[smilespt-0].number) } + case 45: + //line smiles.y:106 + { smilesVAL.number = -1 } + case 46: + //line smiles.y:107 + { smilesVAL.number = -2 } + case 47: + //line smiles.y:108 + { smilesVAL.number = -int(smilesS[smilespt-1].number*10+smilesS[smilespt-0].number) } + case 48: + smilesVAL.number = smilesS[smilespt-0].number + case 49: + smilesVAL.number = smilesS[smilespt-0].number + case 50: + //line smiles.y:114 + { smilesVAL.number = smilesS[smilespt-1].number * 10 + smilesS[smilespt-0].number } + } + goto smilesstack /* stack new state and value */ +} diff --git a/parsers/go/y.output b/parsers/go/y.output new file mode 100644 index 0000000..ebaa487 --- /dev/null +++ b/parsers/go/y.output @@ -0,0 +1,759 @@ + +state 0 + $accept: .top $end + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 3 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + CHAIN goto 2 + top goto 1 + +state 1 + $accept: top.$end + + $end accept + . error + + +state 2 + top: CHAIN. (1) + CHAIN: CHAIN.BRANCHED_ATOM + CHAIN: CHAIN.minus BRANCHED_ATOM + CHAIN: CHAIN.chainbond BRANCHED_ATOM + CHAIN: CHAIN.dot BRANCHED_ATOM + + chainbond shift 17 + dot shift 18 + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + minus shift 16 + [ shift 14 + . reduce 1 (src line 41) + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 15 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 3 + CHAIN: BRANCHED_ATOM. (2) + BRANCHED_ATOM: BRANCHED_ATOM.( CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( minus CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( chainbond CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( dot CHAIN ) + + ( shift 19 + . reduce 2 (src line 43) + + +state 4 + RINGED_ATOM: RINGED_ATOM.digit + RINGED_ATOM: RINGED_ATOM.% digit digit + RINGED_ATOM: RINGED_ATOM.ringbond digit + RINGED_ATOM: RINGED_ATOM.ringbond % digit digit + BRANCHED_ATOM: RINGED_ATOM. (28) + + ringbond shift 22 + digit shift 20 + % shift 21 + . reduce 28 (src line 87) + + +state 5 + RINGED_ATOM: ATOM. (23) + + . reduce 23 (src line 79) + + +state 6 + ATOM: BRACKET_ATOM. (19) + + . reduce 19 (src line 73) + + +state 7 + ATOM: aliphatic_organic. (20) + + . reduce 20 (src line 74) + + +state 8 + ATOM: aromatic_organic. (21) + + . reduce 21 (src line 75) + + +state 9 + ATOM: wildcard. (22) + + . reduce 22 (src line 76) + + +state 10 + BRACKET_ATOM: BRACKET_ATOM4.] + BRACKET_ATOM: BRACKET_ATOM4.CLASS ] + + digit shift 26 + ] shift 23 + . error + + CLASS goto 24 + NUMBER goto 25 + +state 11 + BRACKET_ATOM4: BRACKET_ATOM3. (15) + BRACKET_ATOM4: BRACKET_ATOM3.CHARGE + + minus shift 29 + + shift 28 + . reduce 15 (src line 65) + + CHARGE goto 27 + +state 12 + BRACKET_ATOM3: BRACKET_ATOM2. (13) + BRACKET_ATOM3: BRACKET_ATOM2.HCOUNT + + hydrogen shift 31 + . reduce 13 (src line 61) + + HCOUNT goto 30 + +state 13 + BRACKET_ATOM2: BRACKET_ATOM1. (11) + BRACKET_ATOM2: BRACKET_ATOM1.chirality + + chirality shift 32 + . reduce 11 (src line 57) + + +state 14 + BRACKET_ATOM1: [.BRACKET_ATOM0 + BRACKET_ATOM1: [.ISOTOPE BRACKET_ATOM0 + + hydrogen shift 38 + aliphatic_organic shift 39 + aromatic_organic shift 41 + aromatic_other shift 42 + other shift 40 + digit shift 26 + . error + + ELEMENT_SYMBOLS goto 35 + AROMATIC_SYMBOLS goto 36 + BRACKET_ATOM0 goto 33 + ISOTOPE goto 34 + NUMBER goto 37 + +state 15 + CHAIN: CHAIN BRANCHED_ATOM. (3) + BRANCHED_ATOM: BRANCHED_ATOM.( CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( minus CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( chainbond CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( dot CHAIN ) + + ( shift 19 + . reduce 3 (src line 44) + + +state 16 + CHAIN: CHAIN minus.BRANCHED_ATOM + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 43 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 17 + CHAIN: CHAIN chainbond.BRANCHED_ATOM + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 44 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 18 + CHAIN: CHAIN dot.BRANCHED_ATOM + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 45 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 19 + BRANCHED_ATOM: BRANCHED_ATOM (.CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM (.minus CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM (.chainbond CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM (.dot CHAIN ) + + chainbond shift 48 + dot shift 49 + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + minus shift 47 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 3 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + CHAIN goto 46 + +state 20 + RINGED_ATOM: RINGED_ATOM digit. (24) + + . reduce 24 (src line 80) + + +state 21 + RINGED_ATOM: RINGED_ATOM %.digit digit + + digit shift 50 + . error + + +state 22 + RINGED_ATOM: RINGED_ATOM ringbond.digit + RINGED_ATOM: RINGED_ATOM ringbond.% digit digit + + digit shift 51 + % shift 52 + . error + + +state 23 + BRACKET_ATOM: BRACKET_ATOM4 ]. (17) + + . reduce 17 (src line 69) + + +state 24 + BRACKET_ATOM: BRACKET_ATOM4 CLASS.] + + ] shift 53 + . error + + +state 25 + CLASS: NUMBER. (48) + NUMBER: NUMBER.digit + + digit shift 54 + . reduce 48 (src line 111) + + +state 26 + NUMBER: digit. (49) + + . reduce 49 (src line 113) + + +state 27 + BRACKET_ATOM4: BRACKET_ATOM3 CHARGE. (16) + + . reduce 16 (src line 66) + + +28: shift/reduce conflict (shift 56(0), red'n 41(0)) on digit +state 28 + CHARGE: +. (41) + CHARGE: +.+ + CHARGE: +.digit + CHARGE: +.digit digit + + digit shift 56 + + shift 55 + . reduce 41 (src line 102) + + +29: shift/reduce conflict (shift 58(0), red'n 45(0)) on digit +state 29 + CHARGE: minus. (45) + CHARGE: minus.minus + CHARGE: minus.digit digit + + minus shift 57 + digit shift 58 + . reduce 45 (src line 106) + + +state 30 + BRACKET_ATOM3: BRACKET_ATOM2 HCOUNT. (14) + + . reduce 14 (src line 62) + + +31: shift/reduce conflict (shift 26(0), red'n 39(0)) on digit +state 31 + HCOUNT: hydrogen. (39) + HCOUNT: hydrogen.NUMBER + + digit shift 26 + . reduce 39 (src line 98) + + NUMBER goto 59 + +state 32 + BRACKET_ATOM2: BRACKET_ATOM1 chirality. (12) + + . reduce 12 (src line 58) + + +state 33 + BRACKET_ATOM1: [ BRACKET_ATOM0. (9) + + . reduce 9 (src line 53) + + +state 34 + BRACKET_ATOM1: [ ISOTOPE.BRACKET_ATOM0 + + hydrogen shift 38 + aliphatic_organic shift 39 + aromatic_organic shift 41 + aromatic_other shift 42 + other shift 40 + . error + + ELEMENT_SYMBOLS goto 35 + AROMATIC_SYMBOLS goto 36 + BRACKET_ATOM0 goto 60 + +state 35 + BRACKET_ATOM0: ELEMENT_SYMBOLS. (7) + + . reduce 7 (src line 49) + + +state 36 + BRACKET_ATOM0: AROMATIC_SYMBOLS. (8) + + . reduce 8 (src line 50) + + +state 37 + ISOTOPE: NUMBER. (38) + NUMBER: NUMBER.digit + + digit shift 54 + . reduce 38 (src line 97) + + +state 38 + ELEMENT_SYMBOLS: hydrogen. (33) + + . reduce 33 (src line 94) + + +state 39 + ELEMENT_SYMBOLS: aliphatic_organic. (34) + + . reduce 34 (src line 94) + + +state 40 + ELEMENT_SYMBOLS: other. (35) + + . reduce 35 (src line 94) + + +state 41 + AROMATIC_SYMBOLS: aromatic_organic. (36) + + . reduce 36 (src line 95) + + +state 42 + AROMATIC_SYMBOLS: aromatic_other. (37) + + . reduce 37 (src line 95) + + +state 43 + CHAIN: CHAIN minus BRANCHED_ATOM. (4) + BRANCHED_ATOM: BRANCHED_ATOM.( CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( minus CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( chainbond CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( dot CHAIN ) + + ( shift 19 + . reduce 4 (src line 45) + + +state 44 + CHAIN: CHAIN chainbond BRANCHED_ATOM. (5) + BRANCHED_ATOM: BRANCHED_ATOM.( CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( minus CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( chainbond CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( dot CHAIN ) + + ( shift 19 + . reduce 5 (src line 46) + + +state 45 + CHAIN: CHAIN dot BRANCHED_ATOM. (6) + BRANCHED_ATOM: BRANCHED_ATOM.( CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( minus CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( chainbond CHAIN ) + BRANCHED_ATOM: BRANCHED_ATOM.( dot CHAIN ) + + ( shift 19 + . reduce 6 (src line 47) + + +state 46 + CHAIN: CHAIN.BRANCHED_ATOM + CHAIN: CHAIN.minus BRANCHED_ATOM + CHAIN: CHAIN.chainbond BRANCHED_ATOM + CHAIN: CHAIN.dot BRANCHED_ATOM + BRANCHED_ATOM: BRANCHED_ATOM ( CHAIN.) + + chainbond shift 17 + dot shift 18 + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + minus shift 16 + [ shift 14 + ) shift 61 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 15 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 47 + BRANCHED_ATOM: BRANCHED_ATOM ( minus.CHAIN ) + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 3 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + CHAIN goto 62 + +state 48 + BRANCHED_ATOM: BRANCHED_ATOM ( chainbond.CHAIN ) + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 3 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + CHAIN goto 63 + +state 49 + BRANCHED_ATOM: BRANCHED_ATOM ( dot.CHAIN ) + + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + [ shift 14 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 3 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + CHAIN goto 64 + +state 50 + RINGED_ATOM: RINGED_ATOM % digit.digit + + digit shift 65 + . error + + +state 51 + RINGED_ATOM: RINGED_ATOM ringbond digit. (26) + + . reduce 26 (src line 82) + + +state 52 + RINGED_ATOM: RINGED_ATOM ringbond %.digit digit + + digit shift 66 + . error + + +state 53 + BRACKET_ATOM: BRACKET_ATOM4 CLASS ]. (18) + + . reduce 18 (src line 70) + + +state 54 + NUMBER: NUMBER digit. (50) + + . reduce 50 (src line 114) + + +state 55 + CHARGE: + +. (42) + + . reduce 42 (src line 103) + + +56: shift/reduce conflict (shift 67(0), red'n 43(0)) on digit +state 56 + CHARGE: + digit. (43) + CHARGE: + digit.digit + + digit shift 67 + . reduce 43 (src line 104) + + +state 57 + CHARGE: minus minus. (46) + + . reduce 46 (src line 107) + + +state 58 + CHARGE: minus digit.digit + + digit shift 68 + . error + + +59: shift/reduce conflict (shift 54(0), red'n 40(0)) on digit +state 59 + HCOUNT: hydrogen NUMBER. (40) + NUMBER: NUMBER.digit + + digit shift 54 + . reduce 40 (src line 99) + + +state 60 + BRACKET_ATOM1: [ ISOTOPE BRACKET_ATOM0. (10) + + . reduce 10 (src line 54) + + +state 61 + BRANCHED_ATOM: BRANCHED_ATOM ( CHAIN ). (29) + + . reduce 29 (src line 88) + + +state 62 + CHAIN: CHAIN.BRANCHED_ATOM + CHAIN: CHAIN.minus BRANCHED_ATOM + CHAIN: CHAIN.chainbond BRANCHED_ATOM + CHAIN: CHAIN.dot BRANCHED_ATOM + BRANCHED_ATOM: BRANCHED_ATOM ( minus CHAIN.) + + chainbond shift 17 + dot shift 18 + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + minus shift 16 + [ shift 14 + ) shift 69 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 15 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 63 + CHAIN: CHAIN.BRANCHED_ATOM + CHAIN: CHAIN.minus BRANCHED_ATOM + CHAIN: CHAIN.chainbond BRANCHED_ATOM + CHAIN: CHAIN.dot BRANCHED_ATOM + BRANCHED_ATOM: BRANCHED_ATOM ( chainbond CHAIN.) + + chainbond shift 17 + dot shift 18 + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + minus shift 16 + [ shift 14 + ) shift 70 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 15 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 64 + CHAIN: CHAIN.BRANCHED_ATOM + CHAIN: CHAIN.minus BRANCHED_ATOM + CHAIN: CHAIN.chainbond BRANCHED_ATOM + CHAIN: CHAIN.dot BRANCHED_ATOM + BRANCHED_ATOM: BRANCHED_ATOM ( dot CHAIN.) + + chainbond shift 17 + dot shift 18 + aliphatic_organic shift 7 + aromatic_organic shift 8 + wildcard shift 9 + minus shift 16 + [ shift 14 + ) shift 71 + . error + + ATOM goto 5 + RINGED_ATOM goto 4 + BRANCHED_ATOM goto 15 + BRACKET_ATOM goto 6 + BRACKET_ATOM1 goto 13 + BRACKET_ATOM2 goto 12 + BRACKET_ATOM3 goto 11 + BRACKET_ATOM4 goto 10 + +state 65 + RINGED_ATOM: RINGED_ATOM % digit digit. (25) + + . reduce 25 (src line 81) + + +state 66 + RINGED_ATOM: RINGED_ATOM ringbond % digit.digit + + digit shift 72 + . error + + +state 67 + CHARGE: + digit digit. (44) + + . reduce 44 (src line 105) + + +state 68 + CHARGE: minus digit digit. (47) + + . reduce 47 (src line 108) + + +state 69 + BRANCHED_ATOM: BRANCHED_ATOM ( minus CHAIN ). (30) + + . reduce 30 (src line 89) + + +state 70 + BRANCHED_ATOM: BRANCHED_ATOM ( chainbond CHAIN ). (31) + + . reduce 31 (src line 90) + + +state 71 + BRANCHED_ATOM: BRANCHED_ATOM ( dot CHAIN ). (32) + + . reduce 32 (src line 91) + + +state 72 + RINGED_ATOM: RINGED_ATOM ringbond % digit digit. (27) + + . reduce 27 (src line 83) + + +22 terminals, 19 nonterminals +51 grammar rules, 73/2000 states +5 shift/reduce, 0 reduce/reduce conflicts reported +68 working sets used +memory: parser 97/30000 +41 extra closures +116 shift entries, 1 exceptions +33 goto entries +90 entries saved by goto default +Optimizer space used: output 119/30000 +119 table entries, 0 zero +maximum spread: 22, maximum offset: 64