#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cstring>
using namespace clang;
static void InitCharacterInfo();
bool Token::isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const {
if (IdentifierInfo *II = getIdentifierInfo())
return II->getObjCKeywordID() == objcKey;
return false;
}
tok::ObjCKeywordKind Token::getObjCKeywordID() const {
IdentifierInfo *specId = getIdentifierInfo();
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword;
}
void Lexer::anchor() { }
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
InitCharacterInfo();
BufferStart = BufStart;
BufferPtr = BufPtr;
BufferEnd = BufEnd;
assert(BufEnd[0] == 0 &&
"We assume that the input buffer has a null character at the end"
" to simplify lexing!");
if (BufferStart == BufferPtr) {
StringRef Buf(BufferStart, BufferEnd - BufferStart);
size_t BOMLength = llvm::StringSwitch<size_t>(Buf)
.StartsWith("\xEF\xBB\xBF", 3) .Default(0);
BufferPtr += BOMLength;
}
Is_PragmaLexer = false;
CurrentConflictMarkerState = CMK_None;
IsAtStartOfLine = true;
ParsingPreprocessorDirective = false;
ParsingFilename = false;
LexingRawMode = false;
ExtendedTokenMode = 0;
}
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
: PreprocessorLexer(&PP, FID),
FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)),
LangOpts(PP.getLangOpts()) {
InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
InputFile->getBufferEnd());
SetCommentRetentionState(PP.getCommentRetentionState());
}
Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts,
const char *BufStart, const char *BufPtr, const char *BufEnd)
: FileLoc(fileloc), LangOpts(langOpts) {
InitLexer(BufStart, BufPtr, BufEnd);
LexingRawMode = true;
}
Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile,
const SourceManager &SM, const LangOptions &langOpts)
: FileLoc(SM.getLocForStartOfFile(FID)), LangOpts(langOpts) {
InitLexer(FromFile->getBufferStart(), FromFile->getBufferStart(),
FromFile->getBufferEnd());
LexingRawMode = true;
}
Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
SourceLocation ExpansionLocStart,
SourceLocation ExpansionLocEnd,
unsigned TokLen, Preprocessor &PP) {
SourceManager &SM = PP.getSourceManager();
FileID SpellingFID = SM.getFileID(SpellingLoc);
const llvm::MemoryBuffer *InputFile = SM.getBuffer(SpellingFID);
Lexer *L = new Lexer(SpellingFID, InputFile, PP);
const char *StrData = SM.getCharacterData(SpellingLoc);
L->BufferPtr = StrData;
L->BufferEnd = StrData+TokLen;
assert(L->BufferEnd[0] == 0 && "Buffer is not nul terminated!");
L->FileLoc = SM.createExpansionLoc(SM.getLocForStartOfFile(SpellingFID),
ExpansionLocStart,
ExpansionLocEnd, TokLen);
L->ParsingPreprocessorDirective = true;
L->Is_PragmaLexer = true;
return L;
}
std::string Lexer::Stringify(const std::string &Str, bool Charify) {
std::string Result = Str;
char Quote = Charify ? '\'' : '"';
for (unsigned i = 0, e = Result.size(); i != e; ++i) {
if (Result[i] == '\\' || Result[i] == Quote) {
Result.insert(Result.begin()+i, '\\');
++i; ++e;
}
}
return Result;
}
void Lexer::Stringify(SmallVectorImpl<char> &Str) {
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
if (Str[i] == '\\' || Str[i] == '"') {
Str.insert(Str.begin()+i, '\\');
++i; ++e;
}
}
}
StringRef Lexer::getSpelling(SourceLocation loc,
SmallVectorImpl<char> &buffer,
const SourceManager &SM,
const LangOptions &options,
bool *invalid) {
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
bool invalidTemp = false;
StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
if (invalidTemp) {
if (invalid) *invalid = true;
return StringRef();
}
const char *tokenBegin = file.data() + locInfo.second;
Lexer lexer(SM.getLocForStartOfFile(locInfo.first), options,
file.begin(), tokenBegin, file.end());
Token token;
lexer.LexFromRawLexer(token);
unsigned length = token.getLength();
if (!token.needsCleaning())
return StringRef(tokenBegin, length);
buffer.clear();
buffer.reserve(length);
for (const char *ti = tokenBegin, *te = ti + length; ti != te; ) {
unsigned charSize;
buffer.push_back(Lexer::getCharAndSizeNoWarn(ti, charSize, options));
ti += charSize;
}
return StringRef(buffer.data(), buffer.size());
}
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
bool CharDataInvalid = false;
const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
&CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
if (CharDataInvalid)
return std::string();
if (!Tok.needsCleaning())
return std::string(TokStart, TokStart+Tok.getLength());
std::string Result;
Result.reserve(Tok.getLength());
for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
Ptr != End; ) {
unsigned CharSize;
Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts));
Ptr += CharSize;
}
assert(Result.size() != unsigned(Tok.getLength()) &&
"NeedsCleaning flag set on something that didn't need cleaning!");
return Result;
}
unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
const char *TokStart = 0;
if (Tok.is(tok::raw_identifier))
TokStart = Tok.getRawIdentifierData();
else if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
Buffer = II->getNameStart();
return II->getLength();
}
if (Tok.isLiteral())
TokStart = Tok.getLiteralData();
if (TokStart == 0) {
bool CharDataInvalid = false;
TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
if (CharDataInvalid) {
Buffer = "";
return 0;
}
}
if (!Tok.needsCleaning()) {
Buffer = TokStart;
return Tok.getLength();
}
char *OutBuf = const_cast<char*>(Buffer);
for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
Ptr != End; ) {
unsigned CharSize;
*OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts);
Ptr += CharSize;
}
assert(unsigned(OutBuf-Buffer) != Tok.getLength() &&
"NeedsCleaning flag set on something that didn't need cleaning!");
return OutBuf-Buffer;
}
static bool isWhitespace(unsigned char c);
unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
Loc = SM.getExpansionLoc(Loc);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return 0;
const char *StrData = Buffer.data()+LocInfo.second;
if (isWhitespace(StrData[0]))
return 0;
Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
Buffer.begin(), StrData, Buffer.end());
TheLexer.SetCommentRetentionState(true);
Token TheTok;
TheLexer.LexFromRawLexer(TheTok);
return TheTok.getLength();
}
static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
assert(Loc.isFileID());
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
if (LocInfo.first.isInvalid())
return Loc;
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
return Loc;
const char *BufStart = Buffer.data();
if (LocInfo.second >= Buffer.size())
return Loc;
const char *StrData = BufStart+LocInfo.second;
if (StrData[0] == '\n' || StrData[0] == '\r')
return Loc;
const char *LexStart = StrData;
while (LexStart != BufStart) {
if (LexStart[0] == '\n' || LexStart[0] == '\r') {
++LexStart;
break;
}
--LexStart;
}
SourceLocation LexerStartLoc = Loc.getLocWithOffset(-LocInfo.second);
Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end());
TheLexer.SetCommentRetentionState(true);
Token TheTok;
do {
TheLexer.LexFromRawLexer(TheTok);
if (TheLexer.getBufferLocation() > StrData) {
if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData)
return TheTok.getLocation();
break;
}
} while (TheTok.getKind() != tok::eof);
return Loc;
}
SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
if (Loc.isFileID())
return getBeginningOfFileToken(Loc, SM, LangOpts);
if (!SM.isMacroArgExpansion(Loc))
return Loc;
SourceLocation FileLoc = SM.getSpellingLoc(Loc);
SourceLocation BeginFileLoc = getBeginningOfFileToken(FileLoc, SM, LangOpts);
std::pair<FileID, unsigned> FileLocInfo = SM.getDecomposedLoc(FileLoc);
std::pair<FileID, unsigned> BeginFileLocInfo
= SM.getDecomposedLoc(BeginFileLoc);
assert(FileLocInfo.first == BeginFileLocInfo.first &&
FileLocInfo.second >= BeginFileLocInfo.second);
return Loc.getLocWithOffset(BeginFileLocInfo.second - FileLocInfo.second);
}
namespace {
enum PreambleDirectiveKind {
PDK_Skipped,
PDK_StartIf,
PDK_EndIf,
PDK_Unknown
};
}
std::pair<unsigned, bool>
Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer,
const LangOptions &LangOpts, unsigned MaxLines) {
const unsigned StartOffset = 1;
SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset);
Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(),
Buffer->getBufferStart(), Buffer->getBufferEnd());
SourceLocation StartLoc = TheLexer.getSourceLocation();
bool InPreprocessorDirective = false;
Token TheTok;
Token IfStartTok;
unsigned IfCount = 0;
unsigned MaxLineOffset = 0;
if (MaxLines) {
const char *CurPtr = Buffer->getBufferStart();
unsigned CurLine = 0;
while (CurPtr != Buffer->getBufferEnd()) {
char ch = *CurPtr++;
if (ch == '\n') {
++CurLine;
if (CurLine == MaxLines)
break;
}
}
if (CurPtr != Buffer->getBufferEnd())
MaxLineOffset = CurPtr - Buffer->getBufferStart();
}
do {
TheLexer.LexFromRawLexer(TheTok);
if (InPreprocessorDirective) {
if (TheTok.getKind() == tok::eof) {
break;
}
if (!TheTok.isAtStartOfLine())
continue;
InPreprocessorDirective = false;
}
if (TheTok.isAtStartOfLine()) {
unsigned TokOffset = TheTok.getLocation().getRawEncoding() - StartOffset;
if (MaxLineOffset && TokOffset >= MaxLineOffset)
break;
}
if (TheTok.getKind() == tok::comment)
continue;
if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) {
Token HashTok = TheTok;
InPreprocessorDirective = true;
TheLexer.LexFromRawLexer(TheTok);
if (TheTok.getKind() == tok::raw_identifier && !TheTok.needsCleaning()) {
StringRef Keyword(TheTok.getRawIdentifierData(),
TheTok.getLength());
PreambleDirectiveKind PDK
= llvm::StringSwitch<PreambleDirectiveKind>(Keyword)
.Case("include", PDK_Skipped)
.Case("__include_macros", PDK_Skipped)
.Case("define", PDK_Skipped)
.Case("undef", PDK_Skipped)
.Case("line", PDK_Skipped)
.Case("error", PDK_Skipped)
.Case("pragma", PDK_Skipped)
.Case("import", PDK_Skipped)
.Case("include_next", PDK_Skipped)
.Case("warning", PDK_Skipped)
.Case("ident", PDK_Skipped)
.Case("sccs", PDK_Skipped)
.Case("assert", PDK_Skipped)
.Case("unassert", PDK_Skipped)
.Case("if", PDK_StartIf)
.Case("ifdef", PDK_StartIf)
.Case("ifndef", PDK_StartIf)
.Case("elif", PDK_Skipped)
.Case("else", PDK_Skipped)
.Case("endif", PDK_EndIf)
.Default(PDK_Unknown);
switch (PDK) {
case PDK_Skipped:
continue;
case PDK_StartIf:
if (IfCount == 0)
IfStartTok = HashTok;
++IfCount;
continue;
case PDK_EndIf:
if (IfCount == 0)
break;
--IfCount;
continue;
case PDK_Unknown:
break;
}
}
InPreprocessorDirective = false;
TheTok = HashTok;
}
break;
} while (true);
SourceLocation End = IfCount? IfStartTok.getLocation() : TheTok.getLocation();
return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(),
IfCount? IfStartTok.isAtStartOfLine()
: TheTok.isAtStartOfLine());
}
SourceLocation Lexer::AdvanceToTokenCharacter(SourceLocation TokStart,
unsigned CharNo,
const SourceManager &SM,
const LangOptions &LangOpts) {
bool Invalid = false;
const char *TokPtr = SM.getCharacterData(TokStart, &Invalid);
if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr)))
return TokStart;
unsigned PhysOffset = 0;
while (Lexer::isObviouslySimpleCharacter(*TokPtr)) {
if (CharNo == 0)
return TokStart.getLocWithOffset(PhysOffset);
++TokPtr, --CharNo, ++PhysOffset;
}
for (; CharNo; --CharNo) {
unsigned Size;
Lexer::getCharAndSizeNoWarn(TokPtr, Size, LangOpts);
TokPtr += Size;
PhysOffset += Size;
}
if (!Lexer::isObviouslySimpleCharacter(*TokPtr))
PhysOffset += Lexer::SkipEscapedNewLines(TokPtr)-TokPtr;
return TokStart.getLocWithOffset(PhysOffset);
}
SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
const SourceManager &SM,
const LangOptions &LangOpts) {
if (Loc.isInvalid())
return SourceLocation();
if (Loc.isMacroID()) {
if (Offset > 0 || !isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation(); }
unsigned Len = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
if (Len > Offset)
Len = Len - Offset;
else
return Loc;
return Loc.getLocWithOffset(Len);
}
bool Lexer::isAtStartOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
const LangOptions &LangOpts,
SourceLocation *MacroBegin) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
std::pair<FileID, unsigned> infoLoc = SM.getDecomposedLoc(loc);
if (infoLoc.second > 0)
return false;
SourceLocation expansionLoc =
SM.getSLocEntry(infoLoc.first).getExpansion().getExpansionLocStart();
if (expansionLoc.isFileID()) {
if (MacroBegin)
*MacroBegin = expansionLoc;
return true;
}
return isAtStartOfMacroExpansion(expansionLoc, SM, LangOpts, MacroBegin);
}
bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc,
const SourceManager &SM,
const LangOptions &LangOpts,
SourceLocation *MacroEnd) {
assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
SourceLocation spellLoc = SM.getSpellingLoc(loc);
unsigned tokLen = MeasureTokenLength(spellLoc, SM, LangOpts);
if (tokLen == 0)
return false;
FileID FID = SM.getFileID(loc);
SourceLocation afterLoc = loc.getLocWithOffset(tokLen+1);
if (SM.isInFileID(afterLoc, FID))
return false;
SourceLocation expansionLoc =
SM.getSLocEntry(FID).getExpansion().getExpansionLocEnd();
if (expansionLoc.isFileID()) {
if (MacroEnd)
*MacroEnd = expansionLoc;
return true;
}
return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd);
}
static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range,
const SourceManager &SM,
const LangOptions &LangOpts) {
SourceLocation Begin = Range.getBegin();
SourceLocation End = Range.getEnd();
assert(Begin.isFileID() && End.isFileID());
if (Range.isTokenRange()) {
End = Lexer::getLocForEndOfToken(End, 0, SM,LangOpts);
if (End.isInvalid())
return CharSourceRange();
}
FileID FID;
unsigned BeginOffs;
llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
if (FID.isInvalid())
return CharSourceRange();
unsigned EndOffs;
if (!SM.isInFileID(End, FID, &EndOffs) ||
BeginOffs > EndOffs)
return CharSourceRange();
return CharSourceRange::getCharRange(Begin, End);
}
CharSourceRange Lexer::makeFileCharRange(CharSourceRange Range,
const SourceManager &SM,
const LangOptions &LangOpts) {
SourceLocation Begin = Range.getBegin();
SourceLocation End = Range.getEnd();
if (Begin.isInvalid() || End.isInvalid())
return CharSourceRange();
if (Begin.isFileID() && End.isFileID())
return makeRangeFromFileLocs(Range, SM, LangOpts);
if (Begin.isMacroID() && End.isFileID()) {
if (!isAtStartOfMacroExpansion(Begin, SM, LangOpts, &Begin))
return CharSourceRange();
Range.setBegin(Begin);
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
if (Begin.isFileID() && End.isMacroID()) {
if ((Range.isTokenRange() && !isAtEndOfMacroExpansion(End, SM, LangOpts,
&End)) ||
(Range.isCharRange() && !isAtStartOfMacroExpansion(End, SM, LangOpts,
&End)))
return CharSourceRange();
Range.setEnd(End);
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
assert(Begin.isMacroID() && End.isMacroID());
SourceLocation MacroBegin, MacroEnd;
if (isAtStartOfMacroExpansion(Begin, SM, LangOpts, &MacroBegin) &&
((Range.isTokenRange() && isAtEndOfMacroExpansion(End, SM, LangOpts,
&MacroEnd)) ||
(Range.isCharRange() && isAtStartOfMacroExpansion(End, SM, LangOpts,
&MacroEnd)))) {
Range.setBegin(MacroBegin);
Range.setEnd(MacroEnd);
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
FileID FID;
unsigned BeginOffs;
llvm::tie(FID, BeginOffs) = SM.getDecomposedLoc(Begin);
if (FID.isInvalid())
return CharSourceRange();
unsigned EndOffs;
if (!SM.isInFileID(End, FID, &EndOffs) ||
BeginOffs > EndOffs)
return CharSourceRange();
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
if (Expansion.isMacroArgExpansion() &&
Expansion.getSpellingLoc().isFileID()) {
SourceLocation SpellLoc = Expansion.getSpellingLoc();
Range.setBegin(SpellLoc.getLocWithOffset(BeginOffs));
Range.setEnd(SpellLoc.getLocWithOffset(EndOffs));
return makeRangeFromFileLocs(Range, SM, LangOpts);
}
return CharSourceRange();
}
StringRef Lexer::getSourceText(CharSourceRange Range,
const SourceManager &SM,
const LangOptions &LangOpts,
bool *Invalid) {
Range = makeFileCharRange(Range, SM, LangOpts);
if (Range.isInvalid()) {
if (Invalid) *Invalid = true;
return StringRef();
}
std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Range.getBegin());
if (beginInfo.first.isInvalid()) {
if (Invalid) *Invalid = true;
return StringRef();
}
unsigned EndOffs;
if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) ||
beginInfo.second > EndOffs) {
if (Invalid) *Invalid = true;
return StringRef();
}
bool invalidTemp = false;
StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp);
if (invalidTemp) {
if (Invalid) *Invalid = true;
return StringRef();
}
if (Invalid) *Invalid = false;
return file.substr(beginInfo.second, EndOffs - beginInfo.second);
}
StringRef Lexer::getImmediateMacroName(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
assert(Loc.isMacroID() && "Only reasonble to call this on macros");
while (1) {
FileID FID = SM.getFileID(Loc);
const SrcMgr::SLocEntry *E = &SM.getSLocEntry(FID);
const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
Loc = Expansion.getExpansionLocStart();
if (!Expansion.isMacroArgExpansion())
break;
Loc = SM.getImmediateExpansionRange(Loc).first;
SourceLocation SpellLoc = Expansion.getSpellingLoc();
if (SpellLoc.isFileID())
break;
FileID MacroFID = SM.getFileID(Loc);
if (SM.isInFileID(SpellLoc, MacroFID))
break;
Loc = SpellLoc;
}
Loc = SM.getSpellingLoc(Loc);
std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
enum {
CHAR_HORZ_WS = 0x01, CHAR_VERT_WS = 0x02, CHAR_LETTER = 0x04, CHAR_NUMBER = 0x08, CHAR_UNDER = 0x10, CHAR_PERIOD = 0x20, CHAR_RAWDEL = 0x40 };
static const unsigned char CharInfo[256] =
{
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS,
CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 ,
CHAR_HORZ_WS, CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
0 , 0 , CHAR_RAWDEL , CHAR_RAWDEL ,
CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL ,
CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
CHAR_NUMBER , CHAR_NUMBER , CHAR_RAWDEL , CHAR_RAWDEL ,
CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER ,
0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0
};
static void InitCharacterInfo() {
static bool isInited = false;
if (isInited) return;
assert(CHAR_HORZ_WS == CharInfo[(int)' ']);
assert(CHAR_HORZ_WS == CharInfo[(int)'\t']);
assert(CHAR_HORZ_WS == CharInfo[(int)'\f']);
assert(CHAR_HORZ_WS == CharInfo[(int)'\v']);
assert(CHAR_VERT_WS == CharInfo[(int)'\n']);
assert(CHAR_VERT_WS == CharInfo[(int)'\r']);
assert(CHAR_UNDER == CharInfo[(int)'_']);
assert(CHAR_PERIOD == CharInfo[(int)'.']);
for (unsigned i = 'a'; i <= 'z'; ++i) {
assert(CHAR_LETTER == CharInfo[i]);
assert(CHAR_LETTER == CharInfo[i+'A'-'a']);
}
for (unsigned i = '0'; i <= '9'; ++i)
assert(CHAR_NUMBER == CharInfo[i]);
isInited = true;
}
static inline bool isIdentifierHead(unsigned char c) {
return (CharInfo[c] & (CHAR_LETTER|CHAR_UNDER)) ? true : false;
}
static inline bool isIdentifierBody(unsigned char c) {
return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER)) ? true : false;
}
static inline bool isHorizontalWhitespace(unsigned char c) {
return (CharInfo[c] & CHAR_HORZ_WS) ? true : false;
}
static inline bool isVerticalWhitespace(unsigned char c) {
return (CharInfo[c] & CHAR_VERT_WS) ? true : false;
}
static inline bool isWhitespace(unsigned char c) {
return (CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS)) ? true : false;
}
static inline bool isNumberBody(unsigned char c) {
return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ?
true : false;
}
static inline bool isRawStringDelimBody(unsigned char c) {
return (CharInfo[c] &
(CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL)) ?
true : false;
}
bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) {
return isIdentifierBody(c) || (c == '$' && LangOpts.DollarIdents);
}
static LLVM_ATTRIBUTE_NOINLINE SourceLocation GetMappedTokenLoc(
Preprocessor &PP, SourceLocation FileLoc, unsigned CharNo, unsigned TokLen);
static SourceLocation GetMappedTokenLoc(Preprocessor &PP,
SourceLocation FileLoc,
unsigned CharNo, unsigned TokLen) {
assert(FileLoc.isMacroID() && "Must be a macro expansion");
SourceManager &SM = PP.getSourceManager();
SourceLocation SpellingLoc = SM.getSpellingLoc(FileLoc);
SpellingLoc = SpellingLoc.getLocWithOffset(CharNo);
std::pair<SourceLocation,SourceLocation> II =
SM.getImmediateExpansionRange(FileLoc);
return SM.createExpansionLoc(SpellingLoc, II.first, II.second, TokLen);
}
SourceLocation Lexer::getSourceLocation(const char *Loc,
unsigned TokLen) const {
assert(Loc >= BufferStart && Loc <= BufferEnd &&
"Location out of range for this buffer!");
unsigned CharNo = Loc-BufferStart;
if (FileLoc.isFileID())
return FileLoc.getLocWithOffset(CharNo);
assert(PP && "This doesn't work on raw lexers");
return GetMappedTokenLoc(*PP, FileLoc, CharNo, TokLen);
}
DiagnosticBuilder Lexer::Diag(const char *Loc, unsigned DiagID) const {
return PP->Diag(getSourceLocation(Loc), DiagID);
}
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 '~';
}
}
static char DecodeTrigraphChar(const char *CP, Lexer *L) {
char Res = GetTrigraphCharForLetter(*CP);
if (!Res || !L) return Res;
if (!L->getLangOpts().Trigraphs) {
if (!L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_ignored);
return 0;
}
if (!L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_converted) << StringRef(&Res, 1);
return Res;
}
unsigned Lexer::getEscapedNewLineSize(const char *Ptr) {
unsigned Size = 0;
while (isWhitespace(Ptr[Size])) {
++Size;
if (Ptr[Size-1] != '\n' && Ptr[Size-1] != '\r')
continue;
if ((Ptr[Size] == '\r' || Ptr[Size] == '\n') &&
Ptr[Size-1] != Ptr[Size])
++Size;
return Size;
}
return 0;
}
const char *Lexer::SkipEscapedNewLines(const char *P) {
while (1) {
const char *AfterEscape;
if (*P == '\\') {
AfterEscape = P+1;
} else if (*P == '?') {
if (P[1] != '?' || P[2] != '/')
return P;
AfterEscape = P+3;
} else {
return P;
}
unsigned NewLineSize = Lexer::getEscapedNewLineSize(AfterEscape);
if (NewLineSize == 0) return P;
P = AfterEscape+NewLineSize;
}
}
SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
tok::TokenKind TKind,
const SourceManager &SM,
const LangOptions &LangOpts,
bool SkipTrailingWhitespaceAndNewLine) {
if (Loc.isMacroID()) {
if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
return SourceLocation();
}
Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
bool InvalidTemp = false;
llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
if (InvalidTemp)
return SourceLocation();
const char *TokenBegin = File.data() + LocInfo.second;
Lexer lexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
TokenBegin, File.end());
Token Tok;
lexer.LexFromRawLexer(Tok);
if (Tok.isNot(TKind))
return SourceLocation();
SourceLocation TokenLoc = Tok.getLocation();
unsigned NumWhitespaceChars = 0;
if (SkipTrailingWhitespaceAndNewLine) {
const char *TokenEnd = SM.getCharacterData(TokenLoc) +
Tok.getLength();
unsigned char C = *TokenEnd;
while (isHorizontalWhitespace(C)) {
C = *(++TokenEnd);
NumWhitespaceChars++;
}
if (C == '\n' || C == '\r') {
char PrevC = C;
C = *(++TokenEnd);
NumWhitespaceChars++;
if ((C == '\n' || C == '\r') && C != PrevC)
NumWhitespaceChars++;
}
}
return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars);
}
char Lexer::getCharAndSizeSlow(const char *Ptr, unsigned &Size,
Token *Tok) {
if (Ptr[0] == '\\') {
++Size;
++Ptr;
Slash:
if (!isWhitespace(Ptr[0])) return '\\';
if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
if (Tok) Tok->setFlag(Token::NeedsCleaning);
if (Ptr[0] != '\n' && Ptr[0] != '\r' && Tok && !isLexingRawMode())
Diag(Ptr, diag::backslash_newline_space);
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
return ' ';
return getCharAndSizeSlow(Ptr, Size, Tok);
}
return '\\';
}
if (Ptr[0] == '?' && Ptr[1] == '?') {
if (char C = DecodeTrigraphChar(Ptr+2, Tok ? this : 0)) {
if (Tok) Tok->setFlag(Token::NeedsCleaning);
Ptr += 3;
Size += 3;
if (C == '\\') goto Slash;
return C;
}
}
++Size;
return *Ptr;
}
char Lexer::getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size,
const LangOptions &LangOpts) {
if (Ptr[0] == '\\') {
++Size;
++Ptr;
Slash:
if (!isWhitespace(Ptr[0])) return '\\';
if (unsigned EscapedNewLineSize = getEscapedNewLineSize(Ptr)) {
Size += EscapedNewLineSize;
Ptr += EscapedNewLineSize;
if (*Ptr == '\n' || *Ptr == '\r' || *Ptr == '\0')
return ' ';
return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts);
}
return '\\';
}
if (LangOpts.Trigraphs && Ptr[0] == '?' && Ptr[1] == '?') {
if (char C = GetTrigraphCharForLetter(Ptr[2])) {
Ptr += 3;
Size += 3;
if (C == '\\') goto Slash;
return C;
}
}
++Size;
return *Ptr;
}
void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
BufferPtr += Bytes;
if (BufferPtr > BufferEnd)
BufferPtr = BufferEnd;
IsAtStartOfLine = StartOfLine;
}
void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
unsigned Size;
unsigned char C = *CurPtr++;
while (isIdentifierBody(C))
C = *CurPtr++;
--CurPtr;
if (C != '\\' && C != '?' && (C != '$' || !LangOpts.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::raw_identifier);
Result.setRawIdentifierData(IdStart);
if (LexingRawMode)
return;
IdentifierInfo *II = PP->LookUpIdentifierInfo(Result);
if (II->isHandleIdentifierCase())
PP->HandleIdentifier(Result);
return;
}
C = getCharAndSize(CurPtr, Size);
while (1) {
if (C == '$') {
if (!LangOpts.DollarIdents) goto FinishIdentifier;
if (!isLexingRawMode())
Diag(CurPtr, diag::ext_dollar_in_identifier);
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
continue;
} else if (!isIdentifierBody(C)) { goto FinishIdentifier;
}
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
while (isIdentifierBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
}
}
}
bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) {
unsigned Size;
char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts);
if (C1 != '0')
return false;
char C2 = Lexer::getCharAndSizeNoWarn(Start + Size, Size, LangOpts);
return (C2 == 'x' || C2 == 'X');
}
void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
while (isNumberBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result);
PrevCh = C;
C = getCharAndSize(CurPtr, Size);
}
if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) {
if (!LangOpts.MicrosoftExt || !isHexaLiteral(BufferPtr, LangOpts))
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) {
bool IsHexFloat = true;
if (!LangOpts.C99) {
if (!isHexaLiteral(BufferPtr, LangOpts))
IsHexFloat = false;
else if (std::find(BufferPtr, CurPtr, '_') != CurPtr)
IsHexFloat = false;
}
if (IsHexFloat)
return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result));
}
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::numeric_constant);
Result.setLiteralData(TokStart);
}
const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
assert(getLangOpts().CPlusPlus);
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
if (isIdentifierHead(C)) {
if (!getLangOpts().CPlusPlus0x) {
if (!isLexingRawMode())
Diag(CurPtr,
C == '_' ? diag::warn_cxx11_compat_user_defined_literal
: diag::warn_cxx11_compat_reserved_user_defined_literal)
<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
return CurPtr;
}
if (C != '_') {
if (!isLexingRawMode())
Diag(CurPtr, getLangOpts().MicrosoftMode ?
diag::ext_ms_reserved_user_defined_literal :
diag::ext_reserved_user_defined_literal)
<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
return CurPtr;
}
Result.setFlag(Token::HasUDSuffix);
do {
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
} while (isIdentifierBody(C));
}
return CurPtr;
}
void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
const char *NulCharacter = 0;
if (!isLexingRawMode() &&
(Kind == tok::utf8_string_literal ||
Kind == tok::utf16_string_literal ||
Kind == tok::utf32_string_literal))
Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '"') {
if (C == '\\')
C = getAndAdvanceChar(CurPtr, Result);
if (C == '\n' || C == '\r' || (C == 0 && CurPtr-1 == BufferEnd)) { if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_string);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
}
if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return cutOffLexing();
}
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
}
if (getLangOpts().CPlusPlus)
CurPtr = LexUDSuffix(Result, CurPtr);
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_string);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
}
void Lexer::LexRawStringLiteral(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::warn_cxx98_compat_raw_string_literal);
unsigned PrefixLen = 0;
while (PrefixLen != 16 && isRawStringDelimBody(CurPtr[PrefixLen]))
++PrefixLen;
if (CurPtr[PrefixLen] != '(') {
if (!isLexingRawMode()) {
const char *PrefixEnd = &CurPtr[PrefixLen];
if (PrefixLen == 16) {
Diag(PrefixEnd, diag::err_raw_delim_too_long);
} else {
Diag(PrefixEnd, diag::err_invalid_char_raw_delim)
<< StringRef(PrefixEnd, 1);
}
}
while (1) {
char C = *CurPtr++;
if (C == '"')
break;
if (C == 0 && CurPtr-1 == BufferEnd) {
--CurPtr;
break;
}
}
FormTokenWithChars(Result, CurPtr, tok::unknown);
return;
}
const char *Prefix = CurPtr;
CurPtr += PrefixLen + 1;
while (1) {
char C = *CurPtr++;
if (C == ')') {
if (strncmp(CurPtr, Prefix, PrefixLen) == 0 && CurPtr[PrefixLen] == '"') {
CurPtr += PrefixLen + 1; break;
}
} else if (C == 0 && CurPtr-1 == BufferEnd) { if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_raw_string)
<< StringRef(Prefix, PrefixLen);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
}
}
if (getLangOpts().CPlusPlus)
CurPtr = LexUDSuffix(Result, CurPtr);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
}
void Lexer::LexAngledStringLiteral(Token &Result, const char *CurPtr) {
const char *NulCharacter = 0; const char *AfterLessPos = CurPtr;
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '>') {
if (C == '\\') {
getAndAdvanceChar(CurPtr, Result);
} else if (C == '\n' || C == '\r' || (C == 0 && (CurPtr-1 == BufferEnd || isCodeCompletionPoint(CurPtr-1)))) {
FormTokenWithChars(Result, AfterLessPos, tok::less);
return;
} else if (C == 0) {
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
}
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_string);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::angle_string_literal);
Result.setLiteralData(TokStart);
}
void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
tok::TokenKind Kind) {
const char *NulCharacter = 0;
if (!isLexingRawMode() &&
(Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_empty_character);
FormTokenWithChars(Result, CurPtr, tok::unknown);
return;
}
while (C != '\'') {
if (C == '\\') {
getAndAdvanceChar(CurPtr, Result);
} else if (C == '\n' || C == '\r' || (C == 0 && CurPtr-1 == BufferEnd)) { if (!isLexingRawMode() && !LangOpts.AsmPreprocessor)
Diag(BufferPtr, diag::ext_unterminated_char);
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return;
} else if (C == 0) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
FormTokenWithChars(Result, CurPtr-1, tok::unknown);
return cutOffLexing();
}
NulCharacter = CurPtr-1;
}
C = getAndAdvanceChar(CurPtr, Result);
}
if (getLangOpts().CPlusPlus)
CurPtr = LexUDSuffix(Result, CurPtr);
if (NulCharacter && !isLexingRawMode())
Diag(NulCharacter, diag::null_in_char);
const char *TokStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, Kind);
Result.setLiteralData(TokStart);
}
bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
unsigned char Char = *CurPtr; while (1) {
while (isHorizontalWhitespace(Char))
Char = *++CurPtr;
if (Char != '\n' && Char != '\r')
break;
if (ParsingPreprocessorDirective) {
BufferPtr = CurPtr;
return false;
}
Result.setFlag(Token::StartOfLine);
Result.clearFlag(Token::LeadingSpace);
Char = *++CurPtr;
}
char PrevChar = CurPtr[-1];
if (PrevChar != '\n' && PrevChar != '\r')
Result.setFlag(Token::LeadingSpace);
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
BufferPtr = CurPtr;
return false;
}
bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
if (!LangOpts.BCPLComment && !isLexingRawMode()) {
Diag(BufferPtr, diag::ext_bcpl_comment);
LangOpts.BCPLComment = true;
}
char C;
do {
C = *CurPtr;
while (C != 0 && C != '\n' && C != '\r') C = *++CurPtr;
const char *NextLine = CurPtr;
if (C != 0) {
const char *EscapePtr = CurPtr-1;
while (isHorizontalWhitespace(*EscapePtr)) --EscapePtr;
if (*EscapePtr == '\\') CurPtr = EscapePtr;
else if (EscapePtr[0] == '/' && EscapePtr[-1] == '?' &&
EscapePtr[-2] == '?') CurPtr = EscapePtr-2;
else
break; }
const char *OldPtr = CurPtr;
bool OldRawMode = isLexingRawMode();
LexingRawMode = true;
C = getAndAdvanceChar(CurPtr, Result);
LexingRawMode = OldRawMode;
if (C != 0 && CurPtr == OldPtr+1) {
CurPtr = NextLine;
break;
}
if (CurPtr != OldPtr+1 && C != '/' && CurPtr[0] != '/') {
for (; OldPtr != CurPtr; ++OldPtr)
if (OldPtr[0] == '\n' || OldPtr[0] == '\r') {
if (isWhitespace(C)) {
const char *ForwardPtr = CurPtr;
while (isWhitespace(*ForwardPtr)) ++ForwardPtr;
if (ForwardPtr[0] == '/' && ForwardPtr[1] == '/')
break;
}
if (!isLexingRawMode())
Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment);
break;
}
}
if (CurPtr == BufferEnd+1) {
--CurPtr;
break;
}
if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
cutOffLexing();
return false;
}
} while (C != '\n' && C != '\r');
if (PP && !isLexingRawMode() &&
PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; }
if (inKeepCommentMode())
return SaveBCPLComment(Result, CurPtr);
if (ParsingPreprocessorDirective || CurPtr == BufferEnd) {
BufferPtr = CurPtr;
return false;
}
++CurPtr;
Result.setFlag(Token::StartOfLine);
Result.clearFlag(Token::LeadingSpace);
BufferPtr = CurPtr;
return false;
}
bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, CurPtr, tok::comment);
if (!ParsingPreprocessorDirective || LexingRawMode)
return true;
bool Invalid = false;
std::string Spelling = PP->getSpelling(Result, &Invalid);
if (Invalid)
return true;
assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?");
Spelling[1] = '*'; Spelling += "*/";
Result.setKind(tok::comment);
PP->CreateString(Spelling, Result,
Result.getLocation(), Result.getLocation());
return true;
}
static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
Lexer *L) {
assert(CurPtr[0] == '\n' || CurPtr[0] == '\r');
--CurPtr;
if (CurPtr[0] == '\n' || CurPtr[0] == '\r') {
if (CurPtr[0] == CurPtr[1])
return false;
--CurPtr;
}
bool HasSpace = false;
while (isHorizontalWhitespace(*CurPtr) || *CurPtr == 0) {
--CurPtr;
HasSpace = true;
}
if (*CurPtr == '\\') {
if (CurPtr[-1] != '*') return false;
} else {
if (CurPtr[0] != '/' || CurPtr[-1] != '?' || CurPtr[-2] != '?' ||
CurPtr[-3] != '*')
return false;
CurPtr -= 2;
if (!L->getLangOpts().Trigraphs) {
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::trigraph_ignored_block_comment);
return false;
}
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::trigraph_ends_block_comment);
}
if (!L->isLexingRawMode())
L->Diag(CurPtr, diag::escaped_newline_block_comment_end);
if (HasSpace && !L->isLexingRawMode())
L->Diag(CurPtr, diag::backslash_newline_space);
return true;
}
#ifdef __SSE2__
#include <emmintrin.h>
#elif __ALTIVEC__
#include <altivec.h>
#undef bool
#endif
bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
unsigned CharSize;
unsigned char C = getCharAndSize(CurPtr, CharSize);
CurPtr += CharSize;
if (C == 0 && CurPtr == BufferEnd+1) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_block_comment);
--CurPtr;
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
BufferPtr = CurPtr;
return false;
}
if (C == '/')
C = *CurPtr++;
while (1) {
if (CurPtr + 24 < BufferEnd &&
!(PP && PP->getCodeCompletionFileLoc() == FileLoc)) {
while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
C = *CurPtr++;
if (C == '/') goto FoundSlash;
#ifdef __SSE2__
__m128i Slashes = _mm_set1_epi8('/');
while (CurPtr+16 <= BufferEnd) {
int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr,
Slashes));
if (cmp != 0) {
CurPtr += llvm::CountTrailingZeros_32(cmp) + 1;
goto FoundSlash;
}
CurPtr += 16;
}
#elif __ALTIVEC__
__vector unsigned char Slashes = {
'/', '/', '/', '/', '/', '/', '/', '/',
'/', '/', '/', '/', '/', '/', '/', '/'
};
while (CurPtr+16 <= BufferEnd &&
!vec_any_eq(*(vector unsigned char*)CurPtr, Slashes))
CurPtr += 16;
#else
while (CurPtr[0] != '/' &&
CurPtr[1] != '/' &&
CurPtr[2] != '/' &&
CurPtr[3] != '/' &&
CurPtr+4 < BufferEnd) {
CurPtr += 4;
}
#endif
C = *CurPtr++;
}
while (C != '/' && C != '\0')
C = *CurPtr++;
if (C == '/') {
FoundSlash:
if (CurPtr[-2] == '*') break;
if ((CurPtr[-2] == '\n' || CurPtr[-2] == '\r')) {
if (isEndOfBlockCommentWithEscapedNewLine(CurPtr-2, this)) {
break;
}
}
if (CurPtr[0] == '*' && CurPtr[1] != '/') {
if (!isLexingRawMode())
Diag(CurPtr-1, diag::warn_nested_block_comment);
}
} else if (C == 0 && CurPtr == BufferEnd+1) {
if (!isLexingRawMode())
Diag(BufferPtr, diag::err_unterminated_block_comment);
--CurPtr;
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return true;
}
BufferPtr = CurPtr;
return false;
} else if (C == '\0' && isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
cutOffLexing();
return false;
}
C = *CurPtr++;
}
if (PP && !isLexingRawMode() &&
PP->HandleComment(Result, SourceRange(getSourceLocation(BufferPtr),
getSourceLocation(CurPtr)))) {
BufferPtr = CurPtr;
return true; }
if (inKeepCommentMode()) {
FormTokenWithChars(Result, CurPtr, tok::comment);
return true;
}
if (isHorizontalWhitespace(*CurPtr)) {
Result.setFlag(Token::LeadingSpace);
SkipWhitespace(Result, CurPtr+1);
return false;
}
BufferPtr = CurPtr;
Result.setFlag(Token::LeadingSpace);
return false;
}
void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) {
assert(ParsingPreprocessorDirective && ParsingFilename == false &&
"Must be in a preprocessing directive!");
Token Tmp;
const char *CurPtr = BufferPtr;
while (1) {
char Char = getAndAdvanceChar(CurPtr, Tmp);
switch (Char) {
default:
if (Result)
Result->push_back(Char);
break;
case 0: if (CurPtr-1 != BufferEnd) {
if (isCodeCompletionPoint(CurPtr-1)) {
PP->CodeCompleteNaturalLanguage();
cutOffLexing();
return;
}
if (Result)
Result->push_back(Char);
break;
}
case '\r':
case '\n':
assert(CurPtr[-1] == Char && "Trigraphs for newline?");
BufferPtr = CurPtr-1;
Lex(Tmp);
if (Tmp.is(tok::code_completion)) {
if (PP)
PP->CodeCompleteNaturalLanguage();
Lex(Tmp);
}
assert(Tmp.is(tok::eod) && "Unexpected token!");
return;
}
}
}
bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
if (ParsingPreprocessorDirective) {
ParsingPreprocessorDirective = false;
FormTokenWithChars(Result, CurPtr, tok::eod);
SetCommentRetentionState(PP->getCommentRetentionState());
return true; }
if (isLexingRawMode()) {
Result.startToken();
BufferPtr = BufferEnd;
FormTokenWithChars(Result, BufferEnd, tok::eof);
return true;
}
while (!ConditionalStack.empty()) {
if (PP->getCodeCompletionFileLoc() != FileLoc)
PP->Diag(ConditionalStack.back().IfLoc,
diag::err_pp_unterminated_conditional);
ConditionalStack.pop_back();
}
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
Diag(BufferEnd, LangOpts.CPlusPlus0x ? diag::warn_cxx98_compat_no_newline_eof : diag::ext_no_newline_eof)
<< FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
BufferPtr = CurPtr;
return PP->HandleEndOfFile(Result, isPragmaLexer());
}
unsigned Lexer::isNextPPTokenLParen() {
assert(!LexingRawMode && "How can we expand a macro from a skipping buffer?");
LexingRawMode = true;
const char *TmpBufferPtr = BufferPtr;
bool inPPDirectiveMode = ParsingPreprocessorDirective;
Token Tok;
Tok.startToken();
LexTokenInternal(Tok);
BufferPtr = TmpBufferPtr;
ParsingPreprocessorDirective = inPPDirectiveMode;
LexingRawMode = false;
if (Tok.is(tok::eof))
return 2;
return Tok.is(tok::l_paren);
}
static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd,
ConflictMarkerKind CMK) {
const char *Terminator = CMK == CMK_Perforce ? "<<<<\n" : ">>>>>>>";
size_t TermLen = CMK == CMK_Perforce ? 5 : 7;
StringRef RestOfBuffer(CurPtr+TermLen, BufferEnd-CurPtr-TermLen);
size_t Pos = RestOfBuffer.find(Terminator);
while (Pos != StringRef::npos) {
if (RestOfBuffer[Pos-1] != '\r' &&
RestOfBuffer[Pos-1] != '\n') {
RestOfBuffer = RestOfBuffer.substr(Pos+TermLen);
Pos = RestOfBuffer.find(Terminator);
continue;
}
return RestOfBuffer.data()+Pos;
}
return 0;
}
bool Lexer::IsStartOfConflictMarker(const char *CurPtr) {
if (CurPtr != BufferStart &&
CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
return false;
if ((BufferEnd-CurPtr < 8 || StringRef(CurPtr, 7) != "<<<<<<<") &&
(BufferEnd-CurPtr < 6 || StringRef(CurPtr, 5) != ">>>> "))
return false;
if (CurrentConflictMarkerState || isLexingRawMode())
return false;
ConflictMarkerKind Kind = *CurPtr == '<' ? CMK_Normal : CMK_Perforce;
if (FindConflictEnd(CurPtr, BufferEnd, Kind)) {
Diag(CurPtr, diag::err_conflict_marker);
CurrentConflictMarkerState = Kind;
while (*CurPtr != '\r' && *CurPtr != '\n') {
assert(CurPtr != BufferEnd && "Didn't find end of line");
++CurPtr;
}
BufferPtr = CurPtr;
return true;
}
return false;
}
bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) {
if (CurPtr != BufferStart &&
CurPtr[-1] != '\n' && CurPtr[-1] != '\r')
return false;
if (!CurrentConflictMarkerState || isLexingRawMode())
return false;
for (unsigned i = 1; i != 4; ++i)
if (CurPtr[i] != CurPtr[0])
return false;
if (const char *End = FindConflictEnd(CurPtr, BufferEnd,
CurrentConflictMarkerState)) {
CurPtr = End;
while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n')
++CurPtr;
BufferPtr = CurPtr;
CurrentConflictMarkerState = CMK_None;
return true;
}
return false;
}
bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
if (PP && PP->isCodeCompletionEnabled()) {
SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
return Loc == PP->getCodeCompletionLoc();
}
return false;
}
void Lexer::LexTokenInternal(Token &Result) {
LexNextToken:
Result.clearFlag(Token::NeedsCleaning);
Result.setIdentifierInfo(0);
const char *CurPtr = BufferPtr;
if ((*CurPtr == ' ') || (*CurPtr == '\t')) {
++CurPtr;
while ((*CurPtr == ' ') || (*CurPtr == '\t'))
++CurPtr;
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
return;
}
BufferPtr = CurPtr;
Result.setFlag(Token::LeadingSpace);
}
unsigned SizeTmp, SizeTmp2;
char Char = getAndAdvanceChar(CurPtr, Result);
tok::TokenKind Kind;
switch (Char) {
case 0: if (CurPtr-1 == BufferEnd) {
Preprocessor *PPCache = PP;
if (LexEndOfFile(Result, CurPtr-1)) return; assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
return PPCache->Lex(Result);
}
if (isCodeCompletionPoint(CurPtr-1)) {
Result.startToken();
FormTokenWithChars(Result, CurPtr, tok::code_completion);
return;
}
if (!isLexingRawMode())
Diag(CurPtr-1, diag::null_in_file);
Result.setFlag(Token::LeadingSpace);
if (SkipWhitespace(Result, CurPtr))
return;
goto LexNextToken;
case 26: if (LangOpts.MicrosoftExt) {
Preprocessor *PPCache = PP;
if (LexEndOfFile(Result, CurPtr-1)) return; assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
return PPCache->Lex(Result);
}
Kind = tok::unknown;
break;
case '\n':
case '\r':
if (ParsingPreprocessorDirective) {
ParsingPreprocessorDirective = false;
if (PP)
SetCommentRetentionState(PP->getCommentRetentionState());
IsAtStartOfLine = true;
Kind = tok::eod;
break;
}
Result.setFlag(Token::StartOfLine);
Result.clearFlag(Token::LeadingSpace);
if (SkipWhitespace(Result, CurPtr))
return; goto LexNextToken; case ' ':
case '\t':
case '\f':
case '\v':
SkipHorizontalWhitespace:
Result.setFlag(Token::LeadingSpace);
if (SkipWhitespace(Result, CurPtr))
return;
SkipIgnoredUnits:
CurPtr = BufferPtr;
if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
LangOpts.BCPLComment && !LangOpts.TraditionalCPP) {
if (SkipBCPLComment(Result, CurPtr+2))
return; goto SkipIgnoredUnits;
} else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
if (SkipBlockComment(Result, CurPtr+2))
return; goto SkipIgnoredUnits;
} else if (isHorizontalWhitespace(*CurPtr)) {
goto SkipHorizontalWhitespace;
}
goto LexNextToken;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
MIOpt.ReadToken();
return LexNumericConstant(Result, CurPtr);
case 'u': MIOpt.ReadToken();
if (LangOpts.CPlusPlus0x) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf16_string_literal);
if (Char == '\'')
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf16_char_constant);
if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf16_string_literal);
if (Char == '8') {
char Char2 = getCharAndSize(CurPtr + SizeTmp, SizeTmp2);
if (Char2 == '"')
return LexStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf8_string_literal);
if (Char2 == 'R') {
unsigned SizeTmp3;
char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
if (Char3 == '"') {
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
SizeTmp3, Result),
tok::utf8_string_literal);
}
}
}
}
return LexIdentifier(Result, CurPtr);
case 'U': MIOpt.ReadToken();
if (LangOpts.CPlusPlus0x) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf32_string_literal);
if (Char == '\'')
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::utf32_char_constant);
if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::utf32_string_literal);
}
return LexIdentifier(Result, CurPtr);
case 'R': MIOpt.ReadToken();
if (LangOpts.CPlusPlus0x) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexRawStringLiteral(Result,
ConsumeChar(CurPtr, SizeTmp, Result),
tok::string_literal);
}
return LexIdentifier(Result, CurPtr);
case 'L': MIOpt.ReadToken();
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
return LexStringLiteral(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_string_literal);
if (LangOpts.CPlusPlus0x && Char == 'R' &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
tok::wide_string_literal);
if (Char == '\'')
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_char_constant);
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'S': case 'T':
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 'v': case 'w': case 'x': case 'y': case 'z':
case '_':
MIOpt.ReadToken();
return LexIdentifier(Result, CurPtr);
case '$': if (LangOpts.DollarIdents) {
if (!isLexingRawMode())
Diag(CurPtr-1, diag::ext_dollar_in_identifier);
MIOpt.ReadToken();
return LexIdentifier(Result, CurPtr);
}
Kind = tok::unknown;
break;
case '\'':
MIOpt.ReadToken();
return LexCharConstant(Result, CurPtr, tok::char_constant);
case '"':
MIOpt.ReadToken();
return LexStringLiteral(Result, CurPtr, tok::string_literal);
case '?':
Kind = tok::question;
break;
case '[':
Kind = tok::l_square;
break;
case ']':
Kind = tok::r_square;
break;
case '(':
Kind = tok::l_paren;
break;
case ')':
Kind = tok::r_paren;
break;
case '{':
Kind = tok::l_brace;
break;
case '}':
Kind = tok::r_brace;
break;
case '.':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char >= '0' && Char <= '9') {
MIOpt.ReadToken();
return LexNumericConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result));
} else if (LangOpts.CPlusPlus && Char == '*') {
Kind = tok::periodstar;
CurPtr += SizeTmp;
} else if (Char == '.' &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '.') {
Kind = tok::ellipsis;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else {
Kind = tok::period;
}
break;
case '&':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '&') {
Kind = tok::ampamp;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '=') {
Kind = tok::ampequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::amp;
}
break;
case '*':
if (getCharAndSize(CurPtr, SizeTmp) == '=') {
Kind = tok::starequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::star;
}
break;
case '+':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '+') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::plusplus;
} else if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::plusequal;
} else {
Kind = tok::plus;
}
break;
case '-':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '-') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::minusminus;
} else if (Char == '>' && LangOpts.CPlusPlus &&
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '*') { CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
Kind = tok::arrowstar;
} else if (Char == '>') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::arrow;
} else if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::minusequal;
} else {
Kind = tok::minus;
}
break;
case '~':
Kind = tok::tilde;
break;
case '!':
if (getCharAndSize(CurPtr, SizeTmp) == '=') {
Kind = tok::exclaimequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::exclaim;
}
break;
case '/':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '/') { if ((LangOpts.BCPLComment ||
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
!LangOpts.TraditionalCPP) {
if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return;
goto SkipIgnoredUnits;
}
}
if (Char == '*') { if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; goto LexNextToken; }
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::slashequal;
} else {
Kind = tok::slash;
}
break;
case '%':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
Kind = tok::percentequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_brace; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (LangOpts.Digraphs && Char == ':') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '%' && getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == ':') {
Kind = tok::hashhash; CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else if (Char == '@' && LangOpts.MicrosoftExt) { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
if (!isLexingRawMode())
Diag(BufferPtr, diag::ext_charize_microsoft);
Kind = tok::hashat;
} else { if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
Kind = tok::hash;
}
} else {
Kind = tok::percent;
}
break;
case '<':
Char = getCharAndSize(CurPtr, SizeTmp);
if (ParsingFilename) {
return LexAngledStringLiteral(Result, CurPtr);
} else if (Char == '<') {
char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
if (After == '=') {
Kind = tok::lesslessequal;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else if (After == '<' && IsStartOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (After == '<' && HandleEndOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (LangOpts.CUDA && After == '<') {
Kind = tok::lesslessless;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessless;
}
} else if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
} else if (LangOpts.Digraphs && Char == ':') { if (LangOpts.CPlusPlus0x &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') {
unsigned SizeTmp3;
char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
if (After != ':' && After != '>') {
Kind = tok::less;
if (!isLexingRawMode())
Diag(BufferPtr, diag::warn_cxx98_compat_less_colon_colon);
break;
}
}
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_square;
} else if (LangOpts.Digraphs && Char == '%') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::l_brace;
} else {
Kind = tok::less;
}
break;
case '>':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::greaterequal;
} else if (Char == '>') {
char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2);
if (After == '=') {
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
Kind = tok::greatergreaterequal;
} else if (After == '>' && IsStartOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) {
goto LexNextToken;
} else if (LangOpts.CUDA && After == '>') {
Kind = tok::greatergreatergreater;
CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result);
} else {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::greatergreater;
}
} else {
Kind = tok::greater;
}
break;
case '^':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::caretequal;
} else {
Kind = tok::caret;
}
break;
case '|':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
Kind = tok::pipeequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '|') {
if (CurPtr[1] == '|' && HandleEndOfConflictMarker(CurPtr-1))
goto LexNextToken;
Kind = tok::pipepipe;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::pipe;
}
break;
case ':':
Char = getCharAndSize(CurPtr, SizeTmp);
if (LangOpts.Digraphs && Char == '>') {
Kind = tok::r_square; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (LangOpts.CPlusPlus && Char == ':') {
Kind = tok::coloncolon;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::colon;
}
break;
case ';':
Kind = tok::semi;
break;
case '=':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '=') {
if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1))
goto LexNextToken;
Kind = tok::equalequal;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
Kind = tok::equal;
}
break;
case ',':
Kind = tok::comma;
break;
case '#':
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '#') {
Kind = tok::hashhash;
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else if (Char == '@' && LangOpts.MicrosoftExt) { Kind = tok::hashat;
if (!isLexingRawMode())
Diag(BufferPtr, diag::ext_charize_microsoft);
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
} else {
if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
goto HandleDirective;
Kind = tok::hash;
}
break;
case '@':
if (CurPtr[-1] == '@' && LangOpts.ObjC1)
Kind = tok::at;
else
Kind = tok::unknown;
break;
case '\\':
default:
Kind = tok::unknown;
break;
}
MIOpt.ReadToken();
FormTokenWithChars(Result, CurPtr, Kind);
return;
HandleDirective:
FormTokenWithChars(Result, CurPtr, tok::hash);
PP->HandleDirective(Result);
if (PP->isCurrentLexer(this)) {
if (IsAtStartOfLine) {
Result.setFlag(Token::StartOfLine);
Result.clearFlag(Token::LeadingSpace);
IsAtStartOfLine = false;
}
goto LexNextToken; }
return PP->Lex(Result);
}