MC/AsmParser: Add macro argument substitution support.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108654 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2010-07-18 19:00:10 +00:00
parent c64a0d7c3e
commit 7a570d09ac
3 changed files with 130 additions and 8 deletions

View File

@ -61,7 +61,8 @@ struct MacroInstantiation {
SMLoc ExitLoc;
public:
MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL);
MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL,
const std::vector<std::vector<AsmToken> > &A);
};
/// \brief The concrete assembly parser instance.
@ -909,19 +910,71 @@ bool AsmParser::ParseStatement() {
return HadError;
}
MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL)
MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL,
const std::vector<std::vector<AsmToken> > &A)
: TheMacro(M), InstantiationLoc(IL), ExitLoc(EL)
{
// Macro instantiation is lexical, unfortunately. We construct a new buffer
// to hold the macro body with substitutions.
llvm::SmallString<256> Buf;
Buf += M->Body;
SmallString<256> Buf;
raw_svector_ostream OS(Buf);
StringRef Body = M->Body;
while (!Body.empty()) {
// Scan for the next substitution.
std::size_t End = Body.size(), Pos = 0;
for (; Pos != End; ++Pos) {
// Check for a substitution or escape.
if (Body[Pos] != '$' || Pos + 1 == End)
continue;
char Next = Body[Pos + 1];
if (Next == '$' || Next == 'n' || isdigit(Next))
break;
}
// Add the prefix.
OS << Body.slice(0, Pos);
// Check if we reached the end.
if (Pos == End)
break;
switch (Body[Pos+1]) {
// $$ => $
case '$':
OS << '$';
break;
// $n => number of arguments
case 'n':
OS << A.size();
break;
// $[0-9] => argument
default: {
// Missing arguments are ignored.
unsigned Index = Body[Pos+1] - '0';
if (Index >= A.size())
break;
// Otherwise substitute with the token values, with spaces eliminated.
for (std::vector<AsmToken>::const_iterator it = A[Index].begin(),
ie = A[Index].end(); it != ie; ++it)
OS << it->getString();
break;
}
}
// Update the scan point.
Body = Body.substr(Pos + 2);
}
// We include the .endmacro in the buffer as our queue to exit the macro
// instantiation.
Buf += ".endmacro\n";
OS << ".endmacro\n";
Instantiation = MemoryBuffer::getMemBufferCopy(Buf, "<instantiation>");
Instantiation = MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
}
bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc,
@ -931,12 +984,36 @@ bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc,
if (ActiveMacros.size() == 20)
return TokError("macros cannot be nested more than 20 levels deep");
EatToEndOfStatement();
// Parse the macro instantiation arguments.
std::vector<std::vector<AsmToken> > MacroArguments;
MacroArguments.push_back(std::vector<AsmToken>());
unsigned ParenLevel = 0;
for (;;) {
if (Lexer.is(AsmToken::Eof))
return TokError("unexpected token in macro instantiation");
if (Lexer.is(AsmToken::EndOfStatement))
break;
// If we aren't inside parentheses and this is a comma, start a new token
// list.
if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) {
MacroArguments.push_back(std::vector<AsmToken>());
} else if (Lexer.is(AsmToken::LParen)) {
++ParenLevel;
} else if (Lexer.is(AsmToken::RParen)) {
if (ParenLevel)
--ParenLevel;
} else {
MacroArguments.back().push_back(getTok());
}
Lex();
}
// Create the macro instantiation object and add to the current macro
// instantiation stack.
MacroInstantiation *MI = new MacroInstantiation(M, NameLoc,
getTok().getLoc());
getTok().getLoc(),
MacroArguments);
ActiveMacros.push_back(MI);
// Jump to the macro instantiation and prime the lexer.

View File

@ -0,0 +1,13 @@
// RUN: llvm-mc %s | FileCheck %s
.macro .make_macro
$0 $1
$2 $3
$4
.endmacro
.make_macro .macro,.mybyte,.byte,$0,.endmacro
.data
// CHECK: .byte 10
.mybyte 10

View File

@ -0,0 +1,32 @@
// RUN: llvm-mc %s 2> %t.err | FileCheck %s
// RUN: FileCheck --check-prefix=CHECK-ERRORS %s < %t.err
.macro .test0
.macrobody0
.endmacro
.macro .test1
.test0
.endmacro
.test1
// CHECK-ERRORS: <instantiation>:1:1: warning: ignoring directive for now
// CHECK-ERRORS-NEXT: macrobody0
// CHECK-ERRORS-NEXT: ^
// CHECK-ERRORS: <instantiation>:1:1: note: while in macro instantiation
// CHECK-ERRORS-NEXT: .test0
// CHECK-ERRORS-NEXT: ^
// CHECK-ERRORS: 11:1: note: while in macro instantiation
// CHECK-ERRORS-NEXT: .test1
// CHECK-ERRORS-NEXT: ^
.macro test2
.byte $0
.endmacro
test2 10
.macro test3
.globl "$0 $1 $2 $$3 $n"
.endmacro
// CHECK: .globl "1 23 $3 2"
test3 1,2 3