implement the pragma handling infrastructure. The only pragma so far is

#pragma once, and it is not completely implemented.

llvm-svn: 38566
This commit is contained in:
Chris Lattner 2006-06-24 21:31:03 +00:00
parent 4da3a353b6
commit b876183219
5 changed files with 360 additions and 32 deletions

116
clang/Lex/Pragma.cpp Normal file
View File

@ -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

View File

@ -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 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
// There is no file-change handler yet.
FileChangeHandler = 0;
// Initialize the pragma handlers.
PragmaHandlers = new PragmaNamespace(0);
RegisterBuiltinPragmas();
}
Preprocessor::~Preprocessor() {
@ -72,6 +77,9 @@ Preprocessor::~Preprocessor() {
delete IncludeStack.back().TheLexer;
IncludeStack.pop_back();
}
// Release pragma information.
delete PragmaHandlers;
}
/// getFileInfo - Return the PerFileInfo structure for the specified
@ -837,11 +845,11 @@ void Preprocessor::HandleDirective(LexerToken &Result) {
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 @@ void Preprocessor::HandleDirective(LexerToken &Result) {
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 @@ void Preprocessor::HandleDirective(LexerToken &Result) {
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 @@ void Preprocessor::HandleDirective(LexerToken &Result) {
break;
case 8:
if (Directive[0] == 'u' && !strcmp(Directive, "unassert")) {
isExtension = true;
isExtension = true; // FIXME: implement #unassert
}
break;
case 12:
@ -924,6 +922,10 @@ void Preprocessor::HandleUserDiagnosticDirective(LexerToken &Result,
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 @@ void Preprocessor::HandleImportDirective(LexerToken &ImportTok) {
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 @@ void Preprocessor::HandleUndefDirective(LexerToken &UndefTok) {
}
//===----------------------------------------------------------------------===//
// Preprocessor Conditional Directive Handling.
//===----------------------------------------------------------------------===//
/// HandleIfdefDirective - Implements the #ifdef/#ifndef directive. isIfndef is
/// true when this is a #ifndef directive.
///
@ -1233,3 +1243,84 @@ void Preprocessor::HandleElifDirective(LexerToken &ElifToken) {
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")));
}

View File

@ -86,6 +86,8 @@ DIAG(pp_include_next_absolute_path, WARNING,
"#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")

View File

@ -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

View File

@ -28,6 +28,8 @@ class SourceManager;
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 @@ class Preprocessor {
/// 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 @@ public:
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
@ -247,6 +256,12 @@ public:
///
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
/// a <> reference. If successful, this returns 'UsedDir', the
@ -339,6 +354,9 @@ public:
/// 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 @@ private:
/// 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 @@ private:
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 @@ private:
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