[cfe-commits] r38566 - in /cfe/cfe/trunk: Lex/Pragma.cpp Lex/Preprocessor.cpp include/clang/Basic/DiagnosticKinds.def include/clang/Lex/Pragma.h include/clang/Lex/Preprocessor.h
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:22:44 PDT 2007
Author: sabre
Date: Wed Jul 11 11:22:44 2007
New Revision: 38566
URL: http://llvm.org/viewvc/llvm-project?rev=38566&view=rev
Log:
implement the pragma handling infrastructure. The only pragma so far is
#pragma once, and it is not completely implemented.
Added:
cfe/cfe/trunk/Lex/Pragma.cpp (with props)
cfe/cfe/trunk/include/clang/Lex/Pragma.h (with props)
Modified:
cfe/cfe/trunk/Lex/Preprocessor.cpp
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
Added: cfe/cfe/trunk/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Pragma.cpp?rev=38566&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/Pragma.cpp (added)
+++ cfe/cfe/trunk/Lex/Pragma.cpp Wed Jul 11 11:22:44 2007
@@ -0,0 +1,116 @@
+//===--- Pragma.cpp - Pragma registration and handling --------------------===//
+//
+// 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 implements the PragmaHandler and PragmaTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
+using namespace llvm;
+using namespace clang;
+
+// Out-of-line destructor to provide a home for the class.
+PragmaHandler::~PragmaHandler() {
+}
+
+void PragmaNamespace::HandlePragma(Preprocessor &PP, LexerToken &Tok) {
+ // Read the 'namespace' that the directive is in, e.g. STDC. Do not macro
+ // expand it, the user can have a STDC #define, that should not affect this.
+ PP.LexUnexpandedToken(Tok);
+
+ // Get the handler for this token. If there is no handler, ignore the pragma.
+ PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo(), false);
+ if (Handler == 0) return;
+
+ // Otherwise, pass it down.
+ Handler->HandlePragma(PP, Tok);
+}
+
+
+
+#if 0
+/* Contains a registered pragma or pragma namespace. */
+typedef void (*pragma_cb) (cpp_reader *);
+struct pragma_entry
+{
+ struct pragma_entry *next;
+ const cpp_hashnode *pragma; /* Name and length. */
+ bool is_nspace;
+ bool is_internal;
+ bool is_deferred;
+ bool allow_expansion;
+ union {
+ pragma_cb handler;
+ struct pragma_entry *space;
+ unsigned int ident;
+ } u;
+};
+
+
+
+/* Register a pragma NAME in namespace SPACE. If SPACE is null, it
+goes in the global namespace. HANDLER is the handler it will call,
+which must be non-NULL. If ALLOW_EXPANSION is set, allow macro
+expansion while parsing pragma NAME. This function is exported
+from libcpp. */
+void
+cpp_register_pragma (cpp_reader *pfile, const char *space, const char *name,
+ pragma_cb handler, bool allow_expansion)
+{
+ struct pragma_entry *entry;
+
+ if (!handler)
+ {
+ cpp_error (pfile, CPP_DL_ICE, "registering pragma with NULL handler");
+ return;
+ }
+
+ entry = register_pragma_1 (pfile, space, name, false);
+ if (entry)
+ {
+ entry->allow_expansion = allow_expansion;
+ entry->u.handler = handler;
+ }
+}
+
+/* Similarly, but create mark the pragma for deferred processing.
+When found, a CPP_PRAGMA token will be insertted into the stream
+with IDENT in the token->u.pragma slot. */
+void
+cpp_register_deferred_pragma (cpp_reader *pfile, const char *space,
+ const char *name, unsigned int ident,
+ bool allow_expansion, bool allow_name_expansion)
+{
+ struct pragma_entry *entry;
+
+ entry = register_pragma_1 (pfile, space, name, allow_name_expansion);
+ if (entry)
+ {
+ entry->is_deferred = true;
+ entry->allow_expansion = allow_expansion;
+ entry->u.ident = ident;
+ }
+}
+
+
+/* Register the pragmas the preprocessor itself handles. */
+void
+_cpp_init_internal_pragmas (cpp_reader *pfile)
+{
+ /* Pragmas in the global namespace. */
+ register_pragma_internal (pfile, 0, "once", do_pragma_once);
+
+ /* New GCC-specific pragmas should be put in the GCC namespace. */
+ register_pragma_internal (pfile, "GCC", "poison", do_pragma_poison);
+ register_pragma_internal (pfile, "GCC", "system_header",
+ do_pragma_system_header);
+ register_pragma_internal (pfile, "GCC", "dependency", do_pragma_dependency);
+}
+#endif
Propchange: cfe/cfe/trunk/Lex/Pragma.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/Pragma.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Modified: cfe/cfe/trunk/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Preprocessor.cpp?rev=38566&r1=38565&r2=38566&view=diff
==============================================================================
--- cfe/cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/cfe/trunk/Lex/Preprocessor.cpp Wed Jul 11 11:22:44 2007
@@ -35,6 +35,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Pragma.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -62,6 +63,10 @@
// There is no file-change handler yet.
FileChangeHandler = 0;
+
+ // Initialize the pragma handlers.
+ PragmaHandlers = new PragmaNamespace(0);
+ RegisterBuiltinPragmas();
}
Preprocessor::~Preprocessor() {
@@ -72,6 +77,9 @@
delete IncludeStack.back().TheLexer;
IncludeStack.pop_back();
}
+
+ // Release pragma information.
+ delete PragmaHandlers;
}
/// getFileInfo - Return the PerFileInfo structure for the specified
@@ -837,11 +845,11 @@
switch (Result.getIdentifierInfo()->getNameLength()) {
case 4:
if (Directive[0] == 'l' && !strcmp(Directive, "line"))
- ;
+ ; // FIXME: implement #line
if (Directive[0] == 'e' && !strcmp(Directive, "elif"))
return HandleElifDirective(Result);
if (Directive[0] == 's' && !strcmp(Directive, "sccs")) {
- isExtension = true;
+ isExtension = true; // FIXME: implement #sccs
// SCCS is the same as #ident.
}
break;
@@ -855,7 +863,7 @@
if (Directive[0] == 'e' && !strcmp(Directive, "error"))
return HandleUserDiagnosticDirective(Result, false);
if (Directive[0] == 'i' && !strcmp(Directive, "ident"))
- isExtension = true;
+ isExtension = true; // FIXME: implement #ident
break;
case 6:
if (Directive[0] == 'd' && !strcmp(Directive, "define"))
@@ -864,20 +872,10 @@
return HandleIfdefDirective(Result, true);
if (Directive[0] == 'i' && !strcmp(Directive, "import"))
return HandleImportDirective(Result);
- if (Directive[0] == 'p' && !strcmp(Directive, "pragma")) {
- // FIXME: implement #pragma
- ++NumPragma;
-#if 1
- // Read the rest of the PP line.
- do {
- Lex(Result);
- } while (Result.getKind() != tok::eom);
-
- return;
-#endif
- } else if (Directive[0] == 'a' && !strcmp(Directive, "assert")) {
- isExtension = true;
- }
+ if (Directive[0] == 'p' && !strcmp(Directive, "pragma"))
+ return HandlePragmaDirective(Result);
+ if (Directive[0] == 'a' && !strcmp(Directive, "assert"))
+ isExtension = true; // FIXME: implement #assert
break;
case 7:
if (Directive[0] == 'i' && !strcmp(Directive, "include"))
@@ -889,7 +887,7 @@
break;
case 8:
if (Directive[0] == 'u' && !strcmp(Directive, "unassert")) {
- isExtension = true;
+ isExtension = true; // FIXME: implement #unassert
}
break;
case 12:
@@ -924,6 +922,10 @@
return Diag(Result, DiagID, Message);
}
+//===----------------------------------------------------------------------===//
+// Preprocessor Include Directive Handling.
+//===----------------------------------------------------------------------===//
+
/// HandleIncludeDirective - The "#include" tokens have just been read, read the
/// file to be included from the lexer, then include it! This is a common
/// routine with functionality shared between #include, #include_next and
@@ -1035,6 +1037,10 @@
return HandleIncludeDirective(ImportTok, 0, true);
}
+//===----------------------------------------------------------------------===//
+// Preprocessor Macro Directive Handling.
+//===----------------------------------------------------------------------===//
+
/// HandleDefineDirective - Implements #define. This consumes the entire macro
/// line then lets the caller lex the next real token.
///
@@ -1128,6 +1134,10 @@
}
+//===----------------------------------------------------------------------===//
+// Preprocessor Conditional Directive Handling.
+//===----------------------------------------------------------------------===//
+
/// HandleIfdefDirective - Implements the #ifdef/#ifndef directive. isIfndef is
/// true when this is a #ifndef directive.
///
@@ -1233,3 +1243,84 @@
return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
/*FoundElse*/CI.FoundElse);
}
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Pragma Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandlePragmaDirective - The "#pragma" directive has been parsed with
+/// PragmaTok containing the "pragma" identifier. Lex the rest of the pragma,
+/// passing it to the registered pragma handlers.
+void Preprocessor::HandlePragmaDirective(LexerToken &PragmaTok) {
+ ++NumPragma;
+
+ // Invoke the first level of pragma handlers which reads the namespace id.
+ LexerToken Tok;
+ PragmaHandlers->HandlePragma(*this, Tok);
+
+ // If the pragma handler didn't read the rest of the line, consume it now.
+ if (CurLexer->ParsingPreprocessorDirective) {
+ do {
+ LexUnexpandedToken(Tok);
+ } while (Tok.getKind() != tok::eom);
+ }
+}
+
+/// HandlePragmaOnce - Handle #pragma once. OnceTok is the 'once'.
+void Preprocessor::HandlePragmaOnce(LexerToken &OnceTok) {
+ if (IncludeStack.empty()) {
+ Diag(OnceTok, diag::pp_pragma_once_in_main_file);
+ return;
+ }
+}
+
+
+/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
+/// If 'Namespace' is non-null, then it is a token required to exist on the
+/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
+void Preprocessor::AddPragmaHandler(const char *Namespace,
+ PragmaHandler *Handler) {
+ PragmaNamespace *InsertNS = PragmaHandlers;
+
+ // If this is specified to be in a namespace, step down into it.
+ if (Namespace) {
+ IdentifierTokenInfo *NSID = getIdentifierInfo(Namespace);
+
+ // If there is already a pragma handler with the name of this namespace,
+ // we either have an error (directive with the same name as a namespace) or
+ // we already have the namespace to insert into.
+ if (PragmaHandler *Existing = PragmaHandlers->FindHandler(NSID)) {
+ InsertNS = Existing->getIfNamespace();
+ assert(InsertNS != 0 && "Cannot have a pragma namespace and pragma"
+ " handler with the same name!");
+ } else {
+ // Otherwise, this namespace doesn't exist yet, create and insert the
+ // handler for it.
+ InsertNS = new PragmaNamespace(NSID);
+ PragmaHandlers->AddPragma(InsertNS);
+ }
+ }
+
+ // Check to make sure we don't already have a pragma for this identifier.
+ assert(!InsertNS->FindHandler(Handler->getName()) &&
+ "Pragma handler already exists for this identifier!");
+ InsertNS->AddPragma(Handler);
+}
+
+class PragmaOnceHandler : public PragmaHandler {
+public:
+ PragmaOnceHandler(const IdentifierTokenInfo *OnceID) : PragmaHandler(OnceID){}
+ virtual void HandlePragma(Preprocessor &PP, LexerToken &OnceTok) {
+ PP.CheckEndOfDirective("#pragma once");
+ PP.HandlePragmaOnce(OnceTok);
+ }
+};
+
+
+/// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
+/// #pragma GCC poison/system_header/dependency and #pragma once.
+void Preprocessor::RegisterBuiltinPragmas() {
+ AddPragmaHandler(0, new PragmaOnceHandler(getIdentifierInfo("once")));
+
+}
Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=38566&r1=38565&r2=38566&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:22:44 2007
@@ -86,6 +86,8 @@
"#include_next with absolute path")
DIAG(ext_c99_whitespace_required_after_macro_name, WARNING,
"ISO C99 requires whitespace after the macro name")
+DIAG(pp_pragma_once_in_main_file, WARNING,
+ "#pragma once in main file")
DIAG(ext_pp_import_directive, EXTENSION,
"#import is a language extension")
Added: cfe/cfe/trunk/include/clang/Lex/Pragma.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Pragma.h?rev=38566&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Pragma.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/Pragma.h Wed Jul 11 11:22:44 2007
@@ -0,0 +1,94 @@
+//===--- Pragma.h - Pragma registration and handling ------------*- 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 PragmaHandler and PragmaTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PRAGMA_H
+#define LLVM_CLANG_PRAGMA_H
+
+#include <cassert>
+#include <vector>
+
+namespace llvm {
+namespace clang {
+ class Preprocessor;
+ class LexerToken;
+ class IdentifierTokenInfo;
+ class PragmaNamespace;
+
+/// PragmaHandler - Instances of this interface defined to handle the various
+/// pragmas that the language front-end uses. Each handler optionally has a
+/// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with
+/// that identifier is found. If a handler does not match any of the declared
+/// pragmas the handler with a null identifier is invoked, if it exists.
+///
+/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g.
+/// we treat "#pragma STDC" and "#pragma GCC" as namespaces that contain other
+/// pragmas.
+class PragmaHandler {
+ const IdentifierTokenInfo *Name;
+public:
+ PragmaHandler(const IdentifierTokenInfo *name) : Name(name) {}
+ virtual ~PragmaHandler();
+
+ const IdentifierTokenInfo *getName() const { return Name; }
+ virtual void HandlePragma(Preprocessor &PP, LexerToken &FirstToken) = 0;
+
+ /// getIfNamespace - If this is a namespace, return it. This is equivalent to
+ /// using a dynamic_cast, but doesn't require RTTI.
+ virtual PragmaNamespace *getIfNamespace() { return 0; }
+};
+
+
+class PragmaNamespace : public PragmaHandler {
+ /// Handlers - This is the list of handlers in this namespace.
+ ///
+ std::vector<PragmaHandler*> Handlers;
+public:
+ PragmaNamespace(const IdentifierTokenInfo *Name) : PragmaHandler(Name) {}
+ ~PragmaNamespace() {
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i)
+ delete Handlers[i];
+ }
+
+ /// FindHandler - Check to see if there is already a handler for the
+ /// specified name. If not, return the handler for the null identifier if it
+ /// exists, otherwise return null. If IgnoreNull is true (the default) then
+ /// the null handler isn't returned on failure to match.
+ PragmaHandler *FindHandler(const IdentifierTokenInfo *Name,
+ bool IgnoreNull = true) const {
+ PragmaHandler *NullHandler = 0;
+ for (unsigned i = 0, e = Handlers.size(); i != e; ++i) {
+ if (Handlers[i]->getName() == Name)
+ return Handlers[i];
+
+ if (Handlers[i]->getName() == 0)
+ NullHandler = Handlers[i];
+ }
+ return IgnoreNull ? 0 : NullHandler;
+ }
+
+ /// AddPragma - Add a pragma to this namespace.
+ ///
+ void AddPragma(PragmaHandler *Handler) {
+ Handlers.push_back(Handler);
+ }
+
+ virtual void HandlePragma(Preprocessor &PP, LexerToken &FirstToken);
+
+ virtual PragmaNamespace *getIfNamespace() { return this; }
+};
+
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Lex/Pragma.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Lex/Pragma.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=38566&r1=38565&r2=38566&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/cfe/trunk/include/clang/Lex/Preprocessor.h Wed Jul 11 11:22:44 2007
@@ -28,6 +28,8 @@
class FileManager;
class DirectoryEntry;
class FileEntry;
+class PragmaNamespace;
+class PragmaHandler;
/// DirectoryLookup - This class is used to specify the search order for
/// directories in #include directives.
@@ -109,6 +111,10 @@
/// the program, including program keywords.
IdentifierTable IdentifierInfo;
+ /// PragmaHandlers - This tracks all of the pragmas that the client registered
+ /// with this preprocessor.
+ PragmaNamespace *PragmaHandlers;
+
/// CurLexer - This is the current top of the stack that we're lexing from if
/// not expanding a macro. One of CurLexer and CurMacroExpander must be null.
Lexer *CurLexer;
@@ -221,6 +227,9 @@
if (SkippingContents) return 0;
return &IdentifierInfo.get(NameStart, NameEnd);
}
+ IdentifierTokenInfo *getIdentifierInfo(const char *NameStr) {
+ return getIdentifierInfo(NameStr, NameStr+strlen(NameStr));
+ }
/// AddKeyword - This method is used to associate a token ID with specific
/// identifiers because they are language keywords. This causes the lexer to
@@ -246,6 +255,12 @@
/// AddKeywords - Add all keywords to the symbol table.
///
void AddKeywords();
+
+
+ /// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
+ /// If 'Namespace' is non-null, then it is a token required to exist on the
+ /// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
+ void AddPragmaHandler(const char *Namespace, PragmaHandler *Handler);
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
/// return null on failure. isAngled indicates whether the file reference is
@@ -339,6 +354,9 @@
/// read is the correct one.
void HandleDirective(LexerToken &Result);
+ /// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
+ /// not, emit a diagnostic and consume up until the eom.
+ void CheckEndOfDirective(const char *Directive);
private:
/// getFileInfo - Return the PerFileInfo structure for the specified
/// FileEntry.
@@ -353,10 +371,6 @@
/// and discards the rest of the macro line if the macro name is invalid.
void ReadMacroName(LexerToken &MacroNameTok);
- /// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
- /// not, emit a diagnostic and consume up until the eom.
- void CheckEndOfDirective(const char *Directive);
-
/// SkipExcludedConditionalBlock - We just read a #if or related directive and
/// decided that the subsequent tokens are in the #if'd out portion of the
/// file. Lex the rest of the file, until we see an #endif. If
@@ -378,6 +392,10 @@
bool EvaluateDirectiveSubExpr(int &LHS, unsigned MinPrec,
LexerToken &PeekTok);
+ /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas:
+ /// #pragma GCC poison/system_header/dependency and #pragma once.
+ void RegisterBuiltinPragmas();
+
//===--------------------------------------------------------------------===//
/// Handle*Directive - implement the various preprocessor directives. These
/// should side-effect the current preprocessor object so that the next call
@@ -386,22 +404,29 @@
void HandleUserDiagnosticDirective(LexerToken &Result, bool isWarning);
// File inclusion.
- void HandleIncludeDirective(LexerToken &Result,
+ void HandleIncludeDirective(LexerToken &Tok,
const DirectoryLookup *LookupFrom = 0,
bool isImport = false);
- void HandleIncludeNextDirective(LexerToken &Result);
- void HandleImportDirective(LexerToken &Result);
+ void HandleIncludeNextDirective(LexerToken &Tok);
+ void HandleImportDirective(LexerToken &Tok);
// Macro handling.
- void HandleDefineDirective(LexerToken &Result);
- void HandleUndefDirective(LexerToken &Result);
+ void HandleDefineDirective(LexerToken &Tok);
+ void HandleUndefDirective(LexerToken &Tok);
+ // HandleAssertDirective(LexerToken &Tok);
+ // HandleUnassertDirective(LexerToken &Tok);
// Conditional Inclusion.
- void HandleIfdefDirective(LexerToken &Result, bool isIfndef);
- void HandleIfDirective(LexerToken &Result);
- void HandleEndifDirective(LexerToken &Result);
- void HandleElseDirective(LexerToken &Result);
- void HandleElifDirective(LexerToken &Result);
+ void HandleIfdefDirective(LexerToken &Tok, bool isIfndef);
+ void HandleIfDirective(LexerToken &Tok);
+ void HandleEndifDirective(LexerToken &Tok);
+ void HandleElseDirective(LexerToken &Tok);
+ void HandleElifDirective(LexerToken &Tok);
+
+ // Pragmas.
+ void HandlePragmaDirective(LexerToken &Result);
+public:
+ void HandlePragmaOnce(LexerToken &OnceTok);
};
} // end namespace clang
More information about the cfe-commits
mailing list