[cfe-commits] r38646 - in /cfe/cfe/trunk: Lex/Lexer.cpp Lex/Pragma.cpp Lex/Preprocessor.cpp include/clang/Lex/Lexer.h include/clang/Lex/MultipleIncludeOpt.h include/clang/Lex/Preprocessor.h

sabre at cs.uiuc.edu sabre at cs.uiuc.edu
Wed Jul 11 09:23:29 PDT 2007


Author: sabre
Date: Wed Jul 11 11:23:29 2007
New Revision: 38646

URL: http://llvm.org/viewvc/llvm-project?rev=38646&view=rev
Log:
Implement the automaton for recognizing files with controlling macros.

Added:
    cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h   (with props)
Modified:
    cfe/cfe/trunk/Lex/Lexer.cpp
    cfe/cfe/trunk/Lex/Pragma.cpp
    cfe/cfe/trunk/Lex/Preprocessor.cpp
    cfe/cfe/trunk/include/clang/Lex/Lexer.h
    cfe/cfe/trunk/include/clang/Lex/Preprocessor.h

Modified: cfe/cfe/trunk/Lex/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Lexer.cpp?rev=38646&r1=38645&r2=38646&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Lexer.cpp (original)
+++ cfe/cfe/trunk/Lex/Lexer.cpp Wed Jul 11 11:23:29 2007
@@ -979,6 +979,8 @@
     goto LexNextToken;   // GCC isn't tail call eliminating.
 
   case 'L':
+    // Notify MIOpt that we read a non-whitespace/non-comment token.
+    MIOpt.ReadToken();
     Char = getCharAndSize(CurPtr, SizeTmp);
 
     // Wide string literal.
@@ -1000,20 +1002,28 @@
   case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
   case 'v': case 'w': case 'x': case 'y': case 'z':
   case '_':
+    // Notify MIOpt that we read a non-whitespace/non-comment token.
+    MIOpt.ReadToken();
     return LexIdentifier(Result, CurPtr);
     
   // C99 6.4.4.1: Integer Constants.
   // C99 6.4.4.2: Floating Constants.
   case '0': case '1': case '2': case '3': case '4':
   case '5': case '6': case '7': case '8': case '9':
+    // Notify MIOpt that we read a non-whitespace/non-comment token.
+    MIOpt.ReadToken();
     return LexNumericConstant(Result, CurPtr);
     
   // C99 6.4.4: Character Constants.
   case '\'':
+    // Notify MIOpt that we read a non-whitespace/non-comment token.
+    MIOpt.ReadToken();
     return LexCharConstant(Result, CurPtr);
 
   // C99 6.4.5: String Literals.
   case '"':
+    // Notify MIOpt that we read a non-whitespace/non-comment token.
+    MIOpt.ReadToken();
     return LexStringLiteral(Result, CurPtr);
 
   // C99 6.4.6: Punctuators.
@@ -1041,6 +1051,9 @@
   case '.':
     Char = getCharAndSize(CurPtr, SizeTmp);
     if (Char >= '0' && Char <= '9') {
+      // Notify MIOpt that we read a non-whitespace/non-comment token.
+      MIOpt.ReadToken();
+
       return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
     } else if (Features.CPlusPlus && Char == '*') {
       Result.SetKind(tok::periodstar);
@@ -1333,6 +1346,8 @@
       break;
     } else if (CurPtr[-1] == '$' && Features.DollarIdents) {// $ in identifiers.
       Diag(CurPtr-1, diag::ext_dollar_in_identifier);
+      // Notify MIOpt that we read a non-whitespace/non-comment token.
+      MIOpt.ReadToken();
       return LexIdentifier(Result, CurPtr);
     }
     
@@ -1341,6 +1356,9 @@
     goto LexNextToken;   // GCC isn't tail call eliminating.
   }
   
+  // Notify MIOpt that we read a non-whitespace/non-comment token.
+  MIOpt.ReadToken();
+
   // Update the location of token as well as BufferPtr.
   FormTokenWithChars(Result, CurPtr);
 }

Modified: cfe/cfe/trunk/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Pragma.cpp?rev=38646&r1=38645&r2=38646&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Pragma.cpp (original)
+++ cfe/cfe/trunk/Lex/Pragma.cpp Wed Jul 11 11:23:29 2007
@@ -74,6 +74,9 @@
 void Preprocessor::HandlePragmaDirective() {
   ++NumPragma;
   
+  // Inform MIOpt that we found a side-effect of parsing this file.
+  CurLexer->MIOpt.ReadDirective();
+  
   // Invoke the first level of pragma handlers which reads the namespace id.
   LexerToken Tok;
   PragmaHandlers->HandlePragma(*this, Tok);

Modified: cfe/cfe/trunk/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Preprocessor.cpp?rev=38646&r1=38645&r2=38646&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/cfe/trunk/Lex/Preprocessor.cpp Wed Jul 11 11:23:29 2007
@@ -739,6 +739,14 @@
     return;
   }
   
+  // See if this file had a controlling macro.
+  if (CurLexer) {  // Not ending a macro...
+    if (const IdentifierTokenInfo *ControllingMacro = 
+          CurLexer->MIOpt.GetControllingMacroAtEndOfFile()) {
+      ;
+    }
+  }
+  
   // If this is a #include'd file, pop it off the include stack and continue
   // lexing the #includer file.
   if (!IncludeMacroStack.empty()) {
@@ -1049,6 +1057,11 @@
   
   ++NumDirectives;
   
+  // We are about to read a token.  For the multiple-include optimization FA to
+  // work, we have to remember if we had read any tokens *before* this 
+  // pp-directive.
+  bool ReadAnyTokensBeforeDirective = CurLexer->MIOpt.getHasReadAnyTokensVal();
+  
   // Read the next token, the directive flavor.
   LexUnexpandedToken(Result);
   
@@ -1059,6 +1072,7 @@
 
 #if 0
   case tok::numeric_constant:
+    MIOpt.ReadDirective();
     // FIXME: implement # 7 line numbers!
     break;
 #endif
@@ -1073,7 +1087,7 @@
     switch (Result.getIdentifierInfo()->getNameLength()) {
     case 4:
       if (Directive[0] == 'l' && !strcmp(Directive, "line"))
-        ;  // FIXME: implement #line
+        CurLexer->MIOpt.ReadDirective();  // FIXME: implement #line
       if (Directive[0] == 'e' && !strcmp(Directive, "elif"))
         return HandleElifDirective(Result);
       if (Directive[0] == 's' && !strcmp(Directive, "sccs"))
@@ -1083,7 +1097,7 @@
       if (Directive[0] == 'e' && !strcmp(Directive, "endif"))
         return HandleEndifDirective(Result);
       if (Directive[0] == 'i' && !strcmp(Directive, "ifdef"))
-        return HandleIfdefDirective(Result, false);
+        return HandleIfdefDirective(Result, false, true/*not valid for miopt*/);
       if (Directive[0] == 'u' && !strcmp(Directive, "undef"))
         return HandleUndefDirective(Result);
       if (Directive[0] == 'e' && !strcmp(Directive, "error"))
@@ -1095,7 +1109,7 @@
       if (Directive[0] == 'd' && !strcmp(Directive, "define"))
         return HandleDefineDirective(Result);
       if (Directive[0] == 'i' && !strcmp(Directive, "ifndef"))
-        return HandleIfdefDirective(Result, true);
+        return HandleIfdefDirective(Result, true, ReadAnyTokensBeforeDirective);
       if (Directive[0] == 'i' && !strcmp(Directive, "import"))
         return HandleImportDirective(Result);
       if (Directive[0] == 'p' && !strcmp(Directive, "pragma"))
@@ -1128,9 +1142,7 @@
   Diag(Result, diag::err_pp_invalid_directive);
   
   // Read the rest of the PP line.
-  do {
-    Lex(Result);
-  } while (Result.getKind() != tok::eom);
+  DiscardUntilEndOfDirective();
   
   // Okay, we're done parsing the directive.
 }
@@ -1151,8 +1163,13 @@
 /// HandleIdentSCCSDirective - Handle a #ident/#sccs directive.
 ///
 void Preprocessor::HandleIdentSCCSDirective(LexerToken &Tok) {
+  // Inform MIOpt that we found a side-effect of parsing this file.
+  CurLexer->MIOpt.ReadDirective();
+  
+  // Yes, this directive is an extension.
   Diag(Tok, diag::ext_pp_ident_directive);
   
+  // Read the string argument.
   LexerToken StrTok;
   Lex(StrTok);
   
@@ -1179,6 +1196,10 @@
                                           const DirectoryLookup *LookupFrom,
                                           bool isImport) {
   ++NumIncluded;
+
+  // Inform MIOpt that we found a side-effect of parsing this file.
+  CurLexer->MIOpt.ReadDirective();
+
   LexerToken FilenameTok;
   std::string Filename = CurLexer->LexIncludeFilename(FilenameTok);
   
@@ -1225,8 +1246,7 @@
   }
 
   // Look up the file, create a File ID for it.
-  unsigned FileID = 
-    SourceMgr.createFileID(File, FilenameTok.getLocation());
+  unsigned FileID = SourceMgr.createFileID(File, FilenameTok.getLocation());
   if (FileID == 0)
     return Diag(FilenameTok, diag::err_pp_file_not_found);
 
@@ -1276,6 +1296,10 @@
 ///
 void Preprocessor::HandleDefineDirective(LexerToken &DefineTok) {
   ++NumDefined;
+
+  // Inform MIOpt that we found a side-effect of parsing this file.
+  CurLexer->MIOpt.ReadDirective();
+
   LexerToken MacroNameTok;
   ReadMacroName(MacroNameTok, true);
   
@@ -1345,6 +1369,10 @@
 ///
 void Preprocessor::HandleUndefDirective(LexerToken &UndefTok) {
   ++NumUndefined;
+
+  // Inform MIOpt that we found a side-effect of parsing this file.
+  CurLexer->MIOpt.ReadDirective();
+
   LexerToken MacroNameTok;
   ReadMacroName(MacroNameTok, true);
   
@@ -1375,12 +1403,15 @@
 //===----------------------------------------------------------------------===//
 
 /// HandleIfdefDirective - Implements the #ifdef/#ifndef directive.  isIfndef is
-/// true when this is a #ifndef directive.
+/// true when this is a #ifndef directive.  ReadAnyTokensBeforeDirective is true
+/// if any tokens have been returned or pp-directives activated before this
+/// #ifndef has been lexed.
 ///
-void Preprocessor::HandleIfdefDirective(LexerToken &Result, bool isIfndef) {
+void Preprocessor::HandleIfdefDirective(LexerToken &Result, bool isIfndef,
+                                        bool ReadAnyTokensBeforeDirective) {
   ++NumIf;
   LexerToken DirectiveTok = Result;
-  
+
   LexerToken MacroNameTok;
   ReadMacroName(MacroNameTok);
   
@@ -1389,7 +1420,14 @@
     return;
   
   // Check to see if this is the last token on the #if[n]def line.
-  CheckEndOfDirective("#ifdef");
+  CheckEndOfDirective(isIfndef ? "#ifndef" : "#ifdef");
+  
+  // If the start of a top-level #ifdef, inform MIOpt.
+  if (!ReadAnyTokensBeforeDirective &&
+      CurLexer->getConditionalStackDepth() == 0) {
+    assert(isIfndef && "#ifdef shouldn't reach here");
+    CurLexer->MIOpt.EnterTopLevelIFNDEF(MacroNameTok.getIdentifierInfo());
+  }
   
   MacroInfo *MI = MacroNameTok.getIdentifierInfo()->getMacroInfo();
 
@@ -1413,6 +1451,11 @@
 ///
 void Preprocessor::HandleIfDirective(LexerToken &IfToken) {
   ++NumIf;
+  
+  // FIXME: Detect "#if !defined(X)" for the MIOpt.
+  CurLexer->MIOpt.ReadDirective();
+
+  // Parse and evaluation the conditional expression.
   bool ConditionalTrue = EvaluateDirectiveExpression();
   
   // Should we include the stuff contained by this directive?
@@ -1431,6 +1474,7 @@
 ///
 void Preprocessor::HandleEndifDirective(LexerToken &EndifToken) {
   ++NumEndif;
+  
   // Check that this is the whole directive.
   CheckEndOfDirective("#endif");
   
@@ -1440,6 +1484,10 @@
     return Diag(EndifToken, diag::err_pp_endif_without_if);
   }
   
+  // If this the end of a top-level #endif, inform MIOpt.
+  if (CurLexer->getConditionalStackDepth() == 0)
+    CurLexer->MIOpt.ExitTopLevelConditional();
+  
   assert(!CondInfo.WasSkipping && !isSkipping() &&
          "This code should only be reachable in the non-skipping case!");
 }
@@ -1447,12 +1495,17 @@
 
 void Preprocessor::HandleElseDirective(LexerToken &Result) {
   ++NumElse;
+  
   // #else directive in a non-skipping conditional... start skipping.
   CheckEndOfDirective("#else");
   
   PPConditionalInfo CI;
   if (CurLexer->popConditionalLevel(CI))
     return Diag(Result, diag::pp_err_else_without_if);
+  
+  // If this is a top-level #else, inform the MIOpt.
+  if (CurLexer->getConditionalStackDepth() == 0)
+    CurLexer->MIOpt.FoundTopLevelElse();
 
   // If this is a #else with a #else before it, report the error.
   if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else);
@@ -1465,6 +1518,7 @@
 
 void Preprocessor::HandleElifDirective(LexerToken &ElifToken) {
   ++NumElse;
+  
   // #elif directive in a non-skipping conditional... start skipping.
   // We don't care what the condition is, because we will always skip it (since
   // the block immediately before it was included).
@@ -1474,6 +1528,10 @@
   if (CurLexer->popConditionalLevel(CI))
     return Diag(ElifToken, diag::pp_err_elif_without_if);
   
+  // If this is a top-level #elif, inform the MIOpt.
+  if (CurLexer->getConditionalStackDepth() == 0)
+    CurLexer->MIOpt.FoundTopLevelElse();
+  
   // If this is a #elif with a #else before it, report the error.
   if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else);
 

Modified: cfe/cfe/trunk/include/clang/Lex/Lexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Lexer.h?rev=38646&r1=38645&r2=38646&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Lexer.h (original)
+++ cfe/cfe/trunk/include/clang/Lex/Lexer.h Wed Jul 11 11:23:29 2007
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_LEXER_H
 
 #include "clang/Lex/LexerToken.h"
+#include "clang/Lex/MultipleIncludeOpt.h"
 #include <string>
 #include <vector>
 
@@ -66,7 +67,11 @@
   bool ParsingFilename;          // True after #include: turn <xx> into string.
   
   // Context that changes as the file is lexed.
-    
+  
+  /// MIOpt - This is a state machine that detects the #ifndef-wrapping a file 
+  /// idiom for the multiple-include optimization.
+  MultipleIncludeOpt MIOpt;
+  
   /// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks
   /// we are currently in.
   std::vector<PPConditionalInfo> ConditionalStack;
@@ -114,7 +119,8 @@
       IsAtStartOfLine = false;
     }
    
-    // Get a token.
+    // Get a token.  Note that this may delete the current lexer if the end of
+    // file is reached.
     LexTokenInternal(Result);
   }
   

Added: cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h?rev=38646&view=auto

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h Wed Jul 11 11:23:29 2007
@@ -0,0 +1,111 @@
+//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the MultipleIncludeOpt interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H
+#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H
+
+namespace llvm {
+namespace clang {
+class IdentifierTokenInfo;
+
+/// MultipleIncludeOpt - This class implements the simple state machine that the
+/// Lexer class uses to detect files subject to the 'multiple-include'
+/// optimization.  The public methods in this class are triggered by various
+/// events that occur when a file is lexed, and after the entire file is lexed,
+/// information about which macro (if any) controls the header is returned.
+class MultipleIncludeOpt {
+  /// ReadAnyTokens - This is set to false when a file is first opened and true
+  /// any time a token is returned to the client or a (non-multiple-include)
+  /// directive is parsed.  When the final #endif is parsed this is reset back
+  /// to false, that way any tokens before the first #ifdef or after the last
+  /// #endif can be easily detected.
+  bool ReadAnyTokens;
+  
+  /// TheMacro - The controlling macro for a file, if valid.
+  ///
+  const IdentifierTokenInfo *TheMacro;
+public:
+  MultipleIncludeOpt() : ReadAnyTokens(false), TheMacro(0) {}
+  
+  /// Invalidate - Permenantly mark this file as not being suitable for the
+  /// include-file optimization.
+  void Invalidate() {
+    // If we have read tokens but have no controlling macro, the state-machine
+    // below can never "accept".
+    ReadAnyTokens = true;
+    TheMacro = 0;
+  }
+  
+  /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the
+  /// top of the file when reading preprocessor directives.  Otherwise, reading
+  /// the "ifndef x" would count as reading tokens.
+  bool getHasReadAnyTokensVal() const { return ReadAnyTokens; }
+  
+  // If a token or directive is read, remember that we have seen a side-effect
+  // in this file.
+  void ReadToken()     { ReadAnyTokens = true; }
+  void ReadDirective() { ReadAnyTokens = true; } 
+  
+  /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the
+  /// "#if !defined" equivalent) without any preceding tokens, this method is
+  /// called.
+  void EnterTopLevelIFNDEF(const IdentifierTokenInfo *M) {
+    // Note, we don't care about the input value of 'ReadAnyTokens'.  The caller
+    // ensures that this is only called if there are no tokens read before the
+    // #ifndef.
+    
+    // If the macro is already set, this is after the top-level #endif.
+    if (TheMacro)
+      return Invalidate();
+    
+    // Remember that we're in the #if and that we have the macro.
+    ReadAnyTokens = true;
+    TheMacro = M;
+  }
+
+  /// FoundTopLevelElse - This is invoked when an #else/#elif directive is found
+  /// in the top level conditional in the file.
+  void FoundTopLevelElse() {
+    /// If a #else directive is found at the top level, there is a chunk of the
+    /// file not guarded by the controlling macro.
+    Invalidate();
+  }
+  
+  /// ExitTopLevelConditional - This method is called when the lexer exits the
+  /// top-level conditional.
+  void ExitTopLevelConditional() {
+    // If we have a macro, that means the top of the file was ok.  Set our state
+    // back to "not having read any tokens" so we can detect anything after the
+    // #endif.
+    if (!TheMacro) return Invalidate();
+    
+    // At this point, we haven't "read any tokens" but we do have a controlling
+    // macro.
+    ReadAnyTokens = false;
+  }
+  
+  /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if
+  /// there is a controlling macro, return it.
+  const IdentifierTokenInfo *GetControllingMacroAtEndOfFile() const {
+    // If we haven't read any tokens after the #endif, return the controlling
+    // macro if it's valid (if it isn't, it will be null).
+    if (!ReadAnyTokens)
+      return TheMacro;
+    return 0;
+  }
+};
+
+}  // end namespace clang
+}  // end namespace llvm
+
+#endif

Propchange: cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h

------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=38646&r1=38645&r2=38646&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/cfe/trunk/include/clang/Lex/Preprocessor.h Wed Jul 11 11:23:29 2007
@@ -482,7 +482,8 @@
   // HandleUnassertDirective(LexerToken &Tok);
   
   // Conditional Inclusion.
-  void HandleIfdefDirective(LexerToken &Tok, bool isIfndef);
+  void HandleIfdefDirective(LexerToken &Tok, bool isIfndef,
+                            bool ReadAnyTokensBeforeDirective);
   void HandleIfDirective(LexerToken &Tok);
   void HandleEndifDirective(LexerToken &Tok);
   void HandleElseDirective(LexerToken &Tok);





More information about the cfe-commits mailing list