Set up infrastructure for function-like macro expansion with preexpansion
stringizing, etc. llvm-svn: 38707
This commit is contained in:
parent
b94ec7b668
commit
b935d8cd90
|
@ -33,29 +33,112 @@ MacroFormalArgs::MacroFormalArgs(const MacroInfo *MI) {
|
|||
ArgTokens.reserve(NumArgs);
|
||||
}
|
||||
|
||||
/// StringifyArgument - Implement C99 6.10.3.2p2.
|
||||
static LexerToken StringifyArgument(const std::vector<LexerToken> &Toks,
|
||||
Preprocessor &PP) {
|
||||
LexerToken Tok;
|
||||
Tok.StartToken();
|
||||
Tok.SetKind(tok::string_literal);
|
||||
|
||||
std::string Val = "\"XXYZLAKSDFJAS\"";
|
||||
Tok.SetLength(Val.size());
|
||||
Tok.SetLocation(PP.CreateString(&Val[0], Val.size()));
|
||||
return Tok;
|
||||
}
|
||||
|
||||
/// getStringifiedArgument - Compute, cache, and return the specified argument
|
||||
/// that has been 'stringified' as required by the # operator.
|
||||
const LexerToken &MacroFormalArgs::getStringifiedArgument(unsigned ArgNo,
|
||||
Preprocessor &PP) {
|
||||
assert(ArgNo < ArgTokens.size() && "Invalid argument number!");
|
||||
if (StringifiedArgs.empty()) {
|
||||
StringifiedArgs.resize(ArgTokens.size());
|
||||
memset(&StringifiedArgs[0], 0, sizeof(StringifiedArgs[0])*ArgTokens.size());
|
||||
}
|
||||
if (StringifiedArgs[ArgNo].getKind() != tok::string_literal)
|
||||
StringifiedArgs[ArgNo] = StringifyArgument(ArgTokens[ArgNo], PP);
|
||||
return StringifiedArgs[ArgNo];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MacroExpander Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MacroExpander::MacroExpander(LexerToken &Tok, MacroFormalArgs *Formals,
|
||||
Preprocessor &pp)
|
||||
: Macro(*Tok.getIdentifierInfo()->getMacroInfo()), FormalArgs(Formals),
|
||||
PP(pp), CurToken(0),
|
||||
: Macro(*Tok.getIdentifierInfo()->getMacroInfo()),
|
||||
FormalArgs(Formals), PP(pp), CurToken(0),
|
||||
InstantiateLoc(Tok.getLocation()),
|
||||
AtStartOfLine(Tok.isAtStartOfLine()),
|
||||
HasLeadingSpace(Tok.hasLeadingSpace()) {
|
||||
MacroTokens = &Macro.getReplacementTokens();
|
||||
|
||||
// If this is a function-like macro, expand the arguments and change
|
||||
// MacroTokens to point to the expanded tokens.
|
||||
if (Macro.isFunctionLike() && Macro.getNumArgs())
|
||||
ExpandFunctionArguments();
|
||||
}
|
||||
|
||||
MacroExpander::~MacroExpander() {
|
||||
// If this was a function-like macro that actually uses its arguments, delete
|
||||
// the expanded tokens.
|
||||
if (MacroTokens != &Macro.getReplacementTokens())
|
||||
delete MacroTokens;
|
||||
|
||||
// MacroExpander owns its formal arguments.
|
||||
delete FormalArgs;
|
||||
}
|
||||
|
||||
/// Expand the arguments of a function-like macro so that we can quickly
|
||||
/// return preexpanded tokens from MacroTokens.
|
||||
void MacroExpander::ExpandFunctionArguments() {
|
||||
std::vector<LexerToken> ResultToks;
|
||||
|
||||
// Loop through the MacroTokens 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 MacroTokens.
|
||||
bool MadeChange = false;
|
||||
for (unsigned i = 0, e = MacroTokens->size(); 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 LexerToken &CurTok = (*MacroTokens)[i];
|
||||
if (CurTok.getKind() == tok::hash) {
|
||||
int ArgNo = Macro.getArgumentNum((*MacroTokens)[i+1].getIdentifierInfo());
|
||||
assert(ArgNo != -1 && "Token following # is not an argument?");
|
||||
|
||||
ResultToks.push_back(FormalArgs->getStringifiedArgument(ArgNo, PP));
|
||||
|
||||
// FIXME: Should the stringified string leading space flag get set to
|
||||
// match the # or the identifier?
|
||||
|
||||
MadeChange = true;
|
||||
++i; // Skip arg name.
|
||||
} else {
|
||||
// FIXME: handle microsoft charize extension.
|
||||
|
||||
ResultToks.push_back(CurTok);
|
||||
}
|
||||
}
|
||||
|
||||
// If anything changed, install this as the new MacroTokens list.
|
||||
if (MadeChange) {
|
||||
// This is deleted in the dtor.
|
||||
std::vector<LexerToken> *Res = new std::vector<LexerToken>();
|
||||
Res->swap(ResultToks);
|
||||
MacroTokens = Res;
|
||||
}
|
||||
}
|
||||
|
||||
/// Lex - Lex and return a token from this macro stream.
|
||||
///
|
||||
void MacroExpander::Lex(LexerToken &Tok) {
|
||||
// Lexing off the end of the macro, pop this macro off the expansion stack.
|
||||
if (CurToken == Macro.getNumTokens())
|
||||
if (isAtEnd())
|
||||
return PP.HandleEndOfMacro(Tok);
|
||||
|
||||
// Get the next token to return.
|
||||
Tok = Macro.getReplacementToken(CurToken++);
|
||||
Tok = (*MacroTokens)[CurToken++];
|
||||
|
||||
// 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
|
||||
|
@ -84,8 +167,7 @@ void MacroExpander::Lex(LexerToken &Tok) {
|
|||
/// 1, otherwise return 0.
|
||||
unsigned MacroExpander::isNextTokenLParen() const {
|
||||
// Out of tokens?
|
||||
if (CurToken == Macro.getNumTokens())
|
||||
if (isAtEnd())
|
||||
return 2;
|
||||
|
||||
return Macro.getReplacementToken(CurToken).getKind() == tok::l_paren;
|
||||
return (*MacroTokens)[CurToken].getKind() == tok::l_paren;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ namespace clang {
|
|||
/// the formal arguments specified to a function-like macro invocation.
|
||||
class MacroFormalArgs {
|
||||
std::vector<std::vector<LexerToken> > ArgTokens;
|
||||
|
||||
/// StringifiedArgs - This contains arguments in 'stringified' form. If the
|
||||
/// stringified form of an argument has not yet been computed, this is empty.
|
||||
std::vector<LexerToken> StringifiedArgs;
|
||||
public:
|
||||
MacroFormalArgs(const MacroInfo *MI);
|
||||
|
||||
|
@ -37,6 +41,10 @@ public:
|
|||
ArgTokens.back().swap(ArgToks);
|
||||
}
|
||||
|
||||
/// getStringifiedArgument - Compute, cache, and return the specified argument
|
||||
/// that has been 'stringified' as required by the # operator.
|
||||
const LexerToken &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP);
|
||||
|
||||
/// getNumArguments - Return the number of arguments passed into this macro
|
||||
/// invocation.
|
||||
unsigned getNumArguments() const { return ArgTokens.size(); }
|
||||
|
@ -50,7 +58,7 @@ class MacroExpander {
|
|||
/// Macro - The macro we are expanding from.
|
||||
///
|
||||
MacroInfo &Macro;
|
||||
|
||||
|
||||
/// FormalArgs - The formal arguments specified for a function-like macro, or
|
||||
/// null. The MacroExpander owns the pointed-to object.
|
||||
MacroFormalArgs *FormalArgs;
|
||||
|
@ -58,8 +66,13 @@ class MacroExpander {
|
|||
/// PP - The current preprocessor object we are expanding for.
|
||||
///
|
||||
Preprocessor &PP;
|
||||
|
||||
/// MacroTokens - This is the pointer to the list of tokens that the macro is
|
||||
/// defined to, with arguments expanded for function-like macros.
|
||||
const std::vector<LexerToken> *MacroTokens;
|
||||
|
||||
/// CurToken - This is the next token that Lex will return.
|
||||
///
|
||||
unsigned CurToken;
|
||||
|
||||
/// InstantiateLoc - The source location where this macro was instantiated.
|
||||
|
@ -77,10 +90,7 @@ public:
|
|||
/// arguments. Note that this ctor takes ownership of the FormalArgs pointer.
|
||||
MacroExpander(LexerToken &Tok, MacroFormalArgs *FormalArgs,
|
||||
Preprocessor &pp);
|
||||
~MacroExpander() {
|
||||
// MacroExpander owns its formal arguments.
|
||||
delete FormalArgs;
|
||||
}
|
||||
~MacroExpander();
|
||||
|
||||
/// isNextTokenLParen - If the next token lexed will pop this macro off the
|
||||
/// expansion stack, return 2. If the next unexpanded token is a '(', return
|
||||
|
@ -91,6 +101,17 @@ public:
|
|||
|
||||
/// Lex - Lex and return a token from this macro stream.
|
||||
void Lex(LexerToken &Tok);
|
||||
|
||||
private:
|
||||
/// isAtEnd - Return true if the next lex call will pop this macro off the
|
||||
/// include stack.
|
||||
bool isAtEnd() const {
|
||||
return CurToken == MacroTokens->size();
|
||||
}
|
||||
|
||||
/// Expand the arguments of a function-like macro so that we can quickly
|
||||
/// return preexpanded tokens from MacroTokens.
|
||||
void ExpandFunctionArguments();
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -98,6 +98,14 @@ public:
|
|||
void addArgument(IdentifierInfo *Arg) {
|
||||
Arguments.push_back(Arg);
|
||||
}
|
||||
|
||||
/// getArgumentNum - Return the argument number of the specified identifier,
|
||||
/// or -1 if the identifier is not a formal argument identifier.
|
||||
int getArgumentNum(IdentifierInfo *Arg) {
|
||||
for (unsigned i = 0, e = Arguments.size(); i != e; ++i)
|
||||
if (Arguments[i] == Arg) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Arguments - The list of arguments for a function-like macro. This can be
|
||||
/// empty, for, e.g. "#define X()".
|
||||
|
@ -137,6 +145,10 @@ public:
|
|||
assert(Tok < ReplacementTokens.size() && "Invalid token #");
|
||||
return ReplacementTokens[Tok];
|
||||
}
|
||||
|
||||
const std::vector<LexerToken> &getReplacementTokens() const {
|
||||
return ReplacementTokens;
|
||||
}
|
||||
|
||||
/// AddTokenToBody - Add the specified token to the replacement text for the
|
||||
/// macro.
|
||||
|
|
Loading…
Reference in New Issue