您最多能選擇 25 個主題 主題必須以字母或數字為開頭,可包含連接號「-」且最長為 35 個字元。
koffice/kformula/fsparser.cc

830 行
26 KiB

/* This file is part of the KDE project
Copyright (C) 2002 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <tqptrlist.h>
#include <kdebug.h>
#include <tdelocale.h>
#include <kformuladefs.h>
#include <kformuladocument.h>
#include <symboltable.h>
#include "fsparser.h"
using namespace std;
class ParserNode {
public:
ParserNode() { debugCount++; }
virtual ~ParserNode() { debugCount--; }
//virtual void output( ostream& ) = 0;
virtual void buildXML( TQDomDocument& doc, TQDomElement element ) = 0;
virtual bool isSimple() { return false; }
static int debugCount;
};
int ParserNode::debugCount = 0;
class PrimaryNode : public ParserNode {
public:
PrimaryNode( TQString primary ) : m_primary( primary ), m_functionName( false ) {}
//virtual void output( ostream& stream ) { stream << "PrimaryNode {" << m_primary << "}" << endl; }
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
virtual bool isSimple() { return true; }
void setUnicode( TQChar unicode ) { m_unicode = unicode; }
void setFunctionName( bool functionName ) { m_functionName = functionName; }
TQString primary() const { return m_primary; }
private:
TQString m_primary;
TQChar m_unicode;
bool m_functionName;
};
void PrimaryNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
if ( m_unicode != TQChar::null ) {
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", TQString( m_unicode ) );
de.setAttribute( "SYMBOL", "3" );
element.appendChild( de );
}
else {
if ( m_functionName ) {
TQDomElement namesequence = doc.createElement( "NAMESEQUENCE" );
element.appendChild( namesequence );
element = namesequence;
}
for ( uint i = 0; i < m_primary.length(); i++ ) {
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", TQString( m_primary[i] ) );
element.appendChild( de );
}
}
}
class UnaryMinus : public ParserNode {
public:
UnaryMinus( ParserNode* primary ) : m_primary( primary ) {}
~UnaryMinus() { delete m_primary; }
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
private:
ParserNode* m_primary;
};
void UnaryMinus::buildXML( TQDomDocument& doc, TQDomElement element )
{
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", "-" );
element.appendChild( de );
m_primary->buildXML( doc, element );
}
class OperatorNode : public ParserNode {
public:
OperatorNode( TQString type, ParserNode* lhs, ParserNode* rhs )
: m_type( type ), m_lhs( lhs ), m_rhs( rhs ) {}
~OperatorNode() { delete m_rhs; delete m_lhs; }
// virtual void output( ostream& stream ) {
// stream << "OperatorNode {";
// m_lhs->output( stream ); stream << m_type; m_rhs->output( stream );
// stream << "}" << endl; }
protected:
TQString m_type;
ParserNode* m_lhs;
ParserNode* m_rhs;
};
class AssignNode : public OperatorNode {
public:
AssignNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
};
void AssignNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
m_lhs->buildXML( doc, element );
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", TQString( m_type ) );
element.appendChild( de );
m_rhs->buildXML( doc, element );
}
class ExprNode : public OperatorNode {
public:
ExprNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
};
void ExprNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
m_lhs->buildXML( doc, element );
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", TQString( m_type ) );
element.appendChild( de );
m_rhs->buildXML( doc, element );
}
class TermNode : public OperatorNode {
public:
TermNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
};
void TermNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
if ( m_type == "*" ) {
m_lhs->buildXML( doc, element );
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", TQString( m_type ) );
element.appendChild( de );
m_rhs->buildXML( doc, element );
}
else {
TQDomElement fraction = doc.createElement( "FRACTION" );
TQDomElement numerator = doc.createElement( "NUMERATOR" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
m_lhs->buildXML( doc, sequence );
numerator.appendChild( sequence );
fraction.appendChild( numerator );
TQDomElement denominator = doc.createElement( "DENOMINATOR" );
sequence = doc.createElement( "SEQUENCE" );
m_rhs->buildXML( doc, sequence );
denominator.appendChild( sequence );
fraction.appendChild( denominator );
element.appendChild( fraction );
}
}
class PowerNode : public OperatorNode {
public:
PowerNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
};
void PowerNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
TQDomElement index = doc.createElement( "INDEX" );
TQDomElement content = doc.createElement( "CONTENT" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
content.appendChild( sequence );
index.appendChild( content );
if ( !m_lhs->isSimple() ) {
TQDomElement bracket = doc.createElement( "BRACKET" );
bracket.setAttribute( "LEFT", '(' );
bracket.setAttribute( "RIGHT", ')' );
sequence.appendChild( bracket );
content = doc.createElement( "CONTENT" );
bracket.appendChild( content );
sequence = doc.createElement( "SEQUENCE" );
content.appendChild( sequence );
}
m_lhs->buildXML( doc, sequence );
if ( m_type == "_" ) {
TQDomElement lowerRight = doc.createElement( "LOWERRIGHT" );
sequence = doc.createElement( "SEQUENCE" );
m_rhs->buildXML( doc, sequence );
lowerRight.appendChild( sequence );
index.appendChild( lowerRight );
}
else {
TQDomElement upperRight = doc.createElement( "UPPERRIGHT" );
sequence = doc.createElement( "SEQUENCE" );
m_rhs->buildXML( doc, sequence );
upperRight.appendChild( sequence );
index.appendChild( upperRight );
}
element.appendChild( index );
}
class FunctionNode : public ParserNode {
public:
FunctionNode( PrimaryNode* name, TQPtrList<ParserNode>& args ) : m_name( name ), m_args( args ) {
m_args.setAutoDelete( true );
}
~FunctionNode() { delete m_name; }
//virtual void output( ostream& stream );
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
private:
void buildSymbolXML( TQDomDocument& doc, TQDomElement element, KFormula::SymbolType type );
PrimaryNode* m_name;
TQPtrList<ParserNode> m_args;
};
void FunctionNode::buildSymbolXML( TQDomDocument& doc, TQDomElement element, KFormula::SymbolType type )
{
TQDomElement symbol = doc.createElement( "SYMBOL" );
symbol.setAttribute( "TYPE", type );
TQDomElement content = doc.createElement( "CONTENT" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
m_args.at( 0 )->buildXML( doc, sequence );
content.appendChild( sequence );
symbol.appendChild( content );
if ( m_args.count() > 2 ) {
ParserNode* lowerLimit = m_args.at( m_args.count()-2 );
ParserNode* upperLimit = m_args.at( m_args.count()-1 );
TQDomElement lower = doc.createElement( "LOWER" );
sequence = doc.createElement( "SEQUENCE" );
lowerLimit->buildXML( doc, sequence );
lower.appendChild( sequence );
symbol.appendChild( lower );
TQDomElement upper = doc.createElement( "UPPER" );
sequence = doc.createElement( "SEQUENCE" );
upperLimit->buildXML( doc, sequence );
upper.appendChild( sequence );
symbol.appendChild( upper );
}
element.appendChild( symbol );
}
void FunctionNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
if ( ( m_name->primary() == "sqrt" ) && ( m_args.count() == 1 ) ) {
TQDomElement root = doc.createElement( "ROOT" );
TQDomElement content = doc.createElement( "CONTENT" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
m_args.at( 0 )->buildXML( doc, sequence );
content.appendChild( sequence );
root.appendChild( content );
element.appendChild( root );
}
else if ( ( m_name->primary() == "pow" ) && ( m_args.count() == 2 ) ) {
TQDomElement index = doc.createElement( "INDEX" );
TQDomElement content = doc.createElement( "CONTENT" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
m_args.at( 0 )->buildXML( doc, sequence );
content.appendChild( sequence );
index.appendChild( content );
TQDomElement upperRight = doc.createElement( "UPPERRIGHT" );
sequence = doc.createElement( "SEQUENCE" );
m_args.at( 1 )->buildXML( doc, sequence );
upperRight.appendChild( sequence );
index.appendChild( upperRight );
element.appendChild( index );
}
else if ( ( m_name->primary() == "sum" ) && ( m_args.count() > 0 ) ) {
buildSymbolXML( doc, element, KFormula::Sum );
}
else if ( ( m_name->primary() == "prod" ) && ( m_args.count() > 0 ) ) {
buildSymbolXML( doc, element, KFormula::Product );
}
else if ( ( ( m_name->primary() == "int" ) ||
( m_name->primary() == "integrate" ) ||
( m_name->primary() == "quad" ) )
&& ( m_args.count() > 0 ) ) {
buildSymbolXML( doc, element, KFormula::Integral );
}
else {
m_name->buildXML( doc, element );
TQDomElement bracket = doc.createElement( "BRACKET" );
bracket.setAttribute( "LEFT", '(' );
bracket.setAttribute( "RIGHT", ')' );
TQDomElement content = doc.createElement( "CONTENT" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
for ( uint i = 0; i < m_args.count(); i++ ) {
m_args.at( i )->buildXML( doc, sequence );
if ( i < m_args.count()-1 ) {
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", "," );
sequence.appendChild( de );
}
}
content.appendChild( sequence );
bracket.appendChild( content );
element.appendChild( bracket );
}
}
// void FunctionNode::output( ostream& stream )
// {
// m_name->output( stream );
// for ( uint i = 0; i < m_args.count(); i++ ) {
// m_args.at( i )->output( stream );
// }
// }
class RowNode : public ParserNode {
public:
RowNode( TQPtrList<ParserNode> row ) : m_row( row ) { m_row.setAutoDelete( true ); }
//virtual void output( ostream& stream );
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
uint columns() const { return m_row.count(); }
void setRequiredColumns( uint requiredColumns ) { m_requiredColumns = requiredColumns; }
private:
TQPtrList<ParserNode> m_row;
uint m_requiredColumns;
};
void RowNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
for ( uint i = 0; i < m_requiredColumns; i++ ) {
TQDomElement sequence = doc.createElement( "SEQUENCE" );
if ( i < m_row.count() ) {
m_row.at( i )->buildXML( doc, sequence );
}
else {
TQDomElement de = doc.createElement( "TEXT" );
de.setAttribute( "CHAR", "0" );
sequence.appendChild( de );
}
element.appendChild( sequence );
}
}
// void RowNode::output( ostream& stream )
// {
// stream << "[";
// for ( uint i = 0; i < m_row.count(); i++ ) {
// m_row.at( i )->output( stream );
// if ( i < m_row.count()-1 ) {
// stream << ", ";
// }
// }
// stream << "]";
// }
class MatrixNode : public ParserNode {
public:
MatrixNode( TQPtrList<RowNode> rows ) : m_rows( rows ) { m_rows.setAutoDelete( true ); }
//virtual void output( ostream& stream );
virtual void buildXML( TQDomDocument& doc, TQDomElement element );
virtual bool isSimple() { return true; }
uint columns();
uint rows() { return m_rows.count(); }
private:
TQPtrList<RowNode> m_rows;
};
uint MatrixNode::columns()
{
uint columns = 0;
for ( uint i = 0; i < m_rows.count(); i++ ) {
columns = TQMAX( columns, m_rows.at( i )->columns() );
}
return columns;
}
void MatrixNode::buildXML( TQDomDocument& doc, TQDomElement element )
{
TQDomElement bracket = doc.createElement( "BRACKET" );
bracket.setAttribute( "LEFT", '(' );
bracket.setAttribute( "RIGHT", ')' );
TQDomElement content = doc.createElement( "CONTENT" );
TQDomElement sequence = doc.createElement( "SEQUENCE" );
uint cols = columns();
TQDomElement matrix = doc.createElement( "MATRIX" );
matrix.setAttribute( "ROWS", m_rows.count() );
matrix.setAttribute( "COLUMNS", cols );
for ( uint i = 0; i < m_rows.count(); i++ ) {
m_rows.at( i )->setRequiredColumns( cols );
m_rows.at( i )->buildXML( doc, matrix );
matrix.appendChild( doc.createComment( "end of row" ) );
}
sequence.appendChild( matrix );
content.appendChild( sequence );
bracket.appendChild( content );
element.appendChild( bracket );
}
// void MatrixNode::output( ostream& stream )
// {
// stream << "[";
// for ( uint i = 0; i < m_rows.count(); i++ ) {
// m_rows.at( i )->output( stream );
// if ( i < m_rows.count()-1 ) {
// stream << ", ";
// }
// }
// stream << "]";
// }
FormulaStringParser::FormulaStringParser( const KFormula::SymbolTable& symbolTable, TQString formula )
: m_symbolTable( symbolTable ), m_formula( formula ),
pos( 0 ), line( 1 ), column( 1 ), m_newlineIsSpace( true )
{
}
FormulaStringParser::~FormulaStringParser()
{
delete head;
if ( ParserNode::debugCount != 0 ) {
kdDebug( KFormula::DEBUGID ) << "ParserNode::debugCount = " << ParserNode::debugCount << endl;
}
}
TQDomDocument FormulaStringParser::parse()
{
nextToken();
head = parseAssign();
//head->output( cout );
if ( !eol() ) {
error( TQString( i18n( "Aborted parsing at %1:%2" ) ).arg( line ).arg( column ) );
}
TQDomDocument doc = KFormula::Document::createDomDocument();
TQDomElement root = doc.documentElement();
TQDomElement de = doc.createElement( "FORMULA" );
// here comes the current version of FormulaElement
//de.setAttribute( "VERSION", "4" );
head->buildXML( doc, de );
root.appendChild(de);
kdDebug( 39001 ) << doc.toString() << endl;
return doc;
}
ParserNode* FormulaStringParser::parseAssign()
{
ParserNode* lhs = parseExpr();
for ( ;; ) {
switch ( currentType ) {
case ASSIGN: {
TQString c = current;
nextToken();
lhs = new AssignNode( c, lhs, parseExpr() );
break;
}
default:
return lhs;
}
}
}
ParserNode* FormulaStringParser::parseExpr()
{
ParserNode* lhs = parseTerm();
for ( ;; ) {
switch ( currentType ) {
case PLUS:
case SUB: {
TQString c = current;
nextToken();
lhs = new ExprNode( c, lhs, parseTerm() );
break;
}
default:
return lhs;
}
}
}
ParserNode* FormulaStringParser::parseTerm()
{
ParserNode* lhs = parsePower();
for ( ;; ) {
switch ( currentType ) {
case MUL:
case DIV: {
TQString c = current;
nextToken();
lhs = new TermNode( c, lhs, parsePower() );
break;
}
default:
return lhs;
}
}
}
ParserNode* FormulaStringParser::parsePower()
{
ParserNode* lhs = parsePrimary();
for ( ;; ) {
switch ( currentType ) {
case INDEX:
case POW: {
TQString c = current;
nextToken();
lhs = new PowerNode( c, lhs, parsePrimary() );
break;
}
default:
return lhs;
}
}
}
ParserNode* FormulaStringParser::parsePrimary()
{
switch ( currentType ) {
case NUMBER: {
PrimaryNode* node = new PrimaryNode( current );
nextToken();
return node;
}
case NAME: {
PrimaryNode* node = new PrimaryNode( current );
node->setUnicode( m_symbolTable.unicode( current ) );
nextToken();
if ( currentType == LP ) {
nextToken();
TQPtrList<ParserNode> args;
args.setAutoDelete( false );
while ( ( currentType != EOL ) && ( currentType != RP ) ) {
ParserNode* node = parseExpr();
args.append( node );
if ( currentType == COMMA ) {
nextToken();
}
}
expect( RP, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ")" ) );
node->setFunctionName( true );
return new FunctionNode( node, args );
}
return node;
}
case SUB: {
nextToken();
//ParserNode* node = new UnaryMinus( parsePrimary() );
ParserNode* node = new UnaryMinus( parseTerm() );
return node;
}
case LP: {
nextToken();
ParserNode* node = parseExpr();
expect( RP, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ")" ) );
return node;
}
case LB: {
nextToken();
TQPtrList<RowNode> rows;
rows.setAutoDelete( false );
bool innerBrackets = currentType == LB;
m_newlineIsSpace = innerBrackets;
while ( ( currentType != EOL ) && ( currentType != RB ) ) {
if ( innerBrackets ) {
expect( LB, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "[" ) );
}
TQPtrList<ParserNode> row;
row.setAutoDelete( false );
while ( ( currentType != EOL ) && ( currentType != RB ) &&
( innerBrackets || ( currentType != SEMIC && currentType != NEWLINE ) ) ) {
row.append( parseExpr() );
if ( currentType == COMMA ) {
nextToken();
}
}
if ( innerBrackets ) {
expect( RB, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "]" ) );
if ( currentType == COMMA ) {
nextToken();
}
}
else {
if ( currentType != RB ) {
if ( currentType == NEWLINE ) {
nextToken();
}
else {
expect( SEMIC, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ";" ) );
}
}
}
rows.append( new RowNode( row ) );
}
m_newlineIsSpace = true;
expect( RB, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "]" ) );
MatrixNode* node = new MatrixNode( rows );
if ( node->columns() == 0 ) {
error( TQString( i18n( "Null columns in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
}
if ( node->rows() == 0 ) {
error( TQString( i18n( "Null rows in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
}
return node;
}
case OTHER: {
ParserNode* node = new PrimaryNode( current );
nextToken();
return node;
}
default:
error( TQString( i18n( "Unexpected token at %1:%2" ) ).arg( line ).arg( column ) );
return new PrimaryNode( "?" );
}
}
void FormulaStringParser::expect( TokenType type, TQString msg )
{
if ( currentType == type ) {
nextToken();
}
else {
error( msg );
}
}
TQString FormulaStringParser::nextToken()
{
// We skip any ' or " so that we can parse string literals.
while ( !eol() && ( m_formula[pos].isSpace() ||
( m_formula[pos] == '"' ) ||
( m_formula[pos] == '\'' ) ) ) {
if ( m_formula[pos] == '\n' ) {
line++;
if ( m_newlineIsSpace ) {
column = 0;
}
else {
pos++;
column = 1;
currentType = NEWLINE;
return current = "\n";
}
}
pos++; column++;
}
if ( eol() ) {
currentType = EOL;
return TQString();
}
if ( m_formula[pos].isDigit() || m_formula[pos] == '.' ) {
uint begin = pos;
readNumber();
currentType = NUMBER;
current = m_formula.mid( begin, pos-begin );
if ( current[0] == '.' ) {
current = "0" + current;
}
if ( current[current.length()-1] == '.' ) {
current = current + "0";
}
return current;
}
else if ( m_formula[pos].isLetter() ) {
uint begin = pos;
pos++; column++;
while ( !eol() && m_formula[pos].isLetter() ) {
pos++; column++;
}
currentType = NAME;
return current = m_formula.mid( begin, pos-begin );
}
else {
switch ( m_formula[pos].latin1() ) {
case '+':
pos++; column++;
currentType = PLUS;
return current = "+";
case '-':
pos++; column++;
currentType = SUB;
return current = "-";
case '*':
pos++; column++;
if ( !eol() && m_formula[pos] == '*' ) {
pos++; column++;
currentType = POW;
return current = "**";
}
currentType = MUL;
return current = "*";
case '/':
pos++; column++;
currentType = DIV;
return current = "/";
case '^':
pos++; column++;
currentType = POW;
return current = "**";
case '_':
pos++; column++;
currentType = INDEX;
return current = "_";
case '(':
pos++; column++;
currentType = LP;
return current = "(";
case ')':
pos++; column++;
currentType = RP;
return current = ")";
case '[':
pos++; column++;
currentType = LB;
return current = "[";
case ']':
pos++; column++;
currentType = RB;
return current = "]";
case ',':
pos++; column++;
currentType = COMMA;
return current = ",";
case ';':
pos++; column++;
currentType = SEMIC;
return current = ";";
case '=':
pos++; column++;
currentType = ASSIGN;
return current = "=";
default:
pos++; column++;
currentType = OTHER;
return current = m_formula.mid( pos-1, 1 );
}
}
}
void FormulaStringParser::readNumber()
{
bool digitsBeforeDot = m_formula[pos] != '.';
readDigits();
if ( pos < m_formula.length()-1 ) {
TQChar ch = m_formula[pos];
// Look for a dot.
if ( ch == '.' ) {
pos++;
column++;
ch = m_formula[pos];
if ( ch.isDigit() ) {
readDigits();
}
else if ( !digitsBeforeDot ) {
error( TQString( i18n( "A single '.' is not a number at %1:%2" ) ).arg( line ).arg( column ) );
return;
}
}
// there might as well be an exponent
if ( pos < m_formula.length()-1 ) {
ch = m_formula[pos];
if ( ( ch == 'E' ) || ( ch == 'e' ) ) {
pos++;
column++;
ch = m_formula[pos];
// signs are allowed after the exponent
if ( ( ( ch == '+' ) || ( ch == '-' ) ) &&
( pos < m_formula.length()-1 ) ) {
pos++;
column++;
ch = m_formula[pos];
if ( ch.isDigit() ) {
readDigits();
}
else {
pos -= 2;
column -= 2;
return;
}
}
else if ( ch.isDigit() ) {
readDigits();
}
else {
pos--;
column--;
}
}
}
}
}
void FormulaStringParser::readDigits()
{
while ( !eol() && m_formula[pos].isDigit() ) {
pos++;
column++;
}
}
void FormulaStringParser::error( TQString err )
{
kdDebug( KFormula::DEBUGID ) << err << " (" << currentType << "; " << current << ")" << endl;
m_errorList.push_back( err );
}