From: Daniel Dunbar Date: Sun, 18 Jul 2010 19:00:10 +0000 (+0000) Subject: MC/AsmParser: Add macro argument substitution support. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=7a570d09ac8630f782d394878baf6645cfd264e7;p=oota-llvm.git MC/AsmParser: Add macro argument substitution support. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108654 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 69f71304bbe..397f7e20dde 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -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 > &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 > &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::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 = MemoryBuffer::getMemBufferCopy(OS.str(), ""); } 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 > MacroArguments; + MacroArguments.push_back(std::vector()); + 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()); + } 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. diff --git a/test/MC/AsmParser/macro-def-in-instantiation.s b/test/MC/AsmParser/macro-def-in-instantiation.s new file mode 100644 index 00000000000..f6680000f17 --- /dev/null +++ b/test/MC/AsmParser/macro-def-in-instantiation.s @@ -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 diff --git a/test/MC/AsmParser/macros.s b/test/MC/AsmParser/macros.s new file mode 100644 index 00000000000..159dd36bdab --- /dev/null +++ b/test/MC/AsmParser/macros.s @@ -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: :1:1: warning: ignoring directive for now +// CHECK-ERRORS-NEXT: macrobody0 +// CHECK-ERRORS-NEXT: ^ +// CHECK-ERRORS: :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