kformula

fsparser.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <tqptrlist.h>
21
22#include <kdebug.h>
23#include <tdelocale.h>
24
25#include <kformuladefs.h>
26#include <kformuladocument.h>
27#include <symboltable.h>
28
29#include "fsparser.h"
30
31
32using namespace std;
33
34class ParserNode {
35public:
36 ParserNode() { debugCount++; }
37 virtual ~ParserNode() { debugCount--; }
38 //virtual void output( ostream& ) = 0;
39 virtual void buildXML( TQDomDocument& doc, TQDomElement element ) = 0;
40 virtual bool isSimple() { return false; }
41
42 static int debugCount;
43};
44
45int ParserNode::debugCount = 0;
46
47class PrimaryNode : public ParserNode {
48public:
49 PrimaryNode( TQString primary ) : m_primary( primary ), m_functionName( false ) {}
50 //virtual void output( ostream& stream ) { stream << "PrimaryNode {" << m_primary << "}" << endl; }
51 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
52 virtual bool isSimple() { return true; }
53 void setUnicode( TQChar unicode ) { m_unicode = unicode; }
54 void setFunctionName( bool functionName ) { m_functionName = functionName; }
55 TQString primary() const { return m_primary; }
56private:
57 TQString m_primary;
58 TQChar m_unicode;
59 bool m_functionName;
60};
61
62void PrimaryNode::buildXML( TQDomDocument& doc, TQDomElement element )
63{
64 if ( m_unicode != TQChar::null ) {
65 TQDomElement de = doc.createElement( "TEXT" );
66 de.setAttribute( "CHAR", TQString( m_unicode ) );
67 de.setAttribute( "SYMBOL", "3" );
68 element.appendChild( de );
69 }
70 else {
71 if ( m_functionName ) {
72 TQDomElement namesequence = doc.createElement( "NAMESEQUENCE" );
73 element.appendChild( namesequence );
74 element = namesequence;
75 }
76 for ( uint i = 0; i < m_primary.length(); i++ ) {
77 TQDomElement de = doc.createElement( "TEXT" );
78 de.setAttribute( "CHAR", TQString( m_primary[i] ) );
79 element.appendChild( de );
80 }
81 }
82}
83
84class UnaryMinus : public ParserNode {
85public:
86 UnaryMinus( ParserNode* primary ) : m_primary( primary ) {}
87 ~UnaryMinus() { delete m_primary; }
88 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
89private:
90 ParserNode* m_primary;
91};
92
93void UnaryMinus::buildXML( TQDomDocument& doc, TQDomElement element )
94{
95 TQDomElement de = doc.createElement( "TEXT" );
96 de.setAttribute( "CHAR", "-" );
97 element.appendChild( de );
98 m_primary->buildXML( doc, element );
99}
100
101class OperatorNode : public ParserNode {
102public:
103 OperatorNode( TQString type, ParserNode* lhs, ParserNode* rhs )
104 : m_type( type ), m_lhs( lhs ), m_rhs( rhs ) {}
105 ~OperatorNode() { delete m_rhs; delete m_lhs; }
106// virtual void output( ostream& stream ) {
107// stream << "OperatorNode {";
108// m_lhs->output( stream ); stream << m_type; m_rhs->output( stream );
109// stream << "}" << endl; }
110protected:
111 TQString m_type;
112 ParserNode* m_lhs;
113 ParserNode* m_rhs;
114};
115
116class AssignNode : public OperatorNode {
117public:
118 AssignNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
119 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
120};
121
122void AssignNode::buildXML( TQDomDocument& doc, TQDomElement element )
123{
124 m_lhs->buildXML( doc, element );
125 TQDomElement de = doc.createElement( "TEXT" );
126 de.setAttribute( "CHAR", TQString( m_type ) );
127 element.appendChild( de );
128 m_rhs->buildXML( doc, element );
129}
130
131class ExprNode : public OperatorNode {
132public:
133 ExprNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
134 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
135};
136
137void ExprNode::buildXML( TQDomDocument& doc, TQDomElement element )
138{
139 m_lhs->buildXML( doc, element );
140 TQDomElement de = doc.createElement( "TEXT" );
141 de.setAttribute( "CHAR", TQString( m_type ) );
142 element.appendChild( de );
143 m_rhs->buildXML( doc, element );
144}
145
146class TermNode : public OperatorNode {
147public:
148 TermNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
149 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
150};
151
152void TermNode::buildXML( TQDomDocument& doc, TQDomElement element )
153{
154 if ( m_type == "*" ) {
155 m_lhs->buildXML( doc, element );
156 TQDomElement de = doc.createElement( "TEXT" );
157 de.setAttribute( "CHAR", TQString( m_type ) );
158 element.appendChild( de );
159 m_rhs->buildXML( doc, element );
160 }
161 else {
162 TQDomElement fraction = doc.createElement( "FRACTION" );
163 TQDomElement numerator = doc.createElement( "NUMERATOR" );
164 TQDomElement sequence = doc.createElement( "SEQUENCE" );
165 m_lhs->buildXML( doc, sequence );
166 numerator.appendChild( sequence );
167 fraction.appendChild( numerator );
168 TQDomElement denominator = doc.createElement( "DENOMINATOR" );
169 sequence = doc.createElement( "SEQUENCE" );
170 m_rhs->buildXML( doc, sequence );
171 denominator.appendChild( sequence );
172 fraction.appendChild( denominator );
173 element.appendChild( fraction );
174 }
175}
176
177
178class PowerNode : public OperatorNode {
179public:
180 PowerNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
181 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
182};
183
184void PowerNode::buildXML( TQDomDocument& doc, TQDomElement element )
185{
186 TQDomElement index = doc.createElement( "INDEX" );
187 TQDomElement content = doc.createElement( "CONTENT" );
188 TQDomElement sequence = doc.createElement( "SEQUENCE" );
189 content.appendChild( sequence );
190 index.appendChild( content );
191
192 if ( !m_lhs->isSimple() ) {
193 TQDomElement bracket = doc.createElement( "BRACKET" );
194 bracket.setAttribute( "LEFT", '(' );
195 bracket.setAttribute( "RIGHT", ')' );
196 sequence.appendChild( bracket );
197
198 content = doc.createElement( "CONTENT" );
199 bracket.appendChild( content );
200
201 sequence = doc.createElement( "SEQUENCE" );
202 content.appendChild( sequence );
203 }
204 m_lhs->buildXML( doc, sequence );
205 if ( m_type == "_" ) {
206 TQDomElement lowerRight = doc.createElement( "LOWERRIGHT" );
207 sequence = doc.createElement( "SEQUENCE" );
208 m_rhs->buildXML( doc, sequence );
209 lowerRight.appendChild( sequence );
210 index.appendChild( lowerRight );
211 }
212 else {
213 TQDomElement upperRight = doc.createElement( "UPPERRIGHT" );
214 sequence = doc.createElement( "SEQUENCE" );
215 m_rhs->buildXML( doc, sequence );
216 upperRight.appendChild( sequence );
217 index.appendChild( upperRight );
218 }
219 element.appendChild( index );
220}
221
222
223class FunctionNode : public ParserNode {
224public:
225 FunctionNode( PrimaryNode* name, TQPtrList<ParserNode>& args ) : m_name( name ), m_args( args ) {
226 m_args.setAutoDelete( true );
227 }
228 ~FunctionNode() { delete m_name; }
229 //virtual void output( ostream& stream );
230 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
231private:
232 void buildSymbolXML( TQDomDocument& doc, TQDomElement element, KFormula::SymbolType type );
233 PrimaryNode* m_name;
234 TQPtrList<ParserNode> m_args;
235};
236
237void FunctionNode::buildSymbolXML( TQDomDocument& doc, TQDomElement element, KFormula::SymbolType type )
238{
239 TQDomElement symbol = doc.createElement( "SYMBOL" );
240 symbol.setAttribute( "TYPE", type );
241 TQDomElement content = doc.createElement( "CONTENT" );
242 TQDomElement sequence = doc.createElement( "SEQUENCE" );
243 m_args.at( 0 )->buildXML( doc, sequence );
244 content.appendChild( sequence );
245 symbol.appendChild( content );
246 if ( m_args.count() > 2 ) {
247 ParserNode* lowerLimit = m_args.at( m_args.count()-2 );
248 ParserNode* upperLimit = m_args.at( m_args.count()-1 );
249
250 TQDomElement lower = doc.createElement( "LOWER" );
251 sequence = doc.createElement( "SEQUENCE" );
252 lowerLimit->buildXML( doc, sequence );
253 lower.appendChild( sequence );
254 symbol.appendChild( lower );
255
256 TQDomElement upper = doc.createElement( "UPPER" );
257 sequence = doc.createElement( "SEQUENCE" );
258 upperLimit->buildXML( doc, sequence );
259 upper.appendChild( sequence );
260 symbol.appendChild( upper );
261 }
262 element.appendChild( symbol );
263}
264
265void FunctionNode::buildXML( TQDomDocument& doc, TQDomElement element )
266{
267 if ( ( m_name->primary() == "sqrt" ) && ( m_args.count() == 1 ) ) {
268 TQDomElement root = doc.createElement( "ROOT" );
269 TQDomElement content = doc.createElement( "CONTENT" );
270 TQDomElement sequence = doc.createElement( "SEQUENCE" );
271 m_args.at( 0 )->buildXML( doc, sequence );
272 content.appendChild( sequence );
273 root.appendChild( content );
274 element.appendChild( root );
275 }
276 else if ( ( m_name->primary() == "pow" ) && ( m_args.count() == 2 ) ) {
277 TQDomElement index = doc.createElement( "INDEX" );
278 TQDomElement content = doc.createElement( "CONTENT" );
279 TQDomElement sequence = doc.createElement( "SEQUENCE" );
280 m_args.at( 0 )->buildXML( doc, sequence );
281 content.appendChild( sequence );
282 index.appendChild( content );
283 TQDomElement upperRight = doc.createElement( "UPPERRIGHT" );
284 sequence = doc.createElement( "SEQUENCE" );
285 m_args.at( 1 )->buildXML( doc, sequence );
286 upperRight.appendChild( sequence );
287 index.appendChild( upperRight );
288 element.appendChild( index );
289 }
290 else if ( ( m_name->primary() == "sum" ) && ( m_args.count() > 0 ) ) {
291 buildSymbolXML( doc, element, KFormula::Sum );
292 }
293 else if ( ( m_name->primary() == "prod" ) && ( m_args.count() > 0 ) ) {
294 buildSymbolXML( doc, element, KFormula::Product );
295 }
296 else if ( ( ( m_name->primary() == "int" ) ||
297 ( m_name->primary() == "integrate" ) ||
298 ( m_name->primary() == "quad" ) )
299 && ( m_args.count() > 0 ) ) {
300 buildSymbolXML( doc, element, KFormula::Integral );
301 }
302 else {
303 m_name->buildXML( doc, element );
304 TQDomElement bracket = doc.createElement( "BRACKET" );
305 bracket.setAttribute( "LEFT", '(' );
306 bracket.setAttribute( "RIGHT", ')' );
307 TQDomElement content = doc.createElement( "CONTENT" );
308 TQDomElement sequence = doc.createElement( "SEQUENCE" );
309
310 for ( uint i = 0; i < m_args.count(); i++ ) {
311 m_args.at( i )->buildXML( doc, sequence );
312 if ( i < m_args.count()-1 ) {
313 TQDomElement de = doc.createElement( "TEXT" );
314 de.setAttribute( "CHAR", "," );
315 sequence.appendChild( de );
316 }
317 }
318
319 content.appendChild( sequence );
320 bracket.appendChild( content );
321 element.appendChild( bracket );
322 }
323}
324
325// void FunctionNode::output( ostream& stream )
326// {
327// m_name->output( stream );
328// for ( uint i = 0; i < m_args.count(); i++ ) {
329// m_args.at( i )->output( stream );
330// }
331// }
332
333class RowNode : public ParserNode {
334public:
335 RowNode( TQPtrList<ParserNode> row ) : m_row( row ) { m_row.setAutoDelete( true ); }
336 //virtual void output( ostream& stream );
337 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
338 uint columns() const { return m_row.count(); }
339 void setRequiredColumns( uint requiredColumns ) { m_requiredColumns = requiredColumns; }
340private:
341 TQPtrList<ParserNode> m_row;
342 uint m_requiredColumns;
343};
344
345void RowNode::buildXML( TQDomDocument& doc, TQDomElement element )
346{
347 for ( uint i = 0; i < m_requiredColumns; i++ ) {
348 TQDomElement sequence = doc.createElement( "SEQUENCE" );
349 if ( i < m_row.count() ) {
350 m_row.at( i )->buildXML( doc, sequence );
351 }
352 else {
353 TQDomElement de = doc.createElement( "TEXT" );
354 de.setAttribute( "CHAR", "0" );
355 sequence.appendChild( de );
356 }
357 element.appendChild( sequence );
358 }
359}
360
361// void RowNode::output( ostream& stream )
362// {
363// stream << "[";
364// for ( uint i = 0; i < m_row.count(); i++ ) {
365// m_row.at( i )->output( stream );
366// if ( i < m_row.count()-1 ) {
367// stream << ", ";
368// }
369// }
370// stream << "]";
371// }
372
373class MatrixNode : public ParserNode {
374public:
375 MatrixNode( TQPtrList<RowNode> rows ) : m_rows( rows ) { m_rows.setAutoDelete( true ); }
376 //virtual void output( ostream& stream );
377 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
378 virtual bool isSimple() { return true; }
379 uint columns();
380 uint rows() { return m_rows.count(); }
381private:
382 TQPtrList<RowNode> m_rows;
383};
384
385uint MatrixNode::columns()
386{
387 uint columns = 0;
388 for ( uint i = 0; i < m_rows.count(); i++ ) {
389 columns = TQMAX( columns, m_rows.at( i )->columns() );
390 }
391 return columns;
392}
393
394void MatrixNode::buildXML( TQDomDocument& doc, TQDomElement element )
395{
396 TQDomElement bracket = doc.createElement( "BRACKET" );
397 bracket.setAttribute( "LEFT", '(' );
398 bracket.setAttribute( "RIGHT", ')' );
399 TQDomElement content = doc.createElement( "CONTENT" );
400 TQDomElement sequence = doc.createElement( "SEQUENCE" );
401
402 uint cols = columns();
403 TQDomElement matrix = doc.createElement( "MATRIX" );
404 matrix.setAttribute( "ROWS", m_rows.count() );
405 matrix.setAttribute( "COLUMNS", cols );
406 for ( uint i = 0; i < m_rows.count(); i++ ) {
407 m_rows.at( i )->setRequiredColumns( cols );
408 m_rows.at( i )->buildXML( doc, matrix );
409 matrix.appendChild( doc.createComment( "end of row" ) );
410 }
411 sequence.appendChild( matrix );
412 content.appendChild( sequence );
413 bracket.appendChild( content );
414 element.appendChild( bracket );
415}
416
417// void MatrixNode::output( ostream& stream )
418// {
419// stream << "[";
420// for ( uint i = 0; i < m_rows.count(); i++ ) {
421// m_rows.at( i )->output( stream );
422// if ( i < m_rows.count()-1 ) {
423// stream << ", ";
424// }
425// }
426// stream << "]";
427// }
428
429
430FormulaStringParser::FormulaStringParser( const KFormula::SymbolTable& symbolTable, TQString formula )
431 : m_symbolTable( symbolTable ), m_formula( formula ),
432 pos( 0 ), line( 1 ), column( 1 ), m_newlineIsSpace( true )
433{
434}
435
436FormulaStringParser::~FormulaStringParser()
437{
438 delete head;
439 if ( ParserNode::debugCount != 0 ) {
440 kdDebug( KFormula::DEBUGID ) << "ParserNode::debugCount = " << ParserNode::debugCount << endl;
441 }
442}
443
444TQDomDocument FormulaStringParser::parse()
445{
446 nextToken();
447 head = parseAssign();
448 //head->output( cout );
449 if ( !eol() ) {
450 error( TQString( i18n( "Aborted parsing at %1:%2" ) ).arg( line ).arg( column ) );
451 }
452
453 TQDomDocument doc = KFormula::Document::createDomDocument();
454 TQDomElement root = doc.documentElement();
455 TQDomElement de = doc.createElement( "FORMULA" );
456 // here comes the current version of FormulaElement
457 //de.setAttribute( "VERSION", "4" );
458 head->buildXML( doc, de );
459 root.appendChild(de);
460
461 kdDebug( 39001 ) << doc.toString() << endl;
462 return doc;
463}
464
465ParserNode* FormulaStringParser::parseAssign()
466{
467 ParserNode* lhs = parseExpr();
468 for ( ;; ) {
469 switch ( currentType ) {
470 case ASSIGN: {
471 TQString c = current;
472 nextToken();
473 lhs = new AssignNode( c, lhs, parseExpr() );
474 break;
475 }
476 default:
477 return lhs;
478 }
479 }
480}
481
482ParserNode* FormulaStringParser::parseExpr()
483{
484 ParserNode* lhs = parseTerm();
485 for ( ;; ) {
486 switch ( currentType ) {
487 case PLUS:
488 case SUB: {
489 TQString c = current;
490 nextToken();
491 lhs = new ExprNode( c, lhs, parseTerm() );
492 break;
493 }
494 default:
495 return lhs;
496 }
497 }
498}
499
500ParserNode* FormulaStringParser::parseTerm()
501{
502 ParserNode* lhs = parsePower();
503 for ( ;; ) {
504 switch ( currentType ) {
505 case MUL:
506 case DIV: {
507 TQString c = current;
508 nextToken();
509 lhs = new TermNode( c, lhs, parsePower() );
510 break;
511 }
512 default:
513 return lhs;
514 }
515 }
516}
517
518ParserNode* FormulaStringParser::parsePower()
519{
520 ParserNode* lhs = parsePrimary();
521 for ( ;; ) {
522 switch ( currentType ) {
523 case INDEX:
524 case POW: {
525 TQString c = current;
526 nextToken();
527 lhs = new PowerNode( c, lhs, parsePrimary() );
528 break;
529 }
530 default:
531 return lhs;
532 }
533 }
534}
535
536ParserNode* FormulaStringParser::parsePrimary()
537{
538 switch ( currentType ) {
539 case NUMBER: {
540 PrimaryNode* node = new PrimaryNode( current );
541 nextToken();
542 return node;
543 }
544 case NAME: {
545 PrimaryNode* node = new PrimaryNode( current );
546 node->setUnicode( m_symbolTable.unicode( current ) );
547 nextToken();
548 if ( currentType == LP ) {
549 nextToken();
550 TQPtrList<ParserNode> args;
551 args.setAutoDelete( false );
552 while ( ( currentType != EOL ) && ( currentType != RP ) ) {
553 ParserNode* node = parseExpr();
554 args.append( node );
555 if ( currentType == COMMA ) {
556 nextToken();
557 }
558 }
559 expect( RP, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ")" ) );
560 node->setFunctionName( true );
561 return new FunctionNode( node, args );
562 }
563 return node;
564 }
565 case SUB: {
566 nextToken();
567 //ParserNode* node = new UnaryMinus( parsePrimary() );
568 ParserNode* node = new UnaryMinus( parseTerm() );
569 return node;
570 }
571 case LP: {
572 nextToken();
573 ParserNode* node = parseExpr();
574 expect( RP, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ")" ) );
575 return node;
576 }
577 case LB: {
578 nextToken();
579 TQPtrList<RowNode> rows;
580 rows.setAutoDelete( false );
581 bool innerBrackets = currentType == LB;
582 m_newlineIsSpace = innerBrackets;
583 while ( ( currentType != EOL ) && ( currentType != RB ) ) {
584 if ( innerBrackets ) {
585 expect( LB, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "[" ) );
586 }
587 TQPtrList<ParserNode> row;
588 row.setAutoDelete( false );
589 while ( ( currentType != EOL ) && ( currentType != RB ) &&
590 ( innerBrackets || ( currentType != SEMIC && currentType != NEWLINE ) ) ) {
591 row.append( parseExpr() );
592 if ( currentType == COMMA ) {
593 nextToken();
594 }
595 }
596 if ( innerBrackets ) {
597 expect( RB, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "]" ) );
598 if ( currentType == COMMA ) {
599 nextToken();
600 }
601 }
602 else {
603 if ( currentType != RB ) {
604 if ( currentType == NEWLINE ) {
605 nextToken();
606 }
607 else {
608 expect( SEMIC, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( ";" ) );
609 }
610 }
611 }
612 rows.append( new RowNode( row ) );
613 }
614 m_newlineIsSpace = true;
615 expect( RB, TQString( i18n( "'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg( "]" ) );
616 MatrixNode* node = new MatrixNode( rows );
617 if ( node->columns() == 0 ) {
618 error( TQString( i18n( "Null columns in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
619 }
620 if ( node->rows() == 0 ) {
621 error( TQString( i18n( "Null rows in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
622 }
623 return node;
624 }
625 case OTHER: {
626 ParserNode* node = new PrimaryNode( current );
627 nextToken();
628 return node;
629 }
630 default:
631 error( TQString( i18n( "Unexpected token at %1:%2" ) ).arg( line ).arg( column ) );
632 return new PrimaryNode( "?" );
633 }
634}
635
636void FormulaStringParser::expect( TokenType type, TQString msg )
637{
638 if ( currentType == type ) {
639 nextToken();
640 }
641 else {
642 error( msg );
643 }
644}
645
646TQString FormulaStringParser::nextToken()
647{
648 // We skip any ' or " so that we can parse string literals.
649 while ( !eol() && ( m_formula[pos].isSpace() ||
650 ( m_formula[pos] == '"' ) ||
651 ( m_formula[pos] == '\'' ) ) ) {
652 if ( m_formula[pos] == '\n' ) {
653 line++;
654 if ( m_newlineIsSpace ) {
655 column = 0;
656 }
657 else {
658 pos++;
659 column = 1;
660 currentType = NEWLINE;
661 return current = "\n";
662 }
663 }
664 pos++; column++;
665 }
666 if ( eol() ) {
667 currentType = EOL;
668 return TQString();
669 }
670 if ( m_formula[pos].isDigit() || m_formula[pos] == '.' ) {
671 uint begin = pos;
672 readNumber();
673 currentType = NUMBER;
674 current = m_formula.mid( begin, pos-begin );
675 if ( current[0] == '.' ) {
676 current = "0" + current;
677 }
678 if ( current[current.length()-1] == '.' ) {
679 current = current + "0";
680 }
681 return current;
682 }
683 else if ( m_formula[pos].isLetter() ) {
684 uint begin = pos;
685 pos++; column++;
686 while ( !eol() && m_formula[pos].isLetter() ) {
687 pos++; column++;
688 }
689 currentType = NAME;
690 return current = m_formula.mid( begin, pos-begin );
691 }
692 else {
693 switch ( m_formula[pos].latin1() ) {
694 case '+':
695 pos++; column++;
696 currentType = PLUS;
697 return current = "+";
698 case '-':
699 pos++; column++;
700 currentType = SUB;
701 return current = "-";
702 case '*':
703 pos++; column++;
704 if ( !eol() && m_formula[pos] == '*' ) {
705 pos++; column++;
706 currentType = POW;
707 return current = "**";
708 }
709 currentType = MUL;
710 return current = "*";
711 case '/':
712 pos++; column++;
713 currentType = DIV;
714 return current = "/";
715 case '^':
716 pos++; column++;
717 currentType = POW;
718 return current = "**";
719 case '_':
720 pos++; column++;
721 currentType = INDEX;
722 return current = "_";
723 case '(':
724 pos++; column++;
725 currentType = LP;
726 return current = "(";
727 case ')':
728 pos++; column++;
729 currentType = RP;
730 return current = ")";
731 case '[':
732 pos++; column++;
733 currentType = LB;
734 return current = "[";
735 case ']':
736 pos++; column++;
737 currentType = RB;
738 return current = "]";
739 case ',':
740 pos++; column++;
741 currentType = COMMA;
742 return current = ",";
743 case ';':
744 pos++; column++;
745 currentType = SEMIC;
746 return current = ";";
747 case '=':
748 pos++; column++;
749 currentType = ASSIGN;
750 return current = "=";
751 default:
752 pos++; column++;
753 currentType = OTHER;
754 return current = m_formula.mid( pos-1, 1 );
755 }
756 }
757}
758
759void FormulaStringParser::readNumber()
760{
761 bool digitsBeforeDot = m_formula[pos] != '.';
762
763 readDigits();
764 if ( pos < m_formula.length()-1 ) {
765 TQChar ch = m_formula[pos];
766
767 // Look for a dot.
768 if ( ch == '.' ) {
769 pos++;
770 column++;
771 ch = m_formula[pos];
772 if ( ch.isDigit() ) {
773 readDigits();
774 }
775 else if ( !digitsBeforeDot ) {
776 error( TQString( i18n( "A single '.' is not a number at %1:%2" ) ).arg( line ).arg( column ) );
777 return;
778 }
779 }
780
781 // there might as well be an exponent
782 if ( pos < m_formula.length()-1 ) {
783 ch = m_formula[pos];
784 if ( ( ch == 'E' ) || ( ch == 'e' ) ) {
785 pos++;
786 column++;
787 ch = m_formula[pos];
788
789 // signs are allowed after the exponent
790 if ( ( ( ch == '+' ) || ( ch == '-' ) ) &&
791 ( pos < m_formula.length()-1 ) ) {
792 pos++;
793 column++;
794 ch = m_formula[pos];
795 if ( ch.isDigit() ) {
796 readDigits();
797 }
798 else {
799 pos -= 2;
800 column -= 2;
801 return;
802 }
803 }
804 else if ( ch.isDigit() ) {
805 readDigits();
806 }
807 else {
808 pos--;
809 column--;
810 }
811 }
812 }
813 }
814}
815
816
817void FormulaStringParser::readDigits()
818{
819 while ( !eol() && m_formula[pos].isDigit() ) {
820 pos++;
821 column++;
822 }
823}
824
825void FormulaStringParser::error( TQString err )
826{
827 kdDebug( KFormula::DEBUGID ) << err << " (" << currentType << "; " << current << ")" << endl;
828 m_errorList.push_back( err );
829}