diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp index 0d83e7cdf1b..761985e410d 100644 --- a/utils/TableGen/TGLexer.cpp +++ b/utils/TableGen/TGLexer.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "TGLexer.h" +#include "TGSourceMgr.h" #include "llvm/Support/Streams.h" #include "llvm/Support/MemoryBuffer.h" #include @@ -23,18 +24,13 @@ #include using namespace llvm; -TGLexer::TGLexer(MemoryBuffer *StartBuf) : CurLineNo(1), CurBuf(StartBuf) { +TGLexer::TGLexer(TGSourceMgr &SM) : SrcMgr(SM) { + CurBuffer = 0; + CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); CurPtr = CurBuf->getBufferStart(); TokStart = 0; } -TGLexer::~TGLexer() { - while (!IncludeStack.empty()) { - delete IncludeStack.back().Buffer; - IncludeStack.pop_back(); - } - delete CurBuf; -} /// ReturnError - Set the error to the specified string at the specified /// location. This is defined to always return tgtok::Error. @@ -43,36 +39,9 @@ tgtok::TokKind TGLexer::ReturnError(const char *Loc, const std::string &Msg) { return tgtok::Error; } -void TGLexer::PrintIncludeStack(std::ostream &OS) const { - for (unsigned i = 0, e = IncludeStack.size(); i != e; ++i) - OS << "Included from " << IncludeStack[i].Buffer->getBufferIdentifier() - << ":" << IncludeStack[i].LineNo << ":\n"; - OS << "Parsing " << CurBuf->getBufferIdentifier() << ":" - << CurLineNo << ": "; -} -/// PrintError - Print the error at the specified location. -void TGLexer::PrintError(const char *ErrorLoc, const std::string &Msg) const { - PrintIncludeStack(*cerr.stream()); - cerr << Msg << "\n"; - assert(ErrorLoc && "Location not specified!"); - - // Scan backward to find the start of the line. - const char *LineStart = ErrorLoc; - while (LineStart != CurBuf->getBufferStart() && - LineStart[-1] != '\n' && LineStart[-1] != '\r') - --LineStart; - // Get the end of the line. - const char *LineEnd = ErrorLoc; - while (LineEnd != CurBuf->getBufferEnd() && - LineEnd[0] != '\n' && LineEnd[0] != '\r') - ++LineEnd; - // Print out the line. - cerr << std::string(LineStart, LineEnd) << "\n"; - // Print out spaces before the carat. - for (const char *Pos = LineStart; Pos != ErrorLoc; ++Pos) - cerr << (*Pos == '\t' ? '\t' : ' '); - cerr << "^\n"; +void TGLexer::PrintError(LocTy Loc, const std::string &Msg) const { + SrcMgr.PrintError(Loc, Msg); } int TGLexer::getNextChar() { @@ -80,7 +49,7 @@ int TGLexer::getNextChar() { switch (CurChar) { default: return (unsigned char)CurChar; - case 0: + case 0: { // A nul character in the stream is either the end of the current buffer or // a random nul in the file. Disambiguate that here. if (CurPtr-1 != CurBuf->getBufferEnd()) @@ -88,18 +57,18 @@ int TGLexer::getNextChar() { // If this is the end of an included file, pop the parent file off the // include stack. - if (!IncludeStack.empty()) { - delete CurBuf; - CurBuf = IncludeStack.back().Buffer; - CurLineNo = IncludeStack.back().LineNo; - CurPtr = IncludeStack.back().CurPtr; - IncludeStack.pop_back(); + TGLocTy ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); + if (ParentIncludeLoc != TGLocTy()) { + CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); + CurBuf = SrcMgr.getMemoryBuffer(CurBuffer); + CurPtr = ParentIncludeLoc; return getNextChar(); } // Otherwise, return end of file. --CurPtr; // Another call to lex will return EOF again. return EOF; + } case '\n': case '\r': // Handle the newline character by ignoring it and incrementing the line @@ -108,8 +77,6 @@ int TGLexer::getNextChar() { if ((*CurPtr == '\n' || (*CurPtr == '\r')) && *CurPtr != CurChar) ++CurPtr; // Eat the two char newline sequence. - - ++CurLineNo; return '\n'; } } @@ -272,9 +239,8 @@ bool TGLexer::LexInclude() { } // Save the line number and lex buffer of the includer. - IncludeStack.push_back(IncludeRec(CurBuf, CurPtr, CurLineNo)); + CurBuffer = SrcMgr.AddNewSourceBuffer(NewBuf, CurPtr); - CurLineNo = 1; // Reset line numbering. CurBuf = NewBuf; CurPtr = CurBuf->getBufferStart(); return false; diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h index 0e67f680557..59e9fa0ef5f 100644 --- a/utils/TableGen/TGLexer.h +++ b/utils/TableGen/TGLexer.h @@ -22,6 +22,7 @@ namespace llvm { class MemoryBuffer; +class TGSourceMgr; namespace tgtok { enum TokKind { @@ -55,33 +56,27 @@ namespace tgtok { /// TGLexer - TableGen Lexer class. class TGLexer { + TGSourceMgr &SrcMgr; + const char *CurPtr; - unsigned CurLineNo; - MemoryBuffer *CurBuf; + const MemoryBuffer *CurBuf; // Information about the current token. const char *TokStart; tgtok::TokKind CurCode; std::string CurStrVal; // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT int64_t CurIntVal; // This is valid for INTVAL. - - /// IncludeRec / IncludeStack - This captures the current set of include - /// directives we are nested within. - struct IncludeRec { - MemoryBuffer *Buffer; - const char *CurPtr; - unsigned LineNo; - IncludeRec(MemoryBuffer *buffer, const char *curPtr, unsigned lineNo) - : Buffer(buffer), CurPtr(curPtr), LineNo(lineNo) {} - }; - std::vector IncludeStack; + + /// CurBuffer - This is the current buffer index we're lexing from as managed + /// by the SourceMgr object. + int CurBuffer; // IncludeDirectories - This is the list of directories we should search for // include files in. std::vector IncludeDirectories; public: - TGLexer(MemoryBuffer *StartBuf); - ~TGLexer(); + TGLexer(TGSourceMgr &SrcMgr); + ~TGLexer() {} void setIncludeDirs(const std::vector &Dirs) { IncludeDirectories = Dirs; @@ -109,8 +104,6 @@ public: void PrintError(LocTy Loc, const std::string &Msg) const; - void PrintIncludeStack(std::ostream &OS) const; - private: /// LexToken - Read the next token and return its code. tgtok::TokKind LexToken(); diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h index edbc4c1fc9d..a1aa8a9c2b8 100644 --- a/utils/TableGen/TGParser.h +++ b/utils/TableGen/TGParser.h @@ -47,7 +47,7 @@ class TGParser { public: typedef TGLexer::LocTy LocTy; - TGParser(MemoryBuffer *StartBuf) : Lex(StartBuf), CurMultiClass(0) {} + TGParser(TGSourceMgr &SrcMgr) : Lex(SrcMgr), CurMultiClass(0) {} void setIncludeDirs(const std::vector &D){Lex.setIncludeDirs(D);} diff --git a/utils/TableGen/TGSourceMgr.cpp b/utils/TableGen/TGSourceMgr.cpp new file mode 100644 index 00000000000..1e0ab7e3683 --- /dev/null +++ b/utils/TableGen/TGSourceMgr.cpp @@ -0,0 +1,104 @@ +//===- TGSourceMgr.cpp - Manager for Source Buffers & Diagnostics ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TGSourceMgr class. +// +//===----------------------------------------------------------------------===// + +#include "TGSourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +TGSourceMgr::~TGSourceMgr() { + while (!Buffers.empty()) { + delete Buffers.back().Buffer; + Buffers.pop_back(); + } +} + +/// FindBufferContainingLoc - Return the ID of the buffer containing the +/// specified location, returning -1 if not found. +int TGSourceMgr::FindBufferContainingLoc(TGLocTy Loc) const { + for (unsigned i = 0, e = Buffers.size(); i != e; ++i) + if (Loc >= Buffers[i].Buffer->getBufferStart() && + Loc < Buffers[i].Buffer->getBufferEnd()) + return i; + return -1; +} + +/// FindLineNumber - Find the line number for the specified location in the +/// specified file. This is not a fast method. +unsigned TGSourceMgr::FindLineNumber(TGLocTy Loc, int BufferID) const { + if (BufferID == -1) BufferID = FindBufferContainingLoc(Loc); + assert(BufferID != -1 && "Invalid Location!"); + + MemoryBuffer *Buff = getBufferInfo(BufferID).Buffer; + + // Count the number of \n's between the start of the file and the specified + // location. + unsigned LineNo = 1; + + const char *Ptr = Buff->getBufferStart(); + + for (; Ptr != Loc; ++Ptr) + if (*Ptr == '\n') ++LineNo; + return LineNo; +} + +void TGSourceMgr::PrintIncludeStack(TGLocTy IncludeLoc) const { + if (IncludeLoc == TGLocTy()) return; // Top of stack. + + int CurBuf = FindBufferContainingLoc(IncludeLoc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + + PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc); + + errs() << "Included from " + << getBufferInfo(CurBuf).Buffer->getBufferIdentifier() + << ":" << FindLineNumber(IncludeLoc, CurBuf) << ":\n"; +} + + +void TGSourceMgr::PrintError(TGLocTy ErrorLoc, const std::string &Msg) const { + raw_ostream &OS = errs(); + + // First thing to do: find the current buffer containing the specified + // location. + int CurBuf = FindBufferContainingLoc(ErrorLoc); + assert(CurBuf != -1 && "Invalid or unspecified location!"); + + PrintIncludeStack(getBufferInfo(CurBuf).IncludeLoc); + + MemoryBuffer *CurMB = getBufferInfo(CurBuf).Buffer; + + + OS << "Parsing " << CurMB->getBufferIdentifier() << ":" + << FindLineNumber(ErrorLoc, CurBuf) << ": "; + + OS << Msg << "\n"; + assert(ErrorLoc && "Location not specified!"); + + // Scan backward to find the start of the line. + const char *LineStart = ErrorLoc; + while (LineStart != CurMB->getBufferStart() && + LineStart[-1] != '\n' && LineStart[-1] != '\r') + --LineStart; + // Get the end of the line. + const char *LineEnd = ErrorLoc; + while (LineEnd != CurMB->getBufferEnd() && + LineEnd[0] != '\n' && LineEnd[0] != '\r') + ++LineEnd; + // Print out the line. + OS << std::string(LineStart, LineEnd) << "\n"; + // Print out spaces before the carat. + for (const char *Pos = LineStart; Pos != ErrorLoc; ++Pos) + OS << (*Pos == '\t' ? '\t' : ' '); + OS << "^\n"; +} diff --git a/utils/TableGen/TGSourceMgr.h b/utils/TableGen/TGSourceMgr.h new file mode 100644 index 00000000000..9a61a9b009f --- /dev/null +++ b/utils/TableGen/TGSourceMgr.h @@ -0,0 +1,88 @@ +//===- TGSourceMgr.h - Manager for Source Buffers & Diagnostics -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the TGSourceMgr class. +// +//===----------------------------------------------------------------------===// + +#ifndef TGSOURCEMGR_H +#define TGSOURCEMGR_H + +#include + +namespace llvm { + class MemoryBuffer; + +/// FIXME: Make this a struct that is opaque. +typedef const char *TGLocTy; + +/// TGSourceMgr - This owns the files read by tblgen, handles include stacks, +/// and handles printing of diagnostics. +class TGSourceMgr { + struct SrcBuffer { + /// Buffer - The memory buffer for the file. + MemoryBuffer *Buffer; + + /// IncludeLoc - This is the location of the parent include, or null if at + /// the top level. + TGLocTy IncludeLoc; + }; + + /// Buffers - This is all of the buffers that we are reading from. + std::vector Buffers; + + TGSourceMgr(const TGSourceMgr&); // DO NOT IMPLEMENT + void operator=(const TGSourceMgr&); // DO NOT IMPLEMENT +public: + TGSourceMgr() {} + ~TGSourceMgr(); + + const SrcBuffer &getBufferInfo(unsigned i) const { + assert(i < Buffers.size() && "Invalid Buffer ID!"); + return Buffers[i]; + } + + const MemoryBuffer *getMemoryBuffer(unsigned i) const { + assert(i < Buffers.size() && "Invalid Buffer ID!"); + return Buffers[i].Buffer; + } + + TGLocTy getParentIncludeLoc(unsigned i) const { + assert(i < Buffers.size() && "Invalid Buffer ID!"); + return Buffers[i].IncludeLoc; + } + + unsigned AddNewSourceBuffer(MemoryBuffer *F, TGLocTy IncludeLoc) { + SrcBuffer NB; + NB.Buffer = F; + NB.IncludeLoc = IncludeLoc; + Buffers.push_back(NB); + return Buffers.size()-1; + } + + /// FindBufferContainingLoc - Return the ID of the buffer containing the + /// specified location, returning -1 if not found. + int FindBufferContainingLoc(TGLocTy Loc) const; + + /// FindLineNumber - Find the line number for the specified location in the + /// specified file. This is not a fast method. + unsigned FindLineNumber(TGLocTy Loc, int BufferID = -1) const; + + + /// PrintError - Emit an error message about the specified location with the + /// specified string. + void PrintError(TGLocTy ErrorLoc, const std::string &Msg) const; + +private: + void PrintIncludeStack(TGLocTy IncludeLoc) const; +}; + +} // end llvm namespace + +#endif diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 147db12cf12..c6a1f2e4ab5 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -17,6 +17,7 @@ #include "Record.h" #include "TGParser.h" +#include "TGSourceMgr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Streams.h" #include "llvm/System/Signals.h" @@ -113,15 +114,19 @@ RecordKeeper llvm::Records; /// ParseFile - this function begins the parsing of the specified tablegen /// file. static bool ParseFile(const std::string &Filename, - const std::vector &IncludeDirs) { + const std::vector &IncludeDirs, + TGSourceMgr &SrcMgr) { std::string ErrorStr; MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); if (F == 0) { cerr << "Could not open input file '" + Filename + "': " << ErrorStr <<"\n"; return true; } - - TGParser Parser(F); + + // Tell SrcMgr about this buffer, which is what TGParser will pick up. + SrcMgr.AddNewSourceBuffer(F, TGLocTy()); + + TGParser Parser(SrcMgr); // Record the location of the include directory so that the lexer can find // it later. @@ -135,8 +140,10 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); + TGSourceMgr SrcMgr; + // Parse the input file. - if (ParseFile(InputFilename, IncludeDirs)) + if (ParseFile(InputFilename, IncludeDirs, SrcMgr)) return 1; std::ostream *Out = cout.stream();