KDevelop API Documentation

lib/cppparser/lexer.cpp

Go to the documentation of this file.
00001 /* This file is part of KDevelop 00002 Copyright (C) 2002,2003 Roberto Raggi <roberto@kdevelop.org> 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., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include "lexer.h" 00021 #include "lookup.h" 00022 #include "keywords.lut.h" 00023 00024 #include <kdebug.h> 00025 #include <klocale.h> 00026 00027 #include <qregexp.h> 00028 #include <qmap.h> 00029 #include <qvaluelist.h> 00030 00031 #if defined( KDEVELOP_BGPARSER ) 00032 #include <qthread.h> 00033 00034 class KDevTread: public QThread 00035 { 00036 public: 00037 static void yield() 00038 { 00039 msleep( 0 ); 00040 } 00041 }; 00042 00043 inline void qthread_yield() 00044 { 00045 KDevTread::yield(); 00046 } 00047 00048 #endif 00049 00050 #define CREATE_TOKEN(type, start, len) Token( (type), (start), (len), m_source ) 00051 #define ADD_TOKEN(tk) m_tokens.insert( m_size++, new Token(tk) ); 00052 00053 using namespace std; 00054 00055 struct LexerData 00056 { 00057 typedef QMap<QString, QString> Scope; 00058 typedef QValueList<Scope> StaticChain; 00059 00060 StaticChain staticChain; 00061 00062 void beginScope() 00063 { 00064 Scope scope; 00065 staticChain.push_front( scope ); 00066 } 00067 00068 void endScope() 00069 { 00070 staticChain.pop_front(); 00071 } 00072 00073 void bind( const QString& name, const QString& value ) 00074 { 00075 Q_ASSERT( staticChain.size() > 0 ); 00076 staticChain.front().insert( name, value ); 00077 } 00078 00079 bool hasBind( const QString& name ) const 00080 { 00081 StaticChain::ConstIterator it = staticChain.begin(); 00082 while( it != staticChain.end() ){ 00083 const Scope& scope = *it; 00084 ++it; 00085 00086 if( scope.contains(name) ) 00087 return true; 00088 } 00089 00090 return false; 00091 } 00092 00093 QString apply( const QString& name ) const 00094 { 00095 StaticChain::ConstIterator it = staticChain.begin(); 00096 while( it != staticChain.end() ){ 00097 const Scope& scope = *it; 00098 ++it; 00099 00100 if( scope.contains(name) ) 00101 return scope[ name ]; 00102 } 00103 00104 return QString::null; 00105 } 00106 00107 }; 00108 00109 Lexer::Lexer( Driver* driver ) 00110 : d( new LexerData), 00111 m_driver( driver ), 00112 m_recordComments( false ), 00113 m_recordWhiteSpaces( false ), 00114 m_skipWordsEnabled( true ), 00115 m_preprocessorEnabled( true ), 00116 m_reportWarnings( false ), 00117 m_reportMessages( false ) 00118 { 00119 m_tokens.setAutoDelete( true ); 00120 reset(); 00121 d->beginScope(); 00122 } 00123 00124 Lexer::~Lexer() 00125 { 00126 d->endScope(); 00127 delete( d ); 00128 } 00129 00130 void Lexer::setSource( const QString& source ) 00131 { 00132 reset(); 00133 m_source = source; 00134 m_ptr = 0; 00135 m_endPtr = m_source.length(); 00136 m_inPreproc = false; 00137 00138 tokenize(); 00139 } 00140 00141 void Lexer::reset() 00142 { 00143 m_index = 0; 00144 m_size = 0; 00145 m_tokens.clear(); 00146 m_source = QString::null; 00147 m_ptr = 0; 00148 m_endPtr = 0; 00149 m_startLine = false; 00150 m_ifLevel = 0; 00151 m_skipping.resize( 200 ); 00152 m_skipping.fill( 0 ); 00153 m_trueTest.resize( 200 ); 00154 m_trueTest.fill( 0 ); 00155 00156 m_currentLine = 0; 00157 m_currentColumn = 0; 00158 } 00159 00160 // ### should all be done with a "long" type IMO 00161 int Lexer::toInt( const Token& token ) 00162 { 00163 QString s = token.text(); 00164 if( token.type() == Token_number_literal ){ 00165 // hex literal ? 00166 if( s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) 00167 return s.mid( 2 ).toInt( 0, 16 ); 00168 QString n; 00169 int i = 0; 00170 while( i < int(s.length()) && s[i].isDigit() ) 00171 n += s[i++]; 00172 // ### respect more prefixes and suffixes ? 00173 return n.toInt(); 00174 } else if( token.type() == Token_char_literal ){ 00175 int i = s[0] == 'L' ? 2 : 1; // wide char ? 00176 if( s[i] == '\\' ){ 00177 // escaped char 00178 int c = s[i+1].unicode(); 00179 switch( c ) { 00180 case '0': 00181 return 0; 00182 case 'n': 00183 return '\n'; 00184 // ### more 00185 default: 00186 return c; 00187 } 00188 } else { 00189 return s[i].unicode(); 00190 } 00191 } else { 00192 return 0; 00193 } 00194 } 00195 00196 void Lexer::getTokenPosition( const Token& token, int* line, int* col ) 00197 { 00198 token.getStartPosition( line, col ); 00199 } 00200 00201 void Lexer::nextToken( Token& tk, bool stopOnNewline ) 00202 { 00203 int op = 0; 00204 00205 if( m_size == (int)m_tokens.size() ){ 00206 m_tokens.resize( m_tokens.size() + 5000 ); 00207 } 00208 00209 readWhiteSpaces( !stopOnNewline ); 00210 00211 int startLine = m_currentLine; 00212 int startColumn = m_currentColumn; 00213 00214 QChar ch = currentChar(); 00215 QChar ch1 = peekChar(); 00216 00217 if( ch.isNull() || ch.isSpace() ){ 00218 /* skip */ 00219 } else if( m_startLine && ch == '#' ){ 00220 00221 nextChar(); // skip # 00222 readWhiteSpaces( false ); // skip white spaces 00223 m_startLine = false; 00224 00225 int start = currentPosition(); 00226 readIdentifier(); // read the directive 00227 QString directive = m_source.mid( start, currentPosition() - start ); 00228 00229 handleDirective( directive ); 00230 } else if( m_startLine && m_skipping[ m_ifLevel ] ){ 00231 // skip line and continue 00232 m_startLine = false; 00233 int ppe = preprocessorEnabled(); 00234 setPreprocessorEnabled( false ); 00235 while( currentChar() && currentChar() != '\n' ){ 00236 Token tok; 00237 nextToken( tok, true ); 00238 } 00239 m_startLine = true; 00240 setPreprocessorEnabled( ppe ); 00241 return; 00242 } else if( ch == '/' && ch1 == '/' ){ 00243 int start = currentPosition(); 00244 readLineComment(); 00245 if( recordComments() ){ 00246 tk = CREATE_TOKEN( Token_comment, start, currentPosition() - start ); 00247 tk.setStartPosition( startLine, startColumn ); 00248 tk.setEndPosition( m_currentLine, m_currentColumn ); 00249 } 00250 } else if( ch == '/' && ch1 == '*' ){ 00251 int start = currentPosition(); 00252 nextChar( 2 ); 00253 readMultiLineComment(); 00254 00255 if( recordComments() ){ 00256 tk = CREATE_TOKEN( Token_comment, start, currentPosition() - start ); 00257 tk.setStartPosition( startLine, startColumn ); 00258 tk.setEndPosition( m_currentLine, m_currentColumn ); 00259 } 00260 } else if( ch == '\'' || (ch == 'L' && ch1 == '\'') ){ 00261 int start = currentPosition(); 00262 readCharLiteral(); 00263 tk = CREATE_TOKEN( Token_char_literal, start, currentPosition() - start ); 00264 tk.setStartPosition( startLine, startColumn ); 00265 tk.setEndPosition( m_currentLine, m_currentColumn ); 00266 } else if( ch == '"' ){ 00267 int start = currentPosition(); 00268 readStringLiteral(); 00269 tk = CREATE_TOKEN( Token_string_literal, start, currentPosition() - start ); 00270 tk.setStartPosition( startLine, startColumn ); 00271 tk.setEndPosition( m_currentLine, m_currentColumn ); 00272 } else if( ch.isLetter() || ch == '_' ){ 00273 int start = currentPosition(); 00274 readIdentifier(); 00275 QString ide = m_source.mid( start, currentPosition() - start ); 00276 int k = Lookup::find( &keyword, ide ); 00277 if( m_preprocessorEnabled && m_driver->hasMacro(ide) && 00278 (k == -1 || !m_driver->macro(ide).body().isEmpty()) ){ 00279 00280 00281 bool preproc = m_preprocessorEnabled; 00282 m_preprocessorEnabled = false; 00283 00284 d->beginScope(); 00285 00286 int svLine = currentLine(); 00287 int svColumn = currentColumn(); 00288 00289 // Macro& m = m_driver->macro( ide ); 00290 Macro m = m_driver->macro( ide ); 00291 //m_driver->removeMacro( m.name() ); 00292 00293 QString ellipsisArg; 00294 00295 if( m.hasArguments() ){ 00296 int endIde = currentPosition(); 00297 00298 readWhiteSpaces(); 00299 if( currentChar() == '(' ){ 00300 nextChar(); 00301 int argIdx = 0; 00302 int argCount = m.argumentList().size(); 00303 while( currentChar() && argIdx<argCount ){ 00304 readWhiteSpaces(); 00305 00306 QString argName = m.argumentList()[ argIdx ]; 00307 00308 bool ellipsis = argName == "..."; 00309 00310 QString arg = readArgument(); 00311 00312 if( !ellipsis ) 00313 d->bind( argName, arg ); 00314 else 00315 ellipsisArg += arg; 00316 00317 if( currentChar() == ',' ){ 00318 nextChar(); 00319 if( !ellipsis ){ 00320 ++argIdx; 00321 } else { 00322 ellipsisArg += ", "; 00323 } 00324 } else if( currentChar() == ')' ){ 00325 break; 00326 } 00327 } 00328 if( currentChar() == ')' ){ 00329 // valid macro 00330 nextChar(); 00331 } 00332 } else { 00333 tk = CREATE_TOKEN( Token_identifier, start, endIde - start ); 00334 tk.setStartPosition( svLine, svColumn ); 00335 tk.setEndPosition( svLine, svColumn + (endIde - start) ); 00336 00337 m_startLine = false; 00338 00339 d->endScope(); // OPS!! 00340 m_preprocessorEnabled = preproc; 00341 return; 00342 } 00343 } 00344 00345 int argsEndAtLine = currentLine(); 00346 int argsEndAtColumn = currentColumn(); 00347 00348 #if defined( KDEVELOP_BGPARSER ) 00349 qthread_yield(); 00350 #endif 00351 m_source.insert( currentPosition(), m.body() ); 00352 00353 // tokenize the macro body 00354 00355 QString textToInsert; 00356 00357 m_endPtr = currentPosition() + m.body().length(); 00358 while( currentChar() ){ 00359 00360 readWhiteSpaces(); 00361 00362 Token tok; 00363 nextToken( tok ); 00364 00365 bool stringify = !m_inPreproc && tok == '#'; 00366 bool merge = !m_inPreproc && tok == Token_concat; 00367 00368 if( stringify || merge ) 00369 nextToken( tok ); 00370 00371 if( tok == Token_eof ) 00372 break; 00373 00374 QString tokText = tok.text(); 00375 QString str = (tok == Token_identifier && d->hasBind(tokText)) ? d->apply( tokText ) : tokText; 00376 if( str == ide ){ 00377 //Problem p( i18n("unsafe use of macro '%1'").arg(ide), m_currentLine, m_currentColumn ); 00378 //m_driver->addProblem( m_driver->currentFileName(), p ); 00379 m_driver->removeMacro( ide ); 00380 // str = QString::null; 00381 } 00382 00383 if( stringify ) { 00384 textToInsert.append( QString::fromLatin1("\"") + str + QString::fromLatin1("\" ") ); 00385 } else if( merge ){ 00386 textToInsert.truncate( textToInsert.length() - 1 ); 00387 textToInsert.append( str ); 00388 } else if( tok == Token_ellipsis && d->hasBind("...") ){ 00389 textToInsert.append( ellipsisArg ); 00390 } else { 00391 textToInsert.append( str + QString::fromLatin1(" ") ); 00392 } 00393 } 00394 00395 #if defined( KDEVELOP_BGPARSER ) 00396 qthread_yield(); 00397 #endif 00398 m_source.insert( currentPosition(), textToInsert ); 00399 00400 d->endScope(); 00401 m_preprocessorEnabled = preproc; 00402 //m_driver->addMacro( m ); 00403 m_currentLine = argsEndAtLine; 00404 m_currentColumn = argsEndAtColumn; 00405 m_endPtr = m_source.length(); 00406 } else if( k != -1 ){ 00407 tk = CREATE_TOKEN( k, start, currentPosition() - start ); 00408 tk.setStartPosition( startLine, startColumn ); 00409 tk.setEndPosition( m_currentLine, m_currentColumn ); 00410 } else if( m_skipWordsEnabled ){ 00411 QMap< QString, QPair<SkipType, QString> >::Iterator pos = m_words.find( ide ); 00412 if( pos != m_words.end() ){ 00413 if( (*pos).first == SkipWordAndArguments ){ 00414 readWhiteSpaces(); 00415 if( currentChar() == '(' ) 00416 skip( '(', ')' ); 00417 } 00418 if( !(*pos).second.isEmpty() ){ 00419 #if defined( KDEVELOP_BGPARSER ) 00420 qthread_yield(); 00421 #endif 00422 m_source.insert( currentPosition(), QString(" ") + (*pos).second + QString(" ") ); 00423 m_endPtr = m_source.length(); 00424 } 00425 } else if( /*qt_rx.exactMatch(ide) ||*/ 00426 ide.endsWith("EXPORT") || 00427 (ide.startsWith("Q_EXPORT") && ide != "Q_EXPORT_INTERFACE") || 00428 ide.startsWith("QM_EXPORT") || 00429 ide.startsWith("QM_TEMPLATE")){ 00430 00431 readWhiteSpaces(); 00432 if( currentChar() == '(' ) 00433 skip( '(', ')' ); 00434 } else if( ide.startsWith("K_TYPELIST_") || ide.startsWith("TYPELIST_") ){ 00435 tk = CREATE_TOKEN( Token_identifier, start, currentPosition() - start ); 00436 tk.setStartPosition( startLine, startColumn ); 00437 tk.setEndPosition( m_currentLine, m_currentColumn ); 00438 readWhiteSpaces(); 00439 if( currentChar() == '(' ) 00440 skip( '(', ')' ); 00441 } else{ 00442 tk = CREATE_TOKEN( Token_identifier, start, currentPosition() - start ); 00443 tk.setStartPosition( startLine, startColumn ); 00444 tk.setEndPosition( m_currentLine, m_currentColumn ); 00445 } 00446 } else { 00447 tk = CREATE_TOKEN( Token_identifier, start, currentPosition() - start ); 00448 tk.setStartPosition( startLine, startColumn ); 00449 tk.setEndPosition( m_currentLine, m_currentColumn ); 00450 } 00451 } else if( ch.isNumber() ){ 00452 int start = currentPosition(); 00453 readNumberLiteral(); 00454 tk = CREATE_TOKEN( Token_number_literal, start, currentPosition() - start ); 00455 tk.setStartPosition( startLine, startColumn ); 00456 tk.setEndPosition( m_currentLine, m_currentColumn ); 00457 } else if( -1 != (op = findOperator3()) ){ 00458 tk = CREATE_TOKEN( op, currentPosition(), 3 ); 00459 nextChar( 3 ); 00460 tk.setStartPosition( startLine, startColumn ); 00461 tk.setEndPosition( m_currentLine, m_currentColumn ); 00462 } else if( -1 != (op = findOperator2()) ){ 00463 tk = CREATE_TOKEN( op, currentPosition(), 2 ); 00464 nextChar( 2 ); 00465 tk.setStartPosition( startLine, startColumn ); 00466 tk.setEndPosition( m_currentLine, m_currentColumn ); 00467 } else { 00468 tk = CREATE_TOKEN( ch, currentPosition(), 1 ); 00469 nextChar(); 00470 tk.setStartPosition( startLine, startColumn ); 00471 tk.setEndPosition( m_currentLine, m_currentColumn ); 00472 } 00473 00474 m_startLine = false; 00475 } 00476 00477 00478 void Lexer::tokenize() 00479 { 00480 m_startLine = true; 00481 m_size = 0; 00482 00483 for( ;; ) { 00484 Token tk; 00485 nextToken( tk ); 00486 00487 if( tk.type() != -1 ) 00488 ADD_TOKEN( tk ); 00489 00490 if( currentChar().isNull() ) 00491 break; 00492 } 00493 00494 Token tk = CREATE_TOKEN( Token_eof, currentPosition(), 0 ); 00495 tk.setStartPosition( m_currentLine, m_currentColumn ); 00496 tk.setEndPosition( m_currentLine, m_currentColumn ); 00497 ADD_TOKEN( tk ); 00498 } 00499 00500 void Lexer::resetSkipWords() 00501 { 00502 m_words.clear(); 00503 } 00504 00505 void Lexer::addSkipWord( const QString& word, SkipType skipType, const QString& str ) 00506 { 00507 m_words[ word ] = qMakePair( skipType, str ); 00508 } 00509 00510 void Lexer::skip( int l, int r ) 00511 { 00512 int svCurrentLine = m_currentLine; 00513 int svCurrentColumn = m_currentColumn; 00514 00515 int count = 0; 00516 00517 while( !eof() ){ 00518 Token tk; 00519 nextToken( tk ); 00520 00521 if( (int)tk == l ) 00522 ++count; 00523 else if( (int)tk == r ) 00524 --count; 00525 00526 if( count == 0 ) 00527 break; 00528 } 00529 00530 m_currentLine = svCurrentLine; 00531 m_currentColumn = svCurrentColumn; 00532 } 00533 00534 QString Lexer::readArgument() 00535 { 00536 int count = 0; 00537 00538 QString arg; 00539 00540 readWhiteSpaces(); 00541 while( currentChar() ){ 00542 00543 readWhiteSpaces(); 00544 QChar ch = currentChar(); 00545 00546 if( ch.isNull() || (!count && (ch == ',' || ch == ')')) ) 00547 break; 00548 00549 Token tk; 00550 nextToken( tk ); 00551 00552 if( tk == '(' ){ 00553 ++count; 00554 } else if( tk == ')' ){ 00555 --count; 00556 } 00557 00558 if( tk != -1 ) 00559 arg += tk.text() + " "; 00560 } 00561 00562 return arg.stripWhiteSpace(); 00563 } 00564 00565 void Lexer::handleDirective( const QString& directive ) 00566 { 00567 m_inPreproc = true; 00568 00569 bool skip = skipWordsEnabled(); 00570 bool preproc = preprocessorEnabled(); 00571 00572 setSkipWordsEnabled( false ); 00573 setPreprocessorEnabled( false ); 00574 00575 if( directive == "define" ){ 00576 if( !m_skipping[ m_ifLevel ] ){ 00577 Macro m; 00578 processDefine( m ); 00579 } 00580 } else if( directive == "else" ){ 00581 processElse(); 00582 } else if( directive == "elif" ){ 00583 processElif(); 00584 } else if( directive == "endif" ){ 00585 processEndif(); 00586 } else if( directive == "if" ){ 00587 processIf(); 00588 } else if( directive == "ifdef" ){ 00589 processIfdef(); 00590 } else if( directive == "ifndef" ){ 00591 processIfndef(); 00592 } else if( directive == "include" ){ 00593 if( !m_skipping[ m_ifLevel ] ){ 00594 processInclude(); 00595 } 00596 } else if( directive == "undef" ){ 00597 if( !m_skipping[ m_ifLevel ] ){ 00598 processUndef(); 00599 } 00600 } 00601 00602 // skip line 00603 while( currentChar() && currentChar() != '\n' ){ 00604 Token tk; 00605 nextToken( tk, true ); 00606 } 00607 00608 setSkipWordsEnabled( skip ); 00609 setPreprocessorEnabled( preproc ); 00610 00611 m_inPreproc = false; 00612 } 00613 00614 int Lexer::testIfLevel() 00615 { 00616 int rtn = !m_skipping[ m_ifLevel++ ]; 00617 m_skipping[ m_ifLevel ] = m_skipping[ m_ifLevel - 1 ]; 00618 return rtn; 00619 } 00620 00621 int Lexer::macroDefined() 00622 { 00623 readWhiteSpaces( false ); 00624 int startWord = currentPosition(); 00625 readIdentifier(); 00626 QString word = m_source.mid( startWord, currentPosition() - startWord ); 00627 bool r = m_driver->hasMacro( word ); 00628 00629 return r; 00630 } 00631 00632 void Lexer::processDefine( Macro& m ) 00633 { 00634 m.setFileName( m_driver->currentFileName() ); 00635 readWhiteSpaces( false ); 00636 00637 int startMacroName = currentPosition(); 00638 readIdentifier(); 00639 QString macroName = m_source.mid( startMacroName, int(currentPosition()-startMacroName) ); 00640 m_driver->removeMacro( macroName ); 00641 m.setName( macroName ); 00642 00643 if( currentChar() == '(' ){ 00644 m.setHasArguments( true ); 00645 nextChar(); 00646 00647 readWhiteSpaces( false ); 00648 00649 while( currentChar() && currentChar() != ')' ){ 00650 readWhiteSpaces( false ); 00651 00652 int startArg = currentPosition(); 00653 00654 if( currentChar() == '.' && peekChar() == '.' && peekChar(2) == '.' ) 00655 nextChar( 3 ); 00656 else 00657 readIdentifier(); 00658 00659 QString arg = m_source.mid( startArg, int(currentPosition()-startArg) ); 00660 00661 m.addArgument( Macro::Argument(arg) ); 00662 00663 readWhiteSpaces( false ); 00664 if( currentChar() != ',' ) 00665 break; 00666 00667 nextChar(); // skip ',' 00668 } 00669 00670 if( currentChar() == ')' ) 00671 nextChar(); // skip ')' 00672 } 00673 00674 setPreprocessorEnabled( true ); 00675 00676 QString body; 00677 while( currentChar() && currentChar() != '\n' ){ 00678 00679 if( currentChar().isSpace() ){ 00680 readWhiteSpaces( false ); 00681 body += " "; 00682 } else { 00683 00684 Token tk; 00685 nextToken( tk, true ); 00686 00687 if( tk.type() != -1 ){ 00688 QString s = tk.text(); 00689 body += s; 00690 } 00691 } 00692 } 00693 00694 m.setBody( body ); 00695 m_driver->addMacro( m ); 00696 } 00697 00698 void Lexer::processElse() 00699 { 00700 if( m_ifLevel == 0 ) 00702 return; 00703 00704 if( m_ifLevel > 0 && m_skipping[m_ifLevel-1] ) 00705 m_skipping[ m_ifLevel ] = m_skipping[ m_ifLevel - 1 ]; 00706 else 00707 m_skipping[ m_ifLevel ] = m_trueTest[ m_ifLevel ]; 00708 } 00709 00710 void Lexer::processElif() 00711 { 00712 if( m_ifLevel == 0 ) 00714 return; 00715 00716 if( !m_trueTest[m_ifLevel] ){ 00718 bool inSkip = m_ifLevel > 0 && m_skipping[ m_ifLevel-1 ]; 00719 m_trueTest[ m_ifLevel ] = macroExpression() != 0; 00720 m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ]; 00721 } 00722 else 00723 m_skipping[ m_ifLevel ] = true; 00724 } 00725 00726 void Lexer::processEndif() 00727 { 00728 if( m_ifLevel == 0 ) 00730 return; 00731 00732 m_skipping[ m_ifLevel ] = 0; 00733 m_trueTest[ m_ifLevel-- ] = 0; 00734 } 00735 00736 void Lexer::processIf() 00737 { 00738 bool inSkip = m_skipping[ m_ifLevel ]; 00739 00740 if( testIfLevel() ) { 00741 #if 0 00742 int n; 00743 if( (n = testDefined()) != 0 ) { 00744 int isdef = macroDefined(); 00745 m_trueTest[ m_ifLevel ] = (n == 1 && isdef) || (n == -1 && !isdef); 00746 } else 00747 #endif 00748 m_trueTest[ m_ifLevel ] = macroExpression() != 0; 00749 m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ]; 00750 } 00751 } 00752 00753 void Lexer::processIfdef() 00754 { 00755 bool inSkip = m_skipping[ m_ifLevel ]; 00756 00757 if( testIfLevel() ){ 00758 m_trueTest[ m_ifLevel ] = macroDefined(); 00759 m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ]; 00760 } 00761 } 00762 00763 void Lexer::processIfndef() 00764 { 00765 bool inSkip = m_skipping[ m_ifLevel ]; 00766 00767 if( testIfLevel() ){ 00768 m_trueTest[ m_ifLevel ] = !macroDefined(); 00769 m_skipping[ m_ifLevel ] = inSkip ? inSkip : !m_trueTest[ m_ifLevel ]; 00770 } 00771 } 00772 00773 void Lexer::processInclude() 00774 { 00775 if( m_skipping[m_ifLevel] ) 00776 return; 00777 00778 readWhiteSpaces( false ); 00779 if( currentChar() ){ 00780 QChar ch = currentChar(); 00781 if( ch == '"' || ch == '<' ){ 00782 nextChar(); 00783 QChar ch2 = ch == QChar('"') ? QChar('"') : QChar('>'); 00784 00785 int startWord = currentPosition(); 00786 while( currentChar() && currentChar() != ch2 ) 00787 nextChar(); 00788 if( currentChar() ){ 00789 QString word = m_source.mid( startWord, int(currentPosition()-startWord) ); 00790 m_driver->addDependence( m_driver->currentFileName(), 00791 Dependence(word, ch == '"' ? Dep_Local : Dep_Global) ); 00792 nextChar(); 00793 } 00794 } 00795 } 00796 } 00797 00798 void Lexer::processUndef() 00799 { 00800 readWhiteSpaces(); 00801 int startWord = currentPosition(); 00802 readIdentifier(); 00803 QString word = m_source.mid( startWord, currentPosition() - startWord ); 00804 m_driver->removeMacro( word ); 00805 } 00806 00807 int Lexer::macroPrimary() 00808 { 00809 readWhiteSpaces( false ); 00810 int result = 0; 00811 switch( currentChar() ) { 00812 case '(': 00813 nextChar(); 00814 result = macroExpression(); 00815 if( currentChar() != ')' ){ 00817 return 0; 00818 } 00819 nextChar(); 00820 return result; 00821 00822 case '+': 00823 case '-': 00824 case '!': 00825 case '~': 00826 { 00827 QChar tk = currentChar(); 00828 nextChar(); 00829 int result = macroPrimary(); 00830 if( tk == '-' ) return -result; 00831 else if( tk == '!' ) return !result; 00832 else if( tk == '~' ) return ~result; 00833 } 00834 break; 00835 00836 default: 00837 { 00838 Token tk; 00839 nextToken( tk, false ); 00840 switch( tk.type() ){ 00841 case Token_identifier: 00842 if( tk.text() == "defined" ){ 00843 return macroPrimary(); 00844 } 00846 return m_driver->hasMacro( tk.text() ); 00847 case Token_number_literal: 00848 case Token_char_literal: 00849 return toInt( tk ); 00850 default: 00851 break; 00852 } // end switch 00853 00854 } // end default 00855 00856 } // end switch 00857 00858 return 0; 00859 } 00860 00861 int Lexer::macroMultiplyDivide() 00862 { 00863 int result = macroPrimary(); 00864 int iresult, op; 00865 for (;;) { 00866 readWhiteSpaces( false ); 00867 if( currentChar() == '*' ) 00868 op = 0; 00869 else if( currentChar() == '/' && !(peekChar() == '*' || peekChar() == '/') ) 00870 op = 1; 00871 else if( currentChar() == '%' ) 00872 op = 2; 00873 else 00874 break; 00875 nextChar(); 00876 iresult = macroPrimary(); 00877 result = op == 0 ? (result * iresult) : 00878 op == 1 ? (iresult == 0 ? 0 : (result / iresult)) : 00879 (iresult == 0 ? 0 : (result % iresult)) ; 00880 } 00881 return result; 00882 } 00883 00884 int Lexer::macroAddSubtract() 00885 { 00886 int result = macroMultiplyDivide(); 00887 int iresult, ad; 00888 readWhiteSpaces( false ); 00889 while( currentChar() == '+' || currentChar() == '-') { 00890 ad = currentChar() == '+'; 00891 nextChar(); 00892 iresult = macroMultiplyDivide(); 00893 result = ad ? (result+iresult) : (result-iresult); 00894 } 00895 return result; 00896 } 00897 00898 int Lexer::macroRelational() 00899 { 00900 int result = macroAddSubtract(); 00901 int iresult; 00902 readWhiteSpaces( false ); 00903 while( currentChar() == '<' || currentChar() == '>') { 00904 int lt = currentChar() == '<'; 00905 nextChar(); 00906 if( currentChar() == '=') { 00907 nextChar(); 00908 00909 iresult = macroAddSubtract(); 00910 result = lt ? (result <= iresult) : (result >= iresult); 00911 } 00912 else { 00913 iresult = macroAddSubtract(); 00914 result = lt ? (result < iresult) : (result > iresult); 00915 } 00916 } 00917 00918 return result; 00919 } 00920 00921 int Lexer::macroEquality() 00922 { 00923 int result = macroRelational(); 00924 int iresult, eq; 00925 readWhiteSpaces( false ); 00926 while ((currentChar() == '=' || currentChar() == '!') && peekChar() == '=') { 00927 eq = currentChar() == '='; 00928 nextChar( 2 ); 00929 iresult = macroRelational(); 00930 result = eq ? (result==iresult) : (result!=iresult); 00931 } 00932 return result; 00933 } 00934 00935 int Lexer::macroBoolAnd() 00936 { 00937 int result = macroEquality(); 00938 readWhiteSpaces( false ); 00939 while( currentChar() == '&' && peekChar() != '&') { 00940 nextChar(); 00941 result &= macroEquality(); 00942 } 00943 return result; 00944 } 00945 00946 int Lexer::macroBoolXor() 00947 { 00948 int result = macroBoolAnd(); 00949 readWhiteSpaces( false ); 00950 while( currentChar() == '^') { 00951 nextChar(); 00952 result ^= macroBoolAnd(); 00953 } 00954 return result; 00955 } 00956 00957 int Lexer::macroBoolOr() 00958 { 00959 int result = macroBoolXor(); 00960 readWhiteSpaces( false ); 00961 while( currentChar() == '|' && peekChar() != '|') { 00962 nextChar(); 00963 result |= macroBoolXor(); 00964 } 00965 return result; 00966 } 00967 00968 int Lexer::macroLogicalAnd() 00969 { 00970 int result = macroBoolOr(); 00971 readWhiteSpaces( false ); 00972 while( currentChar() == '&' && peekChar() == '&') { 00973 nextChar( 2 ); 00974 int start = currentPosition(); 00975 result = macroBoolOr() && result; 00976 QString s = m_source.mid( start, currentPosition() - start ); 00977 } 00978 return result; 00979 } 00980 00981 int Lexer::macroLogicalOr() 00982 { 00983 int result = macroLogicalAnd(); 00984 readWhiteSpaces( false ); 00985 while( currentChar() == '|' && peekChar() == '|') { 00986 nextChar( 2 ); 00987 result = macroLogicalAnd() || result; 00988 } 00989 return result; 00990 } 00991 00992 int Lexer::macroExpression() 00993 { 00994 readWhiteSpaces( false ); 00995 return macroLogicalOr(); 00996 } 00997 00998 // *IMPORTANT* 00999 // please, don't include lexer.moc here, because Lexer isn't a QObject class!! 01000 // if you have problem while recompiling try to remove cppsupport/.deps, 01001 // cppsupport/Makefile.in and rerun automake/autoconf 01002
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:07 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003