llvm-project/clang/lib/Lex/TokenLexer.cpp
Chris Lattner 7c2e9809b1 Simplify raw mode lexing by treating an unterminate /**/ comment the
same we we do an unterminated string or character literal.  This makes
it so we can guarantee that the lexer never calls into the 
preprocessor (which would be suicide for a raw lexer).

llvm-svn: 57395
2008-10-12 01:31:51 +00:00

485 lines
18 KiB
C++

//===--- TokenLexer.cpp - Lex from a token stream -------------------------===//
//
// 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 TokenLexer interface.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/TokenLexer.h"
#include "MacroArgs.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
/// Create a TokenLexer for the specified macro with the specified actual
/// arguments. Note that this ctor takes ownership of the ActualArgs pointer.
void TokenLexer::Init(Token &Tok, MacroArgs *Actuals) {
// If the client is reusing a TokenLexer, make sure to free any memory
// associated with it.
destroy();
Macro = PP.getMacroInfo(Tok.getIdentifierInfo());
ActualArgs = Actuals;
CurToken = 0;
InstantiateLoc = Tok.getLocation();
AtStartOfLine = Tok.isAtStartOfLine();
HasLeadingSpace = Tok.hasLeadingSpace();
Tokens = &*Macro->tokens_begin();
OwnsTokens = false;
DisableMacroExpansion = false;
NumTokens = Macro->tokens_end()-Macro->tokens_begin();
// If this is a function-like macro, expand the arguments and change
// Tokens to point to the expanded tokens.
if (Macro->isFunctionLike() && Macro->getNumArgs())
ExpandFunctionArguments();
// Mark the macro as currently disabled, so that it is not recursively
// expanded. The macro must be disabled only after argument pre-expansion of
// function-like macro arguments occurs.
Macro->DisableMacro();
}
/// Create a TokenLexer for the specified token stream. This does not
/// take ownership of the specified token vector.
void TokenLexer::Init(const Token *TokArray, unsigned NumToks,
bool disableMacroExpansion, bool ownsTokens) {
// If the client is reusing a TokenLexer, make sure to free any memory
// associated with it.
destroy();
Macro = 0;
ActualArgs = 0;
Tokens = TokArray;
OwnsTokens = ownsTokens;
DisableMacroExpansion = disableMacroExpansion;
NumTokens = NumToks;
CurToken = 0;
InstantiateLoc = SourceLocation();
AtStartOfLine = false;
HasLeadingSpace = false;
// Set HasLeadingSpace/AtStartOfLine so that the first token will be
// returned unmodified.
if (NumToks != 0) {
AtStartOfLine = TokArray[0].isAtStartOfLine();
HasLeadingSpace = TokArray[0].hasLeadingSpace();
}
}
void TokenLexer::destroy() {
// If this was a function-like macro that actually uses its arguments, delete
// the expanded tokens.
if (OwnsTokens) {
delete [] Tokens;
Tokens = 0;
}
// TokenLexer owns its formal arguments.
if (ActualArgs) ActualArgs->destroy();
}
/// Expand the arguments of a function-like macro so that we can quickly
/// return preexpanded tokens from Tokens.
void TokenLexer::ExpandFunctionArguments() {
llvm::SmallVector<Token, 128> ResultToks;
// Loop through 'Tokens', expanding them into ResultToks. Keep
// track of whether we change anything. If not, no need to keep them. If so,
// we install the newly expanded sequence as the new 'Tokens' list.
bool MadeChange = false;
// NextTokGetsSpace - When this is true, the next token appended to the
// output list will get a leading space, regardless of whether it had one to
// begin with or not. This is used for placemarker support.
bool NextTokGetsSpace = false;
for (unsigned i = 0, e = NumTokens; i != e; ++i) {
// If we found the stringify operator, get the argument stringified. The
// preprocessor already verified that the following token is a macro name
// when the #define was parsed.
const Token &CurTok = Tokens[i];
if (CurTok.is(tok::hash) || CurTok.is(tok::hashat)) {
int ArgNo = Macro->getArgumentNum(Tokens[i+1].getIdentifierInfo());
assert(ArgNo != -1 && "Token following # is not an argument?");
Token Res;
if (CurTok.is(tok::hash)) // Stringify
Res = ActualArgs->getStringifiedArgument(ArgNo, PP);
else {
// 'charify': don't bother caching these.
Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo),
PP, true);
}
// The stringified/charified string leading space flag gets set to match
// the #/#@ operator.
if (CurTok.hasLeadingSpace() || NextTokGetsSpace)
Res.setFlag(Token::LeadingSpace);
ResultToks.push_back(Res);
MadeChange = true;
++i; // Skip arg name.
NextTokGetsSpace = false;
continue;
}
// Otherwise, if this is not an argument token, just add the token to the
// output buffer.
IdentifierInfo *II = CurTok.getIdentifierInfo();
int ArgNo = II ? Macro->getArgumentNum(II) : -1;
if (ArgNo == -1) {
// This isn't an argument, just add it.
ResultToks.push_back(CurTok);
if (NextTokGetsSpace) {
ResultToks.back().setFlag(Token::LeadingSpace);
NextTokGetsSpace = false;
}
continue;
}
// An argument is expanded somehow, the result is different than the
// input.
MadeChange = true;
// Otherwise, this is a use of the argument. Find out if there is a paste
// (##) operator before or after the argument.
bool PasteBefore =
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
// If it is not the LHS/RHS of a ## operator, we must pre-expand the
// argument and substitute the expanded tokens into the result. This is
// C99 6.10.3.1p1.
if (!PasteBefore && !PasteAfter) {
const Token *ResultArgToks;
// Only preexpand the argument if it could possibly need it. This
// avoids some work in common cases.
const Token *ArgTok = ActualArgs->getUnexpArgument(ArgNo);
if (ActualArgs->ArgNeedsPreexpansion(ArgTok, PP))
ResultArgToks = &ActualArgs->getPreExpArgument(ArgNo, PP)[0];
else
ResultArgToks = ArgTok; // Use non-preexpanded tokens.
// If the arg token expanded into anything, append it.
if (ResultArgToks->isNot(tok::eof)) {
unsigned FirstResult = ResultToks.size();
unsigned NumToks = MacroArgs::getArgLength(ResultArgToks);
ResultToks.append(ResultArgToks, ResultArgToks+NumToks);
// If any tokens were substituted from the argument, the whitespace
// before the first token should match the whitespace of the arg
// identifier.
ResultToks[FirstResult].setFlagValue(Token::LeadingSpace,
CurTok.hasLeadingSpace() ||
NextTokGetsSpace);
NextTokGetsSpace = false;
} else {
// If this is an empty argument, and if there was whitespace before the
// formal token, make sure the next token gets whitespace before it.
NextTokGetsSpace = CurTok.hasLeadingSpace();
}
continue;
}
// Okay, we have a token that is either the LHS or RHS of a paste (##)
// argument. It gets substituted as its non-pre-expanded tokens.
const Token *ArgToks = ActualArgs->getUnexpArgument(ArgNo);
unsigned NumToks = MacroArgs::getArgLength(ArgToks);
if (NumToks) { // Not an empty argument?
// If this is the GNU ", ## __VA_ARG__" extension, and we just learned
// that __VA_ARG__ expands to multiple tokens, avoid a pasting error when
// the expander trys to paste ',' with the first token of the __VA_ARG__
// expansion.
if (PasteBefore && ResultToks.size() >= 2 &&
ResultToks[ResultToks.size()-2].is(tok::comma) &&
(unsigned)ArgNo == Macro->getNumArgs()-1 &&
Macro->isVariadic()) {
// Remove the paste operator, report use of the extension.
PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
ResultToks.pop_back();
}
ResultToks.append(ArgToks, ArgToks+NumToks);
// If the next token was supposed to get leading whitespace, ensure it has
// it now.
if (NextTokGetsSpace) {
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
NextTokGetsSpace = false;
}
continue;
}
// If an empty argument is on the LHS or RHS of a paste, the standard (C99
// 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur. We
// implement this by eating ## operators when a LHS or RHS expands to
// empty.
NextTokGetsSpace |= CurTok.hasLeadingSpace();
if (PasteAfter) {
// Discard the argument token and skip (don't copy to the expansion
// buffer) the paste operator after it.
NextTokGetsSpace |= Tokens[i+1].hasLeadingSpace();
++i;
continue;
}
// If this is on the RHS of a paste operator, we've already copied the
// paste operator to the ResultToks list. Remove it.
assert(PasteBefore && ResultToks.back().is(tok::hashhash));
NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
ResultToks.pop_back();
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
// and if the macro had at least one real argument, and if the token before
// the ## was a comma, remove the comma.
if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__
ActualArgs->isVarargsElidedUse() && // Argument elided.
!ResultToks.empty() && ResultToks.back().is(tok::comma)) {
// Never add a space, even if the comma, ##, or arg had a space.
NextTokGetsSpace = false;
// Remove the paste operator, report use of the extension.
PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma);
ResultToks.pop_back();
}
continue;
}
// If anything changed, install this as the new Tokens list.
if (MadeChange) {
// This is deleted in the dtor.
NumTokens = ResultToks.size();
Token *Res = new Token[ResultToks.size()];
if (NumTokens)
memcpy(Res, &ResultToks[0], NumTokens*sizeof(Token));
Tokens = Res;
OwnsTokens = true;
}
}
/// Lex - Lex and return a token from this macro stream.
///
void TokenLexer::Lex(Token &Tok) {
// Lexing off the end of the macro, pop this macro off the expansion stack.
if (isAtEnd()) {
// If this is a macro (not a token stream), mark the macro enabled now
// that it is no longer being expanded.
if (Macro) Macro->EnableMacro();
// Pop this context off the preprocessors lexer stack and get the next
// token. This will delete "this" so remember the PP instance var.
Preprocessor &PPCache = PP;
if (PP.HandleEndOfTokenLexer(Tok))
return;
// HandleEndOfTokenLexer may not return a token. If it doesn't, lex
// whatever is next.
return PPCache.Lex(Tok);
}
// If this is the first token of the expanded result, we inherit spacing
// properties later.
bool isFirstToken = CurToken == 0;
// Get the next token to return.
Tok = Tokens[CurToken++];
// If this token is followed by a token paste (##) operator, paste the tokens!
if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash))
if (PasteTokens(Tok)) {
// When handling the microsoft /##/ extension, the final token is
// returned by PasteTokens, not the pasted token.
return;
}
// The token's current location indicate where the token was lexed from. We
// need this information to compute the spelling of the token, but any
// diagnostics for the expanded token should appear as if they came from
// InstantiationLoc. Pull this information together into a new SourceLocation
// that captures all of this.
if (InstantiateLoc.isValid()) { // Don't do this for token streams.
SourceManager &SrcMgr = PP.getSourceManager();
Tok.setLocation(SrcMgr.getInstantiationLoc(Tok.getLocation(),
InstantiateLoc));
}
// If this is the first token, set the lexical properties of the token to
// match the lexical properties of the macro identifier.
if (isFirstToken) {
Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
}
// Handle recursive expansion!
if (Tok.getIdentifierInfo() && !DisableMacroExpansion)
return PP.HandleIdentifier(Tok);
// Otherwise, return a normal token.
}
/// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ##
/// operator. Read the ## and RHS, and paste the LHS/RHS together. If there
/// are more ## after it, chomp them iteratively. Return the result as Tok.
/// If this returns true, the caller should immediately return the token.
bool TokenLexer::PasteTokens(Token &Tok) {
llvm::SmallVector<char, 128> Buffer;
do {
// Consume the ## operator.
SourceLocation PasteOpLoc = Tokens[CurToken].getLocation();
++CurToken;
assert(!isAtEnd() && "No token on the RHS of a paste operator!");
// Get the RHS token.
const Token &RHS = Tokens[CurToken];
bool isInvalid = false;
// Allocate space for the result token. This is guaranteed to be enough for
// the two tokens and a null terminator.
Buffer.resize(Tok.getLength() + RHS.getLength() + 1);
// Get the spelling of the LHS token in Buffer.
const char *BufPtr = &Buffer[0];
unsigned LHSLen = PP.getSpelling(Tok, BufPtr);
if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer!
memcpy(&Buffer[0], BufPtr, LHSLen);
BufPtr = &Buffer[LHSLen];
unsigned RHSLen = PP.getSpelling(RHS, BufPtr);
if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer!
memcpy(&Buffer[LHSLen], BufPtr, RHSLen);
// Add null terminator.
Buffer[LHSLen+RHSLen] = '\0';
// Trim excess space.
Buffer.resize(LHSLen+RHSLen+1);
// Plop the pasted result (including the trailing newline and null) into a
// scratch buffer where we can lex it.
SourceLocation ResultTokLoc = PP.CreateString(&Buffer[0], Buffer.size());
// Lex the resultant pasted token into Result.
Token Result;
if (Tok.is(tok::identifier) && RHS.is(tok::identifier)) {
// Common paste case: identifier+identifier = identifier. Avoid creating
// a lexer and other overhead.
PP.IncrementPasteCounter(true);
Result.startToken();
Result.setKind(tok::identifier);
Result.setLocation(ResultTokLoc);
Result.setLength(LHSLen+RHSLen);
} else {
PP.IncrementPasteCounter(false);
// Make a lexer to lex this string from.
SourceManager &SourceMgr = PP.getSourceManager();
const char *ResultStrData = SourceMgr.getCharacterData(ResultTokLoc);
const llvm::MemoryBuffer *Buffer =
SourceMgr.getBuffer(ResultTokLoc.getFileID());
// Make a lexer object so that we lex and expand the paste result.
Lexer TL(ResultTokLoc, PP.getLangOptions(), ResultStrData,
ResultStrData+LHSLen+RHSLen /*don't include null*/, Buffer);
// Lex a token in raw mode. This way it won't look up identifiers
// automatically, lexing off the end will return an eof token, and
// warnings are disabled. This returns true if the result token is the
// entire buffer.
bool IsComplete = TL.LexFromRawLexer(Result);
// If we got an EOF token, we didn't form even ONE token. For example, we
// did "/ ## /" to get "//".
IsComplete &= Result.isNot(tok::eof);
isInvalid = !IsComplete;
}
// If pasting the two tokens didn't form a full new token, this is an error.
// This occurs with "x ## +" and other stuff. Return with Tok unmodified
// and with RHS as the next token to lex.
if (isInvalid) {
// Test for the Microsoft extension of /##/ turning into // here on the
// error path.
if (PP.getLangOptions().Microsoft && Tok.is(tok::slash) &&
RHS.is(tok::slash)) {
HandleMicrosoftCommentPaste(Tok);
return true;
} else {
// TODO: If not in assembler language mode.
PP.Diag(PasteOpLoc, diag::err_pp_bad_paste,
std::string(Buffer.begin(), Buffer.end()-1));
return false;
}
}
// Turn ## into 'unknown' to avoid # ## # from looking like a paste
// operator.
if (Result.is(tok::hashhash))
Result.setKind(tok::unknown);
// FIXME: Turn __VA_ARGS__ into "not a token"?
// Transfer properties of the LHS over the the Result.
Result.setFlagValue(Token::StartOfLine , Tok.isAtStartOfLine());
Result.setFlagValue(Token::LeadingSpace, Tok.hasLeadingSpace());
// Finally, replace LHS with the result, consume the RHS, and iterate.
++CurToken;
Tok = Result;
} while (!isAtEnd() && Tokens[CurToken].is(tok::hashhash));
// Now that we got the result token, it will be subject to expansion. Since
// token pasting re-lexes the result token in raw mode, identifier information
// isn't looked up. As such, if the result is an identifier, look up id info.
if (Tok.is(tok::identifier)) {
// Look up the identifier info for the token. We disabled identifier lookup
// by saying we're skipping contents, so we need to do this manually.
Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
}
return false;
}
/// isNextTokenLParen - If the next token lexed will pop this macro off the
/// expansion stack, return 2. If the next unexpanded token is a '(', return
/// 1, otherwise return 0.
unsigned TokenLexer::isNextTokenLParen() const {
// Out of tokens?
if (isAtEnd())
return 2;
return Tokens[CurToken].is(tok::l_paren);
}
/// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes
/// together to form a comment that comments out everything in the current
/// macro, other active macros, and anything left on the current physical
/// source line of the instantiated buffer. Handle this by returning the
/// first token on the next line.
void TokenLexer::HandleMicrosoftCommentPaste(Token &Tok) {
// We 'comment out' the rest of this macro by just ignoring the rest of the
// tokens that have not been lexed yet, if any.
// Since this must be a macro, mark the macro enabled now that it is no longer
// being expanded.
assert(Macro && "Token streams can't paste comments");
Macro->EnableMacro();
PP.HandleMicrosoftCommentPaste(Tok);
}