|
|
|
/***************************************************************************
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
TQValueList<ElementCount *>::ConstIterator it = m_map.constBegin();
|
|
|
|
const TQValueList<ElementCount *>::ConstIterator itEnd = m_map.constEnd();
|
|
|
|
|
|
|
|
for (; it != itEnd; ++it) {
|
|
|
|
if ((*it)->element() == _element)
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ElementCountMap::add(ElementCountMap &_map)
|
|
|
|
{
|
|
|
|
TQValueList<ElementCount *>::ConstIterator it = _map.m_map.constBegin();
|
|
|
|
const TQValueList<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 TQString& _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(TQString _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()
|
|
|
|
{
|
|
|
|
TQString 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 TQString& _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;
|
|
|
|
}
|