00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
00107
00108
00109
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
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
00326
00327
00328
00329
00330
00331
00332
00333 class RowNode : public ParserNode {
00334 public:
00335 RowNode( QPtrList<ParserNode> row ) : m_row( row ) { m_row.setAutoDelete( true ); }
00336
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
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 class MatrixNode : public ParserNode {
00374 public:
00375 MatrixNode( QPtrList<RowNode> rows ) : m_rows( rows ) { m_rows.setAutoDelete( true ); }
00376
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
00418
00419
00420
00421
00422
00423
00424
00425
00426
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
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
00457
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
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
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
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
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
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 }