[cfe-commits] r38694 - in /cfe/cfe/trunk/Lex: MacroExpander.cpp Preprocessor.cpp

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


Author: sabre
Date: Wed Jul 11 11:23:52 2007
New Revision: 38694

URL: http://llvm.org/viewvc/llvm-project?rev=38694&view=rev
Log:
Implement scanning-for-( more correctly.  This implements
test/Preprocessor/macro_fn_lparen_scan.c, but is not yet complete.

Add some FIXME's about missing diagnostics on empty macro args.  Improve some
comments.

Modified:
    cfe/cfe/trunk/Lex/MacroExpander.cpp
    cfe/cfe/trunk/Lex/Preprocessor.cpp

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

==============================================================================
--- cfe/cfe/trunk/Lex/MacroExpander.cpp (original)
+++ cfe/cfe/trunk/Lex/MacroExpander.cpp Wed Jul 11 11:23:52 2007
@@ -78,3 +78,19 @@
 
   // Otherwise, return a normal token.
 }
+
+/// NextTokenIsKnownNotLParen - If the next token lexed will pop this macro
+/// off the expansion stack, return false and set RanOffEnd to true.
+/// Otherwise, return true if we know for sure that the next token returned
+/// will not be a '(' token.  Return false if it is a '(' token or if we are
+/// not sure.  This is used when determining whether to expand a function-like
+/// macro.
+bool MacroExpander::NextTokenIsKnownNotLParen(bool &RanOffEnd) const {
+  // Out of tokens?
+  if (CurToken == Macro.getNumTokens()) {
+    RanOffEnd = true;
+    return false;
+  }
+
+  return Macro.getReplacementToken(CurToken).getKind() != tok::l_paren;
+}

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

==============================================================================
--- cfe/cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/cfe/trunk/Lex/Preprocessor.cpp Wed Jul 11 11:23:52 2007
@@ -507,6 +507,51 @@
   return true;
 }  
 
+/// isNextPPTokenLParen - Determine whether the next preprocessor token to be
+/// lexed is a '('.  If so, consume the token and return true, if not, this
+/// method should have no observable side-effect on the lexed tokens.
+bool Preprocessor::isNextPPTokenLParen() {
+  bool RanOffEnd = false;
+  // Do some quick tests for rejection cases.
+  if (CurLexer) {
+#if 0
+    if (!CurLexer->NextTokenIsKnownNotLParen(RanOffEnd))
+      return false;
+#endif
+  } else {
+    assert(CurMacroExpander && "No token source?");
+    if (CurMacroExpander->NextTokenIsKnownNotLParen(RanOffEnd))
+      return false;
+  }
+
+  // If we ran off the end of the lexer or macro expander, walk the include
+  // stack, looking for whatever will return the next token.
+  for (unsigned i = IncludeMacroStack.size(); RanOffEnd && i != 0; --i) {
+    IncludeStackInfo &Entry = IncludeMacroStack[i-1];
+    RanOffEnd = false;
+    if (Entry.TheLexer) {
+#if 0
+      if (!Entry.TheLexer->NextTokenIsKnownNotLParen(RanOffEnd))
+        return false;
+#endif
+    } else if (Entry.TheMacroExpander->NextTokenIsKnownNotLParen(RanOffEnd))
+      return false;
+  }
+
+  // Okay, if we get here we either know that the next token definitely IS a '('
+  // token, or we don't know what it is.  In either case we will speculatively
+  // read the next token.  If it turns out that it isn't a '(', then we create a
+  // new macro context with just that token on it so that the token gets
+  // reprocessed.
+  
+  LexerToken Tok;
+  LexUnexpandedToken(Tok);
+  if (Tok.getKind() == tok::l_paren)
+    return true;
+  
+  // FIXME: push a fake macro context, push Tok onto it.
+  assert(0 && "FIXME: implement speculation failure code!");
+}
 
 /// HandleMacroExpandedIdentifier - If an identifier token is read that is to be
 /// expanded as a macro, handle it and return the next token as 'Identifier'.
@@ -526,19 +571,11 @@
   
   // If this is a function-like macro, read the arguments.
   if (MI->isFunctionLike()) {
-    // FIXME: We need to query to see if the ( exists without reading it.
-    
     // C99 6.10.3p10: If the preprocessing token immediately after the the macro
     // name isn't a '(', this macro should not be expanded.
-    bool isFunctionInvocation = true;
-    if (!isFunctionInvocation)
+    if (!isNextPPTokenLParen())
       return true;
     
-    LexerToken Tok;
-    LexUnexpandedToken(Tok);
-    assert(Tok.getKind() == tok::l_paren &&
-           "not a function-like macro invocation!");
-
     // Remember that we are now parsing the arguments to a macro invocation.
     // Preprocessor directives used inside macro arguments are not portable, and
     // this enables the warning.
@@ -657,6 +694,8 @@
     unsigned NumParens = 0;
 
     while (1) {
+      // Read arguments as unexpanded tokens.  This avoids issues, e.g., where
+      // an argument value in a macro could expand to ',' or '(' or ')'.
       LexUnexpandedToken(Tok);
       
       if (Tok.getKind() == tok::eof) {
@@ -688,6 +727,8 @@
       ArgTokens.push_back(Tok);
     }
 
+    // FIXME: If not in C99 mode, empty arguments should be ext-warned about!
+    
     // Remember the tokens that make up this argument.  This destroys ArgTokens.
     Args->addArgument(ArgTokens);
     --NumFixedArgsLeft;
@@ -713,9 +754,10 @@
     } else if (MI->getNumArgs() == 1) {
       // #define A(x)
       //   A()
-      // is ok.  Add an empty argument.
+      // is ok because it is an empty argument.  Add it explicitly.
       std::vector<LexerToken> ArgTokens;
       Args->addArgument(ArgTokens);
+      // FIXME: Ext-Warn in C90 mode.
     } else {
       // Otherwise, emit the error.
       Diag(Tok, diag::err_too_few_formals_in_macro_invoc);
@@ -999,7 +1041,7 @@
 }
 
 /// HandleEndOfMacro - This callback is invoked when the lexer hits the end of
-/// the current macro line.
+/// the current macro expansion.
 void Preprocessor::HandleEndOfMacro(LexerToken &Result) {
   assert(CurMacroExpander && !CurLexer &&
          "Ending a macro when currently in a #include file!");





More information about the cfe-commits mailing list