[cfe-commits] r38539 - in /cfe/cfe/trunk: ./ Basic/ Driver/ Lex/ include/ include/clang/ include/clang/Basic/ include/clang/Lex/
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:22:17 PDT 2007
Author: sabre
Date: Wed Jul 11 11:22:17 2007
New Revision: 38539
URL: http://llvm.org/viewvc/llvm-project?rev=38539&view=rev
Log:
Initial checkin of c-language parser
Added:
cfe/cfe/trunk/Basic/
cfe/cfe/trunk/Basic/Diagnostic.cpp (with props)
cfe/cfe/trunk/Basic/FileManager.cpp (with props)
cfe/cfe/trunk/Basic/Makefile (with props)
cfe/cfe/trunk/Basic/SourceBuffer.cpp (with props)
cfe/cfe/trunk/Basic/SourceManager.cpp (with props)
cfe/cfe/trunk/Basic/TokenKinds.cpp (with props)
cfe/cfe/trunk/Driver/
cfe/cfe/trunk/Driver/clang.cpp (with props)
cfe/cfe/trunk/Lex/
cfe/cfe/trunk/Lex/IdentifierTable.cpp (with props)
cfe/cfe/trunk/Lex/Lexer.cpp (with props)
cfe/cfe/trunk/Lex/MacroExpander.cpp (with props)
cfe/cfe/trunk/Lex/MacroInfo.cpp (with props)
cfe/cfe/trunk/Lex/Makefile (with props)
cfe/cfe/trunk/Lex/PPExpressions.cpp (with props)
cfe/cfe/trunk/Lex/Preprocessor.cpp (with props)
cfe/cfe/trunk/Makefile (with props)
cfe/cfe/trunk/README.txt (with props)
cfe/cfe/trunk/include/
cfe/cfe/trunk/include/clang/
cfe/cfe/trunk/include/clang/Basic/
cfe/cfe/trunk/include/clang/Basic/Diagnostic.h (with props)
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (with props)
cfe/cfe/trunk/include/clang/Basic/FileManager.h (with props)
cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h (with props)
cfe/cfe/trunk/include/clang/Basic/SourceLocation.h (with props)
cfe/cfe/trunk/include/clang/Basic/SourceManager.h (with props)
cfe/cfe/trunk/include/clang/Basic/TokenKinds.def (with props)
cfe/cfe/trunk/include/clang/Basic/TokenKinds.h (with props)
cfe/cfe/trunk/include/clang/Lex/
cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h (with props)
cfe/cfe/trunk/include/clang/Lex/Lexer.h (with props)
cfe/cfe/trunk/include/clang/Lex/MacroExpander.h (with props)
cfe/cfe/trunk/include/clang/Lex/MacroInfo.h (with props)
cfe/cfe/trunk/include/clang/Lex/Preprocessor.h (with props)
Added: cfe/cfe/trunk/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Basic/Diagnostic.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Basic/Diagnostic.cpp (added)
+++ cfe/cfe/trunk/Basic/Diagnostic.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,117 @@
+//===--- Diagnostic.cpp - C Language Family Diagnostic 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 Diagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include <cassert>
+using namespace llvm;
+using namespace clang;
+
+/// Flag values for diagnostics.
+enum {
+ // Diagnostic classes.
+ NOTE = 0x01,
+ WARNING = 0x02,
+ EXTENSION = 0x03,
+ ERROR = 0x04,
+ FATAL = 0x05,
+ class_mask = 0x07
+};
+
+/// DiagnosticFlags - A set of flags, or'd together, that describe the
+/// diagnostic.
+static unsigned char DiagnosticFlags[] = {
+#define DIAG(ENUM,FLAGS,DESC) FLAGS,
+#include "clang/Basic/DiagnosticKinds.def"
+ 0
+};
+
+/// getDiagClass - Return the class field of the diagnostic.
+///
+static unsigned getDiagClass(unsigned DiagID) {
+ assert(DiagID < diag::NUM_DIAGNOSTICS && "Diagnostic ID out of range!");
+ return DiagnosticFlags[DiagID] & class_mask;
+}
+
+/// DiagnosticText - An english message to print for the diagnostic. These
+/// should be localized.
+static const char * const DiagnosticText[] = {
+#define DIAG(ENUM,FLAGS,DESC) DESC,
+#include "clang/Basic/DiagnosticKinds.def"
+ 0
+};
+
+/// isNoteWarningOrExtension - Return true if the unmapped diagnostic level of
+/// the specified diagnostic ID is a Note, Warning, or Extension.
+bool Diagnostic::isNoteWarningOrExtension(unsigned DiagID) {
+ return getDiagClass(DiagID) < ERROR;
+}
+
+
+/// getDescription - Given a diagnostic ID, return a description of the
+/// issue.
+const char *Diagnostic::getDescription(unsigned DiagID) {
+ assert(DiagID < diag::NUM_DIAGNOSTICS && "Diagnostic ID out of range!");
+ return DiagnosticText[DiagID];
+}
+
+/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
+/// object, classify the specified diagnostic ID into a Level, consumable by
+/// the DiagnosticClient.
+Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const {
+ unsigned DiagClass = getDiagClass(DiagID);
+
+ // TODO: specific diagnostics may be enabled or disabled. Filter those based
+ // on their DiagID.
+
+ // Map diagnostic classes based on command line argument settings.
+ if (DiagClass == EXTENSION) {
+ if (ErrorOnExtensions)
+ DiagClass = ERROR;
+ else if (WarnOnExtensions)
+ DiagClass = WARNING;
+ else
+ return Ignored;
+ }
+
+ // If warnings are to be treated as errors, indicate this as such.
+ if (DiagClass == WARNING && WarningsAsErrors)
+ DiagClass = ERROR;
+
+ switch (DiagClass) {
+ default: assert(0 && "Unknown diagnostic class!");
+ case NOTE: return Diagnostic::Note;
+ case WARNING: return Diagnostic::Warning;
+ case ERROR: return Diagnostic::Error;
+ case FATAL: return Diagnostic::Fatal;
+ }
+}
+
+/// Report - Issue the message to the client. If the client wants us to stop
+/// compilation, return true, otherwise return false. DiagID is a member of
+/// the diag::kind enum.
+bool Diagnostic::Report(SourceLocation Pos, unsigned DiagID,
+ const std::string &Extra) {
+ // Figure out the diagnostic level of this message.
+ Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID);
+
+ // If the client doesn't care about this message, don't map to the code.
+ if (DiagLevel == Diagnostic::Ignored)
+ return false;
+
+ // Finally, report it.
+ return Client.HandleDiagnostic(DiagLevel, Pos, (diag::kind)DiagID, Extra) ||
+ DiagLevel == Fatal;
+}
+
+DiagnosticClient::~DiagnosticClient() {}
Propchange: cfe/cfe/trunk/Basic/Diagnostic.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Basic/Diagnostic.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Basic/FileManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Basic/FileManager.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Basic/FileManager.cpp (added)
+++ cfe/cfe/trunk/Basic/FileManager.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,136 @@
+//===--- FileManager.cpp - File System Probing and Caching ----------------===//
+//
+// 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 FileManager interface.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: This should index all interesting directories with dirent calls.
+// getdirentries ?
+// opendir/readdir_r/closedir ?
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FileManager.h"
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+// FIXME: Enhance libsystem to support inode and other fields.
+#include <sys/stat.h>
+
+/// getDirectory - Lookup, cache, and verify the specified directory. This
+/// returns null if the directory doesn't exist.
+///
+const DirectoryEntry *FileManager::getDirectory(const std::string &Filename) {
+ ++NumDirLookups;
+ // See if there is already an entry in the map.
+ std::map<std::string, DirectoryEntry*>::iterator I =
+ DirEntries.lower_bound(Filename);
+ if (I != DirEntries.end() && I->first == Filename)
+ return I->second;
+
+ ++NumDirCacheMisses;
+
+ // By default, zero initialize it.
+ DirectoryEntry *&Ent =
+ DirEntries.insert(I, std::make_pair(Filename, (DirectoryEntry*)0))->second;
+
+ // Nope, there isn't. Check to see if the directory exists.
+ struct stat StatBuf;
+ if (stat(Filename.c_str(), &StatBuf) || // Error stat'ing.
+ !S_ISDIR(StatBuf.st_mode)) // Not a directory?
+ return 0;
+
+ // It exists. See if we have already opened a directory with the same inode.
+ // This occurs when one dir is symlinked to another, for example.
+ DirectoryEntry *&UDE =
+ UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
+
+ if (UDE) // Already have an entry with this inode, return it.
+ return Ent = UDE;
+
+ // Otherwise, we don't have this directory yet, add it.
+ DirectoryEntry *DE = new DirectoryEntry();
+ DE->Name = Filename;
+ return Ent = UDE = DE;
+}
+
+/// getFile - Lookup, cache, and verify the specified file. This returns null
+/// if the file doesn't exist.
+///
+const FileEntry *FileManager::getFile(const std::string &Filename) {
+ ++NumFileLookups;
+
+ // See if there is already an entry in the map.
+ std::map<std::string, FileEntry*>::iterator I =
+ FileEntries.lower_bound(Filename);
+ if (I != FileEntries.end() && I->first == Filename)
+ return I->second;
+
+ ++NumFileCacheMisses;
+
+ // By default, zero initialize it.
+ FileEntry *&Ent =
+ FileEntries.insert(I, std::make_pair(Filename, (FileEntry*)0))->second;
+
+ // Figure out what directory it is in.
+ std::string DirName;
+
+ // If the string contains a / in it, strip off everything after it.
+ // FIXME: this logic should be in sys::Path.
+ std::string::size_type SlashPos = Filename.find_last_of('/');
+ if (SlashPos == std::string::npos)
+ DirName = "."; // Use the current directory if file has no path component.
+ else if (SlashPos == Filename.size()-1)
+ return 0; // If filename ends with a /, it's a directory.
+ else
+ DirName = std::string(Filename.begin(), Filename.begin()+SlashPos);
+
+ const DirectoryEntry *DirInfo = getDirectory(DirName);
+ if (DirInfo == 0) // Directory doesn't exist, file can't exist.
+ return 0;
+
+ // FIXME: Use the directory info to prune this, before doing the stat syscall.
+ // FIXME: This will reduce the # syscalls.
+
+ // Nope, there isn't. Check to see if the file exists.
+ struct stat StatBuf;
+ if (stat(Filename.c_str(), &StatBuf) || // Error stat'ing.
+ S_ISDIR(StatBuf.st_mode)) // A directory?
+ return 0;
+
+ // It exists. See if we have already opened a directory with the same inode.
+ // This occurs when one dir is symlinked to another, for example.
+ FileEntry *&UFE =
+ UniqueFiles[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
+
+ if (UFE) // Already have an entry with this inode, return it.
+ return Ent = UFE;
+
+ // Otherwise, we don't have this directory yet, add it.
+ FileEntry *FE = new FileEntry();
+ FE->Size = StatBuf.st_size;
+ FE->Name = Filename;
+ FE->Dir = DirInfo;
+ FE->UID = NextFileUID++;
+ return Ent = UFE = FE;
+}
+
+void FileManager::PrintStats() const {
+ std::cerr << "\n*** File Manager Stats:\n";
+ std::cerr << UniqueFiles.size() << " files found, "
+ << UniqueDirs.size() << " dirs found.\n";
+ std::cerr << NumDirLookups << " dir lookups, "
+ << NumDirCacheMisses << " dir cache misses.\n";
+ std::cerr << NumFileLookups << " file lookups, "
+ << NumFileCacheMisses << " file cache misses.\n";
+
+ //std::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
+}
Propchange: cfe/cfe/trunk/Basic/FileManager.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Basic/FileManager.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Basic/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Basic/Makefile?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Basic/Makefile (added)
+++ cfe/cfe/trunk/Basic/Makefile Wed Jul 11 11:22:17 2007
@@ -0,0 +1,21 @@
+##===- clang/Basic/Makefile --------------------------------*- Makefile -*-===##
+#
+# 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 implements the Basic library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME := clangBasic
+BUILD_ARCHIVE = 1
+
+CPPFLAGS += -I$(LEVEL)/tools/clang/include
+
+include $(LEVEL)/Makefile.common
+
Propchange: cfe/cfe/trunk/Basic/Makefile
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Basic/Makefile
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Basic/SourceBuffer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Basic/SourceBuffer.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Basic/SourceBuffer.cpp (added)
+++ cfe/cfe/trunk/Basic/SourceBuffer.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,162 @@
+//===--- SourceBuffer.cpp - C Language Family Source Buffer Impl. ---------===//
+//
+// 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 SourceBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceBuffer.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/System/MappedFile.h"
+#include "llvm/System/Process.h"
+#include <cstdio>
+#include <cstring>
+using namespace llvm;
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// SourceBuffer implementation itself.
+//===----------------------------------------------------------------------===//
+
+SourceBuffer::~SourceBuffer() {
+ if (MustDeleteBuffer)
+ delete [] BufferStart;
+}
+
+/// initCopyOf - Initialize this source buffer with a copy of the specified
+/// memory range. We make the copy so that we can null terminate it
+/// successfully.
+void SourceBuffer::initCopyOf(const char *BufStart, const char *BufEnd) {
+ size_t Size = BufEnd-BufStart;
+ BufferStart = new char[Size+1];
+ BufferEnd = BufferStart+Size;
+ memcpy(const_cast<char*>(BufferStart), BufStart, Size);
+ *const_cast<char*>(BufferEnd) = 0; // Null terminate buffer.
+ MustDeleteBuffer = false;
+}
+
+/// init - Initialize this SourceBuffer as a reference to externally allocated
+/// memory, memory that we know is already null terminated.
+void SourceBuffer::init(const char *BufStart, const char *BufEnd) {
+ assert(BufEnd[0] == 0 && "Buffer is not null terminated!");
+ BufferStart = BufStart;
+ BufferEnd = BufEnd;
+ MustDeleteBuffer = false;
+}
+
+//===----------------------------------------------------------------------===//
+// SourceBufferMem implementation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class SourceBufferMem : public SourceBuffer {
+ std::string FileID;
+public:
+ SourceBufferMem(const char *Start, const char *End, const char *FID)
+ : FileID(FID) {
+ init(Start, End);
+ }
+
+ virtual const char *getBufferIdentifier() const {
+ return FileID.c_str();
+ }
+};
+}
+
+/// getMemBuffer - Open the specified memory range as a SourceBuffer. Note
+/// that EndPtr[0] must be a null byte and be accessible!
+SourceBuffer *SourceBuffer::getMemBuffer(const char *StartPtr,
+ const char *EndPtr,
+ const char *BufferName) {
+ return new SourceBufferMem(StartPtr, EndPtr, BufferName);
+}
+
+
+//===----------------------------------------------------------------------===//
+// SourceBufferFile implementation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class SourceBufferFile : public SourceBuffer {
+ sys::MappedFile File;
+public:
+ SourceBufferFile(const sys::Path &Filename);
+
+ virtual const char *getBufferIdentifier() const {
+ return File.path().c_str();
+ }
+
+ ~SourceBufferFile();
+};
+}
+
+SourceBufferFile::SourceBufferFile(const sys::Path &Filename) : File(Filename) {
+ // FIXME: This does an extra stat syscall to figure out the size, but we
+ // already know the size!
+ File.map();
+
+ size_t Size = File.size();
+
+ static unsigned PageSize = sys::Process::GetPageSize();
+ assert(((PageSize & (PageSize-1)) == 0) && PageSize &&
+ "Page size is not a power of 2!");
+
+ // If this file is not an exact multiple of the system page size (common
+ // case), then the OS has zero terminated the buffer for us.
+ if ((Size & (PageSize-1))) {
+ init(File.charBase(), File.charBase()+Size);
+ } else {
+ // Otherwise, we allocate a new memory buffer and copy the data over
+ initCopyOf(File.charBase(), File.charBase()+Size);
+
+ // No need to keep the file mapped any longer.
+ File.unmap();
+ }
+}
+
+SourceBufferFile::~SourceBufferFile() {
+ File.unmap();
+}
+
+
+SourceBuffer *SourceBuffer::getFile(const FileEntry *FileEnt) {
+ try {
+ return new SourceBufferFile(sys::Path(FileEnt->getName()));
+ } catch (...) {
+ return 0;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// SourceBufferSTDIN implementation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class STDINBufferFile : public SourceBuffer {
+public:
+ virtual const char *getBufferIdentifier() const {
+ return "<stdin>";
+ }
+};
+}
+
+SourceBuffer *SourceBuffer::getSTDIN() {
+ char Buffer[4096*4];
+
+ std::vector<char> FileData;
+
+ // Read in all of the data from stdin, we cannot mmap stdin.
+ while (size_t ReadBytes = fread(Buffer, 1, 4096*4, stdin))
+ FileData.insert(FileData.end(), Buffer, Buffer+ReadBytes);
+
+ size_t Size = FileData.size();
+ SourceBuffer *B = new STDINBufferFile();
+ B->initCopyOf(&FileData[0], &FileData[Size]);
+ return B;
+}
Propchange: cfe/cfe/trunk/Basic/SourceBuffer.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Basic/SourceBuffer.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Basic/SourceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Basic/SourceManager.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Basic/SourceManager.cpp (added)
+++ cfe/cfe/trunk/Basic/SourceManager.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,213 @@
+//===--- SourceManager.cpp - Track and cache source files -----------------===//
+//
+// 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 SourceManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceBuffer.h"
+#include "llvm/System/Path.h"
+#include <algorithm>
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+SourceManager::~SourceManager() {
+ for (std::map<const FileEntry *, FileInfo>::iterator I = FileInfos.begin(),
+ E = FileInfos.end(); I != E; ++I) {
+ delete I->second.Buffer;
+ delete[] I->second.SourceLineCache;
+ }
+
+ for (std::list<InfoRec>::iterator I = MemBufferInfos.begin(),
+ E = MemBufferInfos.end(); I != E; ++I) {
+ delete I->second.Buffer;
+ delete[] I->second.SourceLineCache;
+ }
+}
+
+/// getFileInfo - Create or return a cached FileInfo for the specified file.
+///
+const SourceManager::InfoRec *
+SourceManager::getInfoRec(const FileEntry *FileEnt) {
+ assert(FileEnt && "Didn't specify a file entry to use?");
+ // Do we already have information about this file?
+ std::map<const FileEntry *, FileInfo>::iterator I =
+ FileInfos.lower_bound(FileEnt);
+ if (I != FileInfos.end() && I->first == FileEnt)
+ return &*I;
+
+ // Nope, get information.
+ const SourceBuffer *File;
+ try {
+ File = clang::SourceBuffer::getFile(FileEnt);
+ if (File == 0)
+ return 0;
+ } catch (...) {
+ return 0;
+ }
+
+ const InfoRec &Entry =
+ *FileInfos.insert(I, std::make_pair(FileEnt, FileInfo()));
+ FileInfo &Info = const_cast<FileInfo &>(Entry.second);
+
+ Info.Buffer = File;
+ Info.SourceLineCache = 0;
+ Info.NumLines = 0;
+ return &Entry;
+}
+
+
+/// createMemBufferInfoRec - Create a new info record for the specified memory
+/// buffer. This does no caching.
+const SourceManager::InfoRec *
+SourceManager::createMemBufferInfoRec(const SourceBuffer *Buffer) {
+ // Add a new info record to the MemBufferInfos list and return it.
+ FileInfo FI;
+ FI.Buffer = Buffer;
+ FI.SourceLineCache = 0;
+ FI.NumLines = 0;
+ MemBufferInfos.push_back(InfoRec(0, FI));
+ return &MemBufferInfos.back();
+}
+
+
+/// createFileID - Create a new fileID for the specified InfoRec and include
+/// position. This works regardless of whether the InfoRec corresponds to a
+/// file or some other input source.
+unsigned SourceManager::createFileID(const InfoRec *File,
+ SourceLocation IncludePos) {
+ // If FileEnt is really large (e.g. it's a large .i file), we may not be able
+ // to fit an arbitrary position in the file in the FilePos field. To handle
+ // this, we create one FileID for each chunk of the file that fits in a
+ // FilePos field.
+ unsigned FileSize = File->second.Buffer->getBufferSize();
+ if (FileSize+1 < (1 << SourceLocation::FilePosBits)) {
+ FileIDs.push_back(FileIDInfo(IncludePos, 0, File));
+ return FileIDs.size();
+ }
+
+ // Create one FileID for each chunk of the file.
+ unsigned Result = FileIDs.size()+1;
+
+ unsigned ChunkNo = 0;
+ while (1) {
+ FileIDs.push_back(FileIDInfo(IncludePos, ChunkNo++, File));
+
+ if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break;
+ FileSize -= (1 << SourceLocation::FilePosBits);
+ }
+
+ return Result;
+}
+
+/// getColumnNumber - Return the column # for the specified include position.
+/// this is significantly cheaper to compute than the line number. This returns
+/// zero if the column number isn't known.
+unsigned SourceManager::getColumnNumber(SourceLocation IncludePos) const {
+ unsigned FileID = IncludePos.getFileID();
+ if (FileID == 0) return 0;
+ FileInfo *FileInfo = getFileInfo(FileID);
+ unsigned FilePos = getFilePos(IncludePos);
+ const SourceBuffer *Buffer = FileInfo->Buffer;
+ const char *Buf = Buffer->getBufferStart();
+
+ unsigned LineStart = FilePos;
+ while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
+ --LineStart;
+ return FilePos-LineStart+1;
+}
+
+/// getLineNumber - Given a SourceLocation, return the physical line number
+/// for the position indicated. This requires building and caching a table of
+/// line offsets for the SourceBuffer, so this is not cheap: use only when
+/// about to emit a diagnostic.
+unsigned SourceManager::getLineNumber(SourceLocation IncludePos) {
+ FileInfo *FileInfo = getFileInfo(IncludePos.getFileID());
+
+ // If this is the first use of line information for this buffer, compute the
+ /// SourceLineCache for it on demand.
+ if (FileInfo->SourceLineCache == 0) {
+ const SourceBuffer *Buffer = FileInfo->Buffer;
+
+ // Find the file offsets of all of the *physical* source lines. This does
+ // not look at trigraphs, escaped newlines, or anything else tricky.
+ std::vector<unsigned> LineOffsets;
+
+ // Line #1 starts at char 0.
+ LineOffsets.push_back(0);
+
+ const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
+ const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
+ unsigned Offs = 0;
+ while (1) {
+ // Skip over the contents of the line.
+ // TODO: Vectorize this? This is very performance sensitive for programs
+ // with lots of diagnostics.
+ const unsigned char *NextBuf = (const unsigned char *)Buf;
+ while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
+ ++NextBuf;
+ Offs += NextBuf-Buf;
+ Buf = NextBuf;
+
+ if (Buf[0] == '\n' || Buf[0] == '\r') {
+ // If this is \n\r or \r\n, skip both characters.
+ if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1])
+ ++Offs, ++Buf;
+ ++Offs, ++Buf;
+ LineOffsets.push_back(Offs);
+ } else {
+ // Otherwise, this is a null. If end of file, exit.
+ if (Buf == End) break;
+ // Otherwise, skip the null.
+ ++Offs, ++Buf;
+ }
+ }
+ LineOffsets.push_back(Offs);
+
+ // Copy the offsets into the FileInfo structure.
+ FileInfo->NumLines = LineOffsets.size();
+ FileInfo->SourceLineCache = new unsigned[LineOffsets.size()];
+ std::copy(LineOffsets.begin(), LineOffsets.end(),
+ FileInfo->SourceLineCache);
+ }
+
+ // Okay, we know we have a line number table. Do a binary search to find the
+ // line number that this character position lands on.
+ unsigned NumLines = FileInfo->NumLines;
+ unsigned *SourceLineCache = FileInfo->SourceLineCache;
+
+ // TODO: If this is performance sensitive, we could try doing simple radix
+ // type approaches to make good (tight?) initial guesses based on the
+ // assumption that all lines are the same average size.
+ unsigned *Pos = std::lower_bound(SourceLineCache, SourceLineCache+NumLines,
+ getFilePos(IncludePos)+1);
+ return Pos-SourceLineCache;
+}
+
+/// PrintStats - Print statistics to stderr.
+///
+void SourceManager::PrintStats() const {
+ std::cerr << "\n*** Source Manager Stats:\n";
+ std::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
+ << " mem buffers mapped, " << FileIDs.size()
+ << " file ID's allocated.\n";
+
+ unsigned NumLineNumsComputed = 0;
+ unsigned NumFileBytesMapped = 0;
+ for (std::map<const FileEntry *, FileInfo>::const_iterator I =
+ FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
+ NumLineNumsComputed += I->second.SourceLineCache != 0;
+ NumFileBytesMapped += I->second.Buffer->getBufferSize();
+ }
+ std::cerr << NumFileBytesMapped << " bytes of files mapped, "
+ << NumLineNumsComputed << " files with line #'s computed.\n";
+}
Propchange: cfe/cfe/trunk/Basic/SourceManager.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Basic/SourceManager.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Basic/TokenKinds.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Basic/TokenKinds.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Basic/TokenKinds.cpp (added)
+++ cfe/cfe/trunk/Basic/TokenKinds.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,28 @@
+//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===//
+//
+// 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 TokenKind enum and support functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TokenKinds.h"
+#include <cassert>
+using namespace llvm;
+using namespace llvm::clang;
+
+static const char * const TokNames[] = {
+#define TOK(X) #X,
+#include "clang/Basic/TokenKinds.def"
+ 0
+};
+
+const char *tok::getTokenName(enum TokenKind Kind) {
+ assert(Kind < tok::NUM_TOKENS);
+ return TokNames[Kind];
+}
Propchange: cfe/cfe/trunk/Basic/TokenKinds.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Basic/TokenKinds.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Driver/clang.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Driver/clang.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Driver/clang.cpp (added)
+++ cfe/cfe/trunk/Driver/clang.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,772 @@
+//===--- clang.cpp - C-Language Front-end ---------------------------------===//
+//
+// 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 utility may be invoked in the following manner:
+// clang --help - Output information about command line switches
+// clang [options] - Read from stdin.
+// clang [options] file - Read from "file".
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: Options to support:
+//
+// -ffatal-errors
+// -ftabstop=width
+// -fdollars-in-identifiers
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceBuffer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/System/MappedFile.h"
+#include "llvm/System/Signals.h"
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Global options.
+//===----------------------------------------------------------------------===//
+
+static cl::opt<bool>
+Verbose("v", cl::desc("Enable verbose output"));
+static cl::opt<bool>
+Stats("stats", cl::desc("Print performance metrics and statistics"));
+
+enum ProgActions {
+ RunPreprocessorOnly, // Just lex, no output.
+ PrintPreprocessedInput, // -E mode.
+ DumpTokens // Token dump mode.
+};
+
+static cl::opt<ProgActions>
+ProgAction(cl::desc("Choose output type:"), cl::ZeroOrMore,cl::init(DumpTokens),
+ cl::values(
+ clEnumValN(RunPreprocessorOnly, "Eonly",
+ "Just run preprocessor, no output (for timings)"),
+ clEnumValN(PrintPreprocessedInput, "E",
+ "Run preprocessor, emit preprocessed file"),
+ clEnumValN(DumpTokens, "dumptokens",
+ "Run preprocessor, dump internal rep of tokens"),
+ clEnumValEnd));
+
+
+//===----------------------------------------------------------------------===//
+// Our DiagnosticClient implementation
+//===----------------------------------------------------------------------===//
+
+// FIXME: Werror should take a list of things, -Werror=foo,bar
+static cl::opt<bool>
+WarningsAsErrors("Werror", cl::desc("Treat all warnings as errors"));
+
+static cl::opt<bool>
+WarnOnExtensions("pedantic",
+ cl::desc("Issue a warning on uses of GCC extensions"));
+
+static cl::opt<bool>
+ErrorOnExtensions("pedantic-errors",
+ cl::desc("Issue an error on uses of GCC extensions"));
+
+/// InitializeDiagnostics - Initialize the diagnostic object, based on the
+/// current command line option settings.
+static void InitializeDiagnostics(Diagnostic &Diags) {
+ Diags.setWarningsAsErrors(WarningsAsErrors);
+ Diags.setWarnOnExtensions(WarnOnExtensions);
+ Diags.setErrorOnExtensions(ErrorOnExtensions);
+}
+
+static cl::opt<bool>
+NoShowColumn("fno-show-column",
+ cl::desc("Do not include column number on diagnostics"));
+static cl::opt<bool>
+NoCaretDiagnostics("fno-caret-diagnostics",
+ cl::desc("Do not include source line and caret with"
+ " diagnostics"));
+
+/// DiagnosticPrinterSTDERR - This is a concrete diagnostic client, which prints
+/// the diagnostics to standard error.
+class DiagnosticPrinterSTDERR : public DiagnosticClient {
+ SourceManager &SourceMgr;
+ SourceLocation LastWarningLoc;
+public:
+ DiagnosticPrinterSTDERR(SourceManager &sourceMgr)
+ : SourceMgr(sourceMgr) {}
+
+ void PrintIncludeStack(SourceLocation Pos);
+
+ virtual bool HandleDiagnostic(Diagnostic::Level DiagLevel,
+ SourceLocation Pos,
+ diag::kind ID, const std::string &Msg);
+};
+
+void DiagnosticPrinterSTDERR::
+PrintIncludeStack(SourceLocation Pos) {
+ unsigned FileID = Pos.getFileID();
+ if (FileID == 0) return;
+
+ // Print out the other include frames first.
+ PrintIncludeStack(SourceMgr.getIncludeLoc(FileID));
+
+ unsigned LineNo = SourceMgr.getLineNumber(Pos);
+
+ const SourceBuffer *Buffer = SourceMgr.getBuffer(FileID);
+ std::cerr << "In file included from " << Buffer->getBufferIdentifier()
+ << ":" << LineNo << ":\n";
+}
+
+
+bool DiagnosticPrinterSTDERR::HandleDiagnostic(Diagnostic::Level Level,
+ SourceLocation Pos,
+ diag::kind ID,
+ const std::string &Extra) {
+ unsigned LineNo = 0, FilePos = 0, FileID = 0, ColNo = 0;
+ unsigned LineStart = 0, LineEnd = 0;
+ const SourceBuffer *Buffer = 0;
+
+ if (Pos.isValid()) {
+ LineNo = SourceMgr.getLineNumber(Pos);
+ FilePos = SourceMgr.getFilePos(Pos);
+ FileID = Pos.getFileID();
+
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ if (LastWarningLoc != SourceMgr.getIncludeLoc(Pos.getFileID())) {
+ LastWarningLoc = SourceMgr.getIncludeLoc(Pos.getFileID());
+ PrintIncludeStack(LastWarningLoc);
+ }
+
+ // Compute the column number. Rewind from the current position to the start
+ // of the line.
+ ColNo = SourceMgr.getColumnNumber(Pos);
+ LineStart = FilePos-ColNo-1; // Column # is 1-based
+
+ // Compute the line end. Scan forward from the error position to the end of
+ // the line.
+ Buffer = SourceMgr.getBuffer(FileID);
+ const char *Buf = Buffer->getBufferStart();
+ const char *BufEnd = Buffer->getBufferEnd();
+ LineEnd = FilePos;
+ while (Buf+LineEnd != BufEnd &&
+ Buf[LineEnd] != '\n' && Buf[LineEnd] != '\r')
+ ++LineEnd;
+
+ std::cerr << Buffer->getBufferIdentifier()
+ << ":" << LineNo << ":";
+ if (ColNo && !NoShowColumn)
+ std::cerr << ColNo << ":";
+ std::cerr << " ";
+ }
+
+ switch (Level) {
+ default: assert(0 && "Unknown diagnostic type!");
+ case Diagnostic::Note: std::cerr << "note: "; break;
+ case Diagnostic::Warning: std::cerr << "warning: "; break;
+ case Diagnostic::Error: std::cerr << "error: "; break;
+ case Diagnostic::Fatal: std::cerr << "fatal error: "; break;
+ case Diagnostic::Sorry: std::cerr << "sorry, unimplemented: "; break;
+ }
+
+ std::string Msg = Diagnostic::getDescription(ID);
+
+ // Replace all instances of %s in Msg with 'Extra'.
+ if (Msg.size() > 1) {
+ for (unsigned i = 0; i < Msg.size()-1; ++i) {
+ if (Msg[i] == '%' && Msg[i+1] == 's') {
+ Msg = std::string(Msg.begin(), Msg.begin()+i) +
+ Extra +
+ std::string(Msg.begin()+i+2, Msg.end());
+ }
+ }
+ }
+ std::cerr << Msg << "\n";
+
+ if (!NoCaretDiagnostics && Pos.isValid()) {
+ // Print out a line of the source file.
+ const char *Buf = Buffer->getBufferStart();
+ std::cerr << std::string(Buf+LineStart, Buf+LineEnd) << "\n";
+
+ // If the source line contained any tab characters between the start of the
+ // line and the diagnostic, replace the space we inserted with a tab, so
+ // that the carat will be indented exactly like the source line.
+ std::string Indent(ColNo-1, ' ');
+ for (unsigned i = LineStart; i != FilePos; ++i)
+ if (Buf[i] == '\t')
+ Indent[i-LineStart] = '\t';
+
+ // Print out the caret itself.
+ std::cerr << Indent << "^\n";
+ }
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Initialization
+//===----------------------------------------------------------------------===//
+
+// FIXME: Preprocessor builtins to support.
+// -A... - Play with #assertions
+// -undef - Undefine all predefined macros
+
+static cl::list<std::string>
+D_macros("D", cl::value_desc("macro"), cl::Prefix,
+ cl::desc("Predefine the specified macro"));
+static cl::list<std::string>
+U_macros("U", cl::value_desc("macro"), cl::Prefix,
+ cl::desc("Undefine the specified macro"));
+
+// Append a #define line to Buf for Macro. Macro should be of the form XXX,
+// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
+// "#define XXX Y z W". To get a #define with no value, use "XXX=".
+static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro,
+ const char *Command = "#define ") {
+ Buf.insert(Buf.end(), Command, Command+strlen(Command));
+ if (const char *Equal = strchr(Macro, '=')) {
+ // Turn the = into ' '.
+ Buf.insert(Buf.end(), Macro, Equal);
+ Buf.push_back(' ');
+ Buf.insert(Buf.end(), Equal+1, Equal+strlen(Equal));
+ } else {
+ // Push "macroname 1".
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back(' ');
+ Buf.push_back('1');
+ }
+ Buf.push_back('\n');
+}
+
+static void InitializePredefinedMacros(Preprocessor &PP,
+ std::vector<char> &Buf) {
+ // FIXME: Implement magic like cpp_init_builtins for things like __STDC__
+ // and __DATE__ etc.
+#if 0
+ /* __STDC__ has the value 1 under normal circumstances.
+ However, if (a) we are in a system header, (b) the option
+ stdc_0_in_system_headers is true (set by target config), and
+ (c) we are not in strictly conforming mode, then it has the
+ value 0. (b) and (c) are already checked in cpp_init_builtins. */
+{
+ case BT_STDC:
+ if (cpp_in_system_header (pfile))
+ number = 0;
+ else
+ number = 1;
+ break;
+}
+#endif
+ DefineBuiltinMacro(Buf, "__STDC__=1");
+
+ // FIXME: This is obviously silly. It should be more like gcc/c-cppbuiltin.c.
+ // Macros predefined by GCC 4.0.1.
+ DefineBuiltinMacro(Buf, "_ARCH_PPC=1");
+ DefineBuiltinMacro(Buf, "_BIG_ENDIAN=1");
+ DefineBuiltinMacro(Buf, "__APPLE_CC__=5250");
+ DefineBuiltinMacro(Buf, "__APPLE__=1");
+ DefineBuiltinMacro(Buf, "__BIG_ENDIAN__=1");
+ DefineBuiltinMacro(Buf, "__CHAR_BIT__=8");
+ DefineBuiltinMacro(Buf, "__CONSTANT_CFSTRINGS__=1");
+ DefineBuiltinMacro(Buf, "__DBL_DENORM_MIN__=4.9406564584124654e-324");
+ DefineBuiltinMacro(Buf, "__DBL_DIG__=15");
+ DefineBuiltinMacro(Buf, "__DBL_EPSILON__=2.2204460492503131e-16");
+ DefineBuiltinMacro(Buf, "__DBL_HAS_INFINITY__=1");
+ DefineBuiltinMacro(Buf, "__DBL_HAS_QUIET_NAN__=1");
+ DefineBuiltinMacro(Buf, "__DBL_MANT_DIG__=53");
+ DefineBuiltinMacro(Buf, "__DBL_MAX_10_EXP__=308");
+ DefineBuiltinMacro(Buf, "__DBL_MAX_EXP__=1024");
+ DefineBuiltinMacro(Buf, "__DBL_MAX__=1.7976931348623157e+308");
+ DefineBuiltinMacro(Buf, "__DBL_MIN_10_EXP__=(-307)");
+ DefineBuiltinMacro(Buf, "__DBL_MIN_EXP__=(-1021)");
+ DefineBuiltinMacro(Buf, "__DBL_MIN__=2.2250738585072014e-308");
+ DefineBuiltinMacro(Buf, "__DECIMAL_DIG__=33");
+ DefineBuiltinMacro(Buf, "__DYNAMIC__=1");
+ DefineBuiltinMacro(Buf, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__=1030");
+ DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0");
+ DefineBuiltinMacro(Buf, "__FLT_DENORM_MIN__=1.40129846e-45F");
+ DefineBuiltinMacro(Buf, "__FLT_DIG__=6");
+ DefineBuiltinMacro(Buf, "__FLT_EPSILON__=1.19209290e-7F");
+ DefineBuiltinMacro(Buf, "__FLT_EVAL_METHOD__=0");
+ DefineBuiltinMacro(Buf, "__FLT_HAS_INFINITY__=1");
+ DefineBuiltinMacro(Buf, "__FLT_HAS_QUIET_NAN__=1");
+ DefineBuiltinMacro(Buf, "__FLT_MANT_DIG__=24");
+ DefineBuiltinMacro(Buf, "__FLT_MAX_10_EXP__=38");
+ DefineBuiltinMacro(Buf, "__FLT_MAX_EXP__=128");
+ DefineBuiltinMacro(Buf, "__FLT_MAX__=3.40282347e+38F");
+ DefineBuiltinMacro(Buf, "__FLT_MIN_10_EXP__=(-37)");
+ DefineBuiltinMacro(Buf, "__FLT_MIN_EXP__=(-125)");
+ DefineBuiltinMacro(Buf, "__FLT_MIN__=1.17549435e-38F");
+ DefineBuiltinMacro(Buf, "__FLT_RADIX__=2");
+ DefineBuiltinMacro(Buf, "__GNUC_MINOR__=0");
+ DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
+ DefineBuiltinMacro(Buf, "__GNUC__=4");
+ DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
+ DefineBuiltinMacro(Buf, "__INTMAX_MAX__=9223372036854775807LL");
+ DefineBuiltinMacro(Buf, "__INTMAX_TYPE__=long long int");
+ DefineBuiltinMacro(Buf, "__INT_MAX__=2147483647");
+ DefineBuiltinMacro(Buf, "__LDBL_DENORM_MIN__=4.940656458412465441765687"
+ "92868221e-324L");
+ DefineBuiltinMacro(Buf, "__LDBL_DIG__=31");
+ DefineBuiltinMacro(Buf, "__LDBL_EPSILON__=4.9406564584124654417656879286822"
+ "1e-324L");
+ DefineBuiltinMacro(Buf, "__LDBL_HAS_INFINITY__=1");
+ DefineBuiltinMacro(Buf, "__LDBL_HAS_QUIET_NAN__=1");
+ DefineBuiltinMacro(Buf, "__LDBL_MANT_DIG__=106");
+ DefineBuiltinMacro(Buf, "__LDBL_MAX_10_EXP__=308");
+ DefineBuiltinMacro(Buf, "__LDBL_MAX_EXP__=1024");
+ DefineBuiltinMacro(Buf, "__LDBL_MAX__=1.7976931348623158079372897140"
+ "5301e+308L");
+ DefineBuiltinMacro(Buf, "__LDBL_MIN_10_EXP__=(-291)");
+ DefineBuiltinMacro(Buf, "__LDBL_MIN_EXP__=(-968)");
+ DefineBuiltinMacro(Buf, "__LDBL_MIN__=2.004168360008972777996108051350"
+ "16e-292L");
+ DefineBuiltinMacro(Buf, "__LONG_DOUBLE_128__=1");
+ DefineBuiltinMacro(Buf, "__LONG_LONG_MAX__=9223372036854775807LL");
+ DefineBuiltinMacro(Buf, "__LONG_MAX__=2147483647L");
+ DefineBuiltinMacro(Buf, "__MACH__=1");
+ DefineBuiltinMacro(Buf, "__NATURAL_ALIGNMENT__=1");
+ DefineBuiltinMacro(Buf, "__NO_INLINE__=1");
+ DefineBuiltinMacro(Buf, "__PIC__=1");
+ DefineBuiltinMacro(Buf, "__POWERPC__=1");
+ DefineBuiltinMacro(Buf, "__PTRDIFF_TYPE__=int");
+ DefineBuiltinMacro(Buf, "__REGISTER_PREFIX__");
+ DefineBuiltinMacro(Buf, "__SCHAR_MAX__=127");
+ DefineBuiltinMacro(Buf, "__SHRT_MAX__=32767");
+ DefineBuiltinMacro(Buf, "__SIZE_TYPE__=long unsigned int");
+ DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1");
+ DefineBuiltinMacro(Buf, "__UINTMAX_TYPE__=long long unsigned int");
+ DefineBuiltinMacro(Buf, "__USER_LABEL_PREFIX__=_");
+ DefineBuiltinMacro(Buf, "__VERSION__=\"4.0.1 (Apple Computer, Inc. "
+ "build 5250)\"");
+ DefineBuiltinMacro(Buf, "__WCHAR_MAX__=2147483647");
+ DefineBuiltinMacro(Buf, "__WCHAR_TYPE__=int");
+ DefineBuiltinMacro(Buf, "__WINT_TYPE__=int");
+ DefineBuiltinMacro(Buf, "__ppc__=1");
+ DefineBuiltinMacro(Buf, "__strong");
+ DefineBuiltinMacro(Buf, "__weak");
+ if (PP.getLangOptions().CPlusPlus) {
+ DefineBuiltinMacro(Buf, "__DEPRECATED=1");
+ DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ DefineBuiltinMacro(Buf, "__GNUG__=4");
+ DefineBuiltinMacro(Buf, "__GXX_WEAK__=1");
+ DefineBuiltinMacro(Buf, "__cplusplus=1");
+ DefineBuiltinMacro(Buf, "__private_extern__=extern");
+ }
+
+ // FIXME: Should emit a #line directive here.
+
+ // Add macros from the command line.
+ // FIXME: Should traverse the #define/#undef lists in parallel.
+ for (unsigned i = 0, e = D_macros.size(); i != e; ++i)
+ DefineBuiltinMacro(Buf, D_macros[i].c_str());
+ for (unsigned i = 0, e = U_macros.size(); i != e; ++i)
+ DefineBuiltinMacro(Buf, U_macros[i].c_str(), "#undef ");
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor include path information.
+//===----------------------------------------------------------------------===//
+
+// This tool exports a large number of command line options to control how the
+// preprocessor searches for header files. At root, however, the Preprocessor
+// object takes a very simple interface: a list of directories to search for
+//
+// FIXME: -nostdinc,-nostdinc++
+// FIXME: -isysroot,-imultilib
+//
+// FIXME: -include,-imacros
+
+static cl::opt<bool>
+nostdinc("nostdinc", cl::desc("Disable standard #include directories"));
+
+// Various command line options. These four add directories to each chain.
+static cl::list<std::string>
+I_dirs("I", cl::value_desc("directory"), cl::Prefix,
+ cl::desc("Add directory to include search path"));
+static cl::list<std::string>
+idirafter_dirs("idirafter", cl::value_desc("directory"), cl::Prefix,
+ cl::desc("Add directory to AFTER include search path"));
+static cl::list<std::string>
+iquote_dirs("iquote", cl::value_desc("directory"), cl::Prefix,
+ cl::desc("Add directory to QUOTE include search path"));
+static cl::list<std::string>
+isystem_dirs("isystem", cl::value_desc("directory"), cl::Prefix,
+ cl::desc("Add directory to SYSTEM include search path"));
+
+// These handle -iprefix/-iwithprefix/-iwithprefixbefore.
+static cl::list<std::string>
+iprefix_vals("iprefix", cl::value_desc("prefix"), cl::Prefix,
+ cl::desc("Set the -iwithprefix/-iwithprefixbefore prefix"));
+static cl::list<std::string>
+iwithprefix_vals("iwithprefix", cl::value_desc("dir"), cl::Prefix,
+ cl::desc("Set directory to SYSTEM include search path with prefix"));
+static cl::list<std::string>
+iwithprefixbefore_vals("iwithprefixbefore", cl::value_desc("dir"), cl::Prefix,
+ cl::desc("Set directory to include search path with prefix"));
+
+// Finally, implement the code that groks the options above.
+enum IncludeDirGroup {
+ Quoted = 0,
+ Angled,
+ System,
+ After
+};
+
+static std::vector<DirectoryLookup> IncludeGroup[4];
+
+/// AddPath - Add the specified path to the specified group list.
+///
+static void AddPath(const std::string &Path, IncludeDirGroup Group,
+ bool isCXXAware, bool isUserSupplied,
+ FileManager &FM) {
+ const DirectoryEntry *DE = FM.getDirectory(Path);
+ if (DE == 0) {
+ if (Verbose)
+ std::cerr << "ignoring nonexistent directory \"" << Path << "\"\n";
+ return;
+ }
+
+ DirectoryLookup::DirType Type;
+ if (Group == Quoted || Group == Angled)
+ Type = DirectoryLookup::NormalHeaderDir;
+ else if (isCXXAware)
+ Type = DirectoryLookup::SystemHeaderDir;
+ else
+ Type = DirectoryLookup::ExternCSystemHeaderDir;
+
+ IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied));
+}
+
+/// RemoveDuplicates - If there are duplicate directory entries in the specified
+/// search list, remove the later (dead) ones.
+static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList) {
+ std::set<const DirectoryEntry *> SeenDirs;
+ for (unsigned i = 0; i != SearchList.size(); ++i) {
+ // If this isn't the first time we've seen this dir, remove it.
+ if (!SeenDirs.insert(SearchList[i].getDir()).second) {
+ if (Verbose)
+ std::cerr << "ignoring duplicate directory \""
+ << SearchList[i].getDir()->getName() << "\"\n";
+ SearchList.erase(SearchList.begin()+i);
+ --i;
+ }
+ }
+}
+
+// Process the -I options and set them in the preprocessor.
+static void InitializeIncludePaths(Preprocessor &PP) {
+ FileManager &FM = PP.getFileManager();
+
+ // Handle -I... options.
+ for (unsigned i = 0, e = I_dirs.size(); i != e; ++i) {
+ if (I_dirs[i] == "-") {
+ // -I- is a deprecated GCC feature.
+ PP.getDiagnostics().Report(SourceLocation(),
+ diag::err_pp_I_dash_not_supported);
+ } else {
+ AddPath(I_dirs[i], Angled, false, true, FM);
+ }
+ }
+
+ // Handle -idirafter... options.
+ for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i)
+ AddPath(idirafter_dirs[i], After, false, true, FM);
+
+ // Handle -iquote... options.
+ for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i)
+ AddPath(iquote_dirs[i], Quoted, false, true, FM);
+
+ // Handle -isystem... options.
+ for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i)
+ AddPath(isystem_dirs[i], System, false, true, FM);
+
+ // Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in
+ // parallel, processing the values in order of occurance to get the right
+ // prefixes.
+ {
+ std::string Prefix = ""; // FIXME: this isn't the correct default prefix.
+ unsigned iprefix_idx = 0;
+ unsigned iwithprefix_idx = 0;
+ unsigned iwithprefixbefore_idx = 0;
+ bool iprefix_done = iprefix_vals.empty();
+ bool iwithprefix_done = iwithprefix_vals.empty();
+ bool iwithprefixbefore_done = iwithprefixbefore_vals.empty();
+ while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) {
+ if (!iprefix_done &&
+ (iwithprefix_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
+ iwithprefix_vals.getPosition(iwithprefix_idx)) &&
+ (iwithprefixbefore_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
+ iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
+ Prefix = iprefix_vals[iprefix_idx];
+ ++iprefix_idx;
+ iprefix_done = iprefix_idx == iprefix_vals.size();
+ } else if (!iwithprefix_done &&
+ (iwithprefixbefore_done ||
+ iwithprefix_vals.getPosition(iwithprefix_idx) <
+ iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
+ AddPath(Prefix+iwithprefix_vals[iwithprefix_idx],
+ System, false, false, FM);
+ ++iwithprefix_idx;
+ iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size();
+ } else {
+ AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx],
+ Angled, false, false, FM);
+ ++iwithprefixbefore_idx;
+ iwithprefixbefore_done =
+ iwithprefixbefore_idx == iwithprefixbefore_vals.size();
+ }
+ }
+ }
+
+ // FIXME: Add contents of the CPATH, C_INCLUDE_PATH, CPLUS_INCLUDE_PATH,
+ // OBJC_INCLUDE_PATH, OBJCPLUS_INCLUDE_PATH environment variables.
+
+ // FIXME: temporary hack: hard-coded paths.
+ if (!nostdinc) {
+ AddPath("/usr/local/include", System, false, false, FM);
+ AddPath("/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/include",
+ System, false, false, FM);
+ AddPath("/usr/lib/gcc/powerpc-apple-darwin8/"
+ "4.0.1/../../../../powerpc-apple-darwin8/include",
+ System, false, false, FM);
+ AddPath("/usr/include", System, false, false, FM);
+ AddPath("/System/Library/Frameworks", System, false, false, FM);
+ AddPath("/Library/Frameworks", System, false, false, FM);
+ }
+
+ // Now that we have collected all of the include paths, merge them all
+ // together and tell the preprocessor about them.
+
+ // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
+ std::vector<DirectoryLookup> SearchList;
+ SearchList = IncludeGroup[Angled];
+ SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
+ IncludeGroup[System].end());
+ SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
+ IncludeGroup[After].end());
+ RemoveDuplicates(SearchList);
+ RemoveDuplicates(IncludeGroup[Quoted]);
+
+ // Prepend QUOTED list on the search list.
+ SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
+ IncludeGroup[Quoted].end());
+
+
+ bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
+ PP.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
+ DontSearchCurDir);
+
+ // If verbose, print the list of directories that will be searched.
+ if (Verbose) {
+ std::cerr << "#include \"...\" search starts here:\n";
+ unsigned QuotedIdx = IncludeGroup[Quoted].size();
+ for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
+ if (i == QuotedIdx)
+ std::cerr << "#include <...> search starts here:\n";
+ std::cerr << " " << SearchList[i].getDir()->getName() << "\n";
+ }
+ }
+}
+
+
+// Read any files specified by -imacros or -include.
+static void ReadPrologFiles(Preprocessor &PP, std::vector<char> &Buf) {
+ // FIXME: IMPLEMENT
+}
+
+
+//===----------------------------------------------------------------------===//
+// Preprocessed output mode.
+//===----------------------------------------------------------------------===//
+
+/// DoPrintPreprocessedInput - This implements -E mode.
+void DoPrintPreprocessedInput(Preprocessor &PP) {
+ LexerToken Tok;
+ char Buffer[256];
+ bool isFirstToken = true;
+ do {
+ if (PP.Lex(Tok)) return;
+
+ // If this token is at the start of a line. Emit the \n and indentation.
+ // FIXME: this shouldn't use the isAtStartOfLine flag. This should use a
+ // "newline callback" from the lexer.
+ // FIXME: For some tests, this fails just because there is no col# info from
+ // macro expansions!
+ if (Tok.isAtStartOfLine()) {
+ if (!isFirstToken)
+ std::cout << "\n";
+ // Print out space characters so that the first token on a line is
+ // indented for easy reading.
+ unsigned ColNo =
+ PP.getSourceManager().getColumnNumber(Tok.getSourceLocation());
+
+ // This hack prevents stuff like:
+ // #define HASH #
+ // HASH define foo bar
+ // From having the # character end up at column 1, which makes it so it
+ // is not handled as a #define next time through the preprocessor if in
+ // -fpreprocessed mode.
+ if (ColNo <= 1 && Tok.getKind() == tok::hash)
+ std::cout << ' ';
+
+ for (; ColNo > 1; --ColNo)
+ std::cout << ' ';
+
+ } else if (Tok.hasLeadingSpace()) {
+ std::cout << ' ';
+ }
+ isFirstToken = false;
+
+ if (Tok.getEnd()-Tok.getStart() < 256) {
+ unsigned Len = Lexer::getSpelling(Tok, Buffer, PP.getLangOptions());
+ Buffer[Len] = 0;
+ std::cout << Buffer;
+ } else {
+ std::string S = Lexer::getSpelling(Tok, PP.getLangOptions());
+ std::cout << S;
+ }
+ } while (Tok.getKind() != tok::eof);
+ std::cout << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Main driver
+//===----------------------------------------------------------------------===//
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
+
+void PrintIdentStats();
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv, " llvm cfe\n");
+ sys::PrintStackTraceOnErrorSignal();
+
+ /// Create a SourceManager object. This tracks and owns all the file buffers
+ /// allocated to the program.
+ SourceManager SourceMgr;
+
+ // Print diagnostics to stderr.
+ DiagnosticPrinterSTDERR OurDiagnosticClient(SourceMgr);
+
+ // Configure our handling of diagnostics.
+ Diagnostic OurDiagnostics(OurDiagnosticClient);
+ InitializeDiagnostics(OurDiagnostics);
+
+ // Turn all options on.
+ // FIXME: add -ansi and -std= options.
+ LangOptions Options;
+ Options.Trigraphs = 1;
+ Options.BCPLComment = 1; // Only for C99/C++.
+ Options.C99 = 1;
+ Options.DollarIdents = Options.Digraphs = 1;
+ Options.ObjC1 = Options.ObjC2 = 1;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ FileManager FileMgr;
+
+ // Set up the preprocessor with these options.
+ Preprocessor PP(OurDiagnostics, Options, FileMgr, SourceMgr);
+
+ // Install things like __POWERPC__, __GNUC__, etc into the macro table.
+ std::vector<char> PrologMacros;
+ InitializePredefinedMacros(PP, PrologMacros);
+
+ // Process the -I options and set them in the preprocessor.
+ InitializeIncludePaths(PP);
+
+ // Read any files specified by -imacros or -include.
+ ReadPrologFiles(PP, PrologMacros);
+
+ // Set up keywords.
+ PP.AddKeywords();
+
+ // Now that we have emitted the predefined macros, #includes, etc into
+ // PrologMacros, preprocess it to populate the initial preprocessor state.
+ {
+ // Memory buffer must end with a null byte!
+ PrologMacros.push_back(0);
+
+ SourceBuffer *SB = SourceBuffer::getMemBuffer(&PrologMacros.front(),
+ &PrologMacros.back(),
+ "<predefines>");
+ assert(SB && "Cannot fail to create predefined source buffer");
+ unsigned FileID = SourceMgr.createFileIDForMemBuffer(SB);
+ assert(FileID && "Could not create FileID for predefines?");
+
+ // Start parsing the predefines.
+ PP.EnterSourceFile(FileID, 0);
+
+ // Lex the file, which will read all the macros.
+ LexerToken Tok;
+ if (PP.Lex(Tok)) return 1;
+ assert(Tok.getKind() == tok::eof && "Didn't read entire file!");
+
+ // Once we've read this, we're done.
+ }
+
+ unsigned MainFileID = 0;
+ if (InputFilename != "-") {
+ const FileEntry *File = FileMgr.getFile(InputFilename);
+ if (File) MainFileID = SourceMgr.createFileID(File, SourceLocation());
+ if (MainFileID == 0) {
+ std::cerr << "Error reading '" << InputFilename << "'!\n";
+ return 1;
+ }
+ } else {
+ SourceBuffer *SB = SourceBuffer::getSTDIN();
+ if (SB) MainFileID = SourceMgr.createFileIDForMemBuffer(SB);
+ if (MainFileID == 0) {
+ std::cerr << "Error reading standard input! Empty?\n";
+ return 1;
+ }
+ }
+
+ // Start parsing the specified input file.
+ PP.EnterSourceFile(MainFileID, 0);
+
+ switch (ProgAction) {
+ case RunPreprocessorOnly: { // Just lex as fast as we can, no output.
+ LexerToken Tok;
+ do {
+ if (PP.Lex(Tok))
+ break;
+ } while (Tok.getKind() != tok::eof);
+ break;
+ }
+
+ case PrintPreprocessedInput: // -E mode.
+ DoPrintPreprocessedInput(PP);
+ break;
+
+ case DumpTokens: { // Token dump mode.
+ LexerToken Tok;
+ do {
+ if (PP.Lex(Tok))
+ break;
+ Tok.dump(true);
+ std::cerr << "\n";
+ } while (Tok.getKind() != tok::eof);
+ break;
+ }
+ }
+
+ if (Stats) {
+ // Printed from low-to-high level.
+ PP.getFileManager().PrintStats();
+ PP.getSourceManager().PrintStats();
+ PP.getIdentifierTable().PrintStats();
+ PP.PrintStats();
+ std::cerr << "\n";
+ }
+}
Propchange: cfe/cfe/trunk/Driver/clang.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Driver/clang.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/IdentifierTable.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/IdentifierTable.cpp (added)
+++ cfe/cfe/trunk/Lex/IdentifierTable.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,268 @@
+//===--- Preprocess.cpp - C Language Family Preprocessor Implementation ---===//
+//
+// 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 IdentifierTokenInfo and IdentifierTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/IdentifierTable.h"
+#include "clang/Lex/MacroInfo.h"
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// IdentifierTokenInfo Implementation
+//===----------------------------------------------------------------------===//
+
+void IdentifierTokenInfo::Destroy() {
+ delete Macro;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Memory Allocation Support
+//===----------------------------------------------------------------------===//
+
+/// The identifier table has a very simple memory allocation pattern: it just
+/// keeps allocating identifiers, then never frees them unless it frees them
+/// all. As such, we use a simple bump-pointer memory allocator to make
+/// allocation speedy. Shark showed that malloc was 27% of the time spent in
+/// IdentifierTable::getIdentifier with malloc, and takes a 4.3% time with this.
+#define USE_ALLOCATOR 1
+#if USE_ALLOCATOR
+
+namespace {
+class MemRegion {
+ unsigned RegionSize;
+ MemRegion *Next;
+ char *NextPtr;
+public:
+ void Init(unsigned size, MemRegion *next) {
+ RegionSize = size;
+ Next = next;
+ NextPtr = (char*)(this+1);
+
+ // FIXME: uses GCC extension.
+ unsigned Alignment = __alignof__(IdentifierTokenInfo);
+ NextPtr = (char*)((intptr_t)(NextPtr+Alignment-1) &
+ ~(intptr_t)(Alignment-1));
+ }
+
+ const MemRegion *getNext() const { return Next; }
+ unsigned getNumBytesAllocated() const {
+ return NextPtr-(const char*)this;
+ }
+
+ /// Allocate - Allocate and return at least the specified number of bytes.
+ ///
+ void *Allocate(unsigned AllocSize, MemRegion **RegPtr) {
+ // FIXME: uses GCC extension.
+ unsigned Alignment = __alignof__(IdentifierTokenInfo);
+ // Round size up to an even multiple of the alignment.
+ AllocSize = (AllocSize+Alignment-1) & ~(Alignment-1);
+
+ // If there is space in this region for the identifier, return it.
+ if (unsigned(NextPtr+AllocSize-(char*)this) <= RegionSize) {
+ void *Result = NextPtr;
+ NextPtr += AllocSize;
+ return Result;
+ }
+
+ // Otherwise, we have to allocate a new chunk. Create one twice as big as
+ // this one.
+ MemRegion *NewRegion = (MemRegion *)malloc(RegionSize*2);
+ NewRegion->Init(RegionSize*2, this);
+
+ // Update the current "first region" pointer to point to the new region.
+ *RegPtr = NewRegion;
+
+ // Try allocating from it now.
+ return NewRegion->Allocate(AllocSize, RegPtr);
+ }
+
+ /// Deallocate - Release all memory for this region to the system.
+ ///
+ void Deallocate() {
+ MemRegion *next = Next;
+ free(this);
+ if (next)
+ next->Deallocate();
+ }
+};
+}
+
+#endif
+
+//===----------------------------------------------------------------------===//
+// IdentifierTable Implementation
+//===----------------------------------------------------------------------===//
+
+
+/// IdentifierLink - There is one of these allocated by IdentifierTokenInfo.
+/// These form the linked list of buckets for the hash table.
+struct IdentifierBucket {
+ /// Next - This is the next bucket in the linked list.
+ IdentifierBucket *Next;
+
+ IdentifierTokenInfo TokInfo;
+ // NOTE: TokInfo must be the last element in this structure, as the string
+ // information for the identifier is allocated right after it.
+};
+
+// FIXME: start hashtablesize off at 8K entries, GROW when density gets to 3.
+static unsigned HASH_TABLE_SIZE = 8096;
+
+IdentifierTable::IdentifierTable() {
+ IdentifierBucket **TableArray = new IdentifierBucket*[HASH_TABLE_SIZE]();
+ TheTable = TableArray;
+ NumIdentifiers = 0;
+#if USE_ALLOCATOR
+ TheMemory = malloc(8*4096);
+ ((MemRegion*)TheMemory)->Init(8*4096, 0);
+#endif
+
+ memset(TheTable, 0, HASH_TABLE_SIZE*sizeof(IdentifierBucket*));
+}
+
+IdentifierTable::~IdentifierTable() {
+ IdentifierBucket **TableArray = (IdentifierBucket**)TheTable;
+ for (unsigned i = 0, e = HASH_TABLE_SIZE; i != e; ++i) {
+ IdentifierBucket *Id = TableArray[i];
+ while (Id) {
+ // Free memory referenced by the identifier (e.g. macro info).
+ Id->TokInfo.Destroy();
+
+ IdentifierBucket *Next = Id->Next;
+#if !USE_ALLOCATOR
+ free(Id);
+#endif
+ Id = Next;
+ }
+ }
+#if USE_ALLOCATOR
+ ((MemRegion*)TheMemory)->Deallocate();
+#endif
+ delete [] TableArray;
+}
+
+/// HashString - Compute a hash code for the specified string.
+///
+static unsigned HashString(const char *Start, const char *End) {
+ unsigned int Result = 0;
+ // Perl hash function.
+ while (Start != End)
+ Result = Result * 33 + *Start++;
+ Result = Result + (Result >> 5);
+ return Result;
+}
+
+IdentifierTokenInfo &IdentifierTable::get(const char *NameStart,
+ const char *NameEnd) {
+ IdentifierBucket **TableArray = (IdentifierBucket**)TheTable;
+
+ unsigned Hash = HashString(NameStart, NameEnd) % HASH_TABLE_SIZE;
+ unsigned Length = NameEnd-NameStart;
+
+ IdentifierBucket *IdentHead = TableArray[Hash];
+ for (IdentifierBucket *Identifier = IdentHead; Identifier;
+ Identifier = Identifier->Next) {
+ if (Identifier->TokInfo.getNameLength() == Length &&
+ memcmp(Identifier->TokInfo.getName(), NameStart, Length) == 0)
+ return Identifier->TokInfo;
+ }
+
+ // Allocate a new identifier, with space for the null-terminated string at the
+ // end.
+ unsigned AllocSize = sizeof(IdentifierBucket)+Length+1;
+#if USE_ALLOCATOR
+ IdentifierBucket *Identifier = (IdentifierBucket*)
+ ((MemRegion*)TheMemory)->Allocate(AllocSize, (MemRegion**)&TheMemory);
+#else
+ IdentifierBucket *Identifier = (IdentifierBucket*)malloc(AllocSize);
+#endif
+ Identifier->TokInfo.NameLen = Length;
+ Identifier->TokInfo.Macro = 0;
+ Identifier->TokInfo.TokenID = tok::identifier;
+ Identifier->TokInfo.IsExtension = false;
+ Identifier->TokInfo.FETokenInfo = 0;
+
+ // Copy the string information.
+ char *StrBuffer = (char*)(Identifier+1);
+ memcpy(StrBuffer, NameStart, Length);
+ StrBuffer[Length] = 0; // Null terminate string.
+
+ // Link it into the hash table.
+ Identifier->Next = IdentHead;
+ TableArray[Hash] = Identifier;
+ return Identifier->TokInfo;
+}
+
+IdentifierTokenInfo &IdentifierTable::get(const std::string &Name) {
+ // Don't use c_str() here: no need to be null terminated.
+ const char *NameBytes = &Name[0];
+ unsigned Size = Name.size();
+ return get(NameBytes, NameBytes+Size);
+}
+
+
+
+/// PrintStats - Print statistics about how well the identifier table is doing
+/// at hashing identifiers.
+void IdentifierTable::PrintStats() const {
+ unsigned NumIdentifiers = 0;
+ unsigned NumEmptyBuckets = 0;
+ unsigned MaxBucketLength = 0;
+ unsigned AverageIdentifierSize = 0;
+ unsigned MaxIdentifierLength = 0;
+
+ IdentifierBucket **TableArray = (IdentifierBucket**)TheTable;
+ for (unsigned i = 0, e = HASH_TABLE_SIZE; i != e; ++i) {
+
+ unsigned NumIdentifiersInBucket = 0;
+ for (IdentifierBucket *Id = TableArray[i]; Id; Id = Id->Next) {
+ AverageIdentifierSize += Id->TokInfo.getNameLength();
+ if (MaxIdentifierLength < Id->TokInfo.getNameLength())
+ MaxIdentifierLength = Id->TokInfo.getNameLength();
+ ++NumIdentifiersInBucket;
+ }
+ if (NumIdentifiersInBucket > MaxBucketLength)
+ MaxBucketLength = NumIdentifiersInBucket;
+ if (NumIdentifiersInBucket == 0)
+ ++NumEmptyBuckets;
+
+ NumIdentifiers += NumIdentifiersInBucket;
+ }
+
+ std::cerr << "\n*** Identifier Table Stats:\n";
+ std::cerr << "# Identifiers: " << NumIdentifiers << "\n";
+ std::cerr << "# Empty Buckets: " << NumEmptyBuckets << "\n";
+ std::cerr << "Max identifiers in one bucket: " << MaxBucketLength << "\n";
+ std::cerr << "Hash density (#identifiers per bucket): "
+ << NumIdentifiers/(double)HASH_TABLE_SIZE << "\n";
+ std::cerr << "Nonempty hash density (average chain length): "
+ << NumIdentifiers/(double)(HASH_TABLE_SIZE-NumEmptyBuckets) << "\n";
+ std::cerr << "Ave identifier length: "
+ << (AverageIdentifierSize/(double)NumIdentifiers) << "\n";
+ std::cerr << "Max identifier length: " << MaxIdentifierLength << "\n";
+
+ // Compute statistics about the memory allocated for identifiers.
+#if USE_ALLOCATOR
+ unsigned BytesUsed = 0;
+ unsigned NumRegions = 0;
+ const MemRegion *R = (MemRegion*)TheMemory;
+ for (; R; R = R->getNext(), ++NumRegions) {
+ BytesUsed += R->getNumBytesAllocated();
+ }
+ std::cerr << "\nNumber of memory regions: " << NumRegions << "\n";
+ std::cerr << "Bytes allocated for identifiers: " << BytesUsed << "\n";
+#endif
+}
+
+
Propchange: cfe/cfe/trunk/Lex/IdentifierTable.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/IdentifierTable.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Lexer.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/Lexer.cpp (added)
+++ cfe/cfe/trunk/Lex/Lexer.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,1473 @@
+//===--- Lexer.cpp - C Language Family Lexer ------------------------------===//
+//
+// 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 Lexer and LexerToken interfaces.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: GCC Diagnostics emitted by the lexer:
+// PEDWARN: (form feed|vertical tab) in preprocessing directive
+//
+// Universal characters, unicode, char mapping:
+// WARNING: `%.*s' is not in NFKC
+// WARNING: `%.*s' is not in NFC
+//
+// Other:
+// ERROR : attempt to use poisoned \"%s\"
+//
+// TODO: Options to support:
+// -fexec-charset,-fwide-exec-charset
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceBuffer.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Config/alloca.h"
+#include <cassert>
+#include <cctype>
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+static void InitCharacterInfo();
+
+Lexer::Lexer(const SourceBuffer *File, unsigned fileid, Preprocessor &pp)
+ : BufferPtr(File->getBufferStart()), BufferStart(BufferPtr),
+ BufferEnd(File->getBufferEnd()), InputFile(File), CurFileID(fileid), PP(pp),
+ Features(PP.getLangOptions()) {
+ InitCharacterInfo();
+
+ assert(BufferEnd[0] == 0 &&
+ "We assume that the input buffer has a null character at the end"
+ " to simplify lexing!");
+
+ // Start of the file is a start of line.
+ IsAtStartOfLine = true;
+
+ // We are not after parsing a #.
+ ParsingPreprocessorDirective = false;
+
+ // We are not after parsing #include.
+ ParsingFilename = false;
+}
+
+//===----------------------------------------------------------------------===//
+// LexerToken implementation.
+//===----------------------------------------------------------------------===//
+
+/// getSourceLocation - Return a source location identifier for the specified
+/// offset in the current file.
+SourceLocation LexerToken::getSourceLocation() const {
+ if (TheLexer)
+ return TheLexer->getSourceLocation(Start);
+ return SourceLocation();
+}
+
+
+/// dump - Print the token to stderr, used for debugging.
+///
+void LexerToken::dump(bool DumpFlags) const {
+ std::cerr << clang::tok::getTokenName(Kind) << " '";
+
+ if (needsCleaning()) {
+ if (getLexer())
+ std::cerr << getLexer()->getSpelling(*this);
+ else {
+ // FIXME: expansion from macros clears location info. Testcase:
+ // #define TWELVE 1\ <whitespace only>
+ // 2
+ // TWELVE
+ std::cerr << "*unspelled*" << std::string(Start, End);
+ }
+ } else
+ std::cerr << std::string(Start, End);
+ std::cerr << "'";
+
+ if (DumpFlags) {
+ std::cerr << "\t";
+ if (isAtStartOfLine())
+ std::cerr << " [StartOfLine]";
+ if (hasLeadingSpace())
+ std::cerr << " [LeadingSpace]";
+ if (needsCleaning())
+ std::cerr << " [Spelling='" << std::string(Start, End) << "']";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Character information.
+//===----------------------------------------------------------------------===//
+
+static unsigned char CharInfo[256];
+
+enum {
+ CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0'
+ CHAR_VERT_WS = 0x02, // '\r', '\n'
+ CHAR_LETTER = 0x04, // a-z,A-Z
+ CHAR_NUMBER = 0x08, // 0-9
+ CHAR_UNDER = 0x10, // _
+ CHAR_PERIOD = 0x20 // .
+};
+
+static void InitCharacterInfo() {
+ static bool isInited = false;
+ if (isInited) return;
+ isInited = true;
+
+ // Intiialize the CharInfo table.
+ // TODO: statically initialize this.
+ CharInfo[(int)' '] = CharInfo[(int)'\t'] =
+ CharInfo[(int)'\f'] = CharInfo[(int)'\v'] = CHAR_HORZ_WS;
+ CharInfo[(int)'\n'] = CharInfo[(int)'\r'] = CHAR_VERT_WS;
+
+ CharInfo[(int)'_'] = CHAR_UNDER;
+ for (unsigned i = 'a'; i <= 'z'; ++i)
+ CharInfo[i] = CharInfo[i+'A'-'a'] = CHAR_LETTER;
+ for (unsigned i = '0'; i <= '9'; ++i)
+ CharInfo[i] = CHAR_NUMBER;
+}
+
+/// isIdentifierBody - Return true if this is the body character of an
+/// identifier, which is [a-zA-Z0-9_].
+static inline bool isIdentifierBody(unsigned char c) {
+ return CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER);
+}
+
+/// isHorizontalWhitespace - Return true if this character is horizontal
+/// whitespace: ' ', '\t', '\f', '\v'. Note that this returns false for '\0'.
+static inline bool isHorizontalWhitespace(unsigned char c) {
+ return CharInfo[c] & CHAR_HORZ_WS;
+}
+
+/// isWhitespace - Return true if this character is horizontal or vertical
+/// whitespace: ' ', '\t', '\f', '\v', '\n', '\r'. Note that this returns false
+/// for '\0'.
+static inline bool isWhitespace(unsigned char c) {
+ return CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS);
+}
+
+/// isNumberBody - Return true if this is the body character of an
+/// preprocessing number, which is [a-zA-Z0-9_.].
+static inline bool isNumberBody(unsigned char c) {
+ return CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD);
+}
+
+//===----------------------------------------------------------------------===//
+// Diagnostics forwarding code.
+//===----------------------------------------------------------------------===//
+
+/// getSourceLocation - Return a source location identifier for the specified
+/// offset in the current file.
+SourceLocation Lexer::getSourceLocation(const char *Loc) const {
+ assert(Loc >= InputFile->getBufferStart() && Loc <= InputFile->getBufferEnd()
+ && "Location out of range for this buffer!");
+ return SourceLocation(CurFileID, Loc-InputFile->getBufferStart());
+}
+
+
+/// Diag - Forwarding function for diagnostics. This translate a source
+/// position in the current buffer into a SourceLocation object for rendering.
+bool Lexer::Diag(const char *Loc, unsigned DiagID,
+ const std::string &Msg) const {
+ return PP.Diag(getSourceLocation(Loc), DiagID, Msg);
+}
+
+//===----------------------------------------------------------------------===//
+// Trigraph and Escaped Newline Handling Code.
+//===----------------------------------------------------------------------===//
+
+/// GetTrigraphCharForLetter - Given a character that occurs after a ?? pair,
+/// return the decoded trigraph letter it corresponds to, or '\0' if nothing.
+static char GetTrigraphCharForLetter(char Letter) {
+ switch (Letter) {
+ default: return 0;
+ case '=': return '#';
+ case ')': return ']';
+ case '(': return '[';
+ case '!': return '|';
+ case '\'': return '^';
+ case '>': return '}';
+ case '/': return '\\';
+ case '<': return '{';
+ case '-': return '~';
+ }
+}
+
+/// DecodeTrigraphChar - If the specified character is a legal trigraph when
+/// prefixed with ??, emit a trigraph warning. If trigraphs are enabled,
+/// return the result character. Finally, emit a warning about trigraph use
+/// whether trigraphs are enabled or not.
+static char DecodeTrigraphChar(const char *CP, Lexer *L) {
+ char Res = GetTrigraphCharForLetter(*CP);
+ if (Res && L) {
+ if (!L->getFeatures().Trigraphs) {
+ L->Diag(CP-2, diag::trigraph_ignored);
+ return 0;
+ } else {
+ L->Diag(CP-2, diag::trigraph_converted, std::string()+Res);
+ }
+ }
+ return Res;
+}
+
+/// getCharAndSizeSlow - Peek a single 'character' from the specified buffer,
+/// get its size, and return it. This is tricky in several cases:
+/// 1. If currently at the start of a trigraph, we warn about the trigraph,
+/// then either return the trigraph (skipping 3 chars) or the '?',
+/// depending on whether trigraphs are enabled or not.
+/// 2. If this is an escaped newline (potentially with whitespace between
+/// the backslash and newline), implicitly skip the newline and return
+/// the char after it.
+/// 3. If this is a UCN, return it. FIXME: for C++?
+///
+/// This handles the slow/uncommon case of the getCharAndSize method. Here we
+/// know that we can accumulate into Size, and that we have already incremented
+/// Ptr by Size bytes.
+///
+/// When this method is updated, getCharAndSizeSlowNoWarn (below) should be
+/// updated to match.
+///
+char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
+ LexerToken *Tok) {
+ // If we have a slash, look for an escaped newline.
+ if (Ptr[0] == '\\') {
+ ++Size;
+ ++Ptr;
+Slash:
+ // Common case, backslash-char where the char is not whitespace.
+ if (!isWhitespace(Ptr[0])) return '\\';
+
+ // See if we have optional whitespace characters followed by a newline.
+ {
+ unsigned SizeTmp = 0;
+ do {
+ ++SizeTmp;
+ if (Ptr[SizeTmp-1] == '\n' || Ptr[SizeTmp-1] == '\r') {
+ // Remember that this token needs to be cleaned.
+ if (Tok) Tok->SetFlag(LexerToken::NeedsCleaning);
+
+ // Warn if there was whitespace between the backslash and newline.
+ if (SizeTmp != 1 && Tok)
+ Diag(Ptr, diag::backslash_newline_space);
+
+ // If this is a \r\n or \n\r, skip the newlines.
+ if ((Ptr[SizeTmp] == '\r' || Ptr[SizeTmp] == '\n') &&
+ Ptr[SizeTmp-1] != Ptr[SizeTmp])
+ ++SizeTmp;
+
+ // Found backslash<whitespace><newline>. Parse the char after it.
+ Size += SizeTmp;
+ Ptr += SizeTmp;
+ // Use slow version to accumulate a correct size field.
+ return getCharAndSizeSlow(Ptr, Size, Tok);
+ }
+ } while (isWhitespace(Ptr[SizeTmp]));
+ }
+
+ // Otherwise, this is not an escaped newline, just return the slash.
+ return '\\';
+ }
+
+ // If this is a trigraph, process it.
+ if (Ptr[0] == '?' && Ptr[1] == '?') {
+ // If this is actually a legal trigraph (not something like "??x"), emit
+ // a trigraph warning. If so, and if trigraphs are enabled, return it.
+ if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) {
+ // Remember that this token needs to be cleaned.
+ if (Tok) Tok->SetFlag(LexerToken::NeedsCleaning);
+
+ Ptr += 3;
+ Size += 3;
+ if (C == '\\') goto Slash;
+ return C;
+ }
+ }
+
+ // If this is neither, return a single character.
+ ++Size;
+ return *Ptr;
+}
+
+/// getCharAndSizeSlowNoWarn - Handle the slow/uncommon case of the
+/// getCharAndSizeNoWarn method. Here we know that we can accumulate into Size,
+/// and that we have already incremented Ptr by Size bytes.
+///
+/// When this method is updated, getCharAndSizeSlow (above) should be updated to
+/// match.
+static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
+ const LangOptions &Features) {
+ // If we have a slash, look for an escaped newline.
+ if (Ptr[0] == '\\') {
+ ++Size;
+ ++Ptr;
+Slash:
+ // Common case, backslash-char where the char is not whitespace.
+ if (!isWhitespace(Ptr[0])) return '\\';
+
+ // See if we have optional whitespace characters followed by a newline.
+ {
+ unsigned SizeTmp = 0;
+ do {
+ ++SizeTmp;
+ if (Ptr[SizeTmp-1] == '\n' || Ptr[SizeTmp-1] == '\r') {
+
+ // If this is a \r\n or \n\r, skip the newlines.
+ if ((Ptr[SizeTmp] == '\r' || Ptr[SizeTmp] == '\n') &&
+ Ptr[SizeTmp-1] != Ptr[SizeTmp])
+ ++SizeTmp;
+
+ // Found backslash<whitespace><newline>. Parse the char after it.
+ Size += SizeTmp;
+ Ptr += SizeTmp;
+
+ // Use slow version to accumulate a correct size field.
+ return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
+ }
+ } while (isWhitespace(Ptr[SizeTmp]));
+ }
+
+ // Otherwise, this is not an escaped newline, just return the slash.
+ return '\\';
+ }
+
+ // If this is a trigraph, process it.
+ if (Features.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') {
+ // If this is actually a legal trigraph (not something like "??x"), return
+ // it.
+ if (char C = GetTrigraphCharForLetter(Ptr[2])) {
+ Ptr += 3;
+ Size += 3;
+ if (C == '\\') goto Slash;
+ return C;
+ }
+ }
+
+ // If this is neither, return a single character.
+ ++Size;
+ return *Ptr;
+}
+
+/// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever
+/// emit a warning.
+static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size,
+ const LangOptions &Features) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (Ptr[0] != '?' && Ptr[0] != '\\') {
+ Size = 1;
+ return *Ptr;
+ }
+
+ Size = 0;
+ return getCharAndSizeSlowNoWarn(Ptr, Size, Features);
+}
+
+
+/// getSpelling() - Return the 'spelling' of this token. The spelling of a
+/// token are the characters used to represent the token in the source file
+/// after trigraph expansion and escaped-newline folding. In particular, this
+/// wants to get the true, uncanonicalized, spelling of things like digraphs
+/// UCNs, etc.
+std::string Lexer::getSpelling(const LexerToken &Tok,
+ const LangOptions &Features) {
+ assert(Tok.getStart() <= Tok.getEnd() && "Token character range is bogus!");
+
+ // If this token contains nothing interesting, return it directly.
+ if (!Tok.needsCleaning())
+ return std::string(Tok.getStart(), Tok.getEnd());
+
+ // Otherwise, hard case, relex the characters into the string.
+ std::string Result;
+ Result.reserve(Tok.getEnd()-Tok.getStart());
+
+ for (const char *Ptr = Tok.getStart(), *End = Tok.getEnd(); Ptr != End; ) {
+ unsigned CharSize;
+ Result.push_back(getCharAndSizeNoWarn(Ptr, CharSize, Features));
+ Ptr += CharSize;
+ }
+ assert(Result.size() != unsigned(Tok.getEnd()-Tok.getStart()) &&
+ "NeedsCleaning flag set on something that didn't need cleaning!");
+ return Result;
+}
+
+/// getSpelling - This method is used to get the spelling of a token into a
+/// preallocated buffer, instead of as an std::string. The caller is required
+/// to allocate enough space for the token, which is guaranteed to be at most
+/// Tok.End-Tok.Start bytes long. The actual length of the token is returned.
+unsigned Lexer::getSpelling(const LexerToken &Tok, char *Buffer,
+ const LangOptions &Features) {
+ assert(Tok.getStart() <= Tok.getEnd() && "Token character range is bogus!");
+
+ // If this token contains nothing interesting, return it directly.
+ if (!Tok.needsCleaning()) {
+ unsigned Size = Tok.getEnd()-Tok.getStart();
+ memcpy(Buffer, Tok.getStart(), Size);
+ return Size;
+ }
+ // Otherwise, hard case, relex the characters into the string.
+ std::string Result;
+ Result.reserve(Tok.getEnd()-Tok.getStart());
+
+ char *OutBuf = Buffer;
+ for (const char *Ptr = Tok.getStart(), *End = Tok.getEnd(); Ptr != End; ) {
+ unsigned CharSize;
+ *OutBuf++ = getCharAndSizeNoWarn(Ptr, CharSize, Features);
+ Ptr += CharSize;
+ }
+ assert(OutBuf-Buffer != Tok.getEnd()-Tok.getStart() &&
+ "NeedsCleaning flag set on something that didn't need cleaning!");
+
+ return OutBuf-Buffer;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Helper methods for lexing.
+//===----------------------------------------------------------------------===//
+
+bool Lexer::LexIdentifier(LexerToken &Result, const char *CurPtr) {
+ // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
+ unsigned Size;
+ unsigned char C = *CurPtr++;
+ while (isIdentifierBody(C)) {
+ C = *CurPtr++;
+ }
+ --CurPtr; // Back up over the skipped character.
+
+ // Fast path, no $,\,? in identifier found. '\' might be an escaped newline
+ // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN.
+ // FIXME: universal chars.
+ if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) {
+FinishIdentifier:
+ Result.SetEnd(BufferPtr = CurPtr);
+ Result.SetKind(tok::identifier);
+
+ // Look up this token, see if it is a macro, or if it is a language keyword.
+ const char *SpelledTokStart, *SpelledTokEnd;
+ if (!Result.needsCleaning()) {
+ // No cleaning needed, just use the characters from the lexed buffer.
+ SpelledTokStart = Result.getStart();
+ SpelledTokEnd = Result.getEnd();
+ } else {
+ // Cleaning needed, alloca a buffer, clean into it, then use the buffer.
+ char *TmpBuf = (char*)alloca(Result.getEnd()-Result.getStart());
+ unsigned Size = getSpelling(Result, TmpBuf);
+ SpelledTokStart = TmpBuf;
+ SpelledTokEnd = TmpBuf+Size;
+ }
+
+ Result.SetIdentifierInfo(PP.getIdentifierInfo(SpelledTokStart,
+ SpelledTokEnd));
+ return PP.HandleIdentifier(Result);
+ }
+
+ // Otherwise, $,\,? in identifier found. Enter slower path.
+
+ C = getCharAndSize(CurPtr, Size);
+ while (1) {
+ if (C == '$') {
+ // If we hit a $ and they are not supported in identifiers, we are done.
+ if (!Features.DollarIdents) goto FinishIdentifier;
+
+ // Otherwise, emit a diagnostic and continue.
+ if (Diag(CurPtr, diag::ext_dollar_in_identifier))
+ return true;
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ C = getCharAndSize(CurPtr, Size);
+ continue;
+ } else if (!isIdentifierBody(C)) { // FIXME: universal chars.
+ // Found end of identifier.
+ goto FinishIdentifier;
+ }
+
+ // Otherwise, this character is good, consume it.
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+
+ C = getCharAndSize(CurPtr, Size);
+ while (isIdentifierBody(C)) { // FIXME: universal chars.
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ C = getCharAndSize(CurPtr, Size);
+ }
+ }
+}
+
+
+/// LexNumericConstant - Lex the remainer of a integer or floating point
+/// constant. From[-1] is the first character lexed. Return the end of the
+/// constant.
+bool Lexer::LexNumericConstant(LexerToken &Result, const char *CurPtr) {
+ unsigned Size;
+ char C = getCharAndSize(CurPtr, Size);
+ char PrevCh = 0;
+ while (isNumberBody(C)) { // FIXME: universal chars?
+ CurPtr = ConsumeChar(CurPtr, Size, Result);
+ PrevCh = C;
+ C = getCharAndSize(CurPtr, Size);
+ }
+
+ // If we fell out, check for a sign, due to 1e+12. If we have one, continue.
+ if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e'))
+ return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
+
+ // If we have a hex FP constant, continue.
+ if (Features.HexFloats &&
+ (C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p'))
+ return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
+
+ Result.SetKind(tok::numeric_constant);
+
+ // Update the end of token position as well as the BufferPtr instance var.
+ Result.SetEnd(BufferPtr = CurPtr);
+ return false;
+}
+
+/// LexStringLiteral - Lex the remainder of a string literal, after having lexed
+/// either " or L".
+bool Lexer::LexStringLiteral(LexerToken &Result, const char *CurPtr) {
+ const char *NulCharacter = 0; // Does this string contain the \0 character?
+
+ char C = getAndAdvanceChar(CurPtr, Result);
+ while (C != '"') {
+ // Skip escaped characters.
+ if (C == '\\') {
+ // Skip the escaped character.
+ C = getAndAdvanceChar(CurPtr, Result);
+ } else if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (Diag(Result.getStart(), diag::err_unterminated_string))
+ return true;
+ BufferPtr = CurPtr-1;
+ return LexTokenInternal(Result);
+ } else if (C == 0) {
+ NulCharacter = CurPtr-1;
+ }
+ C = getAndAdvanceChar(CurPtr, Result);
+ }
+
+ if (NulCharacter && Diag(NulCharacter, diag::null_in_string))
+ return true;
+
+ Result.SetKind(tok::string_literal);
+
+ // Update the end of token position as well as the BufferPtr instance var.
+ Result.SetEnd(BufferPtr = CurPtr);
+ return false;
+}
+
+/// LexAngledStringLiteral - Lex the remainder of an angled string literal,
+/// after having lexed the '<' character. This is used for #include filenames.
+bool Lexer::LexAngledStringLiteral(LexerToken &Result, const char *CurPtr) {
+ const char *NulCharacter = 0; // Does this string contain the \0 character?
+
+ char C = getAndAdvanceChar(CurPtr, Result);
+ while (C != '>') {
+ // Skip escaped characters.
+ if (C == '\\') {
+ // Skip the escaped character.
+ C = getAndAdvanceChar(CurPtr, Result);
+ } else if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (Diag(Result.getStart(), diag::err_unterminated_string))
+ return true;
+ BufferPtr = CurPtr-1;
+ return LexTokenInternal(Result);
+ } else if (C == 0) {
+ NulCharacter = CurPtr-1;
+ }
+ C = getAndAdvanceChar(CurPtr, Result);
+ }
+
+ if (NulCharacter && Diag(NulCharacter, diag::null_in_string))
+ return true;
+
+ Result.SetKind(tok::angle_string_literal);
+
+ // Update the end of token position as well as the BufferPtr instance var.
+ Result.SetEnd(BufferPtr = CurPtr);
+ return false;
+}
+
+
+/// LexCharConstant - Lex the remainder of a character constant, after having
+/// lexed either ' or L'.
+bool Lexer::LexCharConstant(LexerToken &Result, const char *CurPtr) {
+ const char *NulCharacter = 0; // Does this character contain the \0 character?
+
+ // Handle the common case of 'x' and '\y' efficiently.
+ char C = getAndAdvanceChar(CurPtr, Result);
+ if (C == '\'') {
+ if (Diag(Result.getStart(), diag::err_empty_character))
+ return true;
+ BufferPtr = CurPtr;
+ return LexTokenInternal(Result);
+ } else if (C == '\\') {
+ // Skip the escaped character.
+ // FIXME: UCN's.
+ C = getAndAdvanceChar(CurPtr, Result);
+ }
+
+ if (C && C != '\n' && C != '\r' && CurPtr[0] == '\'') {
+ ++CurPtr;
+ } else {
+ // Fall back on generic code for embedded nulls, newlines, wide chars.
+ do {
+ // Skip escaped characters.
+ if (C == '\\') {
+ // Skip the escaped character.
+ C = getAndAdvanceChar(CurPtr, Result);
+ } else if (C == '\n' || C == '\r' || // Newline.
+ (C == 0 && CurPtr-1 == BufferEnd)) { // End of file.
+ if (Diag(Result.getStart(), diag::err_unterminated_char))
+ return true;
+ BufferPtr = CurPtr-1;
+ return LexTokenInternal(Result);
+ } else if (C == 0) {
+ NulCharacter = CurPtr-1;
+ }
+ C = getAndAdvanceChar(CurPtr, Result);
+ } while (C != '\'');
+ }
+
+ if (NulCharacter && Diag(NulCharacter, diag::null_in_char))
+ return true;
+
+ Result.SetKind(tok::char_constant);
+
+ // Update the end of token position as well as the BufferPtr instance var.
+ Result.SetEnd(BufferPtr = CurPtr);
+ return false;
+}
+
+/// SkipWhitespace - Efficiently skip over a series of whitespace characters.
+/// Update BufferPtr to point to the next non-whitespace character and return.
+bool Lexer::SkipWhitespace(LexerToken &Result, const char *CurPtr) {
+ // Whitespace - Skip it, then return the token after the whitespace.
+ unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently.
+ while (1) {
+ // Skip horizontal whitespace very aggressively.
+ while (isHorizontalWhitespace(Char))
+ Char = *++CurPtr;
+
+ // Otherwise if we something other than whitespace, we're done.
+ if (Char != '\n' && Char != '\r')
+ break;
+
+ if (ParsingPreprocessorDirective) {
+ // End of preprocessor directive line, let LexTokenInternal handle this.
+ BufferPtr = CurPtr;
+ return false;
+ }
+
+ // ok, but handle newline.
+ // The returned token is at the start of the line.
+ Result.SetFlag(LexerToken::StartOfLine);
+ // No leading whitespace seen so far.
+ Result.ClearFlag(LexerToken::LeadingSpace);
+ Char = *++CurPtr;
+ }
+
+ // If this isn't immediately after a newline, there is leading space.
+ char PrevChar = CurPtr[-1];
+ if (PrevChar != '\n' && PrevChar != '\r')
+ Result.SetFlag(LexerToken::LeadingSpace);
+
+ // If the next token is obviously a // or /* */ comment, skip it efficiently
+ // too (without going through the big switch stmt).
+ if (Char == '/' && CurPtr[1] == '/') {
+ Result.SetStart(CurPtr);
+ return SkipBCPLComment(Result, CurPtr+1);
+ }
+ if (Char == '/' && CurPtr[1] == '*') {
+ Result.SetStart(CurPtr);
+ return SkipBlockComment(Result, CurPtr+2);
+ }
+ BufferPtr = CurPtr;
+ return false;
+}
+
+// SkipBCPLComment - We have just read the // characters from input. Skip until
+// we find the newline character thats terminate the comment. Then update
+/// BufferPtr and return.
+bool Lexer::SkipBCPLComment(LexerToken &Result, const char *CurPtr) {
+ // If BCPL comments aren't explicitly enabled for this language, emit an
+ // extension warning.
+ if (!Features.BCPLComment) {
+ if (Diag(Result.getStart(), diag::ext_bcpl_comment))
+ return true;
+
+ // Mark them enabled so we only emit one warning for this translation
+ // unit.
+ Features.BCPLComment = true;
+ }
+
+ // Scan over the body of the comment. The common case, when scanning, is that
+ // the comment contains normal ascii characters with nothing interesting in
+ // them. As such, optimize for this case with the inner loop.
+ char C;
+ do {
+ C = *CurPtr;
+ // FIXME: just scan for a \n or \r character. If we find a \n character,
+ // scan backwards, checking to see if it's an escaped newline, like we do
+ // for block comments.
+
+ // Skip over characters in the fast loop.
+ while (C != 0 && // Potentially EOF.
+ C != '\\' && // Potentially escaped newline.
+ C != '?' && // Potentially trigraph.
+ C != '\n' && C != '\r') // Newline or DOS-style newline.
+ C = *++CurPtr;
+
+ // If this is a newline, we're done.
+ if (C == '\n' || C == '\r')
+ break; // Found the newline? Break out!
+
+ // Otherwise, this is a hard case. Fall back on getAndAdvanceChar to
+ // properly decode the character.
+ const char *OldPtr = CurPtr;
+ C = getAndAdvanceChar(CurPtr, Result);
+
+ // If we read multiple characters, and one of those characters was a \r or
+ // \n, then we had an escaped newline within the comment. Emit diagnostic.
+ if (CurPtr != OldPtr+1) {
+ for (; OldPtr != CurPtr; ++OldPtr)
+ if (OldPtr[0] == '\n' || OldPtr[0] == '\r') {
+ if (Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment))
+ return true;
+ }
+ }
+
+ if (CurPtr == BufferEnd+1) goto FoundEOF;
+ } while (C != '\n' && C != '\r');
+
+ // Found and did not consume a newline.
+
+ // If we are inside a preprocessor directive and we see the end of line,
+ // return immediately, so that the lexer can return this as an EOM token.
+ if (ParsingPreprocessorDirective) {
+ BufferPtr = CurPtr;
+ return false;
+ }
+
+ // Otherwise, eat the \n character. We don't care if this is a \n\r or
+ // \r\n sequence.
+ ++CurPtr;
+
+ // The next returned token is at the start of the line.
+ Result.SetFlag(LexerToken::StartOfLine);
+ // No leading whitespace seen so far.
+ Result.ClearFlag(LexerToken::LeadingSpace);
+
+ // It is common for the tokens immediately after a // comment to be
+ // whitespace (indentation for the next line). Instead of going through the
+ // big switch, handle it efficiently now.
+ if (isWhitespace(*CurPtr)) {
+ Result.SetFlag(LexerToken::LeadingSpace);
+ return SkipWhitespace(Result, CurPtr+1);
+ }
+
+ BufferPtr = CurPtr;
+ return false;
+
+FoundEOF: // If we ran off the end of the buffer, return EOF.
+ BufferPtr = CurPtr-1;
+ return false;
+}
+
+/// isEndOfEscapedNewLine - Return true if the specified newline character
+/// (either \n or \r) is part of an escaped newline sequence. Issue a
+/// diagnostic if so. We know that the is inside of a block comment.
+bool Lexer::isBlockCommentEndOfEscapedNewLine(const char *CurPtr,
+ char &PrevChar) {
+ assert(CurPtr[0] == '\n' || CurPtr[0] == '\r');
+ PrevChar = 0;
+
+ // Back up off the newline.
+ --CurPtr;
+
+ // If this is a two-character newline sequence, skip the other character.
+ if (CurPtr[0] == '\n' || CurPtr[0] == '\r') {
+ // \n\n or \r\r -> not escaped newline.
+ if (CurPtr[0] == CurPtr[1])
+ return false;
+ // \n\r or \r\n -> skip the newline.
+ --CurPtr;
+ }
+
+ // If we have horizontal whitespace, skip over it. We allow whitespace
+ // between the slash and newline.
+ bool HasSpace = false;
+ while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) {
+ --CurPtr;
+ HasSpace = true;
+ }
+
+ // If we have a slash, we know this is an escaped newline.
+ if (*CurPtr == '\\') {
+ PrevChar = CurPtr[-1];
+ if (PrevChar != '*') return false;
+ } else {
+ // It isn't a slash, is it the ?? / trigraph?
+ if (*CurPtr != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?')
+ return false;
+ // This is the trigraph. Emit a stern warning!
+ if ((PrevChar = CurPtr[-3]) != '*') return false;
+ CurPtr -= 2;
+
+ // If no trigraphs are enabled, warn that we ignored this trigraph and
+ // ignore this * character.
+ if (!Features.Trigraphs) {
+ PrevChar = 0;
+ return Diag(CurPtr, diag::trigraph_ignored_block_comment);
+ } else {
+ if (Diag(CurPtr, diag::trigraph_ends_block_comment))
+ return true;
+ }
+ }
+
+ // Warn about having an escaped newline between the */ characters.
+ if (Diag(CurPtr, diag::escaped_newline_block_comment_end))
+ return true;
+
+ // If there was space between the backslash and newline, warn about it.
+ if (HasSpace &&
+ Diag(CurPtr, diag::backslash_newline_space))
+ return true;
+
+ return false;
+}
+
+/// SkipBlockComment - We have just read the /* characters from input. Read
+/// until we find the */ characters that terminate the comment. Note that we
+/// don't bother decoding trigraphs or escaped newlines in block comments,
+/// because they cannot cause the comment to end. The only thing that can
+/// happen is the comment could end with an escaped newline between the */ end
+/// of comment.
+bool Lexer::SkipBlockComment(LexerToken &Result, const char *CurPtr) {
+ // Scan one character past where we should, looking for a '/' character. Once
+ // we find it, check to see if it was preceeded by a *. This common
+ // optimization helps people who like to put a lot of * characters in their
+ // comments.
+ unsigned char C = *CurPtr++;
+ if (C == 0 && CurPtr == BufferEnd+1) {
+ if (Diag(Result.getStart(), diag::err_unterminated_block_comment))
+ return true;
+ BufferPtr = CurPtr-1;
+ return false;
+ }
+
+ while (1) {
+ // Skip over all non-interesting characters.
+ // TODO: Vectorize this. Note: memchr on Darwin is slower than this loop.
+ while (C != '/' && C != '\0')
+ C = *CurPtr++;
+
+ if (C == '/') {
+ char T;
+ if (CurPtr[-2] == '*') // We found the final */. We're done!
+ break;
+
+ if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) {
+ char Prev;
+ if (isBlockCommentEndOfEscapedNewLine(CurPtr-2, Prev))
+ return true;
+ if (Prev == '*') {
+ // We found the final */, though it had an escaped newline between the
+ // * and /. We're done!
+ break;
+ }
+ }
+ if (CurPtr[0] == '*' && CurPtr[1] != '/') {
+ // If this is a /* inside of the comment, emit a warning. Don't do this
+ // if this is a /*/, which will end the comment. This misses cases with
+ // embedded escaped newlines, but oh well.
+ if (Diag(CurPtr-1, diag::nested_block_comment))
+ return true;
+ }
+ } else if (C == 0 && CurPtr == BufferEnd+1) {
+ if (Diag(Result.getStart(), diag::err_unterminated_block_comment))
+ return true;
+ // Note: the user probably forgot a */. We could continue immediately
+ // after the /*, but this would involve lexing a lot of what really is the
+ // comment, which surely would confuse the parser.
+ BufferPtr = CurPtr-1;
+ return false;
+ }
+ C = *CurPtr++;
+ }
+
+ // It is common for the tokens immediately after a /**/ comment to be
+ // whitespace. Instead of going through the big switch, handle it
+ // efficiently now.
+ if (isHorizontalWhitespace(*CurPtr)) {
+ Result.SetFlag(LexerToken::LeadingSpace);
+ return SkipWhitespace(Result, CurPtr+1);
+ }
+
+ // Otherwise, just return so that the next character will be lexed as a token.
+ BufferPtr = CurPtr;
+ Result.SetFlag(LexerToken::LeadingSpace);
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Primary Lexing Entry Points
+//===----------------------------------------------------------------------===//
+
+/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
+/// (potentially) macro expand the filename.
+bool Lexer::LexIncludeFilename(LexerToken &Result) {
+ assert(ParsingPreprocessorDirective &&
+ ParsingFilename == false &&
+ "Must be in a preprocessing directive!");
+
+ // We are now parsing a filename!
+ ParsingFilename = true;
+
+ // There should be exactly two tokens here if everything is good: first the
+ // filename, then the EOM.
+ if (Lex(Result)) return true;
+
+ // We should have gotten the filename now.
+ ParsingFilename = false;
+
+ // No filename?
+ if (Result.getKind() == tok::eom)
+ return Diag(Result.getStart(), diag::err_pp_expects_filename);
+
+ // Verify that there is nothing after the filename, other than EOM.
+ LexerToken EndTok;
+ if (Lex(EndTok)) return true;
+
+ if (EndTok.getKind() != tok::eom) {
+ if (Diag(Result.getStart(), diag::err_pp_expects_filename))
+ return true;
+
+ // Lex until the end of the preprocessor directive line.
+ while (EndTok.getKind() != tok::eom) {
+ if (Lex(EndTok)) return true;
+ }
+
+ Result.SetKind(tok::eom);
+ }
+
+ // We're done now.
+ return false;
+}
+
+/// ReadToEndOfLine - Read the rest of the current preprocessor line as an
+/// uninterpreted string. This switches the lexer out of directive mode.
+std::string Lexer::ReadToEndOfLine() {
+ assert(ParsingPreprocessorDirective && ParsingFilename == false &&
+ "Must be in a preprocessing directive!");
+ std::string Result;
+ LexerToken Tmp;
+
+ // CurPtr - Cache BufferPtr in an automatic variable.
+ const char *CurPtr = BufferPtr;
+ Tmp.SetStart(CurPtr);
+
+ while (1) {
+ char Char = getAndAdvanceChar(CurPtr, Tmp);
+ switch (Char) {
+ default:
+ Result += Char;
+ break;
+ case 0: // Null.
+ // Found end of file?
+ if (CurPtr-1 != BufferEnd) {
+ // Nope, normal character, continue.
+ Result += Char;
+ break;
+ }
+ // FALL THROUGH.
+ case '\r':
+ case '\n':
+ // Okay, we found the end of the line. First, back up past the \0, \r, \n.
+ assert(CurPtr[-1] == Char && "Trigraphs for newline?");
+ BufferPtr = CurPtr-1;
+
+ // Next, lex the character, which should handle the EOM transition.
+ bool Err = Lex(Tmp);
+ assert(Tmp.getKind() == tok::eom && "Unexpected token!");
+ assert(!Err && "Shouldn't have error exiting macro!");
+
+ // Finally, we're done, return the string we found.
+ return Result;
+ }
+ }
+}
+
+/// LexEndOfFile - CurPtr points to the end of this file. Handle this
+/// condition, reporting diagnostics and handling other edge cases as required.
+bool Lexer::LexEndOfFile(LexerToken &Result, const char *CurPtr) {
+ // If we hit the end of the file while parsing a preprocessor directive,
+ // end the preprocessor directive first. The next token returned will
+ // then be the end of file.
+ if (ParsingPreprocessorDirective) {
+ // Done parsing the "line".
+ ParsingPreprocessorDirective = false;
+ Result.SetKind(tok::eom);
+ // Update the end of token position as well as the BufferPtr instance var.
+ Result.SetEnd(BufferPtr = CurPtr);
+ return false;
+ }
+
+ // If we are in a #if directive, emit an error.
+ while (!ConditionalStack.empty()) {
+ if (Diag(ConditionalStack.back().IfLoc,
+ diag::err_pp_unterminated_conditional))
+ return true;
+ ConditionalStack.pop_back();
+ }
+
+ // If the file was empty or didn't end in a newline, issue a pedwarn.
+ if (CurPtr[-1] != '\n' && CurPtr[-1] != '\r' &&
+ Diag(BufferEnd, diag::ext_no_newline_eof))
+ return true;
+
+ BufferPtr = CurPtr;
+ return PP.HandleEndOfFile(Result);
+}
+
+
+/// LexTokenInternal - This implements a simple C family lexer. It is an
+/// extremely performance critical piece of code. This assumes that the buffer
+/// has a null character at the end of the file. Return true if an error
+/// occurred and compilation should terminate, false if normal. This returns a
+/// preprocessing token, not a normal token, as such, it is an internal
+/// interface. It assumes that the Flags of result have been cleared before
+/// calling this.
+bool Lexer::LexTokenInternal(LexerToken &Result) {
+LexNextToken:
+ // New token, can't need cleaning yet.
+ Result.ClearFlag(LexerToken::NeedsCleaning);
+
+ // CurPtr - Cache BufferPtr in an automatic variable.
+ const char *CurPtr = BufferPtr;
+ Result.SetStart(CurPtr);
+
+ unsigned SizeTmp, SizeTmp2; // Temporaries for use in cases below.
+
+ // Read a character, advancing over it.
+ char Char = getAndAdvanceChar(CurPtr, Result);
+ switch (Char) {
+ case 0: // Null.
+ // Found end of file?
+ if (CurPtr-1 == BufferEnd)
+ return LexEndOfFile(Result, CurPtr-1); // Retreat back into the file.
+
+ if (Diag(CurPtr-1, diag::null_in_file))
+ return true;
+ Result.SetFlag(LexerToken::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr)) return true;
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ case '\n':
+ case '\r':
+ // If we are inside a preprocessor directive and we see the end of line,
+ // we know we are done with the directive, so return an EOM token.
+ if (ParsingPreprocessorDirective) {
+ // Done parsing the "line".
+ ParsingPreprocessorDirective = false;
+
+ // Since we consumed a newline, we are back at the start of a line.
+ IsAtStartOfLine = true;
+
+ Result.SetKind(tok::eom);
+ break;
+ }
+ // The returned token is at the start of the line.
+ Result.SetFlag(LexerToken::StartOfLine);
+ // No leading whitespace seen so far.
+ Result.ClearFlag(LexerToken::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr)) return true;
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ Result.SetFlag(LexerToken::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr)) return true;
+ goto LexNextToken; // GCC isn't tail call eliminating.
+
+ case 'L':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+
+ // Wide string literal.
+ if (Char == '"')
+ return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result));
+
+ // Wide character constant.
+ if (Char == '\'')
+ return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
+ // FALL THROUGH, treating L like the start of an identifier.
+
+ // C99 6.4.2: Identifiers.
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': /*'L'*/case 'M': case 'N':
+ 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 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+ 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 '_':
+ 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':
+ return LexNumericConstant(Result, CurPtr);
+
+ // C99 6.4.4: Character Constants.
+ case '\'':
+ return LexCharConstant(Result, CurPtr);
+
+ // C99 6.4.5: String Literals.
+ case '"':
+ return LexStringLiteral(Result, CurPtr);
+
+ // C99 6.4.6: Punctuators.
+ case '?':
+ Result.SetKind(tok::question);
+ break;
+ case '[':
+ Result.SetKind(tok::l_square);
+ break;
+ case ']':
+ Result.SetKind(tok::r_square);
+ break;
+ case '(':
+ Result.SetKind(tok::l_paren);
+ break;
+ case ')':
+ Result.SetKind(tok::r_paren);
+ break;
+ case '{':
+ Result.SetKind(tok::l_brace);
+ break;
+ case '}':
+ Result.SetKind(tok::r_brace);
+ break;
+ case '.':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char >= '0' && Char <= '9') {
+ return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
+ } else if (Features.CPlusPlus && Char == '*') {
+ Result.SetKind(tok::periodstar);
+ CurPtr += SizeTmp;
+ } else if (Char == '.' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') {
+ Result.SetKind(tok::ellipsis);
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else {
+ Result.SetKind(tok::period);
+ }
+ break;
+ case '&':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '&') {
+ Result.SetKind(tok::ampamp);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '=') {
+ Result.SetKind(tok::ampequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::amp);
+ }
+ break;
+ case '*':
+ if (getCharAndSize(CurPtr, SizeTmp) == '=') {
+ Result.SetKind(tok::starequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::star);
+ }
+ break;
+ case '+':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '+') {
+ Result.SetKind(tok::plusplus);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '=') {
+ Result.SetKind(tok::plusequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::plus);
+ }
+ break;
+ case '-':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '-') {
+ Result.SetKind(tok::minusminus);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '>' && Features.CPlusPlus &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') {
+ Result.SetKind(tok::arrowstar); // C++ ->*
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else if (Char == '>') {
+ Result.SetKind(tok::arrow);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '=') {
+ Result.SetKind(tok::minusequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::minus);
+ }
+ break;
+ case '~':
+ Result.SetKind(tok::tilde);
+ break;
+ case '!':
+ if (getCharAndSize(CurPtr, SizeTmp) == '=') {
+ Result.SetKind(tok::exclaimequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::exclaim);
+ }
+ break;
+ case '/':
+ // 6.4.9: Comments
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '/') { // BCPL comment.
+ Result.SetFlag(LexerToken::LeadingSpace);
+ if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
+ return true;
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ } else if (Char == '*') { // /**/ comment.
+ Result.SetFlag(LexerToken::LeadingSpace);
+ if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
+ return true;
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ } else if (Char == '=') {
+ Result.SetKind(tok::slashequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::slash);
+ }
+ break;
+ case '%':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Result.SetKind(tok::percentequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.Digraphs && Char == '>') {
+ Result.SetKind(tok::r_brace); // '%>' -> '}'
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.Digraphs && Char == ':') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ if (getCharAndSize(CurPtr, SizeTmp) == '%' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') {
+ Result.SetKind(tok::hashhash); // '%:%:' -> '##'
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else {
+ Result.SetKind(tok::hash); // '%:' -> '#'
+
+ // We parsed a # character. If this occurs at the start of the line,
+ // it's actually the start of a preprocessing directive. Callback to
+ // the preprocessor to handle it.
+ // FIXME: -fpreprocessed mode??
+ if (Result.isAtStartOfLine() && !PP.isSkipping()) {
+ BufferPtr = CurPtr;
+ if (PP.HandleDirective(Result)) return true;
+
+ // As an optimization, if the preprocessor didn't switch lexers, tail
+ // recurse.
+ if (PP.isCurrentLexer(this)) {
+ // Start a new token. If this is a #include or something, the PP may
+ // want us starting at the beginning of the line again. If so, set
+ // the StartOfLine flag.
+ if (IsAtStartOfLine) {
+ Result.SetFlag(LexerToken::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+
+ return PP.Lex(Result);
+ }
+ }
+ } else {
+ Result.SetKind(tok::percent);
+ }
+ break;
+ case '<':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (ParsingFilename) {
+ return LexAngledStringLiteral(Result, CurPtr+SizeTmp);
+ } else if (Char == '<' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
+ Result.SetKind(tok::lesslessequal);
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else if (Char == '<') {
+ Result.SetKind(tok::lessless);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '=') {
+ Result.SetKind(tok::lessequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.Digraphs && Char == ':') {
+ Result.SetKind(tok::l_square); // '<:' -> '['
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.Digraphs && Char == '>') {
+ Result.SetKind(tok::l_brace); // '<%' -> '{'
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.CPPMinMax && Char == '?') { // <?
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ if (Diag(Result.getStart(), diag::min_max_deprecated))
+ return true;
+
+ if (getCharAndSize(CurPtr, SizeTmp) == '=') { // <?=
+ Result.SetKind(tok::lessquestionequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::lessquestion);
+ }
+ } else {
+ Result.SetKind(tok::less);
+ }
+ break;
+ case '>':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Result.SetKind(tok::greaterequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '>' &&
+ getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') {
+ Result.SetKind(tok::greatergreaterequal);
+ CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
+ SizeTmp2, Result);
+ } else if (Char == '>') {
+ Result.SetKind(tok::greatergreater);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.CPPMinMax && Char == '?') {
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ if (Diag(Result.getStart(), diag::min_max_deprecated))
+ return true;
+
+ if (getCharAndSize(CurPtr, SizeTmp) == '=') {
+ Result.SetKind(tok::greaterquestionequal); // >?=
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::greaterquestion); // >?
+ }
+ } else {
+ Result.SetKind(tok::greater);
+ }
+ break;
+ case '^':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Result.SetKind(tok::caretequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::caret);
+ }
+ break;
+ case '|':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Result.SetKind(tok::pipeequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Char == '|') {
+ Result.SetKind(tok::pipepipe);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::pipe);
+ }
+ break;
+ case ':':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Features.Digraphs && Char == '>') {
+ Result.SetKind(tok::r_square); // ':>' -> ']'
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else if (Features.CPlusPlus && Char == ':') {
+ Result.SetKind(tok::coloncolon);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::colon);
+ }
+ break;
+ case ';':
+ Result.SetKind(tok::semi);
+ break;
+ case '=':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '=') {
+ Result.SetKind(tok::equalequal);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::equal);
+ }
+ break;
+ case ',':
+ Result.SetKind(tok::comma);
+ break;
+ case '#':
+ Char = getCharAndSize(CurPtr, SizeTmp);
+ if (Char == '#') {
+ Result.SetKind(tok::hashhash);
+ CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
+ } else {
+ Result.SetKind(tok::hash);
+ // We parsed a # character. If this occurs at the start of the line,
+ // it's actually the start of a preprocessing directive. Callback to
+ // the preprocessor to handle it.
+ // FIXME: not in preprocessed mode??
+ if (Result.isAtStartOfLine() && !PP.isSkipping()) {
+ BufferPtr = CurPtr;
+ if (PP.HandleDirective(Result)) return true;
+
+ // As an optimization, if the preprocessor didn't switch lexers, tail
+ // recurse.
+ if (PP.isCurrentLexer(this)) {
+ // Start a new token. If this is a #include or something, the PP may
+ // want us starting at the beginning of the line again. If so, set
+ // the StartOfLine flag.
+ if (IsAtStartOfLine) {
+ Result.SetFlag(LexerToken::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+ return PP.Lex(Result);
+ }
+ }
+ break;
+
+ case '\\':
+ // FIXME: handle UCN's.
+ // FALL THROUGH.
+ default:
+ // Objective C support.
+ if (CurPtr[-1] == '@' && Features.ObjC1) {
+ Result.SetKind(tok::at);
+ break;
+ } else if (CurPtr[-1] == '$' && Features.DollarIdents) {// $ in identifiers.
+ if (Diag(CurPtr-1, diag::ext_dollar_in_identifier))
+ return true;
+ return LexIdentifier(Result, CurPtr);
+ }
+
+ if (!PP.isSkipping() && Diag(CurPtr-1, diag::err_stray_character))
+ return true;
+ BufferPtr = CurPtr;
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+
+ // Update the end of token position as well as the BufferPtr instance var.
+ Result.SetEnd(BufferPtr = CurPtr);
+ return false;
+}
Propchange: cfe/cfe/trunk/Lex/Lexer.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/Lexer.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/MacroExpander.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/MacroExpander.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/MacroExpander.cpp (added)
+++ cfe/cfe/trunk/Lex/MacroExpander.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,42 @@
+//===--- MacroExpander.cpp - Lex from a macro expansion -------------------===//
+//
+// 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 MacroExpander interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/MacroExpander.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+using namespace llvm;
+using namespace clang;
+
+/// Lex - Lex and return a token from this macro stream.
+bool MacroExpander::Lex(LexerToken &Tok) {
+ // Lexing off the end of the macro, pop this macro off the expansion stack.
+ if (CurToken == Macro.getNumTokens())
+ return PP.HandleEndOfMacro(Tok);
+
+ // Get the next token to return.
+ Tok = Macro.getReplacementToken(CurToken++);
+
+ // If this is the first token, set the lexical properties of the token to
+ // match the lexical properties of the macro identifier.
+ if (CurToken == 1) {
+ Tok.SetFlagValue(LexerToken::StartOfLine , AtStartOfLine);
+ Tok.SetFlagValue(LexerToken::LeadingSpace, HasLeadingSpace);
+ }
+
+ // Handle recursive expansion!
+ if (Tok.getIdentifierInfo())
+ return PP.HandleIdentifier(Tok);
+
+ // Otherwise, return a normal token.
+ return false;
+}
Propchange: cfe/cfe/trunk/Lex/MacroExpander.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/MacroExpander.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/MacroInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/MacroInfo.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/MacroInfo.cpp (added)
+++ cfe/cfe/trunk/Lex/MacroInfo.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,28 @@
+//===--- MacroInfo.cpp - Information about #defined identifiers -----------===//
+//
+// 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 MacroInfo interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/MacroInfo.h"
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+/// dump - Print the macro to stderr, used for debugging.
+///
+void MacroInfo::dump() const {
+ std::cerr << "MACRO: ";
+ for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
+ ReplacementTokens[i].dump();
+ std::cerr << " ";
+ }
+ std::cerr << "\n";
+}
Propchange: cfe/cfe/trunk/Lex/MacroInfo.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/MacroInfo.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Makefile?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/Makefile (added)
+++ cfe/cfe/trunk/Lex/Makefile Wed Jul 11 11:22:17 2007
@@ -0,0 +1,21 @@
+##===- clang/Lex/Makefile ----------------------------------*- Makefile -*-===##
+#
+# 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 implements the Lexer library for the C-Language front-end.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME := clangLex
+BUILD_ARCHIVE = 1
+
+CPPFLAGS += -I$(LEVEL)/tools/clang/include
+
+include $(LEVEL)/Makefile.common
+
Propchange: cfe/cfe/trunk/Lex/Makefile
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/Makefile
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/PPExpressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/PPExpressions.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/PPExpressions.cpp (added)
+++ cfe/cfe/trunk/Lex/PPExpressions.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,367 @@
+//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===//
+//
+// 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 Preprocessor::EvaluateDirectiveExpression method.
+//
+//===----------------------------------------------------------------------===//
+//
+// FIXME: implement testing for asserts.
+// FIXME: Parse integer constants correctly. Reject 123.0, etc.
+// FIXME: Track signed/unsigned correctly.
+// FIXME: Track and report integer overflow correctly.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Basic/Diagnostic.h"
+using namespace llvm;
+using namespace clang;
+
+/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
+/// may occur after a #if or #elif directive. Sets Result to the result of
+/// the expression. Returns false normally, true if lexing must be aborted.
+///
+/// MinPrec is the minimum precedence that this range of the expression is
+/// allowed to include.
+bool Preprocessor::EvaluateDirectiveExpression(bool &Result) {
+ // Peek ahead one token.
+ LexerToken Tok;
+ if (Lex(Tok)) return true;
+
+ // In error cases, bail out with false value.
+ Result = false;
+
+ bool StopParse = false;
+
+ int ResVal = 0;
+ if (EvaluateValue(ResVal, Tok, StopParse)) {
+ // Skip the rest of the macro line.
+ if (!StopParse && Tok.getKind() != tok::eom)
+ StopParse |= DiscardUntilEndOfDirective();
+ return StopParse;
+ }
+
+ if (EvaluateDirectiveSubExpr(ResVal, 1, Tok, StopParse)) {
+ // Skip the rest of the macro line.
+ if (!StopParse && Tok.getKind() != tok::eom)
+ StopParse |= DiscardUntilEndOfDirective();
+ return StopParse;
+ }
+
+ // If we aren't at the tok::eom token, something bad happened, like an extra
+ // ')' token.
+ if (Tok.getKind() != tok::eom) {
+ return Diag(Tok, diag::err_pp_expected_eol) ||
+ DiscardUntilEndOfDirective();
+ }
+
+ Result = ResVal != 0;
+ return false;
+}
+
+/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and
+/// return the computed value in Result. Return true if there was an error
+/// parsing, setting StopParse if parsing should be aborted.
+bool Preprocessor::EvaluateValue(int &Result, LexerToken &PeekTok,
+ bool &StopParse) {
+ Result = 0;
+
+ // If this token's spelling is a pp-identifier, check to see if it is
+ // 'defined' or if it is a macro. Note that we check here because many
+ // keywords are pp-identifiers, so we can't check the kind.
+ if (const IdentifierTokenInfo *II = PeekTok.getIdentifierInfo()) {
+ // If this identifier isn't 'defined' and it wasn't macro expanded, it turns
+ // into a simple 0.
+ if (strcmp(II->getName(), "defined")) {
+ Result = 0;
+ return (StopParse = Lex(PeekTok));
+ }
+
+ // Handle "defined X" and "defined(X)".
+ assert(!DisableMacroExpansion &&
+ "How could macro exp already be disabled?");
+ // Turn off macro expansion.
+ DisableMacroExpansion = true;
+
+ // Get the next token.
+ if ((StopParse = Lex(PeekTok))) return true;
+
+ // Two options, it can either be a pp-identifier or a (.
+ bool InParens = false;
+ if (PeekTok.getKind() == tok::l_paren) {
+ // Found a paren, remember we saw it and skip it.
+ InParens = true;
+ if ((StopParse = Lex(PeekTok))) return true;
+ }
+
+ // If we don't have a pp-identifier now, this is an error.
+ if ((II = PeekTok.getIdentifierInfo()) == 0) {
+ DisableMacroExpansion = false;
+ StopParse = Diag(PeekTok, diag::err_pp_defined_requires_identifier);
+ return true;
+ }
+
+ // Otherwise, we got an identifier, is it defined to something?
+ Result = II->getMacroInfo() != 0;
+
+ // Consume identifier.
+ if ((StopParse = Lex(PeekTok))) return true;
+
+ // If we are in parens, ensure we have a trailing ).
+ if (InParens) {
+ if (PeekTok.getKind() != tok::r_paren) {
+ StopParse = Diag(PeekTok, diag::err_pp_missing_rparen);
+ return true;
+ }
+ // Consume the ).
+ if ((StopParse = Lex(PeekTok))) return true;
+ }
+
+ DisableMacroExpansion = false;
+ return false;
+ }
+
+ switch (PeekTok.getKind()) {
+ default: // Non-value token.
+ StopParse = Diag(PeekTok, diag::err_pp_expr_bad_token);
+ return true;
+ case tok::eom:
+ case tok::r_paren:
+ // If there is no expression, report and exit.
+ StopParse = Diag(PeekTok, diag::err_pp_expected_value_in_expr);
+ return true;
+ case tok::numeric_constant: {
+ // FIXME: faster. FIXME: track signs.
+ std::string Spell = Lexer::getSpelling(PeekTok, getLangOptions());
+ // FIXME: COMPUTE integer constants CORRECTLY.
+ Result = atoi(Spell.c_str());
+ return (StopParse = Lex(PeekTok));
+ }
+ case tok::l_paren:
+ if (StopParse = Lex(PeekTok)) return true; // Eat the (.
+ // Parse the value.
+ if (EvaluateValue(Result, PeekTok, StopParse)) return true;
+
+ // If there are any binary operators involved, parse them.
+ if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, StopParse))
+ return StopParse;
+
+ if (PeekTok.getKind() != tok::r_paren) {
+ StopParse = Diag(PeekTok, diag::err_pp_expected_rparen);
+ return true;
+ }
+ if (StopParse = Lex(PeekTok)) return true; // Eat the ).
+ return false;
+
+ case tok::plus:
+ // Unary plus doesn't modify the value.
+ if (StopParse = Lex(PeekTok)) return true;
+ return EvaluateValue(Result, PeekTok, StopParse);
+ case tok::minus:
+ if (StopParse = Lex(PeekTok)) return true;
+ if (EvaluateValue(Result, PeekTok, StopParse)) return true;
+ Result = -Result;
+ return false;
+
+ case tok::tilde:
+ if (StopParse = Lex(PeekTok)) return true;
+ if (EvaluateValue(Result, PeekTok, StopParse)) return true;
+ Result = ~Result;
+ return false;
+
+ case tok::exclaim:
+ if (StopParse = Lex(PeekTok)) return true;
+ if (EvaluateValue(Result, PeekTok, StopParse)) return true;
+ Result = !Result;
+ return false;
+
+ // FIXME: Handle #assert
+ }
+}
+
+
+
+/// getPrecedence - Return the precedence of the specified binary operator
+/// token. This returns:
+/// ~0 - Invalid token.
+/// 15 - *,/,%
+/// 14 - -,+
+/// 13 - <<,>>
+/// 12 - >=, <=, >, <
+/// 11 - ==, !=
+/// 10 - <?, >? min, max (GCC extensions)
+/// 9 - &
+/// 8 - ^
+/// 7 - |
+/// 6 - &&
+/// 5 - ||
+/// 4 - ?
+/// 3 - :
+/// 0 - eom, )
+static unsigned getPrecedence(tok::TokenKind Kind) {
+ switch (Kind) {
+ default: return ~0U;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return 15;
+ case tok::plus:
+ case tok::minus: return 14;
+ case tok::lessless:
+ case tok::greatergreater: return 13;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal:
+ case tok::greater: return 12;
+ case tok::exclaimequal:
+ case tok::equalequal: return 11;
+ case tok::lessquestion:
+ case tok::greaterquestion: return 10;
+ case tok::amp: return 9;
+ case tok::caret: return 8;
+ case tok::pipe: return 7;
+ case tok::ampamp: return 6;
+ case tok::pipepipe: return 5;
+ case tok::question: return 4;
+ case tok::colon: return 3;
+ case tok::comma: return 2;
+ case tok::r_paren: return 0; // Lowest priority, end of expr.
+ case tok::eom: return 0; // Lowest priority, end of macro.
+ }
+}
+
+
+/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is
+/// PeekTok, and whose precedence is PeekPrec.
+bool Preprocessor::EvaluateDirectiveSubExpr(int &LHS, unsigned MinPrec,
+ LexerToken &PeekTok,
+ bool &StopParse) {
+ unsigned PeekPrec = getPrecedence(PeekTok.getKind());
+ // If this token isn't valid, report the error.
+ if (PeekPrec == ~0U) {
+ StopParse = Diag(PeekTok, diag::err_pp_expr_bad_token);
+ return true;
+ }
+
+ while (1) {
+ // If this token has a lower precedence than we are allowed to parse, return
+ // it so that higher levels of the recursion can parse it.
+ if (PeekPrec < MinPrec)
+ return false;
+
+ tok::TokenKind Operator = PeekTok.getKind();
+
+ // Consume the operator, saving the operator token for error reporting.
+ LexerToken OpToken = PeekTok;
+ if (StopParse = Lex(PeekTok)) return true;
+
+ int RHS;
+ // Parse the RHS of the operator.
+ if (EvaluateValue(RHS, PeekTok, StopParse)) return true;
+
+ // Remember the precedence of this operator and get the precedence of the
+ // operator immediately to the right of the RHS.
+ unsigned ThisPrec = PeekPrec;
+ PeekPrec = getPrecedence(PeekTok.getKind());
+
+ // If this token isn't valid, report the error.
+ if (PeekPrec == ~0U) {
+ StopParse = Diag(PeekTok, diag::err_pp_expr_bad_token);
+ return true;
+ }
+
+ bool isRightAssoc = Operator == tok::question;
+
+ // Get the precedence of the operator to the right of the RHS. If it binds
+ // more tightly with RHS than we do, evaluate it completely first.
+ if (ThisPrec < PeekPrec ||
+ (ThisPrec == PeekPrec && isRightAssoc)) {
+ if (EvaluateDirectiveSubExpr(RHS, ThisPrec+1, PeekTok, StopParse))
+ return true;
+ PeekPrec = getPrecedence(PeekTok.getKind());
+ }
+ assert(PeekPrec <= ThisPrec && "Recursion didn't work!");
+
+ switch (Operator) {
+ default: assert(0 && "Unknown operator token!");
+ case tok::percent:
+ if (RHS == 0) {
+ StopParse = Diag(OpToken, diag::err_pp_remainder_by_zero);
+ return true;
+ }
+ LHS %= RHS;
+ break;
+ case tok::slash:
+ if (RHS == 0) {
+ StopParse = Diag(OpToken, diag::err_pp_division_by_zero);
+ return true;
+ }
+ LHS /= RHS;
+ break;
+ case tok::star : LHS *= RHS; break;
+ case tok::lessless: LHS << RHS; break; // FIXME: shift amt overflow?
+ case tok::greatergreater: LHS >> RHS; break; // FIXME: signed vs unsigned
+ case tok::plus : LHS += RHS; break;
+ case tok::minus: LHS -= RHS; break;
+ case tok::lessequal: LHS = LHS <= RHS; break;
+ case tok::less: LHS = LHS < RHS; break;
+ case tok::greaterequal: LHS = LHS >= RHS; break;
+ case tok::greater: LHS = LHS > RHS; break;
+ case tok::exclaimequal: LHS = LHS != RHS; break;
+ case tok::equalequal: LHS = LHS == RHS; break;
+ case tok::lessquestion: // Deprecation warning emitted by the lexer.
+ LHS = std::min(LHS, RHS);
+ break;
+ case tok::greaterquestion: // Deprecation warning emitted by the lexer.
+ LHS = std::max(LHS, RHS);
+ break;
+ case tok::amp: LHS &= RHS; break;
+ case tok::caret: LHS ^= RHS; break;
+ case tok::pipe: LHS |= RHS; break;
+ case tok::ampamp: LHS = LHS && RHS; break;
+ case tok::pipepipe: LHS = LHS || RHS; break;
+ case tok::comma:
+ if ((StopParse = Diag(OpToken, diag::ext_pp_comma_expr)))
+ return true;
+ LHS = RHS; // LHS = LHS,RHS -> RHS.
+ break;
+ case tok::question: {
+ // Parse the : part of the expression.
+ if (PeekTok.getKind() != tok::colon) {
+ StopParse = Diag(OpToken, diag::err_pp_question_without_colon);
+ return true;
+ }
+ // Consume the :.
+ if (StopParse = Lex(PeekTok)) return true;
+
+ // Evaluate the value after the :.
+ int AfterColonVal = 0;
+ if (EvaluateValue(AfterColonVal, PeekTok, StopParse)) return true;
+
+ // Parse anything after the : RHS that has a higher precedence than ?.
+ if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec+1,
+ PeekTok, StopParse))
+ return true;
+
+ // Now that we have the condition, the LHS and the RHS of the :, evaluate.
+ LHS = LHS ? RHS : AfterColonVal;
+
+ // Figure out the precedence of the token after the : part.
+ PeekPrec = getPrecedence(PeekTok.getKind());
+ break;
+ }
+ case tok::colon:
+ // Don't allow :'s to float around without being part of ?: exprs.
+ StopParse = Diag(OpToken, diag::err_pp_colon_without_question);
+ return true;
+ }
+ }
+
+ return false;
+}
Propchange: cfe/cfe/trunk/Lex/PPExpressions.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/PPExpressions.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Preprocessor.cpp?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Lex/Preprocessor.cpp (added)
+++ cfe/cfe/trunk/Lex/Preprocessor.cpp Wed Jul 11 11:22:17 2007
@@ -0,0 +1,1121 @@
+//===--- Preprocess.cpp - C Language Family Preprocessor Implementation ---===//
+//
+// 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 Preprocessor interface.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: GCC Diagnostics emitted by the lexer:
+//
+// ERROR : __VA_ARGS__ can only appear in the expansion of a C99 variadic macro
+//
+// Options to support:
+// -H - Print the name of each header file used.
+// -C -CC - Do not discard comments for cpp.
+// -P - Do not emit #line directives.
+// -d[MDNI] - Dump various things.
+// -fworking-directory - #line's with preprocessor's working dir.
+// -fpreprocessed
+// -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD
+// -W*
+// -w
+//
+// Messages to emit:
+// "Multiple include guards may be useful for:\n"
+//
+// TODO: Implement the include guard optimization.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include <iostream>
+using namespace llvm;
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+
+Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
+ FileManager &FM, SourceManager &SM)
+ : Diags(diags), Features(opts), FileMgr(FM), SourceMgr(SM),
+ SystemDirIdx(0), NoCurDirSearch(false),
+ CurLexer(0), CurNextDirLookup(0), CurMacroExpander(0) {
+ // Clear stats.
+ NumDirectives = NumIncluded = NumDefined = NumUndefined = NumPragma = 0;
+ NumIf = NumElse = NumEndif = 0;
+ NumEnteredSourceFiles = NumMacroExpanded = NumFastMacroExpanded = 0;
+ MaxIncludeStackDepth = MaxMacroStackDepth = 0;
+ NumSkipped = 0;
+
+ // Macro expansion is enabled.
+ DisableMacroExpansion = false;
+ SkippingContents = false;
+}
+
+Preprocessor::~Preprocessor() {
+ // Free any active lexers.
+ delete CurLexer;
+
+ while (!IncludeStack.empty()) {
+ delete IncludeStack.back().TheLexer;
+ IncludeStack.pop_back();
+ }
+}
+
+/// getFileInfo - Return the PerFileInfo structure for the specified
+/// FileEntry.
+Preprocessor::PerFileInfo &Preprocessor::getFileInfo(const FileEntry *FE) {
+ if (FE->getUID() >= FileInfo.size())
+ FileInfo.resize(FE->getUID()+1);
+ return FileInfo[FE->getUID()];
+}
+
+
+/// AddKeywords - Add all keywords to the symbol table.
+///
+void Preprocessor::AddKeywords() {
+ enum {
+ C90Shift = 0,
+ EXTC90 = 1 << C90Shift,
+ NOTC90 = 2 << C90Shift,
+ C99Shift = 2,
+ EXTC99 = 1 << C99Shift,
+ NOTC99 = 2 << C99Shift,
+ CPPShift = 4,
+ EXTCPP = 1 << CPPShift,
+ NOTCPP = 2 << CPPShift,
+ Mask = 3
+ };
+
+ // Add keywords and tokens for the current language.
+#define KEYWORD(NAME, FLAGS) \
+ AddKeyword(#NAME+1, tok::kw##NAME, \
+ (FLAGS >> C90Shift) & Mask, \
+ (FLAGS >> C99Shift) & Mask, \
+ (FLAGS >> CPPShift) & Mask);
+#define ALIAS(NAME, TOK) \
+ AddKeyword(NAME, tok::kw_ ## TOK, 0, 0, 0);
+#include "clang/Basic/TokenKinds.def"
+}
+
+/// Diag - Forwarding function for diagnostics. This emits a diagnostic at
+/// the specified LexerToken's location, translating the token's start
+/// position in the current buffer into a SourcePosition object for rendering.
+bool Preprocessor::Diag(SourceLocation Loc, unsigned DiagID,
+ const std::string &Msg) {
+ // If we are in a '#if 0' block, don't emit any diagnostics for notes,
+ // warnings or extensions.
+ if (isSkipping() && Diagnostic::isNoteWarningOrExtension(DiagID))
+ return false;
+
+ return Diags.Report(Loc, DiagID, Msg);
+}
+bool Preprocessor::Diag(const LexerToken &Tok, unsigned DiagID,
+ const std::string &Msg) {
+ // If we are in a '#if 0' block, don't emit any diagnostics for notes,
+ // warnings or extensions.
+ if (isSkipping() && Diagnostic::isNoteWarningOrExtension(DiagID))
+ return false;
+
+ return Diag(Tok.getSourceLocation(), DiagID, Msg);
+}
+
+void Preprocessor::PrintStats() {
+ std::cerr << "\n*** Preprocessor Stats:\n";
+ std::cerr << FileInfo.size() << " files tracked.\n";
+ unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
+ for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
+ NumOnceOnlyFiles += FileInfo[i].isImport;
+ if (MaxNumIncludes < FileInfo[i].NumIncludes)
+ MaxNumIncludes = FileInfo[i].NumIncludes;
+ NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
+ }
+ std::cerr << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n";
+ std::cerr << " " << NumSingleIncludedFiles << " included exactly once.\n";
+ std::cerr << " " << MaxNumIncludes << " max times a file is included.\n";
+
+ std::cerr << NumDirectives << " directives found:\n";
+ std::cerr << " " << NumDefined << " #define.\n";
+ std::cerr << " " << NumUndefined << " #undef.\n";
+ std::cerr << " " << NumIncluded << " #include/#include_next/#import.\n";
+ std::cerr << " " << NumEnteredSourceFiles << " source files entered.\n";
+ std::cerr << " " << MaxIncludeStackDepth << " max include stack depth\n";
+ std::cerr << " " << NumIf << " #if/#ifndef/#ifdef.\n";
+ std::cerr << " " << NumElse << " #else/#elif.\n";
+ std::cerr << " " << NumEndif << " #endif.\n";
+ std::cerr << " " << NumPragma << " #pragma.\n";
+ std::cerr << NumSkipped << " #if/#ifndef#ifdef regions skipped\n";
+
+ std::cerr << NumMacroExpanded << " macros expanded, "
+ << NumFastMacroExpanded << " on the fast path.\n";
+ if (MaxMacroStackDepth > 1)
+ std::cerr << " " << MaxMacroStackDepth << " max macroexpand stack depth\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Source File Location Methods.
+//===----------------------------------------------------------------------===//
+
+
+/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
+/// return null on failure. isAngled indicates whether the file reference is
+/// for system #include's or not (i.e. using <> instead of "").
+const FileEntry *Preprocessor::LookupFile(const std::string &Filename,
+ bool isSystem,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&NextDir) {
+ assert(CurLexer && "Cannot enter a #include inside a macro expansion!");
+ NextDir = 0;
+
+ // If 'Filename' is absolute, check to see if it exists and no searching.
+ // FIXME: this should be a sys::Path interface, this doesn't handle things
+ // like C:\foo.txt right, nor win32 \\network\device\blah.
+ if (Filename[0] == '/') {
+ // If this was an #include_next "/absolute/file", fail.
+ if (FromDir) return 0;
+
+ // Otherwise, just return the file.
+ return FileMgr.getFile(Filename);
+ }
+
+ // Step #0, unless disabled, check to see if the file is in the #includer's
+ // directory. This search is not done for <> headers.
+ if (!isSystem && !FromDir && !NoCurDirSearch) {
+ const FileEntry *CurFE =
+ SourceMgr.getFileEntryForFileID(CurLexer->getCurFileID());
+ if (CurFE) {
+ if (const FileEntry *FE =
+ FileMgr.getFile(CurFE->getDir()->getName()+"/"+Filename)) {
+ if (CurNextDirLookup)
+ NextDir = CurNextDirLookup;
+ else
+ NextDir = &SearchDirs[0];
+ return FE;
+ }
+ }
+ }
+
+ // If this is a system #include, ignore the user #include locs.
+ unsigned i = isSystem ? SystemDirIdx : 0;
+
+ // If this is a #include_next request, start searching after the directory the
+ // file was found in.
+ if (FromDir)
+ i = FromDir-&SearchDirs[0];
+
+ // Check each directory in sequence to see if it contains this file.
+ for (; i != SearchDirs.size(); ++i) {
+ // Concatenate the requested file onto the directory.
+ // FIXME: should be in sys::Path.
+ if (const FileEntry *FE =
+ FileMgr.getFile(SearchDirs[i].getDir()->getName()+"/"+Filename)) {
+ NextDir = &SearchDirs[i+1];
+ return FE;
+ }
+ }
+
+ // Otherwise, didn't find it.
+ return 0;
+}
+
+/// EnterSourceFile - Add a source file to the top of the include stack and
+/// start lexing tokens from it instead of the current buffer. Return true
+/// on failure.
+void Preprocessor::EnterSourceFile(unsigned FileID,
+ const DirectoryLookup *NextDir) {
+ ++NumEnteredSourceFiles;
+
+ // Add the current lexer to the include stack.
+ if (CurLexer) {
+ IncludeStack.push_back(IncludeStackInfo(CurLexer, CurNextDirLookup));
+ } else {
+ assert(CurMacroExpander == 0 && "Cannot #include a file inside a macro!");
+ }
+
+ if (MaxIncludeStackDepth < IncludeStack.size())
+ MaxIncludeStackDepth = IncludeStack.size();
+
+ const SourceBuffer *Buffer = SourceMgr.getBuffer(FileID);
+
+ CurLexer = new Lexer(Buffer, FileID, *this);
+ CurNextDirLookup = NextDir;
+}
+
+/// EnterMacro - Add a Macro to the top of the include stack and start lexing
+/// tokens from it instead of the current buffer. Return true on failure.
+bool Preprocessor::EnterMacro(LexerToken &Tok) {
+ IdentifierTokenInfo *Identifier = Tok.getIdentifierInfo();
+ MacroInfo &MI = *Identifier->getMacroInfo();
+ SourceLocation ExpandLoc = Tok.getSourceLocation();
+ unsigned MacroID = SourceMgr.getMacroID(Identifier, ExpandLoc);
+ if (CurLexer) {
+ IncludeStack.push_back(IncludeStackInfo(CurLexer, CurNextDirLookup));
+ CurLexer = 0;
+ CurNextDirLookup = 0;
+ } else if (CurMacroExpander) {
+ MacroStack.push_back(CurMacroExpander);
+ }
+
+ if (MaxMacroStackDepth < MacroStack.size())
+ MaxMacroStackDepth = MacroStack.size();
+
+ // TODO: Figure out arguments.
+
+ // Mark the macro as currently disabled, so that it is not recursively
+ // expanded.
+ MI.DisableMacro();
+
+ CurMacroExpander = new MacroExpander(MI, MacroID, *this,
+ Tok.isAtStartOfLine(),
+ Tok.hasLeadingSpace());
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Lexer Event Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandleIdentifier - This callback is invoked when the lexer reads an
+/// identifier. This callback looks up the identifier in the map and/or
+/// potentially macro expands it or turns it into a named token (like 'for').
+bool Preprocessor::HandleIdentifier(LexerToken &Identifier) {
+ if (Identifier.getIdentifierInfo() == 0) {
+ // If we are skipping tokens (because we are in a #if 0 block), there will
+ // be no identifier info, just return the token.
+ assert(isSkipping() && "Token isn't an identifier?");
+ return false;
+ }
+ IdentifierTokenInfo &ITI = *Identifier.getIdentifierInfo();
+
+ // FIXME: Check for poisoning in ITI?
+
+ if (MacroInfo *MI = ITI.getMacroInfo()) {
+ if (MI->isEnabled() && !DisableMacroExpansion) {
+ ++NumMacroExpanded;
+ // If we started lexing a macro, enter the macro expansion body.
+ // FIXME: Read/Validate the argument list here!
+
+ // If this macro expands to no tokens, don't bother to push it onto the
+ // expansion stack, only to take it right back off.
+ if (MI->getNumTokens() == 0) {
+ // Ignore this macro use, just return the next token in the current
+ // buffer.
+ bool HadLeadingSpace = Identifier.hasLeadingSpace();
+ bool IsAtStartOfLine = Identifier.isAtStartOfLine();
+
+ if (Lex(Identifier)) return true;
+
+ // If the identifier isn't on some OTHER line, inherit the leading
+ // whitespace/first-on-a-line property of this token. This handles
+ // stuff like "! XX," -> "! ," and " XX," -> " ,", when XX is
+ // empty.
+ if (!Identifier.isAtStartOfLine()) {
+ if (IsAtStartOfLine) Identifier.SetFlag(LexerToken::StartOfLine);
+ if (HadLeadingSpace) Identifier.SetFlag(LexerToken::LeadingSpace);
+ }
+ ++NumFastMacroExpanded;
+ return false;
+
+ } else if (MI->getNumTokens() == 1 &&
+ // Don't handle identifiers, which might need recursive
+ // expansion.
+ MI->getReplacementToken(0).getIdentifierInfo() == 0) {
+ // FIXME: Function-style macros only if no arguments?
+
+ // Otherwise, if this macro expands into a single trivially-expanded
+ // token: expand it now. This handles common cases like
+ // "#define VAL 42".
+
+ // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro
+ // identifier to the expanded token.
+ bool isAtStartOfLine = Identifier.isAtStartOfLine();
+ bool hasLeadingSpace = Identifier.hasLeadingSpace();
+
+ // Replace the result token.
+ Identifier = MI->getReplacementToken(0);
+
+ // Restore the StartOfLine/LeadingSpace markers.
+ Identifier.SetFlagValue(LexerToken::StartOfLine , isAtStartOfLine);
+ Identifier.SetFlagValue(LexerToken::LeadingSpace, hasLeadingSpace);
+
+ // FIXME: Get correct macro expansion stack location info!
+
+ // Since this is not an identifier token, it can't be macro expanded, so
+ // we're done.
+ ++NumFastMacroExpanded;
+ return false;
+ }
+
+ // Start expanding the macro (FIXME, pass arguments).
+ if (EnterMacro(Identifier))
+ return true;
+
+ // Now that the macro is at the top of the include stack, ask the
+ // preprocessor to read the next token from it.
+ return Lex(Identifier);
+ }
+ }
+
+ // Change the kind of this identifier to the appropriate token kind, e.g.
+ // turning "for" into a keyword.
+ Identifier.SetKind(ITI.getTokenID());
+
+ // If this is an extension token, diagnose its use.
+ if (ITI.isExtensionToken() && Diag(Identifier, diag::ext_token_used))
+ return true;
+ return false;
+}
+
+/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
+/// the current file. This either returns the EOF token or pops a level off
+/// the include stack and keeps going.
+bool Preprocessor::HandleEndOfFile(LexerToken &Result) {
+ assert(!CurMacroExpander &&
+ "Ending a file when currently in a macro!");
+
+ // If we are in a #if 0 block skipping tokens, and we see the end of the file,
+ // this is an error condition. Just return the EOF token up to
+ // SkipExcludedConditionalBlock. The Lexer will have already have issued
+ // errors for the unterminated #if's on the conditional stack.
+ if (isSkipping()) {
+ Result.StartToken(CurLexer);
+ Result.SetKind(tok::eof);
+ Result.SetStart(CurLexer->BufferEnd);
+ Result.SetEnd(CurLexer->BufferEnd);
+ return false;
+ }
+
+ // If this is a #include'd file, pop it off the include stack and continue
+ // lexing the #includer file.
+ if (!IncludeStack.empty()) {
+ // We're done with the #included file.
+ delete CurLexer;
+ CurLexer = IncludeStack.back().TheLexer;
+ CurNextDirLookup = IncludeStack.back().TheDirLookup;
+ IncludeStack.pop_back();
+ return Lex(Result);
+ }
+
+ Result.StartToken(CurLexer);
+ Result.SetKind(tok::eof);
+ Result.SetStart(CurLexer->BufferEnd);
+ Result.SetEnd(CurLexer->BufferEnd);
+
+ // We're done with the #included file.
+ delete CurLexer;
+ CurLexer = 0;
+ return false;
+}
+
+/// HandleEndOfMacro - This callback is invoked when the lexer hits the end of
+/// the current macro. This either returns the EOF token or pops a level off
+/// the include stack and keeps going.
+bool Preprocessor::HandleEndOfMacro(LexerToken &Result) {
+ assert(CurMacroExpander && !CurLexer &&
+ "Ending a macro when currently in a #include file!");
+
+ // Mark macro not ignored now that it is no longer being expanded.
+ CurMacroExpander->getMacro().EnableMacro();
+ delete CurMacroExpander;
+
+ if (!MacroStack.empty()) {
+ // In a nested macro invocation, continue lexing from the macro.
+ CurMacroExpander = MacroStack.back();
+ MacroStack.pop_back();
+ return Lex(Result);
+ } else {
+ CurMacroExpander = 0;
+ // Handle this like a #include file being popped off the stack.
+ return HandleEndOfFile(Result);
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Utility Methods for Preprocessor Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
+/// current line until the tok::eom token is found.
+bool Preprocessor::DiscardUntilEndOfDirective() {
+ LexerToken Tmp;
+ do {
+ if (LexUnexpandedToken(Tmp)) return true;
+ } while (Tmp.getKind() != tok::eom);
+ return false;
+}
+
+/// ReadMacroName - Lex and validate a macro name, which occurs after a
+/// #define or #undef. This sets the token kind to eom and discards the rest
+/// of the macro line if the macro name is invalid.
+bool Preprocessor::ReadMacroName(LexerToken &MacroNameTok) {
+ // Read the token, don't allow macro expansion on it.
+ if (LexUnexpandedToken(MacroNameTok))
+ return true;
+
+ // Missing macro name?
+ if (MacroNameTok.getKind() == tok::eom)
+ return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
+
+ if (MacroNameTok.getIdentifierInfo() == 0) {
+ if (Diag(MacroNameTok, diag::err_pp_macro_not_identifier))
+ return true;
+ // Fall through on error.
+ } else if (0) {
+ // FIXME: Error if defining a C++ named operator.
+
+ } else if (0) {
+ // FIXME: Error if defining "defined", "__DATE__", and other predef macros
+ // in C99 6.10.8.4.
+ } else {
+ // Okay, we got a good identifier node. Return it.
+ return false;
+ }
+
+
+ // Invalid macro name, read and discard the rest of the line. Then set the
+ // token kind to tok::eom.
+ MacroNameTok.SetKind(tok::eom);
+ return DiscardUntilEndOfDirective();
+}
+
+/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If
+/// not, emit a diagnostic and consume up until the eom.
+bool Preprocessor::CheckEndOfDirective(const char *DirType) {
+ LexerToken Tmp;
+ if (Lex(Tmp)) return true;
+ // There should be no tokens after the directive, but we allow them as an
+ // extension.
+ if (Tmp.getKind() != tok::eom) {
+ if (Diag(Tmp, diag::ext_pp_extra_tokens_at_eol, DirType) ||
+ DiscardUntilEndOfDirective())
+ return true;
+ }
+ return false;
+}
+
+
+
+/// 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
+/// FoundNonSkipPortion is true, then we have already emitted code for part of
+/// this #if directive, so #else/#elif blocks should never be entered. If ElseOk
+/// is true, then #else directives are ok, if not, then we have already seen one
+/// so a #else directive is a duplicate. When this returns, the caller can lex
+/// the first valid token.
+bool Preprocessor::SkipExcludedConditionalBlock(const char *IfTokenLoc,
+ bool FoundNonSkipPortion,
+ bool FoundElse) {
+ ++NumSkipped;
+ assert(MacroStack.empty() && CurMacroExpander == 0 && CurLexer &&
+ "Lexing a macro, not a file?");
+
+ CurLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false,
+ FoundNonSkipPortion, FoundElse);
+
+ // Know that we are going to be skipping tokens. Set this flag to indicate
+ // this, which has a couple of effects:
+ // 1. If EOF of the current lexer is found, the include stack isn't popped.
+ // 2. Identifier information is not looked up for identifier tokens. As an
+ // effect of this, implicit macro expansion is naturally disabled.
+ // 3. "#" tokens at the start of a line are treated as normal tokens, not
+ // implicitly transformed by the lexer.
+ // 4. All notes, warnings, and extension messages are disabled.
+ //
+ SkippingContents = true;
+ LexerToken Tok;
+ while (1) {
+ if (CurLexer->Lex(Tok)) return true;
+
+ // If this is the end of the buffer, we have an error. The lexer will have
+ // already handled this error condition, so just return and let the caller
+ // lex after this #include.
+ if (Tok.getKind() == tok::eof) break;
+
+ // If this token is not a preprocessor directive, just skip it.
+ if (Tok.getKind() != tok::hash || !Tok.isAtStartOfLine())
+ continue;
+
+ // We just parsed a # character at the start of a line, so we're in
+ // directive mode. Tell the lexer this so any newlines we see will be
+ // converted into an EOM token (this terminates the macro).
+ CurLexer->ParsingPreprocessorDirective = true;
+
+ // Read the next token, the directive flavor.
+ if (LexUnexpandedToken(Tok)) return true;
+
+ // If this isn't an identifier directive (e.g. is "# 1\n" or "#\n", or
+ // something bogus), skip it.
+ if (Tok.getKind() != tok::identifier) {
+ CurLexer->ParsingPreprocessorDirective = false;
+ continue;
+ }
+
+ // If the first letter isn't i or e, it isn't intesting to us. We know that
+ // this is safe in the face of spelling differences, because there is no way
+ // to spell an i/e in a strange way that is another letter. Skipping this
+ // allows us to avoid computing the spelling for #define/#undef and other
+ // common directives.
+ char FirstChar = Tok.getStart()[0];
+ if (FirstChar >= 'a' && FirstChar <= 'z' &&
+ FirstChar != 'i' && FirstChar != 'e') {
+ CurLexer->ParsingPreprocessorDirective = false;
+ continue;
+ }
+
+ // Strip out trigraphs and embedded newlines.
+ std::string Directive = Lexer::getSpelling(Tok, Features);
+ FirstChar = Directive[0];
+ if (FirstChar == 'i' && Directive[1] == 'f') {
+ if (Directive == "if" || Directive == "ifdef" || Directive == "ifndef") {
+ // We know the entire #if/#ifdef/#ifndef block will be skipped, don't
+ // bother parsing the condition.
+ if (DiscardUntilEndOfDirective()) return true;
+ CurLexer->pushConditionalLevel(Tok.getStart(), /*wasskipping*/true,
+ /*foundnonskip*/false,/*fnddelse*/false);
+ }
+ } else if (FirstChar == 'e') {
+ if (Directive == "endif") {
+ if (CheckEndOfDirective("#endif")) return true;
+ PPConditionalInfo CondInfo;
+ CondInfo.WasSkipping = true; // Silence bogus warning.
+ bool InCond = CurLexer->popConditionalLevel(CondInfo);
+ assert(!InCond && "Can't be skipping if not in a conditional!");
+
+ // If we popped the outermost skipping block, we're done skipping!
+ if (!CondInfo.WasSkipping)
+ break;
+ } else if (Directive == "else") {
+ // #else directive in a skipping conditional. If not in some other
+ // skipping conditional, and if #else hasn't already been seen, enter it
+ // as a non-skipping conditional.
+ if (CheckEndOfDirective("#else")) return true;
+ PPConditionalInfo &CondInfo = CurLexer->peekConditionalLevel();
+
+ // If this is a #else with a #else before it, report the error.
+ if (CondInfo.FoundElse && Diag(Tok, diag::pp_err_else_after_else))
+ return true;
+
+ // Note that we've seen a #else in this conditional.
+ CondInfo.FoundElse = true;
+
+ // If the conditional is at the top level, and the #if block wasn't
+ // entered, enter the #else block now.
+ if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) {
+ CondInfo.FoundNonSkip = true;
+ break;
+ }
+ } else if (Directive == "elif") {
+ PPConditionalInfo &CondInfo = CurLexer->peekConditionalLevel();
+
+ bool ShouldEnter;
+ // If this is in a skipping block or if we're already handled this #if
+ // block, don't bother parsing the condition.
+ if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) {
+ if (DiscardUntilEndOfDirective()) return true;
+ ShouldEnter = false;
+ } else {
+ // Evaluate the #elif condition!
+ const char *Start = CurLexer->BufferPtr;
+
+ // Restore the value of SkippingContents so that identifiers are
+ // looked up, etc, inside the #elif expression.
+ assert(SkippingContents && "We have to be skipping here!");
+ SkippingContents = false;
+ if (EvaluateDirectiveExpression(ShouldEnter))
+ return true;
+ SkippingContents = true;
+ }
+
+ // If this is a #elif with a #else before it, report the error.
+ if (CondInfo.FoundElse && Diag(Tok, diag::pp_err_elif_after_else))
+ return true;
+
+ // If this condition is true, enter it!
+ if (ShouldEnter) {
+ CondInfo.FoundNonSkip = true;
+ break;
+ }
+ }
+ }
+
+ CurLexer->ParsingPreprocessorDirective = false;
+ }
+
+ // Finally, if we are out of the conditional (saw an #endif or ran off the end
+ // of the file, just stop skipping and return to lexing whatever came after
+ // the #if block.
+ SkippingContents = false;
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Directive Handling.
+//===----------------------------------------------------------------------===//
+
+/// HandleDirective - This callback is invoked when the lexer sees a # token
+/// at the start of a line. This consumes the directive, modifies the
+/// lexer/preprocessor state, and advances the lexer(s) so that the next token
+/// read is the correct one.
+bool Preprocessor::HandleDirective(LexerToken &Result) {
+ // FIXME: TRADITIONAL: # with whitespace before it not recognized by K&R?
+
+ // We just parsed a # character at the start of a line, so we're in directive
+ // mode. Tell the lexer this so any newlines we see will be converted into an
+ // EOM token (this terminates the macro).
+ CurLexer->ParsingPreprocessorDirective = true;
+
+ ++NumDirectives;
+
+ // Read the next token, the directive flavor.
+ if (LexUnexpandedToken(Result))
+ return true; // Bail out.
+
+ switch (Result.getKind()) {
+ default: break;
+ case tok::eom:
+ return false; // null directive.
+
+#if 0
+ case tok::numeric_constant:
+ // FIXME: implement # 7 line numbers!
+ break;
+#endif
+ case tok::kw_else:
+ return HandleElseDirective(Result);
+ case tok::kw_if:
+ return HandleIfDirective(Result);
+ case tok::identifier:
+ // Strip out trigraphs and embedded newlines.
+ std::string Directive = Lexer::getSpelling(Result, Features);
+ bool isExtension = false;
+ switch (Directive.size()) {
+ case 4:
+ if (Directive == "line")
+ ;
+ if (Directive == "elif")
+ return HandleElifDirective(Result);
+ if (Directive == "sccs") {
+ isExtension = true;
+ // SCCS is the same as #ident.
+ }
+ break;
+ case 5:
+ if (Directive == "endif")
+ return HandleEndifDirective(Result);
+ if (Directive == "ifdef")
+ return HandleIfdefDirective(Result, false);
+ if (Directive == "undef")
+ return HandleUndefDirective(Result);
+ if (Directive == "error")
+ return HandleUserDiagnosticDirective(Result, false);
+ if (Directive == "ident")
+ isExtension = true;
+ break;
+ case 6:
+ if (Directive == "define")
+ return HandleDefineDirective(Result);
+ if (Directive == "ifndef")
+ return HandleIfdefDirective(Result, true);
+ if (Directive == "import")
+ return HandleImportDirective(Result);
+ if (Directive == "pragma") {
+ // FIXME: implement #pragma
+ ++NumPragma;
+#if 1
+ // Read the rest of the PP line.
+ do {
+ if (Lex(Result)) return true;
+ } while (Result.getKind() != tok::eom);
+
+ return false;
+#endif
+ } else if (Directive == "assert") {
+ isExtension = true;
+ }
+ break;
+ case 7:
+ if (Directive == "include") // Handle #include.
+ return HandleIncludeDirective(Result);
+ if (Directive == "warning")
+ return Diag(Result, diag::ext_pp_warning_directive) ||
+ HandleUserDiagnosticDirective(Result, true);
+ break;
+ case 8:
+ if (Directive == "unassert") {
+ isExtension = true;
+ }
+ break;
+ case 12:
+ if (Directive == "include_next") // Handle #include_next.
+ return HandleIncludeNextDirective(Result);
+ break;
+ }
+ break;
+ }
+
+ // If we reached here, the preprocessing token is not valid!
+ if (Diag(Result, diag::err_pp_invalid_directive))
+ return true;
+
+ // Read the rest of the PP line.
+ do {
+ if (Lex(Result)) return true;
+ } while (Result.getKind() != tok::eom);
+
+ // Okay, we're done parsing the directive.
+ return false;
+}
+
+bool Preprocessor::HandleUserDiagnosticDirective(LexerToken &Result,
+ bool isWarning) {
+ // Read the rest of the line raw. We do this because we don't want macros
+ // to be expanded and we don't require that the tokens be valid preprocessing
+ // tokens. For example, this is allowed: "#warning ` 'foo". GCC does
+ // collapse multiple consequtive white space between tokens, but this isn't
+ // specified by the standard.
+ std::string Message = CurLexer->ReadToEndOfLine();
+
+ unsigned DiagID = isWarning ? diag::pp_hash_warning : diag::err_pp_hash_error;
+ return Diag(Result, DiagID, Message);
+}
+
+/// 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
+/// #import.
+bool Preprocessor::HandleIncludeDirective(LexerToken &IncludeTok,
+ const DirectoryLookup *LookupFrom,
+ bool isImport) {
+ ++NumIncluded;
+ LexerToken FilenameTok;
+ if (CurLexer->LexIncludeFilename(FilenameTok))
+ return true;
+
+ // If the token kind is EOM, the error has already been diagnosed.
+ if (FilenameTok.getKind() == tok::eom)
+ return false;
+
+ // Check that we don't have infinite #include recursion.
+ if (IncludeStack.size() == MaxAllowedIncludeStackDepth-1)
+ return Diag(FilenameTok, diag::err_pp_include_too_deep);
+
+ // Get the text form of the filename.
+ std::string Filename = CurLexer->getSpelling(FilenameTok);
+ assert(!Filename.empty() && "Can't have tokens with empty spellings!");
+
+ // Make sure the filename is <x> or "x".
+ bool isAngled;
+ if (Filename[0] == '<') {
+ isAngled = true;
+ if (Filename[Filename.size()-1] != '>')
+ return Diag(FilenameTok, diag::err_pp_expects_filename);
+ } else if (Filename[0] == '"') {
+ isAngled = false;
+ if (Filename[Filename.size()-1] != '"')
+ return Diag(FilenameTok, diag::err_pp_expects_filename);
+ } else {
+ return Diag(FilenameTok, diag::err_pp_expects_filename);
+ }
+
+ // Remove the quotes.
+ Filename = std::string(Filename.begin()+1, Filename.end()-1);
+
+ // Diagnose #include "" as invalid.
+ if (Filename.empty())
+ return Diag(FilenameTok, diag::err_pp_empty_filename);
+
+ // Search include directories.
+ const DirectoryLookup *NextDir;
+ const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, NextDir);
+ if (File == 0)
+ return Diag(FilenameTok, diag::err_pp_file_not_found);
+
+ // Get information about this file.
+ PerFileInfo &FileInfo = getFileInfo(File);
+
+ // If this is a #import directive, check that we have not already imported
+ // this header.
+ if (isImport) {
+ // If this has already been imported, don't import it again.
+ FileInfo.isImport = true;
+
+ // Has this already been #import'ed or #include'd?
+ if (FileInfo.NumIncludes) return false;
+ } else {
+ // Otherwise, if this is a #include of a file that was previously #import'd
+ // or if this is the second #include of a #pragma once file, ignore it.
+ if (FileInfo.isImport)
+ return false;
+ }
+
+ // Look up the file, create a File ID for it.
+ unsigned FileID =
+ SourceMgr.createFileID(File, FilenameTok.getSourceLocation());
+ if (FileID == 0)
+ return Diag(FilenameTok, diag::err_pp_file_not_found);
+
+ // Finally, if all is good, enter the new file!
+ EnterSourceFile(FileID, NextDir);
+
+ // Increment the number of times this file has been included.
+ ++FileInfo.NumIncludes;
+
+ return false;
+}
+
+/// HandleIncludeNextDirective - Implements #include_next.
+///
+bool Preprocessor::HandleIncludeNextDirective(LexerToken &IncludeNextTok) {
+ if (Diag(IncludeNextTok, diag::ext_pp_include_next_directive))
+ return true;
+
+ // #include_next is like #include, except that we start searching after
+ // the current found directory. If we can't do this, issue a
+ // diagnostic.
+ const DirectoryLookup *Lookup = CurNextDirLookup;
+ if (IncludeStack.empty()) {
+ Lookup = 0;
+ if (Diag(IncludeNextTok, diag::pp_include_next_in_primary))
+ return true;
+ } else if (Lookup == 0) {
+ if (Diag(IncludeNextTok, diag::pp_include_next_absolute_path))
+ return true;
+ }
+
+ return HandleIncludeDirective(IncludeNextTok, Lookup);
+}
+
+/// HandleImportDirective - Implements #import.
+///
+bool Preprocessor::HandleImportDirective(LexerToken &ImportTok) {
+ if (Diag(ImportTok, diag::ext_pp_import_directive)) return true;
+
+ return HandleIncludeDirective(ImportTok, 0, true);
+}
+
+/// HandleDefineDirective - Implements #define. This consumes the entire macro
+/// line then lets the caller lex the next real token.
+///
+bool Preprocessor::HandleDefineDirective(LexerToken &DefineTok) {
+ ++NumDefined;
+ LexerToken MacroNameTok;
+ if (ReadMacroName(MacroNameTok))
+ return true;
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.getKind() == tok::eom)
+ return false;
+
+ MacroInfo *MI = new MacroInfo(MacroNameTok.getSourceLocation());
+
+ LexerToken Tok;
+ if (LexUnexpandedToken(Tok)) return true;
+
+ if (Tok.getKind() == tok::eom) {
+ // If there is no body to this macro, we have no special handling here.
+ } else if (Tok.getKind() == tok::l_paren && !Tok.hasLeadingSpace()) {
+ // This is a function-like macro definition.
+ //assert(0 && "Function-like macros not implemented!");
+#warning function like macros
+ return DiscardUntilEndOfDirective();
+
+ } else if (!Tok.hasLeadingSpace()) {
+ // C99 requires whitespace between the macro definition and the body. Emit
+ // a diagnostic for something like "#define X+".
+ if (Features.C99) {
+ if (Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name))
+ return true;
+ } else {
+ // FIXME: C90/C++ do not get this diagnostic, but it does get a similar
+ // one in some cases!
+ }
+ } else {
+ // This is a normal token with leading space. Clear the leading space
+ // marker on the first token to get proper expansion.
+ Tok.ClearFlag(LexerToken::LeadingSpace);
+ }
+
+ // Read the rest of the macro body.
+ while (Tok.getKind() != tok::eom) {
+ MI->AddTokenToBody(Tok);
+
+ // FIXME: See create_iso_definition.
+
+ // Get the next token of the macro.
+ if (LexUnexpandedToken(Tok)) return true;
+ }
+
+ // Finally, if this identifier already had a macro defined for it, verify that
+ // the macro bodies are identical and free the old definition.
+ if (MacroInfo *OtherMI = MacroNameTok.getIdentifierInfo()->getMacroInfo()) {
+ // FIXME: Verify the definition is the same.
+ // Macros must be identical. This means all tokes and whitespace separation
+ // must be the same.
+ delete OtherMI;
+ }
+
+ MacroNameTok.getIdentifierInfo()->setMacroInfo(MI);
+ return false;
+}
+
+
+/// HandleUndefDirective - Implements #undef.
+///
+bool Preprocessor::HandleUndefDirective(LexerToken &UndefTok) {
+ ++NumUndefined;
+ LexerToken MacroNameTok;
+ if (ReadMacroName(MacroNameTok))
+ return true;
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.getKind() == tok::eom)
+ return false;
+
+ // Check to see if this is the last token on the #undef line.
+ if (CheckEndOfDirective("#undef")) return true;
+
+ // Okay, we finally have a valid identifier to undef.
+ MacroInfo *MI = MacroNameTok.getIdentifierInfo()->getMacroInfo();
+
+ // If the macro is not defined, this is a noop undef, just return.
+ if (MI == 0) return false;
+
+#if 0 // FIXME: implement warn_unused_macros.
+ if (CPP_OPTION (pfile, warn_unused_macros))
+ _cpp_warn_if_unused_macro (pfile, node, NULL);
+#endif
+
+ // Free macro definition.
+ delete MI;
+ MacroNameTok.getIdentifierInfo()->setMacroInfo(0);
+ return false;
+}
+
+
+/// HandleIfdefDirective - Implements the #ifdef/#ifndef directive. isIfndef is
+/// true when this is a #ifndef directive.
+///
+bool Preprocessor::HandleIfdefDirective(LexerToken &Result, bool isIfndef) {
+ ++NumIf;
+ LexerToken DirectiveTok = Result;
+
+ LexerToken MacroNameTok;
+ if (ReadMacroName(MacroNameTok))
+ return true;
+
+ // Error reading macro name? If so, diagnostic already issued.
+ if (MacroNameTok.getKind() == tok::eom)
+ return false;
+
+ // Check to see if this is the last token on the #if[n]def line.
+ if (CheckEndOfDirective("#ifdef")) return true;
+
+ // Should we include the stuff contained by this directive?
+ if (!MacroNameTok.getIdentifierInfo()->getMacroInfo() == isIfndef) {
+ // Yes, remember that we are inside a conditional, then lex the next token.
+ CurLexer->pushConditionalLevel(DirectiveTok.getStart(), /*wasskip*/false,
+ /*foundnonskip*/true, /*foundelse*/false);
+ return false;
+ } else {
+ // No, skip the contents of this block and return the first token after it.
+ return SkipExcludedConditionalBlock(DirectiveTok.getStart(),
+ /*Foundnonskip*/false,
+ /*FoundElse*/false);
+ }
+}
+
+/// HandleIfDirective - Implements the #if directive.
+///
+bool Preprocessor::HandleIfDirective(LexerToken &IfToken) {
+ ++NumIf;
+ const char *Start = CurLexer->BufferPtr;
+
+ bool ConditionalTrue = false;
+ if (EvaluateDirectiveExpression(ConditionalTrue))
+ return true;
+
+ // Should we include the stuff contained by this directive?
+ if (ConditionalTrue) {
+ // Yes, remember that we are inside a conditional, then lex the next token.
+ CurLexer->pushConditionalLevel(IfToken.getStart(), /*wasskip*/false,
+ /*foundnonskip*/true, /*foundelse*/false);
+ return false;
+ } else {
+ // No, skip the contents of this block and return the first token after it.
+ return SkipExcludedConditionalBlock(IfToken.getStart(),
+ /*Foundnonskip*/false,
+ /*FoundElse*/false);
+ }
+}
+
+/// HandleEndifDirective - Implements the #endif directive.
+///
+bool Preprocessor::HandleEndifDirective(LexerToken &EndifToken) {
+ ++NumEndif;
+ // Check that this is the whole directive.
+ if (CheckEndOfDirective("#endif")) return true;
+
+ PPConditionalInfo CondInfo;
+ if (CurLexer->popConditionalLevel(CondInfo)) {
+ // No conditionals on the stack: this is an #endif without an #if.
+ return Diag(EndifToken, diag::err_pp_endif_without_if);
+ }
+
+ assert(!CondInfo.WasSkipping && !isSkipping() &&
+ "This code should only be reachable in the non-skipping case!");
+ return false;
+}
+
+
+bool Preprocessor::HandleElseDirective(LexerToken &Result) {
+ ++NumElse;
+ // #else directive in a non-skipping conditional... start skipping.
+ if (CheckEndOfDirective("#else")) return true;
+
+ PPConditionalInfo CI;
+ if (CurLexer->popConditionalLevel(CI))
+ return Diag(Result, diag::pp_err_else_without_if);
+
+ // If this is a #else with a #else before it, report the error.
+ if (CI.FoundElse && Diag(Result, diag::pp_err_else_after_else))
+ return true;
+
+ // Finally, skip the rest of the contents of this block and return the first
+ // token after it.
+ return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
+ /*FoundElse*/true);
+}
+
+bool 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).
+ if (DiscardUntilEndOfDirective()) return true;
+
+ PPConditionalInfo CI;
+ if (CurLexer->popConditionalLevel(CI))
+ return Diag(ElifToken, diag::pp_err_elif_without_if);
+
+ // If this is a #elif with a #else before it, report the error.
+ if (CI.FoundElse && Diag(ElifToken, diag::pp_err_elif_after_else))
+ return true;
+
+ // Finally, skip the rest of the contents of this block and return the first
+ // token after it.
+ return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
+ /*FoundElse*/CI.FoundElse);
+}
Propchange: cfe/cfe/trunk/Lex/Preprocessor.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Lex/Preprocessor.cpp
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Makefile?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/Makefile (added)
+++ cfe/cfe/trunk/Makefile Wed Jul 11 11:22:17 2007
@@ -0,0 +1,9 @@
+LEVEL = ../..
+PARALLEL_DIRS := Basic Lex
+CPPFLAGS += -I$(LEVEL)/tools/clang/include
+
+TOOLNAME = clang
+
+USEDLIBS = clangLex.a clangBasic.a LLVMSupport.a LLVMSystem.a
+
+include $(LEVEL)/Makefile.common
Propchange: cfe/cfe/trunk/Makefile
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/Makefile
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/README.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/README.txt?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/README.txt (added)
+++ cfe/cfe/trunk/README.txt Wed Jul 11 11:22:17 2007
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+// C Language Family Front-end
+//===----------------------------------------------------------------------===//
+
+I. Introduction:
+
+ clang: noun
+ 1. A loud, resonant, metallic sound.
+ 2. The strident call of a crane or goose.
+ 3. C-language front-end toolkit.
+
+ Why?
+ Supports Objective-C.
+
+
+II. Current advantages over GCC:
+
+ * Full column number support in diagnostics.
+ * Caret diagnostics.
+ * Full diagnostic customization by client (can format diagnostics however they
+ like, e.g. in an IDE or refactoring tool).
+ * Built as a framework, can be reused by multiple tools.
+ * All languages supported linked into same library (no cc1,cc1obj, ...).
+ * mmap's code in read-only, does not dirty the pages like GCC (mem footprint).
+ * BSD License, can be linked into non-GPL projects.
+
+Future Features:
+ * Full diagnostic control, per diagnostic (use enums).
+ * Fine grained control within the source (#pragma enable/disable warning)
+ * Faster than GCC, preprocessing, parsing, IR generation.
+ * Better token tracking within macros? (Token came from this line, which is
+ a macro argument instantiated here, recursively instantiated here).
+ * Fast #import!!
+
+
+III. Critical Missing Functionality
+
+Lexer:
+ * Source character mapping. GCC supports ASCII and UTF-8.
+ See GCC options: -ftarget-charset and -ftarget-wide-charset.
+ * Universal character support. Experimental in GCC, enabled with
+ -fextended-identifiers.
+ * Poisoned identifiers.
+ * -fpreprocessed mode.
+
+Preprocessor:
+ * #line / #file directives
+ * Detection of "atomic" headers (#ifndef/#define), #pragma once support.
+ * Function-style #define & macro expansion
+ * -E & -C & -P output.
+
+Traditional Preprocessor:
+ * All.
+
+Parser Callbacks:
+ * All.
+
+Parser Actions:
+ * All.
+
\ No newline at end of file
Propchange: cfe/cfe/trunk/README.txt
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/README.txt
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/Diagnostic.h (added)
+++ cfe/cfe/trunk/include/clang/Basic/Diagnostic.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,117 @@
+//===--- Diagnostic.h - C Language Family Diagnostic 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 Diagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DIAGNOSTIC_H
+#define LLVM_CLANG_DIAGNOSTIC_H
+
+#include <string>
+
+namespace llvm {
+namespace clang {
+ class DiagnosticClient;
+ class SourceBuffer;
+ class SourceLocation;
+
+ // Import the diagnostic enums themselves.
+ namespace diag {
+ enum kind {
+#define DIAG(ENUM,FLAGS,DESC) ENUM,
+#include "DiagnosticKinds.def"
+ NUM_DIAGNOSTICS
+ };
+ }
+
+/// Diagnostic - This concrete class is used by the front-end to report
+/// problems and issues. It massages the diagnostics (e.g. handling things like
+/// "report warnings as errors" and passes them off to the DiagnosticClient for
+/// reporting to the user.
+class Diagnostic {
+ bool WarningsAsErrors; // Treat warnings like errors:
+ bool WarnOnExtensions; // Enables warnings for gcc extensions: -pedantic.
+ bool ErrorOnExtensions; // Error on extensions: -pedantic-errors.
+ DiagnosticClient &Client;
+public:
+ Diagnostic(DiagnosticClient &client) : Client(client) {
+ WarningsAsErrors = false;
+ WarnOnExtensions = false;
+ ErrorOnExtensions = false;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Diagnostic characterization methods, used by a client to customize how
+ //
+
+ /// setWarningsAsErrors - When set to true, any warnings reported are issued
+ /// as errors.
+ void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
+ bool getWarningsAsErrors() const { return WarningsAsErrors; }
+
+ /// setWarnOnExtensions - When set to true, issue warnings on GCC extensions,
+ /// the equivalent of GCC's -pedantic.
+ void setWarnOnExtensions(bool Val) { WarnOnExtensions = Val; }
+ bool getWarnOnExtensions() const { return WarnOnExtensions; }
+
+ /// setErrorOnExtensions - When set to true issue errors for GCC extensions
+ /// instead of warnings. This is the equivalent to GCC's -pedantic-errors.
+ void setErrorOnExtensions(bool Val) { ErrorOnExtensions = Val; }
+ bool getErrorOnExtensions() const { return ErrorOnExtensions; }
+
+
+ //===--------------------------------------------------------------------===//
+ // Diagnostic classification and reporting interfaces.
+ //
+
+ /// getDescription - Given a diagnostic ID, return a description of the
+ /// issue.
+ static const char *getDescription(unsigned DiagID);
+
+ /// Level - The level of the diagnostic
+ enum Level {
+ // FIXME: Anachronism?
+ Ignored, Note, Warning, Error, Fatal, Sorry
+ };
+
+ /// isNoteWarningOrExtension - Return true if the unmapped diagnostic level of
+ /// the specified diagnostic ID is a Note, Warning, or Extension.
+ static bool isNoteWarningOrExtension(unsigned DiagID);
+
+ /// getDiagnosticLevel - Based on the way the client configured the Diagnostic
+ /// object, classify the specified diagnostic ID into a Level, consumable by
+ /// the DiagnosticClient.
+ Level getDiagnosticLevel(unsigned DiagID) const;
+
+ /// Report - Issue the message to the client. If the client wants us to stop
+ /// compilation, return true, otherwise return false. DiagID is a member of
+ /// the diag::kind enum.
+ bool Report(SourceLocation Pos, unsigned DiagID,
+ const std::string &Extra = "");
+};
+
+/// DiagnosticClient - This is an abstract interface implemented by clients of
+/// the front-end, which formats and prints fully processed diagnostics.
+class DiagnosticClient {
+public:
+
+ virtual ~DiagnosticClient();
+
+ /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or
+ /// capturing it to a log as needed. If this returns true, compilation will
+ /// be gracefully terminated, otherwise compilation will continue.
+ virtual bool HandleDiagnostic(Diagnostic::Level DiagLevel, SourceLocation Pos,
+ diag::kind ID, const std::string &Msg) = 0;
+};
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Basic/Diagnostic.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/Diagnostic.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (added)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:22:17 2007
@@ -0,0 +1,156 @@
+//===-- DiagnosticKinds.def - C Family Diagnostic Kind Database -*- 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 DiagnosticKind database.
+//
+//===----------------------------------------------------------------------===//
+
+// Flags for diagnostic:
+//
+// DIAG_TYPE - Allows one of:
+// NOTE - Informational message.
+// WARNING - Warning.
+// EXTENSION - Notification that an extension to the language is being used.
+// ERROR - Error, compilation will stop after parsing completes.
+// FATAL - Fatal error: parsing must stop.
+
+
+//===----------------------------------------------------------------------===//
+// Lexer Diagnostics
+//===----------------------------------------------------------------------===//
+
+DIAG(null_in_string, WARNING,
+ "null character(s) preserved in string literal")
+DIAG(null_in_char , WARNING,
+ "null character(s) preserved in character literal")
+DIAG(null_in_file , WARNING,
+ "null character ignored")
+DIAG(nested_block_comment, WARNING,
+ "\"/*\" within block comment")
+DIAG(escaped_newline_block_comment_end, WARNING,
+ "escaped newline between */ characters at block comment end")
+DIAG(min_max_deprecated, WARNING,
+ "minimum/maximum operators are deprecated")
+DIAG(backslash_newline_space, WARNING,
+ "backslash and newline separated by space")
+
+// Trigraphs.
+DIAG(trigraph_ignored, WARNING, "trigraph ignored")
+DIAG(trigraph_ignored_block_comment, WARNING,
+ "ignored trigraph would end block comment")
+DIAG(trigraph_ends_block_comment, WARNING,
+ "trigraph ends block comment")
+DIAG(trigraph_converted, WARNING,
+ "trigraph converted to '%s' character")
+
+DIAG(ext_multi_line_bcpl_comment, EXTENSION,
+ "multi-line // comment")
+DIAG(ext_bcpl_comment, EXTENSION,
+ "// comments are not allowed in this language")
+DIAG(ext_no_newline_eof, EXTENSION,
+ "no newline at end of file")
+DIAG(ext_backslash_newline_eof, EXTENSION,
+ "backslash-newline at end of file")
+DIAG(ext_dollar_in_identifier, EXTENSION,
+ "'$' in identifier")
+
+DIAG(ext_token_used, EXTENSION,
+ "Extension used")
+
+DIAG(err_unterminated_string, ERROR,
+ "missing terminating \" character")
+DIAG(err_unterminated_char, ERROR,
+ "missing terminating ' character")
+DIAG(err_empty_character, ERROR,
+ "empty character constant")
+DIAG(err_unterminated_block_comment, ERROR,
+ "unterminated /* comment")
+DIAG(err_stray_character, ERROR,
+ "stray character in program")
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Diagnostics
+//===----------------------------------------------------------------------===//
+
+DIAG(pp_hash_warning, WARNING,
+ "#warning%s")
+DIAG(pp_include_next_in_primary, WARNING,
+ "#include_next in primary source file")
+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(ext_pp_import_directive, EXTENSION,
+ "#import is a language extension")
+DIAG(ext_pp_include_next_directive, EXTENSION,
+ "#include_next is a language extension")
+DIAG(ext_pp_warning_directive, EXTENSION,
+ "#warning is a language extension")
+DIAG(ext_pp_extra_tokens_at_eol, EXTENSION,
+ "extra tokens at end of %s directive")
+DIAG(ext_pp_comma_expr, EXTENSION,
+ "comma operator in operand of #if")
+
+DIAG(err_pp_invalid_directive, ERROR,
+ "invalid preprocessing directive")
+DIAG(err_pp_hash_error, ERROR,
+ "#error%s")
+DIAG(err_pp_file_not_found, ERROR,
+ "file not found")
+DIAG(err_pp_empty_filename, ERROR,
+ "empty filename")
+DIAG(err_pp_include_too_deep, ERROR,
+ "#include nested too deeply")
+DIAG(err_pp_expects_filename, ERROR,
+ "expected \"FILENAME\" or <FILENAME>")
+DIAG(err_pp_macro_not_identifier, ERROR,
+ "macro names must be identifiers")
+DIAG(err_pp_missing_macro_name, ERROR,
+ "macro name missing")
+DIAG(err_pp_unterminated_conditional, ERROR,
+ "unterminated conditional directive")
+DIAG(pp_err_else_after_else, ERROR,
+ "#else after #else")
+DIAG(pp_err_elif_after_else, ERROR,
+ "#elif after #else")
+DIAG(pp_err_else_without_if, ERROR,
+ "#else without #if")
+DIAG(pp_err_elif_without_if, ERROR,
+ "#elif without #if")
+DIAG(err_pp_endif_without_if, ERROR,
+ "#endif without #if")
+DIAG(err_pp_expected_value_in_expr, ERROR,
+ "expected value in expression")
+DIAG(err_pp_missing_val_before_operator, ERROR,
+ "missing value before operator")
+DIAG(err_pp_expected_rparen, ERROR,
+ "expected ')' in preprocessor expression")
+DIAG(err_pp_expected_eol, ERROR,
+ "expected end of line in preprocessor expression")
+DIAG(err_pp_defined_requires_identifier, ERROR,
+ "operator \"defined\" requires an identifier")
+DIAG(err_pp_missing_rparen, ERROR,
+ "missing ')' after \"defined\"")
+DIAG(err_pp_colon_without_question, ERROR,
+ "':' without preceding '?'")
+DIAG(err_pp_question_without_colon, ERROR,
+ "'?' without following ':'")
+DIAG(err_pp_division_by_zero, ERROR,
+ "division by zero in preprocessor expression")
+DIAG(err_pp_remainder_by_zero, ERROR,
+ "remainder by zero in preprocessor expression")
+
+DIAG(err_pp_expr_bad_token, ERROR,
+ "token is not valid in preprocessor expressions")
+
+// Should be a sorry?
+DIAG(err_pp_I_dash_not_supported, ERROR,
+ "-I- not supported, please use -iquote instead")
+#undef DIAG
Propchange: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/FileManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/FileManager.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/FileManager.h (added)
+++ cfe/cfe/trunk/include/clang/Basic/FileManager.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,103 @@
+//===--- FileManager.h - File System Probing and Caching --------*- 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 FileManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FILEMANAGER_H
+#define LLVM_CLANG_FILEMANAGER_H
+
+#include <map>
+#include <string>
+// FIXME: Enhance libsystem to support inode and other fields in stat.
+#include <sys/types.h>
+
+namespace llvm {
+namespace clang {
+class FileManager;
+
+/// DirectoryEntry - Cached information about one directory on the disk.
+///
+class DirectoryEntry {
+ std::string Name; // Name of the directory.
+ DirectoryEntry() {}
+ friend class FileManager;
+public:
+ const std::string &getName() const { return Name; }
+};
+
+/// FileEntry - Cached information about one file on the disk.
+///
+class FileEntry {
+ std::string Name; // Name of the directory.
+ off_t Size; // File size in bytes.
+ const DirectoryEntry *Dir; // Directory file lives in.
+ unsigned UID; // A unique (small) ID for the file.
+ FileEntry() {}
+ friend class FileManager;
+public:
+
+ const std::string &getName() const { return Name; }
+ off_t getSize() const { return Size; }
+ unsigned getUID() const { return UID; }
+
+ /// getDir - Return the directory the file lives in.
+ ///
+ const DirectoryEntry *getDir() const { return Dir; }
+};
+
+
+/// FileManager - Implements support for file system lookup, file system
+/// caching, and directory search management. This also handles more advanced
+/// properties, such as uniquing files based on "inode", so that a file with two
+/// names (e.g. symlinked) will be treated as a single file.
+///
+class FileManager {
+ /// DirEntries/FileEntries - This is a cache of directory/file entries we have
+ /// looked up.
+ ///
+ std::map<std::string, DirectoryEntry*> DirEntries;
+ std::map<std::string, FileEntry*> FileEntries;
+
+ /// UniqueDirs/UniqueFiles - Cache from ID's to existing directories/files.
+ ///
+ std::map<std::pair<dev_t, ino_t>, DirectoryEntry*> UniqueDirs;
+ std::map<std::pair<dev_t, ino_t>, FileEntry*> UniqueFiles;
+
+ /// NextFileUID - Each FileEntry we create is assigned a unique ID #.
+ ///
+ unsigned NextFileUID;
+
+ // Statistics.
+ unsigned NumDirLookups, NumFileLookups;
+ unsigned NumDirCacheMisses, NumFileCacheMisses;
+public:
+ FileManager() : NextFileUID(0) {
+ NumDirLookups = NumFileLookups = 0;
+ NumDirCacheMisses = NumFileCacheMisses = 0;
+ }
+
+ /// getDirectory - Lookup, cache, and verify the specified directory. This
+ /// returns null if the directory doesn't exist.
+ ///
+ const DirectoryEntry *getDirectory(const std::string &Filename);
+
+ /// getFile - Lookup, cache, and verify the specified file. This returns null
+ /// if the file doesn't exist.
+ ///
+ const FileEntry *getFile(const std::string &Filename);
+
+ void PrintStats() const;
+};
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Basic/FileManager.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/FileManager.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h (added)
+++ cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,68 @@
+//===--- SourceBuffer.h - C Language Family Source Buffer -------*- 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 SourceBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCEBUFFER_H
+#define LLVM_CLANG_SOURCEBUFFER_H
+
+namespace llvm {
+namespace sys { class Path; }
+namespace clang {
+ class FileEntry;
+
+/// SourceFile - This interface provides simple read-only access to the raw bits
+/// in a source file in a memory efficient way. In addition to basic access to
+/// the characters in the file, this interface guarantees you can read one
+/// character past the end of the file, and that this character will read as
+/// '\0'.
+class SourceBuffer {
+ const char *BufferStart; // Start of the buffer.
+ const char *BufferEnd; // End of the buffer.
+
+ /// MustDeleteBuffer - True if we allocated this buffer. If so, the
+ /// destructor must know the delete[] it.
+ bool MustDeleteBuffer;
+protected:
+ SourceBuffer() : MustDeleteBuffer(false) {}
+ void init(const char *BufStart, const char *BufEnd);
+ void initCopyOf(const char *BufStart, const char *BufEnd);
+public:
+ virtual ~SourceBuffer();
+
+ const char *getBufferStart() const { return BufferStart; }
+ const char *getBufferEnd() const { return BufferEnd; }
+ unsigned getBufferSize() const { return BufferEnd-BufferStart; }
+
+ /// getBufferIdentifier - Return an identifier for this buffer, typically the
+ /// filename it was read from.
+ virtual const char *getBufferIdentifier() const {
+ return "Unknown buffer";
+ }
+
+ /// getFile - Open the specified file as a SourceBuffer, returning a new
+ /// SourceBuffer if successful, otherwise returning null.
+ static SourceBuffer *getFile(const FileEntry *FileEnt);
+
+ /// getMemBuffer - Open the specified memory range as a SourceBuffer. Note
+ /// that EndPtr[0] must be a null byte and be accessible!
+ static SourceBuffer *getMemBuffer(const char *StartPtr, const char *EndPtr,
+ const char *BufferName = "");
+
+ /// getSTDIN - Read all of stdin into a file buffer, and return it. This
+ /// fails if stdin is empty.
+ static SourceBuffer *getSTDIN();
+};
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/SourceBuffer.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/SourceLocation.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/SourceLocation.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/SourceLocation.h (added)
+++ cfe/cfe/trunk/include/clang/Basic/SourceLocation.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,81 @@
+//===--- SourceLocation.h - Compact identifier for Source Files -*- 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 SourceLocation class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCELOCATION_H
+#define LLVM_CLANG_SOURCELOCATION_H
+
+namespace llvm {
+namespace clang {
+
+/// SourceLocation - This is a carefully crafted 32-bit identifier that encodes
+/// a full include stack, line and column number information for a position in
+/// an input translation unit.
+class SourceLocation {
+ unsigned ID;
+public:
+ enum {
+ FileIDBits = 12,
+ FilePosBits = 32-FileIDBits
+ };
+
+ SourceLocation() : ID(0) {} // 0 is an invalid FileID.
+
+ /// SourceLocation constructor - Create a new SourceLocation object with the
+ /// specified FileID and FilePos.
+ SourceLocation(unsigned FileID, unsigned FilePos) {
+ // If a FilePos is larger than (1<<FilePosBits), the SourceManager makes
+ // enough consequtive FileIDs that we have one for each chunk.
+ if (FilePos >= (1 << FilePosBits)) {
+ FileID += FilePos >> FilePosBits;
+ FilePos &= (1 << FilePosBits)-1;
+ }
+
+ // FIXME: Find a way to handle out of FileID bits! Maybe MaxFileID is an
+ // escape of some sort?
+ if (FileID >= (1 << FileIDBits))
+ FileID = (1 << FileIDBits)-1;
+
+ ID = (FileID << FilePosBits) | FilePos;
+ }
+
+ /// isValid - Return true if this is a valid SourceLocation object. Invalid
+ /// SourceLocations are often used when events have no corresponding location
+ /// in the source (e.g. a diagnostic is required for a command line option).
+ ///
+ bool isValid() const { return ID != 0; }
+
+ /// getFileID - Return the file identifier for this SourceLocation. This
+ /// FileID can be used with the SourceManager object to obtain an entire
+ /// include stack for a file position reference.
+ unsigned getFileID() const { return ID >> FilePosBits; }
+
+ /// getRawFilePos - Return the byte offset from the start of the file-chunk
+ /// referred to by FileID. This method should not be used to get the offset
+ /// from the start of the file, instead you should use
+ /// SourceManager::getFilePos. This method will be incorrect for large files.
+ unsigned getRawFilePos() const { return ID & ((1 << FilePosBits)-1); }
+};
+
+inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return LHS.getFileID() == RHS.getFileID() &&
+ LHS.getRawFilePos() == RHS.getRawFilePos();
+}
+
+inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return !(LHS == RHS);
+}
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Basic/SourceLocation.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/SourceLocation.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/SourceManager.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/SourceManager.h (added)
+++ cfe/cfe/trunk/include/clang/Basic/SourceManager.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,195 @@
+//===--- SourceManager.h - Track and cache source files ---------*- 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 SourceManager interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SOURCEMANAGER_H
+#define LLVM_CLANG_SOURCEMANAGER_H
+
+#include "clang/Basic/SourceLocation.h"
+#include <vector>
+#include <map>
+#include <list>
+
+namespace llvm {
+namespace clang {
+
+class SourceBuffer;
+class SourceManager;
+class FileEntry;
+class IdentifierTokenInfo;
+
+/// SourceManager - This file handles loading and caching of source files into
+/// memory. This object owns the SourceBuffer objects for all of the loaded
+/// files and assigns unique FileID's for each unique #include chain.
+class SourceManager {
+ /// FileInfo - Once instance of this struct is kept for every file loaded or
+ /// used. This object owns the SourceBuffer object.
+ struct FileInfo {
+ /// Buffer - The actual buffer containing the characters from the input
+ /// file.
+ const SourceBuffer *Buffer;
+
+ /// SourceLineCache - A new[]'d array of offsets for each source line. This
+ /// is lazily computed.
+ ///
+ unsigned *SourceLineCache;
+
+ /// NumLines - The number of lines in this FileInfo. This is only valid if
+ /// SourceLineCache is non-null.
+ unsigned NumLines;
+ };
+
+ typedef std::pair<const FileEntry * const, FileInfo> InfoRec;
+
+ /// FileIDInfo - Information about a FileID, basically just the file that it
+ /// represents and include stack information.
+ struct FileIDInfo {
+ /// IncludeLoc - The location of the #include that brought in this file.
+ /// This SourceLocation object has a FileId of 0 for the main file.
+ SourceLocation IncludeLoc;
+
+ /// ChunkNo - Really large files are broken up into chunks that are each
+ /// (1 << SourceLocation::FilePosBits) in size. This specifies the chunk
+ /// number of this FileID.
+ unsigned ChunkNo;
+
+ /// FileInfo - Information about the file itself.
+ ///
+ const InfoRec *Info;
+
+ FileIDInfo(SourceLocation IL, unsigned CN, const InfoRec *Inf)
+ : IncludeLoc(IL), ChunkNo(CN), Info(Inf) {}
+ };
+
+ /// FileInfos - Memoized information about all of the files tracked by this
+ /// SourceManager.
+ std::map<const FileEntry *, FileInfo> FileInfos;
+
+ /// MemBufferInfos - Information about various memory buffers that we have
+ /// read in. This is a list, instead of a vector, because we need pointers to
+ /// the FileInfo objects to be stable.
+ std::list<InfoRec> MemBufferInfos;
+
+ /// FileIDs - Information about each FileID. FileID #0 is not valid, so all
+ /// entries are off by one.
+ std::vector<FileIDInfo> FileIDs;
+public:
+ ~SourceManager();
+
+ /// createFileID - Create a new FileID that represents the specified file
+ /// being #included from the specified IncludePosition. This returns 0 on
+ /// error and translates NULL into standard input.
+ unsigned createFileID(const FileEntry *SourceFile, SourceLocation IncludePos){
+ const InfoRec *IR = getInfoRec(SourceFile);
+ if (IR == 0) return 0; // Error opening file?
+ return createFileID(IR, IncludePos);
+ }
+
+ /// createFileIDForMemBuffer - Create a new FileID that represents the
+ /// specified memory buffer. This does no caching of the buffer and takes
+ /// ownership of the SourceBuffer, so only pass a SourceBuffer to this once.
+ unsigned createFileIDForMemBuffer(const SourceBuffer *Buffer) {
+ const InfoRec *IR = createMemBufferInfoRec(Buffer);
+ return createFileID(IR, SourceLocation());
+ }
+
+
+ /// getMacroID - Get or create a new FileID that represents a macro with the
+ /// specified identifier being expanded at the specified position. This can
+ /// never fail.
+ unsigned getMacroID(const IdentifierTokenInfo *Identifier,
+ SourceLocation ExpandPos) {
+ // FIXME: Implement ID's for macro expansions!
+ return ExpandPos.getFileID();
+ }
+
+ /// getBuffer - Return the buffer for the specified FileID.
+ ///
+ const SourceBuffer *getBuffer(unsigned FileID) {
+ return getFileInfo(FileID)->Buffer;
+ }
+
+ /// getIncludeLoc - Return the location of the #include for the specified
+ /// FileID.
+ SourceLocation getIncludeLoc(unsigned FileID) const {
+ assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
+ return FileIDs[FileID-1].IncludeLoc;
+ }
+
+ /// getFilePos - This (efficient) method returns the offset from the start of
+ /// the file that the specified SourceLocation represents.
+ unsigned getFilePos(SourceLocation IncludePos) const {
+ assert(IncludePos.getFileID()-1 < FileIDs.size() && "Invalid FileID!");
+ // If this file has been split up into chunks, factor in the chunk number
+ // that the FileID references.
+ unsigned ChunkNo = FileIDs[IncludePos.getFileID()-1].ChunkNo;
+ return IncludePos.getRawFilePos() +
+ (ChunkNo << SourceLocation::FilePosBits);
+ }
+
+ /// getColumnNumber - Return the column # for the specified include position.
+ /// this is significantly cheaper to compute than the line number. This
+ /// returns zero if the column number isn't known.
+ unsigned getColumnNumber(SourceLocation IncludePos) const;
+
+ /// getLineNumber - Given a SourceLocation, return the physical line number
+ /// for the position indicated. This requires building and caching a table of
+ /// line offsets for the SourceBuffer, so this is not cheap: use only when
+ /// about to emit a diagnostic.
+ unsigned getLineNumber(SourceLocation IncludePos);
+
+ /// getFileEntryForFileID - Return the FileEntry record for the specified
+ /// FileID if one exists.
+ const FileEntry *getFileEntryForFileID(unsigned FileID) const {
+ assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
+ return FileIDs[FileID-1].Info->first;
+ }
+
+ /// PrintStats - Print statistics to stderr.
+ ///
+ void PrintStats() const;
+private:
+ /// createFileID - Create a new fileID for the specified InfoRec and include
+ /// position. This works regardless of whether the InfoRec corresponds to a
+ /// file or some other input source.
+ unsigned createFileID(const InfoRec *File, SourceLocation IncludePos);
+
+ /// getFileInfo - Create or return a cached FileInfo for the specified file.
+ /// This returns null on failure.
+ const InfoRec *getInfoRec(const FileEntry *SourceFile);
+
+ /// createMemBufferInfoRec - Create a new info record for the specified memory
+ /// buffer. This does no caching.
+ const InfoRec *createMemBufferInfoRec(const SourceBuffer *Buffer);
+
+ const InfoRec *getInfoRec(unsigned FileID) const {
+ assert(FileID-1 < FileIDs.size() && "Invalid FileID!");
+ return FileIDs[FileID-1].Info;
+ }
+
+ FileInfo *getFileInfo(unsigned FileID) const {
+ if (const InfoRec *IR = getInfoRec(FileID))
+ return const_cast<FileInfo *>(&IR->second);
+ return 0;
+ }
+ FileInfo *getFileInfo(const FileEntry *SourceFile) {
+ if (const InfoRec *IR = getInfoRec(SourceFile))
+ return const_cast<FileInfo *>(&IR->second);
+ return 0;
+ }
+};
+
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Basic/SourceManager.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/SourceManager.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/TokenKinds.def (added)
+++ cfe/cfe/trunk/include/clang/Basic/TokenKinds.def Wed Jul 11 11:22:17 2007
@@ -0,0 +1,241 @@
+//===--- TokenKinds.def - C Family Token Kind Database ----------*- 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 TokenKind database. This includes normal tokens like
+// tok::ampamp (corresponding to the && token) as well as keywords for various
+// languages. Users of this file must optionally #define the TOK/KEYWORD/ALIAS
+// macros to make use of this file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TOK
+#define TOK(X)
+#endif
+#ifndef KEYWORD
+#define KEYWORD(X,Y) TOK(kw ## X)
+#endif
+#ifndef ALIAS
+#define ALIAS(X,Y)
+#endif
+
+TOK(unknown) // Not a token.
+TOK(eof) // End of file.
+TOK(eom) // End of macro (end of line inside a macro).
+
+// C99 6.4.2: Identifiers.
+TOK(identifier) // abcde123
+
+// C99 6.4.4.1: Integer Constants
+// C99 6.4.4.2: Floating Constants
+TOK(numeric_constant) // 0x123
+
+// C99 6.4.4: Character Constants
+TOK(char_constant) // 'a' L'b'
+
+// C99 6.4.5: String Literals.
+TOK(string_literal) // "foo" L"foo"
+TOK(angle_string_literal)// <foo>
+
+// C99 6.4.6: Punctuators.
+TOK(l_square) // [
+TOK(r_square) // ]
+TOK(l_paren) // (
+TOK(r_paren) // )
+TOK(l_brace) // {
+TOK(r_brace) // }
+TOK(period) // .
+TOK(ellipsis) // ...
+TOK(amp) // &
+TOK(ampamp) // &&
+TOK(ampequal) // &=
+TOK(star) // *
+TOK(starequal) // *=
+TOK(plus) // +
+TOK(plusplus) // ++
+TOK(plusequal) // +=
+TOK(minus) // -
+TOK(arrow) // ->
+TOK(minusminus) // --
+TOK(minusequal) // -=
+TOK(tilde) // ~
+TOK(exclaim) // !
+TOK(exclaimequal) // !=
+TOK(slash) // /
+TOK(slashequal) // /=
+TOK(percent) // %
+TOK(percentequal) // %=
+TOK(less) // <
+TOK(lessless) // <<
+TOK(lessequal) // <=
+TOK(lesslessequal) // <<=
+TOK(greater) // >
+TOK(greatergreater) // >>
+TOK(greaterequal) // >=
+TOK(greatergreaterequal) // >>=
+TOK(caret) // ^
+TOK(caretequal) // ^=
+TOK(pipe) // |
+TOK(pipepipe) // ||
+TOK(pipeequal) // |=
+TOK(question) // ?
+TOK(colon) // :
+TOK(semi) // ;
+TOK(equal) // =
+TOK(equalequal) // ==
+TOK(comma) // ,
+TOK(hash) // #
+TOK(hashhash) // ##
+
+// C++ Support
+TOK(periodstar) // .*
+TOK(arrowstar) // ->*
+TOK(coloncolon) // ::
+
+// GNU C++ Extensions
+TOK(lessquestionequal) // <?=
+TOK(greaterquestionequal)// >?=
+TOK(lessquestion) // <?
+TOK(greaterquestion) // >?
+
+// Objective C support.
+TOK(at) // @
+
+// at_identifier // @foo
+// at_string // @"foo"
+
+
+// C99 6.4.1: Keywords. These turn into kw_* tokens. The _ prefix is used to
+// prevent the __VA_ARGS__ token from appearing here.
+// Flags allowed:
+// NOTC90 - In C90, this token is never available.
+// EXTC90 - In C90, this token is an extension that is enabled unless strict.
+// NOTC99 - In C99, this token is never available.
+// EXTC99 - In C99, this token is an extension that is enabled unless strict.
+// NOTCPP - In C++, this token is never available.
+// EXTCPP - In C++, this token is an extension that is enabled unless strict.
+//
+KEYWORD(_auto , 0)
+KEYWORD(_break , 0)
+KEYWORD(_case , 0)
+KEYWORD(_char , 0)
+KEYWORD(_const , 0)
+KEYWORD(_continue , 0)
+KEYWORD(_default , 0)
+KEYWORD(_do , 0)
+KEYWORD(_double , 0)
+KEYWORD(_else , 0)
+KEYWORD(_enum , 0)
+KEYWORD(_extern , 0)
+KEYWORD(_float , 0)
+KEYWORD(_for , 0)
+KEYWORD(_goto , 0)
+KEYWORD(_if , 0)
+KEYWORD(_inline , EXTC90) // Ext in C90, ok in C99/C++
+KEYWORD(_int , 0)
+KEYWORD(_long , 0)
+KEYWORD(_register , 0)
+KEYWORD(_restrict , NOTC90) // Not in C90
+KEYWORD(_return , 0)
+KEYWORD(_short , 0)
+KEYWORD(_signed , 0)
+KEYWORD(_sizeof , 0)
+KEYWORD(_static , 0)
+KEYWORD(_struct , 0)
+KEYWORD(_switch , 0)
+KEYWORD(_typedef , 0)
+KEYWORD(_union , 0)
+KEYWORD(_unsigned , 0)
+KEYWORD(_void , 0)
+KEYWORD(_volatile , 0)
+KEYWORD(_while , 0)
+KEYWORD(__Bool , NOTC90|NOTCPP) // C99 only
+KEYWORD(__Complex , NOTC90) // C99/C++
+KEYWORD(__Imaginary , NOTC90|NOTCPP) // C90 only
+
+// Special tokens to the compiler.
+KEYWORD(___VA_ARGS__ , EXTC90|EXTCPP) // Only in C99.
+KEYWORD(___func__ , EXTC90|EXTCPP) // Only in C99.
+KEYWORD(___FUNCTION__ , EXTC90|EXTC99|EXTCPP) // GCC Extension.
+KEYWORD(___PRETTY_FUNCTION__ , EXTC90|EXTC99|EXTCPP) // GCC Extension.
+
+// C++
+KEYWORD(_asm , EXTC90|EXTC99) // Exts in C90/C99
+KEYWORD(_catch , NOTC90|NOTC99)
+KEYWORD(_class , NOTC90|NOTC99)
+KEYWORD(_const_cast , NOTC90|NOTC99)
+KEYWORD(_delete , NOTC90|NOTC99)
+KEYWORD(_dynamic_cast , NOTC90|NOTC99)
+KEYWORD(_explicit , NOTC90|NOTC99)
+KEYWORD(_export , NOTC90|NOTC99)
+KEYWORD(_false , NOTC90|NOTC99)
+KEYWORD(_friend , NOTC90|NOTC99)
+KEYWORD(_mutable , NOTC90|NOTC99)
+KEYWORD(_namespace , NOTC90|NOTC99)
+KEYWORD(_new , NOTC90|NOTC99)
+KEYWORD(_operator , NOTC90|NOTC99)
+KEYWORD(_private , NOTC90|NOTC99)
+KEYWORD(_protected , NOTC90|NOTC99)
+KEYWORD(_public , NOTC90|NOTC99)
+KEYWORD(_reinterpret_cast , NOTC90|NOTC99)
+KEYWORD(_static_cast , NOTC90|NOTC99)
+KEYWORD(_template , NOTC90|NOTC99)
+KEYWORD(_this , NOTC90|NOTC99)
+KEYWORD(_throw , NOTC90|NOTC99)
+KEYWORD(_true , NOTC90|NOTC99)
+KEYWORD(_try , NOTC90|NOTC99)
+KEYWORD(_typename , NOTC90|NOTC99)
+KEYWORD(_typeid , NOTC90|NOTC99)
+KEYWORD(_using , NOTC90|NOTC99)
+KEYWORD(_virtual , NOTC90|NOTC99)
+KEYWORD(_wchar_t , NOTC90|NOTC99)
+
+// GNU Extensions.
+KEYWORD(__Decimal32 , EXTC90|EXTC99|EXTCPP)
+KEYWORD(__Decimal64 , EXTC90|EXTC99|EXTCPP)
+KEYWORD(__Decimal128 , EXTC90|EXTC99|EXTCPP)
+KEYWORD(_typeof , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___null , NOTC90|NOTC99|EXTCPP) // C++-only Extensn
+KEYWORD(___alignof , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___attribute , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___builtin_choose_expr , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___builtin_offsetof , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___builtin_types_compatible_p, EXTC90|EXTC99|EXTCPP)
+KEYWORD(___builtin_va_arg , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___extension__ , 0) // Not treated as an extension!
+KEYWORD(___imag , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___label__ , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___real , EXTC90|EXTC99|EXTCPP)
+KEYWORD(___thread , EXTC90|EXTC99|EXTCPP)
+
+// Alternate spelling for various tokens. There are GCC extensions in all
+// languages, but should not be disabled in strict conformance mode.
+ALIAS("__attribute__", __attribute)
+ALIAS("__const" , const )
+ALIAS("__const__" , const )
+ALIAS("__alignof__" , __alignof )
+ALIAS("__asm" , asm )
+ALIAS("__asm__" , asm )
+ALIAS("__complex" , _Complex )
+ALIAS("__complex__" , _Complex )
+ALIAS("__imag__" , __imag )
+ALIAS("__inline" , inline )
+ALIAS("__inline__" , inline )
+ALIAS("__real__" , __real )
+ALIAS("__restrict" , restrict )
+ALIAS("__restrict__" , restrict )
+ALIAS("__signed" , signed )
+ALIAS("__signed__" , signed )
+ALIAS("__typeof" , typeof )
+ALIAS("__typeof__" , typeof )
+ALIAS("__volatile" , volatile )
+ALIAS("__volatile__" , volatile )
+
+#undef ALIAS
+#undef KEYWORD
+#undef TOK
Propchange: cfe/cfe/trunk/include/clang/Basic/TokenKinds.def
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/TokenKinds.def
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Basic/TokenKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/TokenKinds.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/TokenKinds.h (added)
+++ cfe/cfe/trunk/include/clang/Basic/TokenKinds.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,36 @@
+//===--- TokenKinds.h - Enum values for C Token Kinds -----------*- 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 TokenKind enum and support functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOKENKINDS_H
+#define LLVM_CLANG_TOKENKINDS_H
+
+namespace llvm {
+namespace clang {
+
+namespace tok {
+
+/// TokenKind - This provides a simple uniform namespace for tokens from all C
+/// languages.
+enum TokenKind {
+#define TOK(X) X,
+#include "clang/Basic/TokenKinds.def"
+ NUM_TOKENS
+};
+
+const char *getTokenName(enum TokenKind Kind);
+
+} // end namespace tok
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Basic/TokenKinds.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Basic/TokenKinds.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,104 @@
+//===--- IdentifierTable.h - Hash table for identifier lookup ---*- 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 IdentifierTokenInfo and IdentifierTable interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_IDENTIFIERTABLE_H
+#define LLVM_CLANG_IDENTIFIERTABLE_H
+
+#include "clang/Basic/TokenKinds.h"
+#include <string>
+
+namespace llvm {
+namespace clang {
+ class IdentifierTable;
+ class MacroInfo;
+
+/// IdentifierTokenInfo - One of these records is kept for each identifier that
+/// is lexed. This contains information about whether the token was #define'd,
+/// is a language keyword, or if it is a front-end token of some sort (e.g. a
+/// variable or function name). The preprocessor keeps this information in a
+/// set, and all tok::identifier tokens have a pointer to one of these.
+class IdentifierTokenInfo {
+ unsigned NameLen; // String that is the identifier.
+ MacroInfo *Macro; // Set if this identifier is #define'd.
+ tok::TokenKind TokenID:8;// Nonzero if this is a front-end token.
+ bool IsExtension : 1; // True if this token is a language extension.
+ void *FETokenInfo; // Managed by the language front-end.
+ friend class IdentifierTable;
+public:
+ /// getName - Return the actual string for this identifier. The length of
+ /// this string is stored in NameLen, and the returned string is properly null
+ /// terminated.
+ ///
+ const char *getName() const {
+ // String data is stored immediately after the IdentifierTokenInfo object.
+ return (const char*)(this+1);
+ }
+
+ /// getNameLength - Return the length of the identifier string.
+ ///
+ unsigned getNameLength() const {
+ return NameLen;
+ }
+
+ /// getMacroInfo - Return macro information about this identifier, or null if
+ /// it is not a macro.
+ MacroInfo *getMacroInfo() const { return Macro; }
+ void setMacroInfo(MacroInfo *I) { Macro = I; }
+
+ /// get/setTokenID - If this is a source-language token (e.g. 'for'), this API
+ /// can be used to cause the lexer to map identifiers to source-language
+ /// tokens.
+ tok::TokenKind getTokenID() const { return TokenID; }
+ void setTokenID(tok::TokenKind ID) { TokenID = ID; }
+
+ /// get/setExtension - Initialize information about whether or not this
+ /// language token is an extension. This controls extension warnings, and is
+ /// only valid if a custom token ID is set.
+ bool isExtensionToken() const { return IsExtension; }
+ void setIsExtensionToken(bool Val) { IsExtension = Val; }
+
+
+ /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
+ /// associate arbitrary metadata with this token.
+ template<typename T>
+ T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }
+ void setFETokenInfo(void *T) { FETokenInfo = T; }
+private:
+ void Destroy();
+};
+
+/// IdentifierTable - This table implements an efficient mapping from strings to
+/// IdentifierTokenInfo nodes. It has no other purpose, but this is an
+/// extremely performance-critical piece of the code, as each occurrance of
+/// every identifier goes through here when lexed.
+class IdentifierTable {
+ void *TheTable;
+ void *TheMemory;
+ unsigned NumIdentifiers;
+public:
+ IdentifierTable();
+ ~IdentifierTable();
+ /// get - Return the identifier token info for the specified named identifier.
+ ///
+ IdentifierTokenInfo &get(const char *NameStart, const char *NameEnd);
+ IdentifierTokenInfo &get(const std::string &Name);
+
+ /// PrintStats - Print some statistics to stderr that indicate how well the
+ /// hashing is doing.
+ void PrintStats() const;
+};
+
+} // end namespace llvm
+} // end namespace clang
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Lex/IdentifierTable.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Lex/Lexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Lexer.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Lexer.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/Lexer.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,416 @@
+//===--- Lexer.h - C Language Family Lexer ----------------------*- 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 Lexer and LexerToken interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEXER_H
+#define LLVM_CLANG_LEXER_H
+
+#include "clang/Basic/TokenKinds.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace clang {
+class Diagnostic;
+class Lexer;
+class Preprocessor;
+class SourceBuffer;
+class SourceLocation;
+class IdentifierTokenInfo;
+
+struct LangOptions {
+ unsigned Trigraphs : 1; // Trigraphs in source files.
+ unsigned BCPLComment : 1; // BCPL-style // comments.
+ unsigned DollarIdents : 1; // '$' allowed in identifiers.
+ unsigned Digraphs : 1; // When added to C? C99?
+ unsigned HexFloats : 1; // C99 Hexadecimal float constants.
+ unsigned C99 : 1; // C99 Support
+ unsigned CPlusPlus : 1; // C++ Support
+ unsigned CPPMinMax : 1; // C++ <?=, >?= tokens.
+ unsigned NoExtensions : 1; // All extensions are disabled, strict mode.
+
+ unsigned ObjC1 : 1; // Objective C 1 support enabled.
+ unsigned ObjC2 : 1; // Objective C 2 support enabled (implies ObjC1).
+
+ LangOptions() {
+ Trigraphs = BCPLComment = DollarIdents = Digraphs = ObjC1 = ObjC2 = 0;
+ C99 = CPlusPlus = CPPMinMax = NoExtensions = 0;
+ }
+};
+
+
+/// LexerToken - This structure provides full information about a lexed token.
+/// it is not intended to be space efficient, it is intended to return as much
+/// information as possible about each returned token. This is expected to be
+/// compressed into a smaller form if memory footprint is important.
+class LexerToken {
+ /// The start and end of the token text itself.
+ const char *Start, *End;
+
+ /// TheLexer - The lexer object this token came from.
+ const Lexer *TheLexer;
+
+ /// IdentifierInfo - If this was an identifier, this points to the uniqued
+ /// information about this identifier.
+ IdentifierTokenInfo *IdentifierInfo;
+
+ /// Kind - The actual flavor of token this is.
+ ///
+ tok::TokenKind Kind : 8;
+
+ /// Flags - Bits we track about this token, members of the TokenFlags enum.
+ unsigned Flags : 8;
+public:
+
+ // Various flags set per token:
+ enum TokenFlags {
+ StartOfLine = 0x01, // At start of line or only after whitespace.
+ LeadingSpace = 0x02, // Whitespace exists before this token.
+ NeedsCleaning = 0x04 // Contained an escaped newline or trigraph.
+ //#define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified.
+ //#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator.
+ };
+
+ tok::TokenKind getKind() const { return Kind; }
+ void SetKind(tok::TokenKind K) { Kind = K; }
+
+ const char *getStart() const { return Start; }
+ const char *getEnd() const { return End; }
+ void SetStart(const char *S) { Start = S; }
+ void SetEnd (const char *E) { End = E; }
+
+ const Lexer *getLexer() const { return TheLexer; }
+
+ /// ClearFlags - Reset all flags to cleared.
+ ///
+ void StartToken(const Lexer *L) {
+ Flags = 0;
+ IdentifierInfo = 0;
+ TheLexer = L;
+ }
+
+ /// ClearPosition - Mark this token as not having a position, FIXME temporary.
+ void ClearPosition() {
+ TheLexer = 0;
+ }
+
+ IdentifierTokenInfo *getIdentifierInfo() const { return IdentifierInfo; }
+ void SetIdentifierInfo(IdentifierTokenInfo *II) {
+ IdentifierInfo = II;
+ }
+
+ /// SetFlag - Set the specified flag.
+ void SetFlag(TokenFlags Flag) {
+ Flags |= Flag;
+ }
+
+ /// ClearFlag - Unset the specified flag.
+ void ClearFlag(TokenFlags Flag) {
+ Flags &= ~Flag;
+ }
+
+ /// SetFlagValue - Set a flag to either true or false.
+ void SetFlagValue(TokenFlags Flag, bool Val) {
+ if (Val)
+ SetFlag(Flag);
+ else
+ ClearFlag(Flag);
+ }
+
+ /// getSourceLocation - Return a source location identifier for the specified
+ /// offset in the current file.
+ SourceLocation getSourceLocation() const;
+
+ /// isAtStartOfLine - Return true if this token is at the start of a line.
+ ///
+ bool isAtStartOfLine() const { return Flags & StartOfLine; }
+
+ /// hasLeadingSpace - Return true if this token has whitespace before it.
+ ///
+ bool hasLeadingSpace() const { return Flags & LeadingSpace; }
+
+ /// needsCleaning - Return true if this token has trigraphs or escaped
+ /// newlines in it.
+ ///
+ bool needsCleaning() const { return Flags & NeedsCleaning; }
+
+ /// dump - Print the token to stderr, used for debugging.
+ ///
+ void dump(bool DumpFlags = false) const;
+};
+
+/// PPConditionalInfo - Information about the conditional stack (#if directives)
+/// currently active.
+struct PPConditionalInfo {
+ /// IfLoc - Location where the conditional started.
+ const char *IfLoc;
+
+ /// WasSkipping - True if this was contained in a skipping directive, e.g.
+ /// in a "#if 0" block.
+ bool WasSkipping;
+
+ /// FoundNonSkip - True if we have emitted tokens already, and now we're in
+ /// an #else block or something. Only useful in Skipping blocks.
+ bool FoundNonSkip;
+
+ /// FoundElse - True if we've seen a #else in this block. If so,
+ /// #elif/#else directives are not allowed.
+ bool FoundElse;
+};
+
+
+/// Lexer - This provides a simple interface that turns a text buffer into a
+/// stream of tokens. This provides no support for file reading or buffering,
+/// or buffering/seeking of tokens, only forward lexing is supported. It relies
+/// on the specified Preprocessor object to handle preprocessor directives, etc.
+class Lexer {
+ char PeekCharacter; // The current char we are peeking ahead.
+ const char *BufferPtr; // Current pointer into the buffer.
+ const char * const BufferStart;// Start of the buffer.
+ const char * const BufferEnd; // End of the buffer.
+ const SourceBuffer *InputFile; // The file we are reading from.
+ unsigned CurFileID; // FileID for the current input file.
+ Preprocessor &PP; // Preprocessor object controlling lexing.
+ LangOptions Features; // Features enabled by this language (cache).
+
+ // Context-specific lexing flags.
+ bool IsAtStartOfLine; // True if sitting at start of line.
+ bool ParsingPreprocessorDirective; // True if parsing #XXX
+ bool ParsingFilename; // True after #include: turn <xx> into string.
+
+ // Context that changes as the file is lexed.
+
+ /// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks
+ /// we are currently in.
+ std::vector<PPConditionalInfo> ConditionalStack;
+
+ friend class Preprocessor;
+public:
+
+ /// Lexer constructor - Create a new lexer object for the specified buffer
+ /// with the specified preprocessor managing the lexing process. This lexer
+ /// assumes that the specified SourceBuffer and Preprocessor objects will
+ /// outlive it, but doesn't take ownership of either pointer.
+ Lexer(const SourceBuffer *InBuffer, unsigned CurFileID, Preprocessor &PP);
+
+ /// getFeatures - Return the language features currently enabled. NOTE: this
+ /// lexer modifies features as a file is parsed!
+ const LangOptions &getFeatures() const { return Features; }
+
+ /// getCurFileID - Return the FileID for the file we are lexing out of. This
+ /// implicitly encodes the include path to get to the file.
+ unsigned getCurFileID() const { return CurFileID; }
+
+ /// Lex - Return the next token in the file. If this is the end of file, it
+ /// return the tok::eof token. Return true if an error occurred and
+ /// compilation should terminate, false if normal. This implicitly involves
+ /// the preprocessor.
+ bool Lex(LexerToken &Result) {
+ // Start a new token.
+ Result.StartToken(this);
+
+ // NOTE, any changes here should also change code after calls to
+ // Preprocessor::HandleDirective
+ if (IsAtStartOfLine) {
+ Result.SetFlag(LexerToken::StartOfLine);
+ IsAtStartOfLine = false;
+ }
+
+ // Get a token.
+ return LexTokenInternal(Result);
+ }
+
+ /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
+ /// (potentially) macro expand the filename. If the sequence parsed is not
+ /// lexically legal, emit a diagnostic and return a result EOM token.
+ bool LexIncludeFilename(LexerToken &Result);
+
+ /// ReadToEndOfLine - Read the rest of the current preprocessor line as an
+ /// uninterpreted string. This switches the lexer out of directive mode.
+ std::string ReadToEndOfLine();
+
+ /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
+ /// token is the characters used to represent the token in the source file
+ /// after trigraph expansion and escaped-newline folding. In particular, this
+ /// wants to get the true, uncanonicalized, spelling of things like digraphs
+ /// UCNs, etc.
+ static std::string getSpelling(const LexerToken &Tok,
+ const LangOptions &Features);
+ std::string getSpelling(const LexerToken &Tok) const {
+ assert(this && "Can't get the spelling of a token with a null lexer!");
+ return getSpelling(Tok, Features);
+ }
+
+ /// getSpelling - This method is used to get the spelling of a token into a
+ /// preallocated buffer, instead of as an std::string. The caller is required
+ /// to allocate enough space for the token, which is guaranteed to be at most
+ /// Tok.End-Tok.Start bytes long. The actual length of the token is returned.
+ static unsigned getSpelling(const LexerToken &Tok, char *Buffer,
+ const LangOptions &Features);
+ unsigned getSpelling(const LexerToken &Tok, char *Buffer) const {
+ assert(this && "Can't get the spelling of a token with a null lexer!");
+ return getSpelling(Tok, Buffer, Features);
+ }
+
+
+ /// Diag - Forwarding function for diagnostics. This translate a source
+ /// position in the current buffer into a SourceLocation object for rendering.
+ bool Diag(const char *Loc, unsigned DiagID,
+ const std::string &Msg = "") const;
+
+ /// getSourceLocation - Return a source location identifier for the specified
+ /// offset in the current file.
+ SourceLocation getSourceLocation(const char *Loc) const;
+
+ //===--------------------------------------------------------------------===//
+ // Internal implementation interfaces.
+private:
+
+ /// LexTokenInternal - Internal interface to lex a preprocessing token. Called
+ /// by Lex.
+ ///
+ bool LexTokenInternal(LexerToken &Result);
+
+
+ //===--------------------------------------------------------------------===//
+ // Lexer character reading interfaces.
+
+ // This lexer is built on two interfaces for reading characters, both of which
+ // automatically provide phase 1/2 translation. getAndAdvanceChar is used
+ // when we know that we will be reading a character from the input buffer and
+ // that this character will be part of the result token. This occurs in (f.e.)
+ // string processing, because we know we need to read until we find the
+ // closing '"' character.
+ //
+ // The second interface is the combination of PeekCharAndSize with
+ // ConsumeChar. PeekCharAndSize reads a phase 1/2 translated character,
+ // returning it and its size. If the lexer decides that this character is
+ // part of the current token, it calls ConsumeChar on it. This two stage
+ // approach allows us to emit diagnostics for characters (e.g. warnings about
+ // trigraphs), knowing that they only are emitted if the character is
+ // consumed.
+
+
+ /// getAndAdvanceChar - Read a single 'character' from the specified buffer,
+ /// advance over it, and return it. This is tricky in several cases. Here we
+ /// just handle the trivial case and fall-back to the non-inlined
+ /// getCharAndSizeSlow method to handle the hard case.
+ inline char getAndAdvanceChar(const char *&Ptr, LexerToken &Tok) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (Ptr[0] != '?' && Ptr[0] != '\\') return *Ptr++;
+
+ unsigned Size = 0;
+ char C = getCharAndSizeSlow(Ptr, Size, &Tok);
+ Ptr += Size;
+ return C;
+ }
+
+ /// ConsumeChar - When a character (identified by PeekCharAndSize) is consumed
+ /// and added to a given token, check to see if there are diagnostics that
+ /// need to be emitted or flags that need to be set on the token. If so, do
+ /// it.
+ const char *ConsumeChar(const char *Ptr, unsigned Size, LexerToken &Tok) {
+ // Normal case, we consumed exactly one token. Just return it.
+ if (Size == 1)
+ return Ptr+Size;
+
+ // Otherwise, re-lex the character with a current token, allowing
+ // diagnostics to be emitted and flags to be set.
+ Size = 0;
+ getCharAndSizeSlow(Ptr, Size, &Tok);
+ return Ptr+Size;
+ }
+
+ /// getCharAndSize - Peek a single 'character' from the specified buffer,
+ /// get its size, and return it. This is tricky in several cases. Here we
+ /// just handle the trivial case and fall-back to the non-inlined
+ /// getCharAndSizeSlow method to handle the hard case.
+ inline char getCharAndSize(const char *Ptr, unsigned &Size) {
+ // If this is not a trigraph and not a UCN or escaped newline, return
+ // quickly.
+ if (Ptr[0] != '?' && Ptr[0] != '\\') {
+ Size = 1;
+ return *Ptr;
+ }
+
+ Size = 0;
+ return getCharAndSizeSlow(Ptr, Size);
+ }
+
+ /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize
+ /// method.
+ char getCharAndSizeSlow(const char *Ptr, unsigned &Size, LexerToken *Tok = 0);
+
+
+ //===--------------------------------------------------------------------===//
+ // #if directive handling.
+
+ /// pushConditionalLevel - When we enter a #if directive, this keeps track of
+ /// what we are currently in for diagnostic emission (e.g. #if with missing
+ /// #endif).
+ void pushConditionalLevel(const char *DirectiveStart, bool WasSkipping,
+ bool FoundNonSkip, bool FoundElse) {
+ PPConditionalInfo CI;
+ CI.IfLoc = DirectiveStart;
+ CI.WasSkipping = WasSkipping;
+ CI.FoundNonSkip = FoundNonSkip;
+ CI.FoundElse = FoundElse;
+ ConditionalStack.push_back(CI);
+ }
+ void pushConditionalLevel(const PPConditionalInfo &CI) {
+ ConditionalStack.push_back(CI);
+ }
+
+ /// popConditionalLevel - Remove an entry off the top of the conditional
+ /// stack, returning information about it. If the conditional stack is empty,
+ /// this returns true and does not fill in the arguments.
+ bool popConditionalLevel(PPConditionalInfo &CI) {
+ if (ConditionalStack.empty()) return true;
+ CI = ConditionalStack.back();
+ ConditionalStack.pop_back();
+ return false;
+ }
+
+ /// peekConditionalLevel - Return the top of the conditional stack. This
+ /// requires that there be a conditional active.
+ PPConditionalInfo &peekConditionalLevel() {
+ assert(!ConditionalStack.empty() && "No conditionals active!");
+ return ConditionalStack.back();
+ }
+
+ unsigned getConditionalStackDepth() const { return ConditionalStack.size(); }
+
+ //===--------------------------------------------------------------------===//
+ // Other lexer functions.
+
+ // Part of block comment parsing.
+ bool isBlockCommentEndOfEscapedNewLine(const char *CurPtr, char &PrevChar);
+
+ // Helper functions to lex the remainder of a token of the specific type.
+ bool LexIdentifier (LexerToken &Result, const char *CurPtr);
+ bool LexNumericConstant (LexerToken &Result, const char *CurPtr);
+ bool LexStringLiteral (LexerToken &Result, const char *CurPtr);
+ bool LexAngledStringLiteral(LexerToken &Result, const char *CurPtr);
+ bool LexCharConstant (LexerToken &Result, const char *CurPtr);
+ bool LexEndOfFile (LexerToken &Result, const char *CurPtr);
+
+ bool SkipWhitespace (LexerToken &Result, const char *CurPtr);
+ bool SkipBCPLComment (LexerToken &Result, const char *CurPtr);
+ bool SkipBlockComment (LexerToken &Result, const char *CurPtr);
+};
+
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Lex/Lexer.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Lex/Lexer.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Lex/MacroExpander.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/MacroExpander.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/MacroExpander.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/MacroExpander.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,63 @@
+//===--- MacroExpander.h - Lex from a macro expansion -----------*- 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 MacroExpander interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_MACROEXPANDER_H
+#define LLVM_CLANG_MACROEXPANDER_H
+
+namespace llvm {
+namespace clang {
+ class MacroInfo;
+ class Preprocessor;
+ class LexerToken;
+
+/// MacroExpander - This implements a lexer that returns token from a macro body
+/// instead of lexing from a character buffer.
+///
+class MacroExpander {
+ /// Macro - The macro we are expanding from.
+ ///
+ MacroInfo &Macro;
+
+ /// CurMacroID - This encodes the instantiation point of the macro being
+ /// expanded and the include stack.
+ unsigned CurMacroID;
+
+ /// PP - The current preprocessor object we are expanding for.
+ ///
+ Preprocessor &PP;
+
+ /// CurToken - This is the next token that Lex will return.
+ unsigned CurToken;
+
+ /// Lexical information about the expansion point of the macro: the identifier
+ /// that the macro expanded from had these properties.
+ bool AtStartOfLine, HasLeadingSpace;
+
+public:
+ MacroExpander(MacroInfo ¯o, unsigned MacroID, Preprocessor &pp,
+ bool atStartOfLine, bool hasLeadingSpace)
+ : Macro(macro), CurMacroID(MacroID), PP(pp), CurToken(0),
+ AtStartOfLine(atStartOfLine), HasLeadingSpace(hasLeadingSpace) {
+ }
+
+ MacroInfo &getMacro() const { return Macro; }
+
+ /// Lex - Lex and return a token from this macro stream.
+ bool Lex(LexerToken &Tok);
+
+};
+
+} // end namespace llvm
+} // end namespace clang
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Lex/MacroExpander.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Lex/MacroExpander.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Lex/MacroInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/MacroInfo.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/MacroInfo.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/MacroInfo.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,106 @@
+//===--- MacroInfo.h - Information about #defined identifiers ---*- 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 MacroInfo interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_MACROINFO_H
+#define LLVM_CLANG_MACROINFO_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include <vector>
+
+namespace llvm {
+namespace clang {
+
+/// MacroInfo - Each identifier that is #define'd has an instance of this class
+/// associated with it, used to implement macro expansion.
+class MacroInfo {
+ /// Location - This is the place the macro is defined.
+ SourceLocation Location;
+
+ // TODO: Parameter list
+ // TODO: # parameters
+
+ /// ReplacementTokens - This is the list of tokens that the macro is defined
+ /// to.
+ std::vector<LexerToken> ReplacementTokens;
+
+ /// isDisabled - True if we have started an expansion of this macro already.
+ /// This disbles recursive expansion, which would be quite bad for things like
+ /// #define A A.
+ bool isDisabled;
+
+#if 0
+ /* Number of tokens in expansion, or bytes for traditional macros. */
+ unsigned int count;
+ /* Number of parameters. */
+ unsigned short paramc;
+ /* If a function-like macro. */
+ unsigned int fun_like : 1;
+ /* If a variadic macro. */
+ unsigned int variadic : 1;
+ /* Nonzero if it has been expanded or had its existence tested. */
+ unsigned int used : 1;
+ /* Indicate which field of 'exp' is in use. */
+ unsigned int traditional : 1;
+#endif
+public:
+ MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
+ isDisabled = false;
+ }
+
+ /// getNumTokens - Return the number of tokens that this macro expands to.
+ ///
+ unsigned getNumTokens() const {
+ return ReplacementTokens.size();
+ }
+
+ const LexerToken &getReplacementToken(unsigned Tok) const {
+ assert(Tok < ReplacementTokens.size() && "Invalid token #");
+ return ReplacementTokens[Tok];
+ }
+
+ /// AddTokenToBody - Add the specified token to the replacement text for the
+ /// macro.
+ void AddTokenToBody(const LexerToken &Tok) {
+ ReplacementTokens.push_back(Tok);
+ // FIXME: Remember where this token came from, do something intelligent with
+ // its location.
+ ReplacementTokens.back().ClearPosition();
+ }
+
+ /// isEnabled - Return true if this macro is enabled: in other words, that we
+ /// are not currently in an expansion of this macro.
+ bool isEnabled() const { return !isDisabled; }
+
+ void EnableMacro() {
+ assert(isDisabled && "Cannot enable an already-enabled macro!");
+ isDisabled = false;
+ }
+
+ void DisableMacro() {
+ assert(!isDisabled && "Cannot disable an already-disabled macro!");
+ isDisabled = true;
+ }
+
+ /// dump - Print the macro to stderr, used for debugging.
+ ///
+ void dump() const;
+
+ // Todo:
+ // bool isDefinedInSystemHeader() { Look this up based on Location }
+};
+
+} // end namespace llvm
+} // end namespace clang
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Lex/MacroInfo.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Lex/MacroInfo.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=38539&view=auto
==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Preprocessor.h (added)
+++ cfe/cfe/trunk/include/clang/Lex/Preprocessor.h Wed Jul 11 11:22:17 2007
@@ -0,0 +1,376 @@
+//===--- Preprocessor.h - C Language Family Preprocessor --------*- 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 Preprocessor interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PREPROCESSOR_H
+#define LLVM_CLANG_PREPROCESSOR_H
+
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/MacroExpander.h"
+#include "clang/Lex/IdentifierTable.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace llvm {
+namespace clang {
+
+class Lexer;
+class LexerToken;
+class SourceManager;
+class FileManager;
+class DirectoryEntry;
+class FileEntry;
+
+/// DirectoryLookup - This class is used to specify the search order for
+/// directories in #include directives.
+class DirectoryLookup {
+public:
+ enum DirType {
+ NormalHeaderDir,
+ SystemHeaderDir,
+ ExternCSystemHeaderDir
+ };
+private:
+ /// Dir - This is the actual directory that we're referring to.
+ ///
+ const DirectoryEntry *Dir;
+
+ /// DirCharacteristic - The type of directory this is, one of the DirType enum
+ /// values.
+ DirType DirCharacteristic : 2;
+
+ /// UserSupplied - True if this is a user-supplied directory.
+ ///
+ bool UserSupplied;
+public:
+ DirectoryLookup(const DirectoryEntry *dir, DirType DT, bool isUser)
+ : Dir(dir), DirCharacteristic(DT), UserSupplied(isUser) {}
+
+ /// getDir - Return the directory that this entry refers to.
+ ///
+ const DirectoryEntry *getDir() const { return Dir; }
+
+ /// DirCharacteristic - The type of directory this is, one of the DirType enum
+ /// values.
+ DirType getDirCharacteristic() const { return DirCharacteristic; }
+
+ /// isUserSupplied - True if this is a user-supplied directory.
+ ///
+ bool isUserSupplied() const { return UserSupplied; }
+};
+
+/// Preprocessor - This object forms engages in a tight little dance to
+/// efficiently preprocess tokens. Lexers know only about tokens within a
+/// single source file, and don't know anything about preprocessor-level issues
+/// like the #include stack, token expansion, etc.
+///
+class Preprocessor {
+ Diagnostic &Diags;
+ const LangOptions &Features;
+ FileManager &FileMgr;
+ SourceManager &SourceMgr;
+
+ // #include search path information. Requests for #include "x" search the
+ /// directory of the #including file first, then each directory in SearchDirs
+ /// consequtively. Requests for <x> search the current dir first, then each
+ /// directory in SearchDirs, starting at SystemDirIdx, consequtively. If
+ /// NoCurDirSearch is true, then the check for the file in the current
+ /// directory is supressed.
+ std::vector<DirectoryLookup> SearchDirs;
+ unsigned SystemDirIdx;
+ bool NoCurDirSearch;
+
+ enum {
+ /// MaxIncludeStackDepth - Maximum depth of #includes.
+ MaxAllowedIncludeStackDepth = 200
+ };
+
+ // State that changes while the preprocessor runs:
+ bool DisableMacroExpansion; // True if macro expansion is disabled.
+ bool SkippingContents; // True if in a #if 0 block.
+
+ /// IdentifierInfo - This is mapping/lookup information for all identifiers in
+ /// the program, including program keywords.
+ IdentifierTable IdentifierInfo;
+
+ /// 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;
+
+ /// CurDirLookup - The next DirectoryLookup structure to search for a file if
+ /// CurLexer is non-null. This allows us to implement #include_next.
+ const DirectoryLookup *CurNextDirLookup;
+
+ /// IncludeStack - This keeps track of the stack of files currently #included,
+ /// not counting CurLexer.
+ struct IncludeStackInfo {
+ Lexer *TheLexer;
+ const DirectoryLookup *TheDirLookup;
+ IncludeStackInfo(Lexer *L, const DirectoryLookup *D)
+ : TheLexer(L), TheDirLookup(D) {
+ }
+ };
+ std::vector<IncludeStackInfo> IncludeStack;
+
+ /// CurMacroExpander - This is the current macro we are expanding, if we are
+ /// expanding a macro. One of CurLexer and CurMacroExpander must be null.
+ MacroExpander *CurMacroExpander;
+
+ /// MacroStack - This keeps track of the macros that are recursively being
+ /// expanded.
+ std::vector<MacroExpander*> MacroStack;
+
+
+ /// PreFileInfo - The preprocessor keeps track of this information for each
+ /// file that is #included.
+ struct PerFileInfo {
+ // isImport - True if this is a #import'd or #pragma once file.
+ bool isImport;
+
+ // NumIncludes - This is the number of times the file has been included
+ // already.
+ unsigned short NumIncludes;
+
+ PerFileInfo() : isImport(false), NumIncludes(0) {}
+ };
+
+ /// FileInfo - This contains all of the preprocessor-specific data about files
+ /// that are included. The vector is indexed by the FileEntry's UID.
+ ///
+ std::vector<PerFileInfo> FileInfo;
+
+ // Various statistics we track for performance analysis.
+ unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma;
+ unsigned NumIf, NumElse, NumEndif;
+ unsigned NumEnteredSourceFiles, MaxIncludeStackDepth;
+ unsigned NumMacroExpanded, NumFastMacroExpanded, MaxMacroStackDepth;
+ unsigned NumSkipped;
+public:
+ Preprocessor(Diagnostic &diags, const LangOptions &opts, FileManager &FM,
+ SourceManager &SM);
+ ~Preprocessor();
+
+ Diagnostic &getDiagnostics() const { return Diags; }
+ const LangOptions &getLangOptions() const { return Features; }
+ FileManager &getFileManager() const { return FileMgr; }
+ SourceManager &getSourceManager() const { return SourceMgr; }
+
+ IdentifierTable &getIdentifierTable() { return IdentifierInfo; }
+
+ /// isSkipping - Return true if we're lexing a '#if 0' block. This causes
+ /// lexer errors/warnings to get ignored.
+ bool isSkipping() const { return SkippingContents; }
+
+ /// isCurrentLexer - Return true if we are lexing directly from the specified
+ /// lexer.
+ bool isCurrentLexer(const Lexer *L) const {
+ return CurLexer == L;
+ }
+
+ /// SetSearchPaths - Interface for setting the file search paths.
+ ///
+ void SetSearchPaths(const std::vector<DirectoryLookup> &dirs,
+ unsigned systemDirIdx, bool noCurDirSearch) {
+ SearchDirs = dirs;
+ SystemDirIdx = systemDirIdx;
+ NoCurDirSearch = noCurDirSearch;
+ }
+
+ /// getIdentifierInfo - Return information about the specified preprocessor
+ /// identifier token. The version of this method that takes two character
+ /// pointers is preferred unless the identifier is already available as a
+ /// string (this avoids allocation and copying of memory to construct an
+ /// std::string).
+ IdentifierTokenInfo *getIdentifierInfo(const char *NameStart,
+ const char *NameEnd) {
+ // If we are in a "#if 0" block, don't bother lookup up identifiers.
+ if (SkippingContents) return 0;
+ return &IdentifierInfo.get(NameStart, NameEnd);
+ }
+ IdentifierTokenInfo *getIdentifierInfo(const std::string &Name) {
+ // If we are in a "#if 0" block, don't bother lookup up identifiers.
+ if (SkippingContents) return 0;
+ return &IdentifierInfo.get(Name);
+ }
+
+ /// AddKeyword - This method is used to associate a token ID with specific
+ /// identifiers because they are language keywords. This causes the lexer to
+ /// automatically map matching identifiers to specialized token codes.
+ ///
+ /// The C90/C99/CPP flags are set to 0 if the token should be enabled in the
+ /// specified langauge, set to 1 if it is an extension in the specified
+ /// language, and set to 2 if disabled in the specified language.
+ void AddKeyword(const std::string &Keyword, tok::TokenKind TokenCode,
+ int C90, int C99, int CPP) {
+ int Flags = Features.CPlusPlus ? CPP : (Features.C99 ? C99 : C90);
+
+ // Don't add this keyword if disabled in this language or if an extension
+ // and extensions are disabled.
+ if (Flags+Features.NoExtensions >= 2) return;
+
+ IdentifierTokenInfo &Info = *getIdentifierInfo(Keyword);
+ Info.setTokenID(TokenCode);
+ Info.setIsExtensionToken(Flags == 1);
+ }
+
+ /// AddKeywords - Add all keywords to the symbol table.
+ ///
+ void AddKeywords();
+
+ /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
+ /// return null on failure. isSystem indicates whether the file reference is
+ /// for system #include's or not. If successful, this returns 'UsedDir', the
+ /// DirectoryLookup member the file was found in, or null if not applicable.
+ /// If FromDir is non-null, the directory search should start with the entry
+ /// after the indicated lookup. This is used to implement #include_next.
+ const FileEntry *LookupFile(const std::string &Filename, bool isSystem,
+ const DirectoryLookup *FromDir,
+ const DirectoryLookup *&NextDir);
+
+ /// EnterSourceFile - Add a source file to the top of the include stack and
+ /// start lexing tokens from it instead of the current buffer.
+ void EnterSourceFile(unsigned CurFileID, const DirectoryLookup *Dir);
+
+ /// EnterMacro - Add a Macro to the top of the include stack and start lexing
+ /// tokens from it instead of the current buffer. Return true on failure.
+ bool EnterMacro(LexerToken &Identifier);
+
+
+ /// Lex - To lex a token from the preprocessor, just pull a token from the
+ /// current lexer or macro object.
+ bool Lex(LexerToken &Result) {
+ if (CurLexer)
+ return CurLexer->Lex(Result);
+ else
+ return CurMacroExpander->Lex(Result);
+ }
+
+ /// LexUnexpandedToken - This is just like Lex, but this disables macro
+ /// expansion of identifier tokens.
+ bool LexUnexpandedToken(LexerToken &Result) {
+ // Disable macro expansion.
+ bool OldVal = DisableMacroExpansion;
+ DisableMacroExpansion = true;
+ // Lex the token.
+ bool ResVal = Lex(Result);
+
+ // Reenable it.
+ DisableMacroExpansion = OldVal;
+ return ResVal;
+ }
+
+ /// Diag - Forwarding function for diagnostics. This emits a diagnostic at
+ /// the specified LexerToken's location, translating the token's start
+ /// position in the current buffer into a SourcePosition object for rendering.
+ bool Diag(const LexerToken &Tok, unsigned DiagID, const std::string &Msg="");
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg="");
+
+ void PrintStats();
+
+ //===--------------------------------------------------------------------===//
+ // Preprocessor callback methods. These are invoked by a lexer as various
+ // directives and events are found.
+
+ /// HandleIdentifier - This callback is invoked when the lexer reads an
+ /// identifier and has filled in the tokens IdentifierInfo member. This
+ /// callback potentially macro expands it or turns it into a named token (like
+ /// 'for').
+ bool HandleIdentifier(LexerToken &Identifier);
+
+ /// HandleEndOfFile - This callback is invoked when the lexer hits the end of
+ /// the current file. This either returns the EOF token or pops a level off
+ /// the include stack and keeps going.
+ bool HandleEndOfFile(LexerToken &Result);
+
+ /// HandleEndOfMacro - This callback is invoked when the lexer hits the end of
+ /// the current macro. This either returns the EOF token or pops a level off
+ /// the include stack and keeps going.
+ bool HandleEndOfMacro(LexerToken &Result);
+
+ /// HandleDirective - This callback is invoked when the lexer sees a # token
+ /// at the start of a line. This consumes the directive, modifies the
+ /// lexer/preprocessor state, and advances the lexer(s) so that the next token
+ /// read is the correct one.
+ bool HandleDirective(LexerToken &Result);
+
+private:
+ /// getFileInfo - Return the PerFileInfo structure for the specified
+ /// FileEntry.
+ PerFileInfo &getFileInfo(const FileEntry *FE);
+
+ /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the
+ /// current line until the tok::eom token is found.
+ bool DiscardUntilEndOfDirective();
+
+ /// ReadMacroName - Lex and validate a macro name, which occurs after a
+ /// #define or #undef. This emits a diagnostic, sets the token kind to eom,
+ /// and discards the rest of the macro line if the macro name is invalid.
+ bool 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.
+ bool 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
+ /// FoundNonSkipPortion is true, then we have already emitted code for part of
+ /// this #if directive, so #else/#elif blocks should never be entered. If
+ /// FoundElse is false, then #else directives are ok, if not, then we have
+ /// already seen one so a #else directive is a duplicate. When this returns,
+ /// the caller can lex the first valid token.
+ bool SkipExcludedConditionalBlock(const char *IfTokenLoc,
+ bool FoundNonSkipPortion, bool FoundElse);
+
+ /// EvaluateDirectiveExpression - Evaluate an integer constant expression that
+ /// may occur after a #if or #elif directive. Sets Result to the result of
+ /// the expression. Returns false normally, true if lexing must be aborted.
+ bool EvaluateDirectiveExpression(bool &Result);
+ /// EvaluateValue - Used to implement EvaluateDirectiveExpression,
+ /// see PPExpressions.cpp.
+ bool EvaluateValue(int &Result, LexerToken &PeekTok, bool &StopParse);
+ /// EvaluateDirectiveSubExpr - Used to implement EvaluateDirectiveExpression,
+ /// see PPExpressions.cpp.
+ bool EvaluateDirectiveSubExpr(int &LHS, unsigned MinPrec,
+ LexerToken &PeekTok, bool &StopParse);
+
+ //===--------------------------------------------------------------------===//
+ /// Handle*Directive - implement the various preprocessor directives. These
+ /// should side-effect the current preprocessor object so that the next call
+ /// to Lex() will return the appropriate token next. If a fatal error occurs
+ /// return true, otherwise return false.
+
+ bool HandleUserDiagnosticDirective(LexerToken &Result, bool isWarning);
+
+ // File inclusion.
+ bool HandleIncludeDirective(LexerToken &Result,
+ const DirectoryLookup *LookupFrom = 0,
+ bool isImport = false);
+ bool HandleIncludeNextDirective(LexerToken &Result);
+ bool HandleImportDirective(LexerToken &Result);
+
+ // Macro handling.
+ bool HandleDefineDirective(LexerToken &Result);
+ bool HandleUndefDirective(LexerToken &Result);
+
+ // Conditional Inclusion.
+ bool HandleIfdefDirective(LexerToken &Result, bool isIfndef);
+ bool HandleIfDirective(LexerToken &Result);
+ bool HandleEndifDirective(LexerToken &Result);
+ bool HandleElseDirective(LexerToken &Result);
+ bool HandleElifDirective(LexerToken &Result);
+};
+
+} // end namespace clang
+} // end namespace llvm
+
+#endif
Propchange: cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
More information about the cfe-commits
mailing list