[cfe-commits] r46845 - in /cfe/trunk: Lex/MacroExpander.cpp Lex/Preprocessor.cpp include/clang/Lex/MacroExpander.h include/clang/Lex/Preprocessor.h test/Preprocessor/macro_paste_mscomment.c

Chris Lattner sabre at nondot.org
Wed Feb 6 22:03:59 PST 2008


Author: lattner
Date: Thu Feb  7 00:03:59 2008
New Revision: 46845

URL: http://llvm.org/viewvc/llvm-project?rev=46845&view=rev
Log:
Implement support for the extremely atrocious MS /##/ extension, 
which pastes together a comment.  This is only enabled with 
-fms-extensions of course.

Added:
    cfe/trunk/test/Preprocessor/macro_paste_mscomment.c
Modified:
    cfe/trunk/Lex/MacroExpander.cpp
    cfe/trunk/Lex/Preprocessor.cpp
    cfe/trunk/include/clang/Lex/MacroExpander.h
    cfe/trunk/include/clang/Lex/Preprocessor.h

Modified: cfe/trunk/Lex/MacroExpander.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Lex/MacroExpander.cpp?rev=46845&r1=46844&r2=46845&view=diff

==============================================================================
--- cfe/trunk/Lex/MacroExpander.cpp (original)
+++ cfe/trunk/Lex/MacroExpander.cpp Thu Feb  7 00:03:59 2008
@@ -508,7 +508,11 @@
   
   // If this token is followed by a token paste (##) operator, paste the tokens!
   if (!isAtEnd() && MacroTokens[CurToken].is(tok::hashhash))
-    PasteTokens(Tok);
+    if (PasteTokens(Tok)) {
+      // When handling the microsoft /##/ extension, the final token is
+      // returned by PasteTokens, not the pasted token.
+      return;
+    }
 
   // The token's current location indicate where the token was lexed from.  We
   // need this information to compute the spelling of the token, but any
@@ -538,7 +542,8 @@
 /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
 /// operator.  Read the ## and RHS, and paste the LHS/RHS together.  If there
 /// are is another ## after it, chomp it iteratively.  Return the result as Tok.
-void MacroExpander::PasteTokens(Token &Tok) {
+/// If this returns true, the caller should immediately return the token.
+bool MacroExpander::PasteTokens(Token &Tok) {
   llvm::SmallVector<char, 128> Buffer;
   do {
     // Consume the ## operator.
@@ -621,10 +626,18 @@
     // This occurs with "x ## +"  and other stuff.  Return with Tok unmodified
     // and with RHS as the next token to lex.
     if (isInvalid) {
-      // If not in assembler language mode.
-      PP.Diag(PasteOpLoc, diag::err_pp_bad_paste, 
-              std::string(Buffer.begin(), Buffer.end()-1));
-      return;
+      // Test for the Microsoft extension of /##/ turning into // here on the
+      // error path.
+      if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) && 
+          RHS.is(tok::slash)) {
+        HandleMicrosoftCommentPaste(Tok);
+        return true;
+      } else {
+        // TODO: If not in assembler language mode.
+        PP.Diag(PasteOpLoc, diag::err_pp_bad_paste, 
+                std::string(Buffer.begin(), Buffer.end()-1));
+        return false;
+      }
     }
     
     // Turn ## into 'other' to avoid # ## # from looking like a paste operator.
@@ -649,6 +662,7 @@
     // by saying we're skipping contents, so we need to do this manually.
     Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
   }
+  return false;
 }
 
 /// isNextTokenLParen - If the next token lexed will pop this macro off the
@@ -660,3 +674,21 @@
     return 2;
   return MacroTokens[CurToken].is(tok::l_paren);
 }
+
+
+/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
+/// together to form a comment that comments out everything in the current
+/// macro, other active macros, and anything left on the current physical
+/// source line of the instantiated buffer.  Handle this by returning the
+/// first token on the next line.
+void MacroExpander::HandleMicrosoftCommentPaste(Token &Tok) {
+  // We 'comment out' the rest of this macro by just ignoring the rest of the
+  // tokens that have not been lexed yet, if any.
+  
+  // Since this must be a macro, mark the macro enabled now that it is no longer
+  // being expanded.
+  assert(Macro && "Token streams can't paste comments");
+  Macro->EnableMacro();
+  
+  PP.HandleMicrosoftCommentPaste(Tok);
+}

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

==============================================================================
--- cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/Lex/Preprocessor.cpp Thu Feb  7 00:03:59 2008
@@ -1358,6 +1358,71 @@
   return HandleEndOfFile(Result, true);
 }
 
+/// HandleMicrosoftCommentPaste - When the macro expander pastes together a
+/// comment (/##/) in microsoft mode, this method handles updating the current
+/// state, returning the token on the next source line.
+void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
+  assert(CurMacroExpander && !CurLexer &&
+         "Pasted comment can only be formed from macro");
+  
+  // We handle this by scanning for the closest real lexer, switching it to
+  // raw mode and preprocessor mode.  This will cause it to return \n as an
+  // explicit EOM token.
+  Lexer *FoundLexer = 0;
+  bool LexerWasInPPMode = false;
+  for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
+    IncludeStackInfo &ISI = *(IncludeMacroStack.end()-i-1);
+    if (ISI.TheLexer == 0) continue;  // Scan for a real lexer.
+    
+    // Once we find a real lexer, mark it as raw mode (disabling macro
+    // expansions) and preprocessor mode (return EOM).  We know that the lexer
+    // was *not* in raw mode before, because the macro that the comment came
+    // from was expanded.  However, it could have already been in preprocessor
+    // mode (#if COMMENT) in which case we have to return it to that mode and
+    // return EOM.
+    FoundLexer = ISI.TheLexer;
+    FoundLexer->LexingRawMode = true;
+    LexerWasInPPMode = FoundLexer->ParsingPreprocessorDirective;
+    FoundLexer->ParsingPreprocessorDirective = true;
+    break;
+  }
+  
+  // Okay, we either found and switched over the lexer, or we didn't find a
+  // lexer.  In either case, finish off the macro the comment came from, getting
+  // the next token.
+  if (!HandleEndOfMacro(Tok)) Lex(Tok);
+  
+  // Discarding comments as long as we don't have EOF or EOM.  This 'comments
+  // out' the rest of the line, including any tokens that came from other macros
+  // that were active, as in:
+  //  #define submacro a COMMENT b
+  //    submacro c
+  // which should lex to 'a' only: 'b' and 'c' should be removed.
+  while (Tok.isNot(tok::eom) && Tok.isNot(tok::eof))
+    Lex(Tok);
+  
+  // If we got an eom token, then we successfully found the end of the line.
+  if (Tok.is(tok::eom)) {
+    assert(FoundLexer && "Can't get end of line without an active lexer");
+    // Restore the lexer back to normal mode instead of raw mode.
+    FoundLexer->LexingRawMode = false;
+    
+    // If the lexer was already in preprocessor mode, just return the EOM token
+    // to finish the preprocessor line.
+    if (LexerWasInPPMode) return;
+    
+    // Otherwise, switch out of PP mode and return the next lexed token.
+    FoundLexer->ParsingPreprocessorDirective = false;
+    return Lex(Tok);
+  }
+  
+  // If we got an EOF token, then we reached the end of the token stream but
+  // didn't find an explicit \n.  This can only happen if there was no lexer
+  // active (an active lexer would return EOM at EOF if there was no \n in
+  // preprocessor directive mode), so just return EOF as our token.
+  assert(!FoundLexer && "Lexer should return EOM before EOF in PP mode");
+  return;
+}
 
 //===----------------------------------------------------------------------===//
 // Utility Methods for Preprocessor Directive Handling.

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

==============================================================================
--- cfe/trunk/include/clang/Lex/MacroExpander.h (original)
+++ cfe/trunk/include/clang/Lex/MacroExpander.h Thu Feb  7 00:03:59 2008
@@ -189,12 +189,20 @@
   /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
   /// operator.  Read the ## and RHS, and paste the LHS/RHS together.  If there
   /// are is another ## after it, chomp it iteratively.  Return the result as
-  /// Tok.
-  void PasteTokens(Token &Tok);
+  /// Tok.  If this returns true, the caller should immediately return the
+  /// token.
+  bool PasteTokens(Token &Tok);
   
   /// Expand the arguments of a function-like macro so that we can quickly
   /// return preexpanded tokens from MacroTokens.
   void ExpandFunctionArguments();
+  
+  /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
+  /// together to form a comment that comments out everything in the current
+  /// macro, other active macros, and anything left on the current physical
+  /// source line of the instantiated buffer.  Handle this by returning the
+  /// first token on the next line.
+  void HandleMicrosoftCommentPaste(Token &Tok);
 };
 
 }  // end namespace clang

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

==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Thu Feb  7 00:03:59 2008
@@ -333,6 +333,11 @@
   
   void PrintStats();
 
+  /// HandleMicrosoftCommentPaste - When the macro expander pastes together a
+  /// comment (/##/) in microsoft mode, this method handles updating the current
+  /// state, returning the token on the next source line.
+  void HandleMicrosoftCommentPaste(Token &Tok);
+  
   //===--------------------------------------------------------------------===//
   // Preprocessor callback methods.  These are invoked by a lexer as various
   // directives and events are found.

Added: cfe/trunk/test/Preprocessor/macro_paste_mscomment.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro_paste_mscomment.c?rev=46845&view=auto

==============================================================================
--- cfe/trunk/test/Preprocessor/macro_paste_mscomment.c (added)
+++ cfe/trunk/test/Preprocessor/macro_paste_mscomment.c Thu Feb  7 00:03:59 2008
@@ -0,0 +1,19 @@
+// RUN: clang %s -fsyntax-only -fms-extensions
+// This horrible stuff should preprocess into (other than whitespace):
+//   int foo;
+//   int bar;
+//   int baz;
+
+int foo;
+
+#define comment /##/  dead tokens live here
+comment This is stupidity
+
+int bar;
+
+#define nested(x) int x comment cute little dead tokens...
+
+nested(baz)  rise of the dead tokens
+
+;
+





More information about the cfe-commits mailing list