/* Generated By:JJTree&JavaCC: Do not edit this line. SMARTSParser.java */
/* $RCSfile$
 * $Author: $
 * $Date: $
 * $Revision: $
 *
 * Copyright (C) 2004-2007  The Chemistry Development Kit (CDK) project
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * (or see http://www.gnu.org/copyleft/lesser.html)
 */

package org.openscience.cdk.smiles.smarts.parser;

/** 
*
* @cdk.module smarts 
*/

import java.io.StringReader;
import java.util.Stack;

import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.isomorphism.matchers.QueryAtomContainer;
import org.openscience.cdk.tools.LoggingTool;

/**
 * This parser implements a nearly complete subset of the SMARTS syntax as defined on
 * <a href="http://www.daylight.com/dayhtml/doc/theory/theory.smarts.html">the
 * Daylight website</a>. 
 *
 * <p>Example code using SMARTS substructure search looks like:
 * <pre>
 * SmilesParser sp = new SmilesParser();
 * AtomContainer atomContainer = sp.parseSmiles("CC(=O)OC(=O)C");
 * QueryAtomContainer query = SMARTSParser.parse("C*C");
 * boolean queryMatch = UniversalIsomorphismTester.isSubgraph(atomContainer, query);
 * </pre>
 *
 * <p>See the cdk.test.smiles.smarts.parser.ParserTest for examples of the implemented
 * subset.
 *
 * This parser is based on JJTree and it generates an AST (Abstract Syntax Tree)
 * <p>To get the AST, the code looks like:
 * <pre>
 * SMARTSParser parser = new SMARTSParser(new java.io.StringReader("C*C"));
 * ASTStart = parser.start();
 * </pre>
 *
 * @see org.openscience.cdk.isomorphism.matchers.smarts.SMARTSAtom
 *
 * @author      Dazhi Jiao
 * @cdk.created 2007-04-23
 * @cdk.githash
 *
 * @cdk.require ant1.6
 * @cdk.module  smarts
 *
 * @cdk.keyword SMARTS
 * @cdk.keyword substructure search
 */
public class SMARTSParser/*@bgen(jjtree)*/implements SMARTSParserTreeConstants, SMARTSParserConstants {/*@bgen(jjtree)*/
  protected JJTSMARTSParserState jjtree = new JJTSMARTSParserState();
        /**
	 * This method parses a Smarts String and returns an instance of 
	 * <code>QueryAtomContainer</code>
	 */
        public static QueryAtomContainer parse(String smarts) throws CDKException {
        QueryAtomContainer container = null;
        StringReader reader = new StringReader(smarts);
        try {
            SMARTSParser parser = new SMARTSParser(reader);
            ASTStart start = parser.Start();
            org.openscience.cdk.smiles.smarts.parser.visitor.SmartsQueryVisitor visitor
                = new org.openscience.cdk.smiles.smarts.parser.visitor.SmartsQueryVisitor();
            container = (QueryAtomContainer)start.jjtAccept(visitor, null);
        } catch (ParseException exception) {
            throw new CDKException("The string " + smarts + " is not a valid" +
              " SMARTS string: " + exception.getMessage(), exception);
        }
        return container;
        }

/**
 *                     Start ::= <ReactionExpression>
 *        ReactionExpression ::= <GroupExpression> (">>" <GroupExpression>)? |
 *                               ">" <GroupExpression> ">" | ">>" <GroupExpression>
 *           GroupExpression ::= ["("] <SmartsExpresion> [")"] ( "." ["("] <SmartsExpression> [")"] )*
 *          SmartsExpression ::= <AtomExpression> ( 
 									( [ <LowAndBond> ] ( <Digit> | <AtomExpression> ) ) |
 									( "(" [ <LowAndBond> ] <SmartsExpression> ")" ) )*
 		      AtomExpression ::= ( "[" [ <AtomicMass> ] <LowAndExpression> "]" ) | <ExplicitAtomExpression>
 *                LowAndBond ::= <OrBond> [ ";" <AndBond> ]
 *                    OrBond ::= <ExplicitHighAndBond> [ "," <OrBond> ]
 *       ExplicitHighAndBond ::= <ImplicitHighAndBond> [ "&" <ExplicitHighAndBond> ]
 *       ImplicitHighAndBond ::= <NotBond> [ <ImplicitHighAndBond> ]
 *                   NotBond ::= [ "!" ] <SimpleBond>
 *                SimpleBond ::= "/" | "\\" | "/?" | "\\?" | "=" | "#" | "~" | "@"
 *    ExplicitAtomExpression ::= [ "B" | "C" | "N" | "O" | "P" | "S" | "F" | "CL" | "BR" | "I" 
 *                               | "c" | "o" | "n" | "*" | "A" | "a" | "p" | "as" | "se" ] 
 *          LowAndExpression ::= <OrExpression> ( ";" <LowAndExpression> )?
 *              OrExpression ::= <ExplicitHighAndExpression> ( "," <OrExpression> ) ?
 * ExplicitHighAndExpression ::= <ImplicitHighAndExpression> ( "&" <ExplicitHighAndExpression> )?
 * ImplicitHighAndExpression ::= <NotExpression> ( <ImplicitHighAndExpression> ) ?
 *             NotExpression ::= "!" ( <PrimitiveAtomExpression> | <RecursiveSmartsExpression> )
 * RecursiveSmartsExpression ::= "$" "(" <SmartsExpression> ")"
 *   PrimitiveAtomExpression ::= <NonHydrogenElement> | "*" | "A" | "a" | "D" (<Digits>)? | "H" (<Digits>)? | "h" (<Digits>)?
 *                               | "R" (<Digit>+)? | "r" (<Digit>+)? | "v" (<Digit>+)? | "#X" | "G" (<DIGIT>+)  
 *                               | "X" (<Digit>+)? | "x" (<Digit>+)? | "^" (<DIGIT>)
 *                               | ("+" | "-") (<Digit>+)? | "#" (<Digit>+) | "@" | "@@" | <Digit>+
 *                     Digit ::= ( "0" - "9")
 *        NonHydrogenElement ::= [ "HE" | "LI" | "BE" | "NE" | "NA" | "MG" | "AL" | "SI" | "AR" | "CA" | "SC" |
 *                               "TI" | "CR" | "MN" | "FE" | "CO" | "NI" | "CU" | "ZN" | "GA" | "GE" | "AS" |
 *                               "SE" | "BR" | "KR" | "RB" | "SR" | "ZR" | "NB" | "MO" | "TC" | "RU" | "RH" |
 *                               "PD" | "AG" | "CD" | "IN" | "SN" | "SB" | "TE" | "XE" | "CS" | "BA" | "LA" |
 *                               "HF" | "TA" | "RE" | "OS" | "IR" | "PT" | "AU" | "HG" | "TL" | "PB" | "BI" |
 *                               "PO" | "AT" | "RN" | "FR" | "RA" | "AC" | "TH" | "PA" |
 *                               "B" | "C" | "N" | "O" | "F" | "P" | "S" | "K" | "V" | "Y" | "I" | "U" |
 *                               "c" | "o" | "n" | "p" | "as" | "se" ]
 */
  final public ASTStart Start() throws ParseException {
                           /*@bgen(jjtree) Start */
  ASTStart jjtn000 = new ASTStart(JJTSTART);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      ReactionExpression();
      jj_consume_token(0);
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
        {if (true) return jjtn000;}
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
    throw new Error("Missing return statement in function");
  }

  final public void ReactionExpression() throws ParseException {
                                       /*@bgen(jjtree) Reaction */
  ASTReaction jjtn000 = new ASTReaction(JJTREACTION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case c:
      case n:
      case o:
      case s:
      case p:
      case as:
      case se:
      case B:
      case C:
      case N:
      case O:
      case F:
      case P:
      case S:
      case CL:
      case BR:
      case I:
      case WILDCARD:
      case a:
      case A:
      case L_PAREN:
      case L_BRACKET:
        GroupExpression();
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case 146:
          jj_consume_token(146);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case c:
          case n:
          case o:
          case s:
          case p:
          case as:
          case se:
          case B:
          case C:
          case N:
          case O:
          case F:
          case P:
          case S:
          case CL:
          case BR:
          case I:
          case WILDCARD:
          case a:
          case A:
          case L_PAREN:
          case L_BRACKET:
            GroupExpression();
            break;
          default:
            jj_la1[0] = jj_gen;
            ;
          }
          break;
        default:
          jj_la1[1] = jj_gen;
          ;
        }
        break;
      case 147:
        jj_consume_token(147);
        GroupExpression();
        jj_consume_token(147);
        break;
      case 146:
        jj_consume_token(146);
        GroupExpression();
        break;
      default:
        jj_la1[2] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void GroupExpression() throws ParseException {
                                 /*@bgen(jjtree) Group */
                                  ASTGroup jjtn000 = new ASTGroup(JJTGROUP);
                                  boolean jjtc000 = true;
                                  jjtree.openNodeScope(jjtn000);ASTSmarts smarts;
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case L_PAREN:
        jj_consume_token(L_PAREN);
        break;
      default:
        jj_la1[3] = jj_gen;
        ;
      }
      SmartsExpression();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case R_PAREN:
        jj_consume_token(R_PAREN);
        break;
      default:
        jj_la1[4] = jj_gen;
        ;
      }
      label_1:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case 148:
          ;
          break;
        default:
          jj_la1[5] = jj_gen;
          break label_1;
        }
        jj_consume_token(148);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case L_PAREN:
          jj_consume_token(L_PAREN);
          break;
        default:
          jj_la1[6] = jj_gen;
          ;
        }
        SmartsExpression();
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case R_PAREN:
          jj_consume_token(R_PAREN);
          break;
        default:
          jj_la1[7] = jj_gen;
          ;
        }
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void SmartsExpression() throws ParseException {
 /*@bgen(jjtree) Smarts */
        ASTSmarts jjtn000 = new ASTSmarts(JJTSMARTS);
        boolean jjtc000 = true;
        jjtree.openNodeScope(jjtn000);ASTAtom atom;
    try {
      atom = AtomExpression();
      label_2:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case NOT:
        case S_BOND:
        case UP_S_BOND:
        case DN_S_BOND:
        case UP_OR_UNSPECIFIED_S_BOND:
        case DN_OR_UNSPECIFIED_S_BOND:
        case D_BOND:
        case T_BOND:
        case AR_BOND:
        case ANY_BOND:
        case R_BOND:
        case c:
        case n:
        case o:
        case s:
        case p:
        case as:
        case se:
        case B:
        case C:
        case N:
        case O:
        case F:
        case P:
        case S:
        case CL:
        case BR:
        case I:
        case WILDCARD:
        case a:
        case A:
        case L_PAREN:
        case L_BRACKET:
        case DIGIT:
          ;
          break;
        default:
          jj_la1[8] = jj_gen;
          break label_2;
        }
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case NOT:
        case S_BOND:
        case UP_S_BOND:
        case DN_S_BOND:
        case UP_OR_UNSPECIFIED_S_BOND:
        case DN_OR_UNSPECIFIED_S_BOND:
        case D_BOND:
        case T_BOND:
        case AR_BOND:
        case ANY_BOND:
        case R_BOND:
        case c:
        case n:
        case o:
        case s:
        case p:
        case as:
        case se:
        case B:
        case C:
        case N:
        case O:
        case F:
        case P:
        case S:
        case CL:
        case BR:
        case I:
        case WILDCARD:
        case a:
        case A:
        case L_BRACKET:
        case DIGIT:
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case NOT:
          case S_BOND:
          case UP_S_BOND:
          case DN_S_BOND:
          case UP_OR_UNSPECIFIED_S_BOND:
          case DN_OR_UNSPECIFIED_S_BOND:
          case D_BOND:
          case T_BOND:
          case AR_BOND:
          case ANY_BOND:
          case R_BOND:
            LowAndBond();
            break;
          default:
            jj_la1[9] = jj_gen;
            ;
          }
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            jj_consume_token(DIGIT);
                                ASTLowAndBond bond = null;
                                ASTRingIdentifier ringId = new ASTRingIdentifier(JJTRINGIDENTIFIER);
                                if (jjtree.peekNode() instanceof ASTLowAndBond) {
                                        bond = (ASTLowAndBond)jjtree.popNode(); // pop the bond
                                        ringId.jjtAddChild(bond, 0);
                                }
                                ringId.setRingId(Integer.parseInt(token.image));
                                atom.jjtAddChild(ringId, atom.jjtGetNumChildren());
            break;
          case c:
          case n:
          case o:
          case s:
          case p:
          case as:
          case se:
          case B:
          case C:
          case N:
          case O:
          case F:
          case P:
          case S:
          case CL:
          case BR:
          case I:
          case WILDCARD:
          case a:
          case A:
          case L_BRACKET:
            atom = AtomExpression();
            break;
          default:
            jj_la1[10] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
          break;
        case L_PAREN:
          jj_consume_token(L_PAREN);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case NOT:
          case S_BOND:
          case UP_S_BOND:
          case DN_S_BOND:
          case UP_OR_UNSPECIFIED_S_BOND:
          case DN_OR_UNSPECIFIED_S_BOND:
          case D_BOND:
          case T_BOND:
          case AR_BOND:
          case ANY_BOND:
          case R_BOND:
            LowAndBond();
            break;
          default:
            jj_la1[11] = jj_gen;
            ;
          }
          SmartsExpression();
          jj_consume_token(R_PAREN);
          break;
        default:
          jj_la1[12] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
    } catch (Throwable jjte000) {
          if (jjtc000) {
            jjtree.clearNodeScope(jjtn000);
            jjtc000 = false;
          } else {
            jjtree.popNode();
          }
          if (jjte000 instanceof RuntimeException) {
            {if (true) throw (RuntimeException)jjte000;}
          }
          if (jjte000 instanceof ParseException) {
            {if (true) throw (ParseException)jjte000;}
          }
          {if (true) throw (Error)jjte000;}
    } finally {
          if (jjtc000) {
            jjtree.closeNodeScope(jjtn000, true);
          }
    }
  }

  final public ASTAtom AtomExpression() throws ParseException {
 /*@bgen(jjtree) Atom */
        ASTAtom jjtn000 = new ASTAtom(JJTATOM);
        boolean jjtc000 = true;
        jjtree.openNodeScope(jjtn000);Token firstToken;
        Token secondToken;
        Token rightBracket;
        ASTAtomicMass massNode = null;
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case L_BRACKET:
        jj_consume_token(L_BRACKET);
                              firstToken = getToken(1); secondToken = getToken(2);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case DIGIT:
          AtomicMass();
                                 massNode = (ASTAtomicMass)jjtree.popNode();
          break;
        default:
          jj_la1[13] = jj_gen;
          ;
        }
        LowAndExpression();
                                if (massNode != null) { // insert AtomicMass node into expression       
                                        ASTLowAndExpression topNode = (ASTLowAndExpression)jjtree.popNode();
                                        topNode.insertLeafChild(massNode);
                                        jjtree.pushNode(topNode);
                                }
        jj_consume_token(R_BRACKET);
                              rightBracket = token;
                        Token HToken = null;
                        // If the LowAndExpression is "[H]", change it to an ExplicitAtom
                        if (firstToken.image.equals("H")) {
                                HToken = firstToken;
                        } else if (massNode != null && massNode.getMass() <= 3 && secondToken != null && secondToken.image.equals("H")) {
                                HToken = secondToken;
                        }
                        if (HToken != null) {
                                if ( (rightBracket.beginColumn - HToken.endColumn) == 1) {
                                        jjtree.popNode();
                                        ASTExplicitAtom explicitAtom = new ASTExplicitAtom(JJTEXPLICITATOM);
                        if (massNode!= null) {
                                                    if (massNode.getMass() == 2) explicitAtom.setSymbol("D");
                                                    else if (massNode.getMass() == 3) explicitAtom.setSymbol("T");
                                                    else if (massNode.getMass() == 1) explicitAtom.setSymbol("H");
                                                    } else {
                                                      explicitAtom.setSymbol("H");
                                                    }
                                                jjtree.pushNode(explicitAtom);
                                }
                        }
        break;
      case c:
      case n:
      case o:
      case s:
      case p:
      case as:
      case se:
      case B:
      case C:
      case N:
      case O:
      case F:
      case P:
      case S:
      case CL:
      case BR:
      case I:
      case WILDCARD:
      case a:
      case A:
        ExplicitAtomExpression();
        break;
      default:
        jj_la1[14] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
          jjtree.closeNodeScope(jjtn000, true);
          jjtc000 = false;
                {if (true) return jjtn000;}
    } catch (Throwable jjte000) {
          if (jjtc000) {
            jjtree.clearNodeScope(jjtn000);
            jjtc000 = false;
          } else {
            jjtree.popNode();
          }
          if (jjte000 instanceof RuntimeException) {
            {if (true) throw (RuntimeException)jjte000;}
          }
          if (jjte000 instanceof ParseException) {
            {if (true) throw (ParseException)jjte000;}
          }
          {if (true) throw (Error)jjte000;}
    } finally {
          if (jjtc000) {
            jjtree.closeNodeScope(jjtn000, true);
          }
    }
    throw new Error("Missing return statement in function");
  }

  final public void LowAndBond() throws ParseException {
                                 /*@bgen(jjtree) LowAndBond */
  ASTLowAndBond jjtn000 = new ASTLowAndBond(JJTLOWANDBOND);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      OrBond();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case L_AND:
        jj_consume_token(L_AND);
        LowAndBond();
        break;
      default:
        jj_la1[15] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void OrBond() throws ParseException {
                         /*@bgen(jjtree) OrBond */
  ASTOrBond jjtn000 = new ASTOrBond(JJTORBOND);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      ExplicitHighAndBond();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case OR:
        jj_consume_token(OR);
        OrBond();
        break;
      default:
        jj_la1[16] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ExplicitHighAndBond() throws ParseException {
                                                   /*@bgen(jjtree) ExplicitHighAndBond */
  ASTExplicitHighAndBond jjtn000 = new ASTExplicitHighAndBond(JJTEXPLICITHIGHANDBOND);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      ImplicitHighAndBond();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case H_AND:
        jj_consume_token(H_AND);
        ExplicitHighAndBond();
        break;
      default:
        jj_la1[17] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ImplicitHighAndBond() throws ParseException {
                                                   /*@bgen(jjtree) ImplicitHighAndBond */
  ASTImplicitHighAndBond jjtn000 = new ASTImplicitHighAndBond(JJTIMPLICITHIGHANDBOND);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      NotBond();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case NOT:
      case S_BOND:
      case UP_S_BOND:
      case DN_S_BOND:
      case UP_OR_UNSPECIFIED_S_BOND:
      case DN_OR_UNSPECIFIED_S_BOND:
      case D_BOND:
      case T_BOND:
      case AR_BOND:
      case ANY_BOND:
      case R_BOND:
        ImplicitHighAndBond();
        break;
      default:
        jj_la1[18] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void NotBond() throws ParseException {
                           /*@bgen(jjtree) NotBond */
  ASTNotBond jjtn000 = new ASTNotBond(JJTNOTBOND);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case NOT:
        jj_consume_token(NOT);
              jjtn000.setType(SMARTSParserConstants.NOT);
        break;
      default:
        jj_la1[19] = jj_gen;
        ;
      }
      SimpleBond();
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void SimpleBond() throws ParseException {
                                 /*@bgen(jjtree) SimpleBond */
  ASTSimpleBond jjtn000 = new ASTSimpleBond(JJTSIMPLEBOND);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      if (jj_2_1(2)) {
        jj_consume_token(S_BOND);
      } else {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case UP_S_BOND:
          jj_consume_token(UP_S_BOND);
          break;
        case DN_S_BOND:
          jj_consume_token(DN_S_BOND);
          break;
        case UP_OR_UNSPECIFIED_S_BOND:
          jj_consume_token(UP_OR_UNSPECIFIED_S_BOND);
          break;
        case DN_OR_UNSPECIFIED_S_BOND:
          jj_consume_token(DN_OR_UNSPECIFIED_S_BOND);
          break;
        case D_BOND:
          jj_consume_token(D_BOND);
          break;
        case T_BOND:
          jj_consume_token(T_BOND);
          break;
        case AR_BOND:
          jj_consume_token(AR_BOND);
          break;
        case ANY_BOND:
          jj_consume_token(ANY_BOND);
          break;
        case R_BOND:
          jj_consume_token(R_BOND);
          break;
        default:
          jj_la1[20] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
        jjtn000.setBondType(token.kind);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ExplicitAtomExpression() throws ParseException {
                                               /*@bgen(jjtree) ExplicitAtom */
  ASTExplicitAtom jjtn000 = new ASTExplicitAtom(JJTEXPLICITATOM);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case B:
        jj_consume_token(B);
        break;
      case C:
        jj_consume_token(C);
        break;
      case N:
        jj_consume_token(N);
        break;
      case O:
        jj_consume_token(O);
        break;
      case P:
        jj_consume_token(P);
        break;
      case S:
        jj_consume_token(S);
        break;
      case F:
        jj_consume_token(F);
        break;
      case CL:
        jj_consume_token(CL);
        break;
      case BR:
        jj_consume_token(BR);
        break;
      case I:
        jj_consume_token(I);
        break;
      case WILDCARD:
        jj_consume_token(WILDCARD);
        break;
      case A:
        jj_consume_token(A);
        break;
      case a:
        jj_consume_token(a);
        break;
      case c:
        jj_consume_token(c);
        break;
      case n:
        jj_consume_token(n);
        break;
      case o:
        jj_consume_token(o);
        break;
      case s:
        jj_consume_token(s);
        break;
      case p:
        jj_consume_token(p);
        break;
      case se:
        jj_consume_token(se);
        break;
      case as:
        jj_consume_token(as);
        break;
      default:
        jj_la1[21] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
        jjtn000.setSymbol(token.image);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

// TODO: This requires a fully implemented SMARTSAtom API (or something else) that 
// could encapsulate logical criterias
  final public void LowAndExpression() throws ParseException {
                                             /*@bgen(jjtree) LowAndExpression */
  ASTLowAndExpression jjtn000 = new ASTLowAndExpression(JJTLOWANDEXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      OrExpression();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case L_AND:
        jj_consume_token(L_AND);
        LowAndExpression();
        break;
      default:
        jj_la1[22] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void OrExpression() throws ParseException {
                                     /*@bgen(jjtree) OrExpression */
  ASTOrExpression jjtn000 = new ASTOrExpression(JJTOREXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      ExplicitHighAndExpression();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case OR:
        jj_consume_token(OR);
        OrExpression();
        break;
      default:
        jj_la1[23] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ExplicitHighAndExpression() throws ParseException {
                                                               /*@bgen(jjtree) ExplicitHighAndExpression */
  ASTExplicitHighAndExpression jjtn000 = new ASTExplicitHighAndExpression(JJTEXPLICITHIGHANDEXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      ImplicitHighAndExpression();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case H_AND:
        jj_consume_token(H_AND);
        ExplicitHighAndExpression();
        break;
      default:
        jj_la1[24] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ImplicitHighAndExpression() throws ParseException {
                                                               /*@bgen(jjtree) ImplicitHighAndExpression */
  ASTImplicitHighAndExpression jjtn000 = new ASTImplicitHighAndExpression(JJTIMPLICITHIGHANDEXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      NotExpression();
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case NOT:
      case S_BOND:
      case T_BOND:
      case R_BOND:
      case c:
      case n:
      case o:
      case s:
      case p:
      case as:
      case se:
      case H:
      case HE:
      case LI:
      case BE:
      case B:
      case C:
      case N:
      case O:
      case F:
      case NE:
      case NA:
      case MG:
      case AL:
      case SI:
      case P:
      case S:
      case CL:
      case AR:
      case K:
      case CA:
      case SC:
      case TI:
      case V:
      case CR:
      case MN:
      case FE:
      case CO:
      case NI:
      case CU:
      case ZN:
      case GA:
      case GE:
      case AS:
      case SE:
      case BR:
      case KR:
      case RB:
      case SR:
      case Y:
      case ZR:
      case NB:
      case MO:
      case TC:
      case RU:
      case RH:
      case PD:
      case AG:
      case CD:
      case IN:
      case SN:
      case SB:
      case TE:
      case I:
      case XE:
      case CS:
      case BA:
      case LA:
      case HF:
      case TA:
      case W:
      case RE:
      case OS:
      case IR:
      case PT:
      case AU:
      case HG:
      case TL:
      case PB:
      case BI:
      case PO:
      case AT:
      case RN:
      case FR:
      case RA:
      case AC:
      case TH:
      case PA:
      case U:
      case PU:
      case AM:
      case CM:
      case BK:
      case CF:
      case ES:
      case FM:
      case MD:
      case NO:
      case LR:
      case NP:
      case CE:
      case ND:
      case PM:
      case SM:
      case EU:
      case GD:
      case TB:
      case DY:
      case HO:
      case ER:
      case TM:
      case YB:
      case LU:
      case PR:
      case WILDCARD:
      case h:
      case a:
      case A:
      case D:
      case R:
      case r:
      case v:
      case X:
      case x:
      case G:
      case HX:
      case CARET:
      case DOLLAR:
      case 149:
      case 150:
      case 151:
      case 152:
      case 153:
      case 154:
      case 155:
      case 156:
      case 157:
      case 158:
      case 159:
      case 160:
      case 161:
      case 162:
      case 163:
      case 164:
        ImplicitHighAndExpression();
        break;
      default:
        jj_la1[25] = jj_gen;
        ;
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void NotExpression() throws ParseException {
 /*@bgen(jjtree) NotExpression */
  ASTNotExpression jjtn000 = new ASTNotExpression(JJTNOTEXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);jjtn000.setType(SMARTSParserConstants.DEFAULT);
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case NOT:
        jj_consume_token(NOT);
              jjtn000.setType(SMARTSParserConstants.NOT);
        break;
      default:
        jj_la1[26] = jj_gen;
        ;
      }
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case S_BOND:
      case T_BOND:
      case R_BOND:
      case c:
      case n:
      case o:
      case s:
      case p:
      case as:
      case se:
      case H:
      case HE:
      case LI:
      case BE:
      case B:
      case C:
      case N:
      case O:
      case F:
      case NE:
      case NA:
      case MG:
      case AL:
      case SI:
      case P:
      case S:
      case CL:
      case AR:
      case K:
      case CA:
      case SC:
      case TI:
      case V:
      case CR:
      case MN:
      case FE:
      case CO:
      case NI:
      case CU:
      case ZN:
      case GA:
      case GE:
      case AS:
      case SE:
      case BR:
      case KR:
      case RB:
      case SR:
      case Y:
      case ZR:
      case NB:
      case MO:
      case TC:
      case RU:
      case RH:
      case PD:
      case AG:
      case CD:
      case IN:
      case SN:
      case SB:
      case TE:
      case I:
      case XE:
      case CS:
      case BA:
      case LA:
      case HF:
      case TA:
      case W:
      case RE:
      case OS:
      case IR:
      case PT:
      case AU:
      case HG:
      case TL:
      case PB:
      case BI:
      case PO:
      case AT:
      case RN:
      case FR:
      case RA:
      case AC:
      case TH:
      case PA:
      case U:
      case PU:
      case AM:
      case CM:
      case BK:
      case CF:
      case ES:
      case FM:
      case MD:
      case NO:
      case LR:
      case NP:
      case CE:
      case ND:
      case PM:
      case SM:
      case EU:
      case GD:
      case TB:
      case DY:
      case HO:
      case ER:
      case TM:
      case YB:
      case LU:
      case PR:
      case WILDCARD:
      case h:
      case a:
      case A:
      case D:
      case R:
      case r:
      case v:
      case X:
      case x:
      case G:
      case HX:
      case CARET:
      case 149:
      case 150:
      case 151:
      case 152:
      case 153:
      case 154:
      case 155:
      case 156:
      case 157:
      case 158:
      case 159:
      case 160:
      case 161:
      case 162:
      case 163:
      case 164:
        PrimitiveAtomExpression();
        break;
      case DOLLAR:
        RecursiveSmartsExpression();
        break;
      default:
        jj_la1[27] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void RecursiveSmartsExpression() throws ParseException {
                                                               /*@bgen(jjtree) RecursiveSmartsExpression */
  ASTRecursiveSmartsExpression jjtn000 = new ASTRecursiveSmartsExpression(JJTRECURSIVESMARTSEXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(DOLLAR);
      jj_consume_token(L_PAREN);
      SmartsExpression();
      jj_consume_token(R_PAREN);
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        {if (true) throw (RuntimeException)jjte000;}
      }
      if (jjte000 instanceof ParseException) {
        {if (true) throw (ParseException)jjte000;}
      }
      {if (true) throw (Error)jjte000;}
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void PrimitiveAtomExpression() throws ParseException {
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
    case c:
    case n:
    case o:
    case s:
    case p:
    case as:
    case se:
    case HE:
    case LI:
    case BE:
    case B:
    case C:
    case N:
    case O:
    case F:
    case NE:
    case NA:
    case MG:
    case AL:
    case SI:
    case P:
    case S:
    case CL:
    case AR:
    case K:
    case CA:
    case SC:
    case TI:
    case V:
    case CR:
    case MN:
    case FE:
    case CO:
    case NI:
    case CU:
    case ZN:
    case GA:
    case GE:
    case AS:
    case SE:
    case BR:
    case KR:
    case RB:
    case SR:
    case Y:
    case ZR:
    case NB:
    case MO:
    case TC:
    case RU:
    case RH:
    case PD:
    case AG:
    case CD:
    case IN:
    case SN:
    case SB:
    case TE:
    case I:
    case XE:
    case CS:
    case BA:
    case LA:
    case HF:
    case TA:
    case W:
    case RE:
    case OS:
    case IR:
    case PT:
    case AU:
    case HG:
    case TL:
    case PB:
    case BI:
    case PO:
    case AT:
    case RN:
    case FR:
    case RA:
    case AC:
    case TH:
    case PA:
    case U:
    case PU:
    case AM:
    case CM:
    case BK:
    case CF:
    case ES:
    case FM:
    case MD:
    case NO:
    case LR:
    case NP:
    case CE:
    case ND:
    case PM:
    case SM:
    case EU:
    case GD:
    case TB:
    case DY:
    case HO:
    case ER:
    case TM:
    case YB:
    case LU:
    case PR:
      NoHydrogenElement();
      break;
    case WILDCARD:
      AnyAtom();
      break;
    case a:
      Aromatic();
      break;
    case A:
      Aliphatic();
      break;
    case D:
      ExplicitConnectivity();
      break;
    case H:
      TotalHCount();
      break;
    case h:
      ImplicitHCount();
      break;
    case R:
      RingMembership();
      break;
    case r:
      SmallestRingSize();
      break;
    case v:
      Valence();
      break;
    case X:
      TotalConnectivity();
      break;
    case x:
      RingConnectivity();
      break;
    case S_BOND:
    case 149:
    case 150:
    case 151:
    case 152:
    case 153:
    case 154:
    case 155:
    case 156:
    case 157:
    case 158:
    case 159:
    case 160:
    case 161:
    case 162:
    case 163:
      Charge();
      break;
    case T_BOND:
      AtomicNumber();
      break;
    case R_BOND:
    case 164:
      Chirality();
      break;
    case G:
      PeriodicGroupNumber();
      break;
    case HX:
      NonCHHeavyAtom();
      break;
    case CARET:
      HybridizationNumber();
      break;
    default:
      jj_la1[28] = jj_gen;
      jj_consume_token(-1);
      throw new ParseException();
    }
  }

  final public void TotalHCount() throws ParseException {
 /*@bgen(jjtree) TotalHCount */
  ASTTotalHCount jjtn000 = new ASTTotalHCount(JJTTOTALHCOUNT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(H);
          jjtn000.setCount(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_3:
        while (true) {
          jj_consume_token(DIGIT);
                                               digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[29] = jj_gen;
            break label_3;
          }
        }
      jjtn000.setCount( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[30] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ImplicitHCount() throws ParseException {
 /*@bgen(jjtree) ImplicitHCount */
  ASTImplicitHCount jjtn000 = new ASTImplicitHCount(JJTIMPLICITHCOUNT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(h);
          jjtn000.setCount(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_4:
        while (true) {
          jj_consume_token(DIGIT);
                                               digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[31] = jj_gen;
            break label_4;
          }
        }
      jjtn000.setCount( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[32] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void ExplicitConnectivity() throws ParseException {
 /*@bgen(jjtree) ExplicitConnectivity */
  ASTExplicitConnectivity jjtn000 = new ASTExplicitConnectivity(JJTEXPLICITCONNECTIVITY);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(D);
          jjtn000.setNumOfConnection(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_5:
        while (true) {
          jj_consume_token(DIGIT);
                  digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[33] = jj_gen;
            break label_5;
          }
        }
      jjtn000.setNumOfConnection( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[34] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void AtomicNumber() throws ParseException {
 /*@bgen(jjtree) AtomicNumber */
  ASTAtomicNumber jjtn000 = new ASTAtomicNumber(JJTATOMICNUMBER);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(T_BOND);
      label_6:
      while (true) {
        jj_consume_token(DIGIT);
                    digits.append(token.image);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case DIGIT:
          ;
          break;
        default:
          jj_la1[35] = jj_gen;
          break label_6;
        }
      }
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
      jjtn000.setNumber( Integer.parseInt(digits.toString()) );
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void HybridizationNumber() throws ParseException {
 /*@bgen(jjtree) HybrdizationNumber */
  ASTHybrdizationNumber jjtn000 = new ASTHybrdizationNumber(JJTHYBRDIZATIONNUMBER);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(CARET);
      jj_consume_token(DIGIT);
                          jjtree.closeNodeScope(jjtn000, true);
                          jjtc000 = false;
        int tmp = Integer.parseInt(token.image);
        if (tmp < 1 || tmp > 8) {if (true) throw new ParseException("Hybridization number must be between 1 & 8");}
        jjtn000.setHybridizationNumber(tmp);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void Charge() throws ParseException {
 /*@bgen(jjtree) Charge */
  ASTCharge jjtn000 = new ASTCharge(JJTCHARGE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      if (jj_2_2(2)) {
        jj_consume_token(149);
          jjtn000.setPositive(true); jjtn000.setCharge(1);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case DIGIT:
          label_7:
          while (true) {
            jj_consume_token(DIGIT);
                    digits.append(token.image);
            switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
            case DIGIT:
              ;
              break;
            default:
              jj_la1[36] = jj_gen;
              break label_7;
            }
          }
        jjtn000.setCharge( Integer.parseInt(digits.toString()) );
          break;
        default:
          jj_la1[37] = jj_gen;
          ;
        }
      } else {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case S_BOND:
          jj_consume_token(S_BOND);
            jjtn000.setPositive(false); jjtn000.setCharge(1);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            label_8:
            while (true) {
              jj_consume_token(DIGIT);
                    digits.append(token.image);
              switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
              case DIGIT:
                ;
                break;
              default:
                jj_la1[38] = jj_gen;
                break label_8;
              }
            }
        jjtn000.setCharge( Integer.parseInt(digits.toString()) );
            break;
          default:
            jj_la1[39] = jj_gen;
            ;
          }
          break;
        case 150:
          jj_consume_token(150);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(2);
          break;
        case 151:
          jj_consume_token(151);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(3);
          break;
        case 152:
          jj_consume_token(152);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(4);
          break;
        case 153:
          jj_consume_token(153);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(5);
          break;
        case 154:
          jj_consume_token(154);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(6);
          break;
        case 155:
          jj_consume_token(155);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(7);
          break;
        case 156:
          jj_consume_token(156);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(false); jjtn000.setCharge(8);
          break;
        case 157:
          jj_consume_token(157);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(2);
          break;
        case 158:
          jj_consume_token(158);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(3);
          break;
        case 159:
          jj_consume_token(159);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(4);
          break;
        case 160:
          jj_consume_token(160);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(5);
          break;
        case 161:
          jj_consume_token(161);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(6);
          break;
        case 162:
          jj_consume_token(162);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(7);
          break;
        case 163:
          jj_consume_token(163);
                      jjtree.closeNodeScope(jjtn000, true);
                      jjtc000 = false;
                      jjtn000.setPositive(true); jjtn000.setCharge(8);
          break;
        default:
          jj_la1[40] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void RingConnectivity() throws ParseException {
                                             /*@bgen(jjtree) RingConnectivity */
  ASTRingConnectivity jjtn000 = new ASTRingConnectivity(JJTRINGCONNECTIVITY);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(x);
          jjtn000.setNumOfConnection(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_9:
        while (true) {
          jj_consume_token(DIGIT);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[41] = jj_gen;
            break label_9;
          }
        }
                     jjtn000.setNumOfConnection( Integer.parseInt(token.image) );
        break;
      default:
        jj_la1[42] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void PeriodicGroupNumber() throws ParseException, ParseException {
 /*@bgen(jjtree) PeriodicGroupNumber */
  ASTPeriodicGroupNumber jjtn000 = new ASTPeriodicGroupNumber(JJTPERIODICGROUPNUMBER);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(G);

      label_10:
      while (true) {
        jj_consume_token(DIGIT);
                digits.append(token.image);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case DIGIT:
          ;
          break;
        default:
          jj_la1[43] = jj_gen;
          break label_10;
        }
      }
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
      int tmpInt = Integer.parseInt(digits.toString());
      if (tmpInt < 1 || tmpInt > 18) {if (true) throw new ParseException("Invalid group number");}
      jjtn000.setGroupNumber( Integer.parseInt(digits.toString()) );
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void TotalConnectivity() throws ParseException {
 /*@bgen(jjtree) TotalConnectivity */
  ASTTotalConnectivity jjtn000 = new ASTTotalConnectivity(JJTTOTALCONNECTIVITY);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(X);
          jjtn000.setNumOfConnection(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_11:
        while (true) {
          jj_consume_token(DIGIT);
                  digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[44] = jj_gen;
            break label_11;
          }
        }
      jjtn000.setNumOfConnection( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[45] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void Valence() throws ParseException {
 /*@bgen(jjtree) Valence */
  ASTValence jjtn000 = new ASTValence(JJTVALENCE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(v);
          jjtn000.setOrder(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_12:
        while (true) {
          jj_consume_token(DIGIT);
                  digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[46] = jj_gen;
            break label_12;
          }
        }
      jjtn000.setOrder( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[47] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void RingMembership() throws ParseException {
 /*@bgen(jjtree) RingMembership */
  ASTRingMembership jjtn000 = new ASTRingMembership(JJTRINGMEMBERSHIP);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(R);
          jjtn000.setNumOfMembership(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_13:
        while (true) {
          jj_consume_token(DIGIT);
                  digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[48] = jj_gen;
            break label_13;
          }
        }
      jjtn000.setNumOfMembership( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[49] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void SmallestRingSize() throws ParseException {
 /*@bgen(jjtree) SmallestRingSize */
  ASTSmallestRingSize jjtn000 = new ASTSmallestRingSize(JJTSMALLESTRINGSIZE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      jj_consume_token(r);
          jjtn000.setSize(1);
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case DIGIT:
        label_14:
        while (true) {
          jj_consume_token(DIGIT);
                  digits.append(token.image);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            ;
            break;
          default:
            jj_la1[50] = jj_gen;
            break label_14;
          }
        }
      jjtn000.setSize( Integer.parseInt(digits.toString()) );
        break;
      default:
        jj_la1[51] = jj_gen;
        ;
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void Aliphatic() throws ParseException {
                               /*@bgen(jjtree) Aliphatic */
  ASTAliphatic jjtn000 = new ASTAliphatic(JJTALIPHATIC);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(A);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void NonCHHeavyAtom() throws ParseException {
                                         /*@bgen(jjtree) NonCHHeavyAtom */
  ASTNonCHHeavyAtom jjtn000 = new ASTNonCHHeavyAtom(JJTNONCHHEAVYATOM);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(HX);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void Aromatic() throws ParseException {
                             /*@bgen(jjtree) Aromatic */
  ASTAromatic jjtn000 = new ASTAromatic(JJTAROMATIC);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(a);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void AnyAtom() throws ParseException {
                           /*@bgen(jjtree) AnyAtom */
  ASTAnyAtom jjtn000 = new ASTAnyAtom(JJTANYATOM);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      jj_consume_token(WILDCARD);
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void AtomicMass() throws ParseException {
 /*@bgen(jjtree) AtomicMass */
  ASTAtomicMass jjtn000 = new ASTAtomicMass(JJTATOMICMASS);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      label_15:
      while (true) {
        jj_consume_token(DIGIT);
                digits.append(token.image);
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case DIGIT:
          ;
          break;
        default:
          jj_la1[52] = jj_gen;
          break label_15;
        }
      }
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
        jjtn000.setMass( Integer.parseInt(digits.toString()) );
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void RingIdentifier() throws ParseException {
                                        /*@bgen(jjtree) RingIdentifier */
  ASTRingIdentifier jjtn000 = new ASTRingIdentifier(JJTRINGIDENTIFIER);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      LowAndBond();
      jj_consume_token(DIGIT);
    } catch (Throwable jjte000) {
          if (jjtc000) {
            jjtree.clearNodeScope(jjtn000);
            jjtc000 = false;
          } else {
            jjtree.popNode();
          }
          if (jjte000 instanceof RuntimeException) {
            {if (true) throw (RuntimeException)jjte000;}
          }
          if (jjte000 instanceof ParseException) {
            {if (true) throw (ParseException)jjte000;}
          }
          {if (true) throw (Error)jjte000;}
    } finally {
          if (jjtc000) {
            jjtree.closeNodeScope(jjtn000, true);
          }
    }
  }

  final public void Chirality() throws ParseException {
 /*@bgen(jjtree) Chirality */
  ASTChirality jjtn000 = new ASTChirality(JJTCHIRALITY);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);StringBuffer digits = new StringBuffer();
    try {
      if (jj_2_3(2)) {
        jj_consume_token(R_BOND);
          jjtree.closeNodeScope(jjtn000, true);
          jjtc000 = false;
          jjtn000.setClockwise(true);
      } else {
        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
        case 164:
          jj_consume_token(164);
                                                 jjtn000.setClockwise(false);
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case DIGIT:
            label_16:
            while (true) {
              jj_consume_token(DIGIT);
                    digits.append(token.image);
              switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
              case DIGIT:
                ;
                break;
              default:
                jj_la1[53] = jj_gen;
                break label_16;
              }
            }
                jjtn000.setDegree( Integer.parseInt(digits.toString()) );
            break;
          default:
            jj_la1[54] = jj_gen;
            ;
          }
          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
          case Q_MARK:
            jj_consume_token(Q_MARK);
                   jjtn000.setUnspecified(true);
            break;
          default:
            jj_la1[55] = jj_gen;
            ;
          }
          break;
        default:
          jj_la1[56] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
  }

  final public void NoHydrogenElement() throws ParseException {
                                    /*@bgen(jjtree) Element */
  ASTElement jjtn000 = new ASTElement(JJTELEMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
    try {
      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
      case HE:
        jj_consume_token(HE);
        break;
      case LI:
        jj_consume_token(LI);
        break;
      case BE:
        jj_consume_token(BE);
        break;
      case NE:
        jj_consume_token(NE);
        break;
      case NA:
        jj_consume_token(NA);
        break;
      case MG:
        jj_consume_token(MG);
        break;
      case AL:
        jj_consume_token(AL);
        break;
      case SI:
        jj_consume_token(SI);
        break;
      case AR:
        jj_consume_token(AR);
        break;
      case CA:
        jj_consume_token(CA);
        break;
      case SC:
        jj_consume_token(SC);
        break;
      case TI:
        jj_consume_token(TI);
        break;
      case CR:
        jj_consume_token(CR);
        break;
      case MN:
        jj_consume_token(MN);
        break;
      case FE:
        jj_consume_token(FE);
        break;
      case CO:
        jj_consume_token(CO);
        break;
      case NI:
        jj_consume_token(NI);
        break;
      case CU:
        jj_consume_token(CU);
        break;
      case ZN:
        jj_consume_token(ZN);
        break;
      case GA:
        jj_consume_token(GA);
        break;
      case GE:
        jj_consume_token(GE);
        break;
      case AS:
        jj_consume_token(AS);
        break;
      case SE:
        jj_consume_token(SE);
        break;
      case BR:
        jj_consume_token(BR);
        break;
      case KR:
        jj_consume_token(KR);
        break;
      case RB:
        jj_consume_token(RB);
        break;
      case SR:
        jj_consume_token(SR);
        break;
      case ZR:
        jj_consume_token(ZR);
        break;
      case NB:
        jj_consume_token(NB);
        break;
      case MO:
        jj_consume_token(MO);
        break;
      case TC:
        jj_consume_token(TC);
        break;
      case RU:
        jj_consume_token(RU);
        break;
      case RH:
        jj_consume_token(RH);
        break;
      case PD:
        jj_consume_token(PD);
        break;
      case AG:
        jj_consume_token(AG);
        break;
      case CD:
        jj_consume_token(CD);
        break;
      case IN:
        jj_consume_token(IN);
        break;
      case SN:
        jj_consume_token(SN);
        break;
      case SB:
        jj_consume_token(SB);
        break;
      case TE:
        jj_consume_token(TE);
        break;
      case XE:
        jj_consume_token(XE);
        break;
      case CS:
        jj_consume_token(CS);
        break;
      case BA:
        jj_consume_token(BA);
        break;
      case LA:
        jj_consume_token(LA);
        break;
      case HF:
        jj_consume_token(HF);
        break;
      case TA:
        jj_consume_token(TA);
        break;
      case W:
        jj_consume_token(W);
        break;
      case RE:
        jj_consume_token(RE);
        break;
      case OS:
        jj_consume_token(OS);
        break;
      case IR:
        jj_consume_token(IR);
        break;
      case PT:
        jj_consume_token(PT);
        break;
      case AU:
        jj_consume_token(AU);
        break;
      case HG:
        jj_consume_token(HG);
        break;
      case TL:
        jj_consume_token(TL);
        break;
      case PB:
        jj_consume_token(PB);
        break;
      case BI:
        jj_consume_token(BI);
        break;
      case PO:
        jj_consume_token(PO);
        break;
      case AT:
        jj_consume_token(AT);
        break;
      case RN:
        jj_consume_token(RN);
        break;
      case FR:
        jj_consume_token(FR);
        break;
      case RA:
        jj_consume_token(RA);
        break;
      case AC:
        jj_consume_token(AC);
        break;
      case TH:
        jj_consume_token(TH);
        break;
      case PA:
        jj_consume_token(PA);
        break;
      case CL:
        jj_consume_token(CL);
        break;
      case B:
        jj_consume_token(B);
        break;
      case C:
        jj_consume_token(C);
        break;
      case N:
        jj_consume_token(N);
        break;
      case O:
        jj_consume_token(O);
        break;
      case F:
        jj_consume_token(F);
        break;
      case P:
        jj_consume_token(P);
        break;
      case S:
        jj_consume_token(S);
        break;
      case K:
        jj_consume_token(K);
        break;
      case V:
        jj_consume_token(V);
        break;
      case Y:
        jj_consume_token(Y);
        break;
      case I:
        jj_consume_token(I);
        break;
      case U:
        jj_consume_token(U);
        break;
      case c:
        jj_consume_token(c);
        break;
      case o:
        jj_consume_token(o);
        break;
      case n:
        jj_consume_token(n);
        break;
      case s:
        jj_consume_token(s);
        break;
      case p:
        jj_consume_token(p);
        break;
      case as:
        jj_consume_token(as);
        break;
      case se:
        jj_consume_token(se);
        break;
      case PU:
        jj_consume_token(PU);
        break;
      case AM:
        jj_consume_token(AM);
        break;
      case CM:
        jj_consume_token(CM);
        break;
      case BK:
        jj_consume_token(BK);
        break;
      case CF:
        jj_consume_token(CF);
        break;
      case ES:
        jj_consume_token(ES);
        break;
      case FM:
        jj_consume_token(FM);
        break;
      case MD:
        jj_consume_token(MD);
        break;
      case NO:
        jj_consume_token(NO);
        break;
      case LR:
        jj_consume_token(LR);
        break;
      case NP:
        jj_consume_token(NP);
        break;
      case CE:
        jj_consume_token(CE);
        break;
      case ND:
        jj_consume_token(ND);
        break;
      case PM:
        jj_consume_token(PM);
        break;
      case SM:
        jj_consume_token(SM);
        break;
      case EU:
        jj_consume_token(EU);
        break;
      case GD:
        jj_consume_token(GD);
        break;
      case TB:
        jj_consume_token(TB);
        break;
      case DY:
        jj_consume_token(DY);
        break;
      case HO:
        jj_consume_token(HO);
        break;
      case ER:
        jj_consume_token(ER);
        break;
      case TM:
        jj_consume_token(TM);
        break;
      case YB:
        jj_consume_token(YB);
        break;
      case LU:
        jj_consume_token(LU);
        break;
      case PR:
        jj_consume_token(PR);
        break;
      default:
        jj_la1[57] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
        jjtn000.setSymbol(token.image);
    } finally {
          if (jjtc000) {
            jjtree.closeNodeScope(jjtn000, true);
          }
    }
  }

  final private boolean jj_2_1(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_1(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(0, xla); }
  }

  final private boolean jj_2_2(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_2(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(1, xla); }
  }

  final private boolean jj_2_3(int xla) {
    jj_la = xla; jj_lastpos = jj_scanpos = token;
    try { return !jj_3_3(); }
    catch(LookaheadSuccess ls) { return true; }
    finally { jj_save(2, xla); }
  }

  final private boolean jj_3_2() {
    if (jj_scan_token(149)) return true;
    Token xsp;
    xsp = jj_scanpos;
    if (jj_3R_17()) jj_scanpos = xsp;
    return false;
  }

  final private boolean jj_3_3() {
    if (jj_scan_token(R_BOND)) return true;
    return false;
  }

  final private boolean jj_3R_18() {
    if (jj_scan_token(DIGIT)) return true;
    return false;
  }

  final private boolean jj_3R_17() {
    Token xsp;
    if (jj_3R_18()) return true;
    while (true) {
      xsp = jj_scanpos;
      if (jj_3R_18()) { jj_scanpos = xsp; break; }
    }
    return false;
  }

  final private boolean jj_3_1() {
    if (jj_scan_token(S_BOND)) return true;
    return false;
  }

  public SMARTSParserTokenManager token_source;
  SimpleCharStream jj_input_stream;
  public Token token, jj_nt;
  private int jj_ntk;
  private Token jj_scanpos, jj_lastpos;
  private int jj_la;
  public boolean lookingAhead = false;
  private boolean jj_semLA;
  private int jj_gen;
  final private int[] jj_la1 = new int[58];
  static private int[] jj_la1_0;
  static private int[] jj_la1_1;
  static private int[] jj_la1_2;
  static private int[] jj_la1_3;
  static private int[] jj_la1_4;
  static private int[] jj_la1_5;
  static {
      jj_la1_0();
      jj_la1_1();
      jj_la1_2();
      jj_la1_3();
      jj_la1_4();
      jj_la1_5();
   }
   private static void jj_la1_0() {
      jj_la1_0 = new int[] {0xf87f0000,0x0,0xf87f0000,0x0,0x0,0x0,0x0,0x0,0xf87fffe0,0xffe0,0xf87f0000,0xffe0,0xf87fffe0,0x0,0xf87f0000,0x4,0x10,0x8,0xffe0,0x20,0xff80,0xf87f0000,0x4,0x10,0x8,0xffff9060,0x20,0xffff9040,0xffff9040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff7f0000,};
   }
   private static void jj_la1_1() {
      jj_la1_1 = new int[] {0x20000e0,0x0,0x20000e0,0x0,0x0,0x0,0x0,0x0,0x20000e0,0x0,0x20000e0,0x0,0x20000e0,0x0,0x20000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000e0,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,};
   }
   private static void jj_la1_2() {
      jj_la1_2 = new int[] {0x800,0x0,0x800,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x800,0x0,0x800,0x0,0x800,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffffff,};
   }
   private static void jj_la1_3() {
      jj_la1_3 = new int[] {0x40000000,0x0,0x40000000,0x0,0x0,0x0,0x0,0x0,0x40000000,0x0,0x40000000,0x0,0x40000000,0x0,0x40000000,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,0x0,0x0,0x0,0xffffffff,0x0,0xffffffff,0xffffffff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fffffff,};
   }
   private static void jj_la1_4() {
      jj_la1_4 = new int[] {0x5003,0x40000,0xc5003,0x1000,0x2000,0x100000,0x1000,0x2000,0x25003,0x0,0x24003,0x0,0x25003,0x20000,0x4003,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0xffe00fff,0x0,0xffe00fff,0xffe007ff,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0xffc00000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x20000,0x10000,0x0,0x0,};
   }
   private static void jj_la1_5() {
      jj_la1_5 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f,0x0,0x1f,0x1f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,};
   }
  final private JJCalls[] jj_2_rtns = new JJCalls[3];
  private boolean jj_rescan = false;
  private int jj_gc = 0;

  public SMARTSParser(java.io.InputStream stream) {
    jj_input_stream = new SimpleCharStream(stream, 1, 1);
    token_source = new SMARTSParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 58; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public void ReInit(java.io.InputStream stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jjtree.reset();
    jj_gen = 0;
    for (int i = 0; i < 58; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public SMARTSParser(java.io.Reader stream) {
    jj_input_stream = new SimpleCharStream(stream, 1, 1);
    token_source = new SMARTSParserTokenManager(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 58; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public void ReInit(java.io.Reader stream) {
    jj_input_stream.ReInit(stream, 1, 1);
    token_source.ReInit(jj_input_stream);
    token = new Token();
    jj_ntk = -1;
    jjtree.reset();
    jj_gen = 0;
    for (int i = 0; i < 58; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public SMARTSParser(SMARTSParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jj_gen = 0;
    for (int i = 0; i < 58; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  public void ReInit(SMARTSParserTokenManager tm) {
    token_source = tm;
    token = new Token();
    jj_ntk = -1;
    jjtree.reset();
    jj_gen = 0;
    for (int i = 0; i < 58; i++) jj_la1[i] = -1;
    for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
  }

  final private Token jj_consume_token(int kind) throws ParseException {
    Token oldToken;
    if ((oldToken = token).next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    if (token.kind == kind) {
      jj_gen++;
      if (++jj_gc > 100) {
        jj_gc = 0;
        for (int i = 0; i < jj_2_rtns.length; i++) {
          JJCalls c = jj_2_rtns[i];
          while (c != null) {
            if (c.gen < jj_gen) c.first = null;
            c = c.next;
          }
        }
      }
      return token;
    }
    token = oldToken;
    jj_kind = kind;
    throw generateParseException();
  }

  static private final class LookaheadSuccess extends java.lang.Error { }
  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
  final private boolean jj_scan_token(int kind) {
    if (jj_scanpos == jj_lastpos) {
      jj_la--;
      if (jj_scanpos.next == null) {
        jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
      } else {
        jj_lastpos = jj_scanpos = jj_scanpos.next;
      }
    } else {
      jj_scanpos = jj_scanpos.next;
    }
    if (jj_rescan) {
      int i = 0; Token tok = token;
      while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
      if (tok != null) jj_add_error_token(kind, i);
    }
    if (jj_scanpos.kind != kind) return true;
    if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
    return false;
  }

  final public Token getNextToken() {
    if (token.next != null) token = token.next;
    else token = token.next = token_source.getNextToken();
    jj_ntk = -1;
    jj_gen++;
    return token;
  }

  final public Token getToken(int index) {
    Token t = lookingAhead ? jj_scanpos : token;
    for (int i = 0; i < index; i++) {
      if (t.next != null) t = t.next;
      else t = t.next = token_source.getNextToken();
    }
    return t;
  }

  final private int jj_ntk() {
    if ((jj_nt=token.next) == null)
      return (jj_ntk = (token.next=token_source.getNextToken()).kind);
    else
      return (jj_ntk = jj_nt.kind);
  }

  private java.util.Vector jj_expentries = new java.util.Vector();
  private int[] jj_expentry;
  private int jj_kind = -1;
  private int[] jj_lasttokens = new int[100];
  private int jj_endpos;

  private void jj_add_error_token(int kind, int pos) {
    if (pos >= 100) return;
    if (pos == jj_endpos + 1) {
      jj_lasttokens[jj_endpos++] = kind;
    } else if (jj_endpos != 0) {
      jj_expentry = new int[jj_endpos];
      for (int i = 0; i < jj_endpos; i++) {
        jj_expentry[i] = jj_lasttokens[i];
      }
      boolean exists = false;
      for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) {
        int[] oldentry = (int[])(e.nextElement());
        if (oldentry.length == jj_expentry.length) {
          exists = true;
          for (int i = 0; i < jj_expentry.length; i++) {
            if (oldentry[i] != jj_expentry[i]) {
              exists = false;
              break;
            }
          }
          if (exists) break;
        }
      }
      if (!exists) jj_expentries.addElement(jj_expentry);
      if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
    }
  }

  public ParseException generateParseException() {
    jj_expentries.removeAllElements();
    boolean[] la1tokens = new boolean[165];
    for (int i = 0; i < 165; i++) {
      la1tokens[i] = false;
    }
    if (jj_kind >= 0) {
      la1tokens[jj_kind] = true;
      jj_kind = -1;
    }
    for (int i = 0; i < 58; i++) {
      if (jj_la1[i] == jj_gen) {
        for (int j = 0; j < 32; j++) {
          if ((jj_la1_0[i] & (1<<j)) != 0) {
            la1tokens[j] = true;
          }
          if ((jj_la1_1[i] & (1<<j)) != 0) {
            la1tokens[32+j] = true;
          }
          if ((jj_la1_2[i] & (1<<j)) != 0) {
            la1tokens[64+j] = true;
          }
          if ((jj_la1_3[i] & (1<<j)) != 0) {
            la1tokens[96+j] = true;
          }
          if ((jj_la1_4[i] & (1<<j)) != 0) {
            la1tokens[128+j] = true;
          }
          if ((jj_la1_5[i] & (1<<j)) != 0) {
            la1tokens[160+j] = true;
          }
        }
      }
    }
    for (int i = 0; i < 165; i++) {
      if (la1tokens[i]) {
        jj_expentry = new int[1];
        jj_expentry[0] = i;
        jj_expentries.addElement(jj_expentry);
      }
    }
    jj_endpos = 0;
    jj_rescan_token();
    jj_add_error_token(0, 0);
    int[][] exptokseq = new int[jj_expentries.size()][];
    for (int i = 0; i < jj_expentries.size(); i++) {
      exptokseq[i] = (int[])jj_expentries.elementAt(i);
    }
    return new ParseException(token, exptokseq, tokenImage);
  }

  final public void enable_tracing() {
  }

  final public void disable_tracing() {
  }

  final private void jj_rescan_token() {
    jj_rescan = true;
    for (int i = 0; i < 3; i++) {
      JJCalls p = jj_2_rtns[i];
      do {
        if (p.gen > jj_gen) {
          jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
          switch (i) {
            case 0: jj_3_1(); break;
            case 1: jj_3_2(); break;
            case 2: jj_3_3(); break;
          }
        }
        p = p.next;
      } while (p != null);
    }
    jj_rescan = false;
  }

  final private void jj_save(int index, int xla) {
    JJCalls p = jj_2_rtns[index];
    while (p.gen > jj_gen) {
      if (p.next == null) { p = p.next = new JJCalls(); break; }
      p = p.next;
    }
    p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
  }

  static final class JJCalls {
    int gen;
    Token first;
    int arg;
    JJCalls next;
  }

}
