Set up infrastructure for function-like macro expansion with preexpansion

stringizing, etc.

llvm-svn: 38707
This commit is contained in:
Chris Lattner 2006-07-14 06:54:44 +00:00
parent b94ec7b668
commit b935d8cd90
3 changed files with 127 additions and 12 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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.