kformula

fsparser.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qptrlist.h>
00021 
00022 #include <kdebug.h>
00023 #include <klocale.h>
00024 
00025 #include <kformuladefs.h>
00026 #include <kformuladocument.h>
00027 #include <symboltable.h>
00028 
00029 #include "fsparser.h"
00030 
00031 
00032 using namespace std;
00033 
00034 class ParserNode {
00035 public:
00036     ParserNode() { debugCount++; }
00037     virtual ~ParserNode() { debugCount--; }
00038     //virtual void output( ostream& ) = 0;
00039     virtual void buildXML( QDomDocument& doc, QDomElement element ) = 0;
00040     virtual bool isSimple() { return false; }
00041 
00042     static int debugCount;
00043 };
00044 
00045 int ParserNode::debugCount = 0;
00046 
00047 class PrimaryNode : public ParserNode {
00048 public:
00049     PrimaryNode( QString primary ) : m_primary( primary ), m_functionName( false ) {}
00050     //virtual void output( ostream& stream ) { stream << "PrimaryNode {" << m_primary << "}" << endl; }
00051     virtual void buildXML( QDomDocument& doc, QDomElement element );
00052     virtual bool isSimple() { return true; }
00053     void setUnicode( QChar unicode ) { m_unicode = unicode; }
00054     void setFunctionName( bool functionName ) { m_functionName = functionName; }
00055     QString primary() const { return m_primary; }
00056 private:
00057     QString m_primary;
00058     QChar m_unicode;
00059     bool m_functionName;
00060 };
00061 
00062 void PrimaryNode::buildXML( QDomDocument& doc, QDomElement element )
00063 {
00064     if ( m_unicode != QChar::null ) {
00065         QDomElement de = doc.createElement( "TEXT" );
00066         de.setAttribute( "CHAR", QString( m_unicode ) );
00067         de.setAttribute( "SYMBOL", "3" );
00068         element.appendChild( de );
00069     }
00070     else {
00071         if ( m_functionName ) {
00072             QDomElement namesequence = doc.createElement( "NAMESEQUENCE" );
00073             element.appendChild( namesequence );
00074             element = namesequence;
00075         }
00076         for ( uint i = 0; i < m_primary.length(); i++ ) {
00077             QDomElement de = doc.createElement( "TEXT" );
00078             de.setAttribute( "CHAR", QString( m_primary[i] ) );
00079             element.appendChild( de );
00080         }
00081     }
00082 }
00083 
00084 class UnaryMinus : public ParserNode {
00085 public:
00086     UnaryMinus( ParserNode* primary ) : m_primary( primary ) {}
00087     ~UnaryMinus() { delete m_primary; }
00088     virtual void buildXML( QDomDocument& doc, QDomElement element );
00089 private:
00090     ParserNode* m_primary;
00091 };
00092 
00093 void UnaryMinus::buildXML( QDomDocument& doc, QDomElement element )
00094 {
00095     QDomElement de = doc.createElement( "TEXT" );
00096     de.setAttribute( "CHAR", "-" );
00097     element.appendChild( de );
00098     m_primary->buildXML( doc, element );
00099 }
00100 
00101 class OperatorNode : public ParserNode {
00102 public:
00103     OperatorNode( QString type, ParserNode* lhs, ParserNode* rhs )
00104         : m_type( type ), m_lhs( lhs ), m_rhs( rhs ) {}
00105     ~OperatorNode() { delete m_rhs; delete m_lhs; }
00106 //     virtual void output( ostream& stream ) {
00107 //         stream << "OperatorNode {";
00108 //         m_lhs->output( stream ); stream << m_type; m_rhs->output( stream );
00109 //         stream << "}" << endl; }
00110 protected:
00111     QString m_type;
00112     ParserNode* m_lhs;
00113     ParserNode* m_rhs;
00114 };
00115 
00116 class AssignNode : public OperatorNode {
00117 public:
00118     AssignNode( QString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
00119     virtual void buildXML( QDomDocument& doc, QDomElement element );
00120 };
00121 
00122 void AssignNode::buildXML( QDomDocument& doc, QDomElement element )
00123 {
00124     m_lhs->buildXML( doc, element );
00125     QDomElement de = doc.createElement( "TEXT" );
00126     de.setAttribute( "CHAR", QString( m_type ) );
00127     element.appendChild( de );
00128     m_rhs->buildXML( doc, element );
00129 }
00130 
00131 class ExprNode : public OperatorNode {
00132 public:
00133     ExprNode( QString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
00134     virtual void buildXML( QDomDocument& doc, QDomElement element );
00135 };
00136 
00137 void ExprNode::buildXML( QDomDocument& doc, QDomElement element )
00138 {
00139     m_lhs->buildXML( doc, element );
00140     QDomElement de = doc.createElement( "TEXT" );
00141     de.setAttribute( "CHAR", QString( m_type ) );
00142     element.appendChild( de );
00143     m_rhs->buildXML( doc, element );
00144 }
00145 
00146 class TermNode : public OperatorNode {
00147 public:
00148     TermNode( QString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
00149     virtual void buildXML( QDomDocument& doc, QDomElement element );
00150 };
00151 
00152 void TermNode::buildXML( QDomDocument& doc, QDomElement element )
00153 {
00154     if ( m_type == "*" ) {
00155         m_lhs->buildXML( doc, element );
00156         QDomElement de = doc.createElement( "TEXT" );
00157         de.setAttribute( "CHAR", QString( m_type ) );
00158         element.appendChild( de );
00159         m_rhs->buildXML( doc, element );
00160     }
00161     else {
00162         QDomElement fraction = doc.createElement( "FRACTION" );
00163         QDomElement numerator = doc.createElement( "NUMERATOR" );
00164         QDomElement sequence = doc.createElement( "SEQUENCE" );
00165         m_lhs->buildXML( doc, sequence );
00166         numerator.appendChild( sequence );
00167         fraction.appendChild( numerator );
00168         QDomElement denominator = doc.createElement( "DENOMINATOR" );
00169         sequence = doc.createElement( "SEQUENCE" );
00170         m_rhs->buildXML( doc, sequence );
00171         denominator.appendChild( sequence );
00172         fraction.appendChild( denominator );
00173         element.appendChild( fraction );
00174     }
00175 }
00176 
00177 
00178 class PowerNode : public OperatorNode {
00179 public:
00180     PowerNode( QString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
00181     virtual void buildXML( QDomDocument& doc, QDomElement element );
00182 };
00183 
00184 void PowerNode::buildXML( QDomDocument& doc, QDomElement element )
00185 {
00186     QDomElement index = doc.createElement( "INDEX" );
00187     QDomElement content = doc.createElement( "CONTENT" );
00188     QDomElement sequence = doc.createElement( "SEQUENCE" );
00189     content.appendChild( sequence );
00190     index.appendChild( content );
00191 
00192     if ( !m_lhs->isSimple() ) {
00193         QDomElement bracket = doc.createElement( "BRACKET" );
00194         bracket.setAttribute( "LEFT", '(' );
00195         bracket.setAttribute( "RIGHT", ')' );
00196         sequence.appendChild( bracket );
00197 
00198         content = doc.createElement( "CONTENT" );
00199         bracket.appendChild( content );
00200 
00201         sequence = doc.createElement( "SEQUENCE" );
00202         content.appendChild( sequence );
00203     }
00204     m_lhs->buildXML( doc, sequence );
00205     if ( m_type == "_" ) {
00206         QDomElement lowerRight = doc.createElement( "LOWERRIGHT" );
00207         sequence = doc.createElement( "SEQUENCE" );
00208         m_rhs->buildXML( doc, sequence );
00209         lowerRight.appendChild( sequence );
00210         index.appendChild( lowerRight );
00211     }
00212     else {
00213         QDomElement upperRight = doc.createElement( "UPPERRIGHT" );
00214         sequence = doc.createElement( "SEQUENCE" );
00215         m_rhs->buildXML( doc, sequence );
00216         upperRight.appendChild( sequence );
00217         index.appendChild( upperRight );
00218     }
00219     element.appendChild( index );
00220 }
00221 
00222 
00223 class FunctionNode : public ParserNode {
00224 public:
00225     FunctionNode( PrimaryNode* name, QPtrList<ParserNode>& args ) : m_name( name ), m_args( args ) {
00226         m_args.setAutoDelete( true );
00227     }
00228     ~FunctionNode() { delete m_name; }
00229     //virtual void output( ostream& stream );
00230     virtual void buildXML( QDomDocument& doc, QDomElement element );
00231 private:
00232     void buildSymbolXML( QDomDocument& doc, QDomElement element, KFormula::SymbolType type );
00233     PrimaryNode* m_name;
00234     QPtrList<ParserNode> m_args;
00235 };
00236 
00237 void FunctionNode::buildSymbolXML( QDomDocument& doc, QDomElement element, KFormula::SymbolType type )
00238 {
00239     QDomElement symbol = doc.createElement( "SYMBOL" );
00240     symbol.setAttribute( "TYPE", type );
00241     QDomElement content = doc.createElement( "CONTENT" );
00242     QDomElement sequence = doc.createElement( "SEQUENCE" );
00243     m_args.at( 0 )->buildXML( doc, sequence );
00244     content.appendChild( sequence );
00245     symbol.appendChild( content );
00246     if ( m_args.count() > 2 ) {
00247         ParserNode* lowerLimit = m_args.at( m_args.count()-2 );
00248         ParserNode* upperLimit = m_args.at( m_args.count()-1 );
00249 
00250         QDomElement lower = doc.createElement( "LOWER" );
00251         sequence = doc.createElement( "SEQUENCE" );
00252         lowerLimit->buildXML( doc, sequence );
00253         lower.appendChild( sequence );
00254         symbol.appendChild( lower );
00255 
00256         QDomElement upper = doc.createElement( "UPPER" );
00257         sequence = doc.createElement( "SEQUENCE" );
00258         upperLimit->buildXML( doc, sequence );
00259         upper.appendChild( sequence );
00260         symbol.appendChild( upper );
00261     }
00262     element.appendChild( symbol );
00263 }
00264 
00265 void FunctionNode::buildXML( QDomDocument& doc, QDomElement element )
00266 {
00267     if ( ( m_name->primary() == "sqrt" ) && ( m_args.count() == 1 ) ) {
00268         QDomElement root = doc.createElement( "ROOT" );
00269         QDomElement content = doc.createElement( "CONTENT" );
00270         QDomElement sequence = doc.createElement( "SEQUENCE" );
00271         m_args.at( 0 )->buildXML( doc, sequence );
00272         content.appendChild( sequence );
00273         root.appendChild( content );
00274         element.appendChild( root );
00275     }
00276     else if ( ( m_name->primary() == "pow" ) && ( m_args.count() == 2 ) ) {
00277         QDomElement index = doc.createElement( "INDEX" );
00278         QDomElement content = doc.createElement( "CONTENT" );
00279         QDomElement sequence = doc.createElement( "SEQUENCE" );
00280         m_args.at( 0 )->buildXML( doc, sequence );
00281         content.appendChild( sequence );
00282         index.appendChild( content );
00283         QDomElement upperRight = doc.createElement( "UPPERRIGHT" );
00284         sequence = doc.createElement( "SEQUENCE" );
00285         m_args.at( 1 )->buildXML( doc, sequence );
00286         upperRight.appendChild( sequence );
00287         index.appendChild( upperRight );
00288         element.appendChild( index );
00289     }
00290     else if ( ( m_name->primary() == "sum" ) && ( m_args.count() > 0 ) ) {
00291         buildSymbolXML( doc, element, KFormula::Sum );
00292     }
00293     else if ( ( m_name->primary() == "prod" ) && ( m_args.count() > 0 ) ) {
00294         buildSymbolXML( doc, element, KFormula::Product );
00295     }
00296     else if ( ( ( m_name->primary() == "int" ) ||
00297                 ( m_name->primary() == "integrate" ) ||
00298                 ( m_name->primary() == "quad" ) )
00299               && ( m_args.count() > 0 ) ) {
00300         buildSymbolXML( doc, element, KFormula::Integral );
00301     }
00302     else {
00303         m_name->buildXML( doc, element );
00304         QDomElement bracket = doc.createElement( "BRACKET" );
00305         bracket.setAttribute( "LEFT", '(' );
00306         bracket.setAttribute( "RIGHT", ')' );
00307         QDomElement content = doc.createElement( "CONTENT" );
00308         QDomElement sequence = doc.createElement( "SEQUENCE" );
00309 
00310         for ( uint i = 0; i < m_args.count(); i++ ) {
00311             m_args.at( i )->buildXML( doc, sequence );
00312             if ( i < m_args.count()-1 ) {
00313                 QDomElement de = doc.createElement( "TEXT" );
00314                 de.setAttribute( "CHAR", "," );
00315                 sequence.appendChild( de );
00316             }
00317         }
00318 
00319         content.appendChild( sequence );
00320         bracket.appendChild( content );
00321         element.appendChild( bracket );
00322     }
00323 }
00324 
00325 // void FunctionNode::output( ostream& stream )
00326 // {
00327 //     m_name->output( stream );
00328 //     for ( uint i = 0; i < m_args.count(); i++ ) {
00329 //         m_args.at( i )->output( stream );
00330 //     }
00331 // }
00332 
00333 class RowNode : public ParserNode {
00334 public:
00335     RowNode( QPtrList<ParserNode> row ) : m_row( row ) { m_row.setAutoDelete( true ); }
00336     //virtual void output( ostream& stream );
00337     virtual void buildXML( QDomDocument& doc, QDomElement element );
00338     uint columns() const { return m_row.count(); }
00339     void setRequiredColumns( uint requiredColumns ) { m_requiredColumns = requiredColumns; }
00340 private:
00341     QPtrList<ParserNode> m_row;
00342     uint m_requiredColumns;
00343 };
00344 
00345 void RowNode::buildXML( QDomDocument& doc, QDomElement element )
00346 {
00347     for ( uint i = 0; i < m_requiredColumns; i++ ) {
00348         QDomElement sequence = doc.createElement( "SEQUENCE" );
00349         if ( i < m_row.count() ) {
00350             m_row.at( i )->buildXML( doc, sequence );
00351         }
00352         else {
00353             QDomElement de = doc.createElement( "TEXT" );
00354             de.setAttribute( "CHAR", "0" );
00355             sequence.appendChild( de );
00356         }
00357         element.appendChild( sequence );
00358     }
00359 }
00360 
00361 // void RowNode::output( ostream& stream )
00362 // {
00363 //     stream << "[";
00364 //     for ( uint i = 0; i < m_row.count(); i++ ) {
00365 //         m_row.at( i )->output( stream );
00366 //         if ( i < m_row.count()-1 ) {
00367 //             stream << ", ";
00368 //         }
00369 //     }
00370 //     stream << "]";
00371 // }
00372 
00373 class MatrixNode : public ParserNode {
00374 public:
00375     MatrixNode( QPtrList<RowNode> rows ) : m_rows( rows ) { m_rows.setAutoDelete( true ); }
00376     //virtual void output( ostream& stream );
00377     virtual void buildXML( QDomDocument& doc, QDomElement element );
00378     virtual bool isSimple() { return true; }
00379     uint columns();
00380     uint rows() { return m_rows.count(); }
00381 private:
00382     QPtrList<RowNode> m_rows;
00383 };
00384 
00385 uint MatrixNode::columns()
00386 {
00387     uint columns = 0;
00388     for ( uint i = 0; i < m_rows.count(); i++ ) {
00389         columns = QMAX( columns, m_rows.at( i )->columns() );
00390     }
00391     return columns;
00392 }
00393 
00394 void MatrixNode::buildXML( QDomDocument& doc, QDomElement element )
00395 {
00396     QDomElement bracket = doc.createElement( "BRACKET" );
00397     bracket.setAttribute( "LEFT", '(' );
00398     bracket.setAttribute( "RIGHT", ')' );
00399     QDomElement content = doc.createElement( "CONTENT" );
00400     QDomElement sequence = doc.createElement( "SEQUENCE" );
00401 
00402     uint cols = columns();
00403     QDomElement matrix = doc.createElement( "MATRIX" );
00404     matrix.setAttribute( "ROWS", m_rows.count() );
00405     matrix.setAttribute( "COLUMNS", cols );
00406     for ( uint i = 0; i < m_rows.count(); i++ ) {
00407         m_rows.at( i )->setRequiredColumns( cols );
00408         m_rows.at( i )->buildXML( doc, matrix );
00409         matrix.appendChild( doc.createComment( "end of row" ) );
00410     }
00411     sequence.appendChild( matrix );
00412     content.appendChild( sequence );
00413     bracket.appendChild( content );
00414     element.appendChild( bracket );
00415 }
00416 
00417 // void MatrixNode::output( ostream& stream )
00418 // {
00419 //     stream << "[";
00420 //     for ( uint i = 0; i < m_rows.count(); i++ ) {
00421 //         m_rows.at( i )->output( stream );
00422 //         if ( i < m_rows.count()-1 ) {
00423 //             stream << ", ";
00424 //         }
00425 //     }
00426 //     stream << "]";
00427 // }
00428 
00429 
00430 FormulaStringParser::FormulaStringParser( const KFormula::SymbolTable& symbolTable, QString formula )
00431     : m_symbolTable( symbolTable ), m_formula( formula ),
00432       pos( 0 ), line( 1 ), column( 1 ), m_newlineIsSpace( true )
00433 {
00434 }
00435 
00436 FormulaStringParser::~FormulaStringParser()
00437 {
00438     delete head;
00439     if ( ParserNode::debugCount != 0 ) {
00440         kdDebug( KFormula::DEBUGID ) << "ParserNode::debugCount = " << ParserNode::debugCount << endl;
00441     }
00442 }
00443 
00444 QDomDocument FormulaStringParser::parse()
00445 {
00446     nextToken();
00447     head = parseAssign();
00448     //head->output( cout );
00449     if ( !eol() ) {
00450         error( QString( i18n( "Aborted parsing at %1:%2" ) ).arg( line ).arg( column ) );
00451     }
00452 
00453     QDomDocument doc = KFormula::Document::createDomDocument();
00454     QDomElement root = doc.documentElement();
00455     QDomElement de = doc.createElement( "FORMULA" );
00456     // here comes the current version of FormulaElement
00457     //de.setAttribute( "VERSION", "4" );
00458     head->buildXML( doc, de );
00459     root.appendChild(de);
00460 
00461     kdDebug( 39001 ) << doc.toString() << endl;
00462     return doc;
00463 }
00464 
00465 ParserNode* FormulaStringParser::parseAssign()
00466 {
00467     ParserNode* lhs = parseExpr();
00468     for ( ;; ) {
00469         switch ( currentType ) {
00470         case ASSIGN: {
00471             QString c = current;
00472             nextToken();
00473             lhs = new AssignNode( c, lhs, parseExpr() );
00474             break;
00475         }
00476         default:
00477             return lhs;
00478         }
00479     }
00480 }
00481 
00482 ParserNode* FormulaStringParser::parseExpr()
00483 {
00484     ParserNode* lhs = parseTerm();
00485     for ( ;; ) {
00486         switch ( currentType ) {
00487         case PLUS:
00488         case SUB: {
00489             QString c = current;
00490             nextToken();
00491             lhs = new ExprNode( c, lhs, parseTerm() );
00492             break;
00493         }
00494         default:
00495             return lhs;
00496         }
00497     }
00498 }
00499 
00500 ParserNode* FormulaStringParser::parseTerm()
00501 {
00502     ParserNode* lhs = parsePower();
00503     for ( ;; ) {
00504         switch ( currentType ) {
00505         case MUL:
00506         case DIV: {
00507             QString c = current;
00508             nextToken();
00509             lhs = new TermNode( c, lhs, parsePower() );
00510             break;
00511         }
00512         default:
00513             return lhs;
00514         }
00515     }
00516 }
00517 
00518 ParserNode* FormulaStringParser::parsePower()
00519 {
00520     ParserNode* lhs = parsePrimary();
00521     for ( ;; ) {
00522         switch ( currentType ) {
00523         case INDEX:
00524         case POW: {
00525             QString c = current;
00526             nextToken();
00527             lhs = new PowerNode( c, lhs, parsePrimary() );
00528             break;
00529         }
00530         default:
00531             return lhs;
00532         }
00533     }
00534 }
00535 
00536 ParserNode* FormulaStringParser::parsePrimary()
00537 {
00538     switch ( currentType ) {
00539     case NUMBER: {
00540         PrimaryNode* node = new PrimaryNode( current );
00541         nextToken();
00542         return node;
00543     }
00544     case NAME: {
00545         PrimaryNode* node = new PrimaryNode( current );
00546         node->setUnicode( m_symbolTable.unicode( current ) );
00547         nextToken();
00548         if ( currentType == LP ) {
00549             nextToken();
00550             QPtrList<ParserNode> args;
00551             args.setAutoDelete( false );
00552             while ( ( currentType != EOL ) && ( currentType != RP ) ) {
00553                 ParserNode* node = parseExpr();
00554                 args.append( node );
00555                 if ( currentType == COMMA ) {
00556                     nextToken();
00557                 }
00558             }
00559             expect( RP, QString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ")" ) );
00560             node->setFunctionName( true );
00561             return new FunctionNode( node, args );
00562         }
00563         return node;
00564     }
00565     case SUB: {
00566         nextToken();
00567         //ParserNode* node = new UnaryMinus( parsePrimary() );
00568         ParserNode* node = new UnaryMinus( parseTerm() );
00569         return node;
00570     }
00571     case LP: {
00572         nextToken();
00573         ParserNode* node = parseExpr();
00574         expect( RP, QString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ")" ) );
00575         return node;
00576     }
00577     case LB: {
00578         nextToken();
00579         QPtrList<RowNode> rows;
00580         rows.setAutoDelete( false );
00581         bool innerBrackets = currentType == LB;
00582         m_newlineIsSpace = innerBrackets;
00583         while ( ( currentType != EOL ) && ( currentType != RB ) ) {
00584             if ( innerBrackets ) {
00585                 expect( LB, QString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "[" ) );
00586             }
00587             QPtrList<ParserNode> row;
00588             row.setAutoDelete( false );
00589             while ( ( currentType != EOL ) && ( currentType != RB ) &&
00590                     ( innerBrackets || ( currentType != SEMIC && currentType != NEWLINE ) ) ) {
00591                 row.append( parseExpr() );
00592                 if ( currentType == COMMA ) {
00593                     nextToken();
00594                 }
00595             }
00596             if ( innerBrackets ) {
00597                 expect( RB, QString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "]" ) );
00598                 if ( currentType == COMMA ) {
00599                     nextToken();
00600                 }
00601             }
00602             else {
00603                 if ( currentType != RB ) {
00604                     if ( currentType == NEWLINE ) {
00605                         nextToken();
00606                     }
00607                     else {
00608                         expect( SEMIC, QString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ";" ) );
00609                     }
00610                 }
00611             }
00612             rows.append( new RowNode( row ) );
00613         }
00614         m_newlineIsSpace = true;
00615         expect( RB, QString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "]" ) );
00616         MatrixNode* node = new MatrixNode( rows );
00617         if ( node->columns() == 0 ) {
00618             error( QString( i18n( "Null columns in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
00619         }
00620         if ( node->rows() == 0 ) {
00621             error( QString( i18n( "Null rows in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
00622         }
00623         return node;
00624     }
00625     case OTHER: {
00626         ParserNode* node = new PrimaryNode( current );
00627         nextToken();
00628         return node;
00629     }
00630     default:
00631         error( QString( i18n( "Unexpected token at %1:%2" ) ).arg( line ).arg( column ) );
00632         return new PrimaryNode( "?" );
00633     }
00634 }
00635 
00636 void FormulaStringParser::expect( TokenType type, QString msg )
00637 {
00638     if ( currentType == type ) {
00639         nextToken();
00640     }
00641     else {
00642         error( msg );
00643     }
00644 }
00645 
00646 QString FormulaStringParser::nextToken()
00647 {
00648     // We skip any ' or " so that we can parse string literals.
00649     while ( !eol() && ( m_formula[pos].isSpace() ||
00650                         ( m_formula[pos] == '"' ) ||
00651                         ( m_formula[pos] == '\'' ) ) ) {
00652         if ( m_formula[pos] == '\n' ) {
00653             line++;
00654             if ( m_newlineIsSpace ) {
00655                 column = 0;
00656             }
00657             else {
00658                 pos++;
00659                 column = 1;
00660                 currentType = NEWLINE;
00661                 return current = "\n";
00662             }
00663         }
00664         pos++; column++;
00665     }
00666     if ( eol() ) {
00667         currentType = EOL;
00668         return QString::null;
00669     }
00670     if ( m_formula[pos].isDigit() || m_formula[pos] == '.' ) {
00671         uint begin = pos;
00672         readNumber();
00673         currentType = NUMBER;
00674         current = m_formula.mid( begin, pos-begin );
00675         if ( current[0] == '.' ) {
00676             current = "0" + current;
00677         }
00678         if ( current[current.length()-1] == '.' ) {
00679             current = current + "0";
00680         }
00681         return current;
00682     }
00683     else if ( m_formula[pos].isLetter() ) {
00684         uint begin = pos;
00685         pos++; column++;
00686         while ( !eol() && m_formula[pos].isLetter() ) {
00687             pos++; column++;
00688         }
00689         currentType = NAME;
00690         return current = m_formula.mid( begin, pos-begin );
00691     }
00692     else {
00693         switch ( m_formula[pos].latin1() ) {
00694         case '+':
00695             pos++; column++;
00696             currentType = PLUS;
00697             return current = "+";
00698         case '-':
00699             pos++; column++;
00700             currentType = SUB;
00701             return current = "-";
00702         case '*':
00703             pos++; column++;
00704             if ( !eol() && m_formula[pos] == '*' ) {
00705                 pos++; column++;
00706                 currentType = POW;
00707                 return current = "**";
00708             }
00709             currentType = MUL;
00710             return current = "*";
00711         case '/':
00712             pos++; column++;
00713             currentType = DIV;
00714             return current = "/";
00715         case '^':
00716             pos++; column++;
00717             currentType = POW;
00718             return current = "**";
00719         case '_':
00720             pos++; column++;
00721             currentType = INDEX;
00722             return current = "_";
00723         case '(':
00724             pos++; column++;
00725             currentType = LP;
00726             return current = "(";
00727         case ')':
00728             pos++; column++;
00729             currentType = RP;
00730             return current = ")";
00731         case '[':
00732             pos++; column++;
00733             currentType = LB;
00734             return current = "[";
00735         case ']':
00736             pos++; column++;
00737             currentType = RB;
00738             return current = "]";
00739         case ',':
00740             pos++; column++;
00741             currentType = COMMA;
00742             return current = ",";
00743         case ';':
00744             pos++; column++;
00745             currentType = SEMIC;
00746             return current = ";";
00747         case '=':
00748             pos++; column++;
00749             currentType = ASSIGN;
00750             return current = "=";
00751         default:
00752             pos++; column++;
00753             currentType = OTHER;
00754             return current = m_formula.mid( pos-1, 1 );
00755         }
00756     }
00757 }
00758 
00759 void FormulaStringParser::readNumber()
00760 {
00761     bool digitsBeforeDot = m_formula[pos] != '.';
00762 
00763     readDigits();
00764     if ( pos < m_formula.length()-1 ) {
00765         QChar ch = m_formula[pos];
00766 
00767         // Look for a dot.
00768         if ( ch == '.' ) {
00769             pos++;
00770             column++;
00771             ch = m_formula[pos];
00772             if ( ch.isDigit() ) {
00773                 readDigits();
00774             }
00775             else if ( !digitsBeforeDot ) {
00776                 error( QString( i18n( "A single '.' is not a number at %1:%2" ) ).arg( line ).arg( column ) );
00777                 return;
00778             }
00779         }
00780 
00781         // there might as well be an exponent
00782         if ( pos < m_formula.length()-1 ) {
00783             ch = m_formula[pos];
00784             if ( ( ch == 'E' ) || ( ch == 'e' ) ) {
00785                 pos++;
00786                 column++;
00787                 ch = m_formula[pos];
00788 
00789                 // signs are allowed after the exponent
00790                 if ( ( ( ch == '+' ) || ( ch == '-' ) ) &&
00791                      ( pos < m_formula.length()-1 ) ) {
00792                     pos++;
00793                     column++;
00794                     ch = m_formula[pos];
00795                     if ( ch.isDigit() ) {
00796                         readDigits();
00797                     }
00798                     else {
00799                         pos -= 2;
00800                         column -= 2;
00801                         return;
00802                     }
00803                 }
00804                 else if ( ch.isDigit() ) {
00805                     readDigits();
00806                 }
00807                 else {
00808                     pos--;
00809                     column--;
00810                 }
00811             }
00812         }
00813     }
00814 }
00815 
00816 
00817 void FormulaStringParser::readDigits()
00818 {
00819     while ( !eol() && m_formula[pos].isDigit() ) {
00820         pos++;
00821         column++;
00822     }
00823 }
00824 
00825 void FormulaStringParser::error( QString err )
00826 {
00827     kdDebug( KFormula::DEBUGID ) << err << " (" << currentType << "; " << current << ")" << endl;
00828     m_errorList.push_back( err );
00829 }
KDE Home | KDE Accessibility Home | Description of Access Keys