diff options
Diffstat (limited to 'kalzium/src/moleculeparser.cpp')
-rw-r--r-- | kalzium/src/moleculeparser.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/kalzium/src/moleculeparser.cpp b/kalzium/src/moleculeparser.cpp new file mode 100644 index 00000000..183f9769 --- /dev/null +++ b/kalzium/src/moleculeparser.cpp @@ -0,0 +1,304 @@ +/*************************************************************************** + copyright : (C) 2005 by Inge Wallin + email : inge@lysator.liu.se + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#include <ctype.h> + +#include <kdebug.h> + +#include "kalziumdataobject.h" +#include "moleculeparser.h" + + +// ================================================================ +// class ElementCountMap + + + +ElementCountMap::ElementCountMap() +{ + m_map.clear(); +} + + +ElementCountMap::~ElementCountMap() +{ +} + + +ElementCount * +ElementCountMap::search(Element *_element) +{ + QValueList<ElementCount *>::ConstIterator it = m_map.constBegin(); + const QValueList<ElementCount *>::ConstIterator itEnd = m_map.constEnd(); + + for (; it != itEnd; ++it) { + if ((*it)->element() == _element) + return *it; + } + + return 0; +} + + +void +ElementCountMap::add(ElementCountMap &_map) +{ + QValueList<ElementCount *>::ConstIterator it = _map.m_map.constBegin(); + const QValueList<ElementCount *>::ConstIterator itEnd = _map.m_map.constEnd(); + + // Step throught _map and for each element, add it to the current one. + for (; it != itEnd; ++it) { + add((*it)->m_element, (*it)->m_count); + } + +} + + +void +ElementCountMap::add(Element *_element, int _count) +{ + ElementCount *elemCount; + + elemCount = search(_element); + if (elemCount) + elemCount->m_count += _count; + else + m_map.append(new ElementCount(_element, _count)); +} + + +void +ElementCountMap::multiply(int _factor) +{ + Iterator it = begin(); + Iterator itEnd = end(); + + for (; it != itEnd; ++it) + (*it)->multiply(_factor); +} + + +// ================================================================ +// class MoleculeParser + + +MoleculeParser::MoleculeParser() + : Parser() +{ +} + + +MoleculeParser::MoleculeParser(const QString& _str) + : Parser(_str) +{ +} + + +MoleculeParser::~MoleculeParser() +{ + //Parser::~Parser(); +} + + +// ---------------------------------------------------------------- +// public methods + + +// Try to parse the molecule and get the weight of it. +// +// This method also acts as the main loop. + +bool +MoleculeParser::weight(QString _moleculeString, + double *_resultMass, + ElementCountMap *_resultMap) +{ + // Clear the result variables and set m_error to false + _resultMap->clear(); + m_error = false; + *_resultMass = 0.0; + + // Initialize the parsing process, and parse te molecule. + start(_moleculeString); + parseSubmolecule(_resultMass, _resultMap); + + if (nextToken() != -1) + return false; + + if ( m_error )//there was an error in the input... + return false; + + return true; +} + + +// ---------------------------------------------------------------- +// helper methods for the public methods + + +// Parse a submolecule. This is a list of terms. +// + +bool +MoleculeParser::parseSubmolecule(double *_resultMass, + ElementCountMap *_resultMap) +{ + double subMass = 0.0; + ElementCountMap subMap; + + *_resultMass = 0.0; + _resultMap->clear(); + while (parseTerm(&subMass, &subMap)) { + //kdDebug() << "Parsed a term, weight = " << subresult << endl; + + // Add the mass and composition of the submolecule to the total. + *_resultMass += subMass; + _resultMap->add(subMap); + } + + return true; +} + + +// Parse a term within the molecule, i.e. a single atom or a +// submolecule within parenthesis followed by an optional number. +// Examples: Bk, Mn2, (COOH)2 +// +// Return true if correct, otherwise return false. + +// If correct, the mass of the term is returned in *_resultMass, and +// the flattened composition of the molecule in *_resultMap. +// + +bool +MoleculeParser::parseTerm(double *_resultMass, + ElementCountMap *_resultMap) +{ + *_resultMass = 0.0; + _resultMap->clear(); + +#if 0 + kdDebug() << "parseTerm(): Next token = " + << nextToken() << endl; +#endif + if (nextToken() == ELEMENT_TOKEN) { + //kdDebug() << "Parsed an element: " << m_elementVal->symbol() << endl; + *_resultMass = m_elementVal->mass(); + _resultMap->add(m_elementVal, 1); + + getNextToken(); + } + + else if (nextToken() == '(') { + // A submolecule. + + getNextToken(); + parseSubmolecule(_resultMass, _resultMap); + + // Must end in a ")". + if (nextToken() == ')') { + //kdDebug() << "Parsed a submolecule. weight = " << *_result << endl; + getNextToken(); + } + else + return false; + } + else + // Neither an element nor a list within (). + return false; + + // Optional number. + if (nextToken() == INT_TOKEN) { + //kdDebug() << "Parsed a number: " << intVal() << endl; + + *_resultMass *= intVal(); + _resultMap->multiply(intVal()); + + getNextToken(); + } + + kdDebug() << "Weight of term = " << *_resultMass << endl; + return true; +} + + +// ---------------------------------------------------------------- +// protected methods + + +// Extend Parser::getNextToken with elements. + +int +MoleculeParser::getNextToken() +{ + QString elementName; + +#if 0 + kdDebug() << "getNextToken(): Next character = " + << nextChar() << endl; +#endif + + // Check if the token is an element name. + if ('A' <= nextChar() && nextChar() <= 'Z') { + elementName = char(nextChar()); + getNextChar(); + + if ('a' <= nextChar() && nextChar() <= 'z') { + elementName.append(char(nextChar())); + getNextChar(); + } + + // Look up the element from the name.. + m_elementVal = lookupElement(elementName); + if (m_elementVal) + { + m_nextToken = ELEMENT_TOKEN; + } + else + m_nextToken = -1; + } + else + return Parser::getNextToken(); + + return m_nextToken; +} + + +// ---------------------------------------------------------------- +// private methods + + +Element * +MoleculeParser::lookupElement( const QString& _name ) +{ + EList elementList = KalziumDataObject::instance()->ElementList; + + //kdDebug() << "looking up " << _name << endl; + + EList::ConstIterator it = elementList.constBegin(); + const EList::ConstIterator end = elementList.constEnd(); + + for (; it != end; ++it) { + if ( (*it)->symbol() == _name ) { + kdDebug() << "Found element " << _name << endl; + return *it; + } + } + + //if there is an error make m_error true. + m_error = true; + + kdDebug() << k_funcinfo << "no such element, parsing error!: " << _name << endl; + return NULL; +} |