KDevelop API Documentation

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.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:35 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003