25#include <kformuladefs.h>
26#include <kformuladocument.h>
27#include <symboltable.h>
36 ParserNode() { debugCount++; }
37 virtual ~ParserNode() { debugCount--; }
39 virtual void buildXML( TQDomDocument& doc, TQDomElement element ) = 0;
40 virtual bool isSimple() {
return false; }
42 static int debugCount;
45int ParserNode::debugCount = 0;
47class PrimaryNode :
public ParserNode {
49 PrimaryNode( TQString primary ) : m_primary( primary ), m_functionName( false ) {}
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; }
62void PrimaryNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
71 if ( m_functionName ) {
72 TQDomElement namesequence = doc.createElement(
"NAMESEQUENCE" );
73 element.appendChild( namesequence );
74 element = namesequence;
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 );
84class UnaryMinus :
public ParserNode {
86 UnaryMinus( ParserNode* primary ) : m_primary( primary ) {}
87 ~UnaryMinus() {
delete m_primary; }
88 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
90 ParserNode* m_primary;
93void UnaryMinus::buildXML( TQDomDocument& doc, TQDomElement element )
95 TQDomElement de = doc.createElement(
"TEXT" );
96 de.setAttribute(
"CHAR",
"-" );
97 element.appendChild( de );
98 m_primary->buildXML( doc, element );
101class OperatorNode :
public ParserNode {
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; }
116class AssignNode :
public OperatorNode {
118 AssignNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
119 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
122void AssignNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
131class ExprNode :
public OperatorNode {
133 ExprNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
134 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
137void ExprNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
146class TermNode :
public OperatorNode {
148 TermNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
149 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
152void TermNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
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 );
178class PowerNode :
public OperatorNode {
180 PowerNode( TQString type, ParserNode* lhs, ParserNode* rhs ) : OperatorNode( type, lhs, rhs ) {}
181 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
184void PowerNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
192 if ( !m_lhs->isSimple() ) {
193 TQDomElement bracket = doc.createElement(
"BRACKET" );
194 bracket.setAttribute(
"LEFT",
'(' );
195 bracket.setAttribute(
"RIGHT",
')' );
196 sequence.appendChild( bracket );
198 content = doc.createElement(
"CONTENT" );
199 bracket.appendChild( content );
201 sequence = doc.createElement(
"SEQUENCE" );
202 content.appendChild( sequence );
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 );
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 );
219 element.appendChild( index );
223class FunctionNode :
public ParserNode {
225 FunctionNode( PrimaryNode* name, TQPtrList<ParserNode>& args ) : m_name( name ), m_args( args ) {
226 m_args.setAutoDelete(
true );
228 ~FunctionNode() {
delete m_name; }
230 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
232 void buildSymbolXML( TQDomDocument& doc, TQDomElement element, KFormula::SymbolType type );
234 TQPtrList<ParserNode> m_args;
237void FunctionNode::buildSymbolXML( TQDomDocument& doc, TQDomElement element, KFormula::SymbolType type )
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 );
250 TQDomElement lower = doc.createElement(
"LOWER" );
251 sequence = doc.createElement(
"SEQUENCE" );
252 lowerLimit->buildXML( doc, sequence );
253 lower.appendChild( sequence );
254 symbol.appendChild( lower );
256 TQDomElement upper = doc.createElement(
"UPPER" );
257 sequence = doc.createElement(
"SEQUENCE" );
258 upperLimit->buildXML( doc, sequence );
259 upper.appendChild( sequence );
260 symbol.appendChild( upper );
262 element.appendChild( symbol );
265void FunctionNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
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 );
290 else if ( ( m_name->primary() ==
"sum" ) && ( m_args.count() > 0 ) ) {
291 buildSymbolXML( doc, element, KFormula::Sum );
293 else if ( ( m_name->primary() ==
"prod" ) && ( m_args.count() > 0 ) ) {
294 buildSymbolXML( doc, element, KFormula::Product );
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 );
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" );
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 );
319 content.appendChild( sequence );
320 bracket.appendChild( content );
321 element.appendChild( bracket );
333class RowNode :
public ParserNode {
335 RowNode( TQPtrList<ParserNode> row ) : m_row( row ) { m_row.setAutoDelete(
true ); }
337 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
338 uint columns()
const {
return m_row.count(); }
339 void setRequiredColumns( uint requiredColumns ) { m_requiredColumns = requiredColumns; }
341 TQPtrList<ParserNode> m_row;
342 uint m_requiredColumns;
345void RowNode::buildXML( TQDomDocument& doc, TQDomElement element )
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 );
353 TQDomElement de = doc.createElement(
"TEXT" );
354 de.setAttribute(
"CHAR",
"0" );
355 sequence.appendChild( de );
357 element.appendChild( sequence );
373class MatrixNode :
public ParserNode {
375 MatrixNode( TQPtrList<RowNode> rows ) : m_rows( rows ) { m_rows.setAutoDelete(
true ); }
377 virtual void buildXML( TQDomDocument& doc, TQDomElement element );
378 virtual bool isSimple() {
return true; }
380 uint rows() {
return m_rows.count(); }
382 TQPtrList<RowNode> m_rows;
385uint MatrixNode::columns()
388 for ( uint i = 0; i < m_rows.count(); i++ ) {
389 columns = TQMAX( columns, m_rows.at( i )->columns() );
394void MatrixNode::buildXML( TQDomDocument& doc, TQDomElement element )
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" );
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" ) );
411 sequence.appendChild( matrix );
412 content.appendChild( sequence );
413 bracket.appendChild( content );
414 element.appendChild( bracket );
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 )
436FormulaStringParser::~FormulaStringParser()
439 if ( ParserNode::debugCount != 0 ) {
440 kdDebug( KFormula::DEBUGID ) <<
"ParserNode::debugCount = " << ParserNode::debugCount << endl;
444TQDomDocument FormulaStringParser::parse()
447 head = parseAssign();
450 error( TQString( i18n(
"Aborted parsing at %1:%2" ) ).arg( line ).arg( column ) );
453 TQDomDocument doc = KFormula::Document::createDomDocument();
454 TQDomElement root = doc.documentElement();
455 TQDomElement de = doc.createElement(
"FORMULA" );
458 head->buildXML( doc, de );
459 root.appendChild(de);
461 kdDebug( 39001 ) << doc.toString() << endl;
465ParserNode* FormulaStringParser::parseAssign()
467 ParserNode* lhs = parseExpr();
469 switch ( currentType ) {
471 TQString c = current;
473 lhs =
new AssignNode( c, lhs, parseExpr() );
482ParserNode* FormulaStringParser::parseExpr()
484 ParserNode* lhs = parseTerm();
486 switch ( currentType ) {
489 TQString c = current;
491 lhs =
new ExprNode( c, lhs, parseTerm() );
500ParserNode* FormulaStringParser::parseTerm()
502 ParserNode* lhs = parsePower();
504 switch ( currentType ) {
507 TQString c = current;
509 lhs =
new TermNode( c, lhs, parsePower() );
518ParserNode* FormulaStringParser::parsePower()
520 ParserNode* lhs = parsePrimary();
522 switch ( currentType ) {
525 TQString c = current;
527 lhs =
new PowerNode( c, lhs, parsePrimary() );
536ParserNode* FormulaStringParser::parsePrimary()
538 switch ( currentType ) {
540 PrimaryNode* node =
new PrimaryNode( current );
545 PrimaryNode* node =
new PrimaryNode( current );
546 node->setUnicode( m_symbolTable.unicode( current ) );
548 if ( currentType == LP ) {
550 TQPtrList<ParserNode> args;
551 args.setAutoDelete(
false );
552 while ( ( currentType != EOL ) && ( currentType != RP ) ) {
553 ParserNode* node = parseExpr();
555 if ( currentType == COMMA ) {
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 );
568 ParserNode* node =
new UnaryMinus( parseTerm() );
573 ParserNode* node = parseExpr();
574 expect( RP, TQString( i18n(
"'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg(
")" ) );
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(
"[" ) );
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 ) {
596 if ( innerBrackets ) {
597 expect( RB, TQString( i18n(
"'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg(
"]" ) );
598 if ( currentType == COMMA ) {
603 if ( currentType != RB ) {
604 if ( currentType == NEWLINE ) {
608 expect( SEMIC, TQString( i18n(
"'%3' expected at %1:%2" ) ).arg( line ).arg( column ).arg(
";" ) );
612 rows.append(
new RowNode( row ) );
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 ) );
620 if ( node->rows() == 0 ) {
621 error( TQString( i18n(
"Null rows in Matrix at %1:%2" ) ).arg( line ).arg( column ) );
626 ParserNode* node =
new PrimaryNode( current );
631 error( TQString( i18n(
"Unexpected token at %1:%2" ) ).arg( line ).arg( column ) );
632 return new PrimaryNode(
"?" );
636void FormulaStringParser::expect( TokenType type, TQString msg )
638 if ( currentType == type ) {
646TQString FormulaStringParser::nextToken()
649 while ( !eol() && ( m_formula[pos].isSpace() ||
650 ( m_formula[pos] ==
'"' ) ||
651 ( m_formula[pos] ==
'\'' ) ) ) {
652 if ( m_formula[pos] ==
'\n' ) {
654 if ( m_newlineIsSpace ) {
660 currentType = NEWLINE;
661 return current =
"\n";
670 if ( m_formula[pos].isDigit() || m_formula[pos] ==
'.' ) {
673 currentType = NUMBER;
674 current = m_formula.mid( begin, pos-begin );
675 if ( current[0] ==
'.' ) {
676 current =
"0" + current;
678 if ( current[current.length()-1] ==
'.' ) {
679 current = current +
"0";
683 else if ( m_formula[pos].isLetter() ) {
686 while ( !eol() && m_formula[pos].isLetter() ) {
690 return current = m_formula.mid( begin, pos-begin );
693 switch ( m_formula[pos].latin1() ) {
697 return current =
"+";
701 return current =
"-";
704 if ( !eol() && m_formula[pos] ==
'*' ) {
707 return current =
"**";
710 return current =
"*";
714 return current =
"/";
718 return current =
"**";
722 return current =
"_";
726 return current =
"(";
730 return current =
")";
734 return current =
"[";
738 return current =
"]";
742 return current =
",";
746 return current =
";";
749 currentType = ASSIGN;
750 return current =
"=";
754 return current = m_formula.mid( pos-1, 1 );
759void FormulaStringParser::readNumber()
761 bool digitsBeforeDot = m_formula[pos] !=
'.';
764 if ( pos < m_formula.length()-1 ) {
765 TQChar ch = m_formula[pos];
772 if ( ch.isDigit() ) {
775 else if ( !digitsBeforeDot ) {
776 error( TQString( i18n(
"A single '.' is not a number at %1:%2" ) ).arg( line ).arg( column ) );
782 if ( pos < m_formula.length()-1 ) {
784 if ( ( ch ==
'E' ) || ( ch ==
'e' ) ) {
790 if ( ( ( ch ==
'+' ) || ( ch ==
'-' ) ) &&
791 ( pos < m_formula.length()-1 ) ) {
795 if ( ch.isDigit() ) {
804 else if ( ch.isDigit() ) {
817void FormulaStringParser::readDigits()
819 while ( !eol() && m_formula[pos].isDigit() ) {
825void FormulaStringParser::error( TQString err )
827 kdDebug( KFormula::DEBUGID ) << err <<
" (" << currentType <<
"; " << current <<
")" << endl;
828 m_errorList.push_back( err );