From aa7a2f2ba308656e206338fe65c422e0b6781c64 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 15 Jun 2012 14:02:34 +0000 Subject: [PATCH] Factor macro argument parsing into helper methods and add support for .irp. Patch extracted from a larger one by the PaX team. I added the testcases and tightened error handling a bit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@158523 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/MCParser/AsmParser.cpp | 145 ++++++++++++++++++++++++++------- test/MC/AsmParser/macro-err1.s | 10 +++ test/MC/AsmParser/macro-irp.s | 8 ++ 3 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 test/MC/AsmParser/macro-err1.s create mode 100644 test/MC/AsmParser/macro-irp.s diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 04603e994a3..f2618e190af 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -206,6 +206,9 @@ private: void EatToEndOfStatement(); + bool ParseMacroArgument(MacroArgument &MA); + bool ParseMacroArguments(const Macro *M, std::vector &A); + /// \brief Parse up to the end of statement and a return the contents from the /// current token until the end of the statement; the current token on exit /// will be either the EndOfStatement or EOF. @@ -273,6 +276,7 @@ private: void InstantiateMacroLikeBody(Macro *M, SMLoc DirectiveLoc, raw_svector_ostream &OS); bool ParseDirectiveRept(SMLoc DirectiveLoc); // ".rept" + bool ParseDirectiveIrp(SMLoc DirectiveLoc); // ".irp" bool ParseDirectiveEndr(SMLoc DirectiveLoc); // ".endr" }; @@ -1274,6 +1278,8 @@ bool AsmParser::ParseStatement() { // Macro-like directives if (IDVal == ".rept") return ParseDirectiveRept(IDLoc); + if (IDVal == ".irp") + return ParseDirectiveIrp(IDLoc); if (IDVal == ".endr") return ParseDirectiveEndr(IDLoc); @@ -1537,44 +1543,76 @@ MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, { } -bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc, - const Macro *M) { - // Arbitrarily limit macro nesting depth, to match 'as'. We can eliminate - // this, although we should protect against infinite loops. - if (ActiveMacros.size() == 20) - return TokError("macros cannot be nested more than 20 levels deep"); - - // Parse the macro instantiation arguments. - std::vector MacroArguments; - MacroArguments.push_back(MacroArgument()); +/// ParseMacroArgument - Extract AsmTokens for a macro argument. +/// This is used for both default macro parameter values and the +/// arguments in macro invocations +bool AsmParser::ParseMacroArgument(MacroArgument &MA) { unsigned ParenLevel = 0; + for (;;) { - if (Lexer.is(AsmToken::Eof)) + SMLoc LastTokenLoc; + + if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) return TokError("unexpected token in macro instantiation"); + + // HandleMacroEntry relies on not advancing the lexer here + // to be able to fill in the remaining default parameter values if (Lexer.is(AsmToken::EndOfStatement)) break; + if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) + 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(MacroArgument()); - } else { - // Adjust the current parentheses level. - if (Lexer.is(AsmToken::LParen)) - ++ParenLevel; - else if (Lexer.is(AsmToken::RParen) && ParenLevel) - --ParenLevel; - - // Append the token to the current argument list. - MacroArguments.back().push_back(getTok()); - } + // Adjust the current parentheses level. + if (Lexer.is(AsmToken::LParen)) + ++ParenLevel; + else if (Lexer.is(AsmToken::RParen) && ParenLevel) + --ParenLevel; + + // Append the token to the current argument list. + MA.push_back(getTok()); Lex(); } - // If the last argument didn't end up with any tokens, it's not a real - // argument and we should remove it from the list. This happens with either - // a tailing comma or an empty argument list. - if (MacroArguments.back().empty()) - MacroArguments.pop_back(); + if (ParenLevel != 0) + return TokError("unbalanced parenthesises in macro argument"); + return false; +} + +// Parse the macro instantiation arguments. +bool AsmParser::ParseMacroArguments(const Macro *M, + std::vector &A) { + const unsigned NParameters = M ? M->Parameters.size() : 0; + + // Parse two kinds of macro invocations: + // - macros defined without any parameters accept an arbitrary number of them + // - macros defined with parameters accept at most that many of them + for (unsigned Parameter = 0; !NParameters || Parameter < NParameters; + ++Parameter) { + MacroArgument MA; + + if (ParseMacroArgument(MA)) + return true; + + if (!MA.empty()) + A.push_back(MA); + if (Lexer.is(AsmToken::EndOfStatement)) + return false; + + if (Lexer.is(AsmToken::Comma)) + Lex(); + } + return TokError("Too many arguments"); +} + +bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc, + const Macro *M) { + // Arbitrarily limit macro nesting depth, to match 'as'. We can eliminate + // this, although we should protect against infinite loops. + if (ActiveMacros.size() == 20) + return TokError("macros cannot be nested more than 20 levels deep"); + + std::vector MacroArguments; + if (ParseMacroArguments(M, MacroArguments)) + return true; // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. @@ -3239,6 +3277,53 @@ bool AsmParser::ParseDirectiveRept(SMLoc DirectiveLoc) { return false; } +/// ParseDirectiveIrp +/// ::= .irp symbol,values +bool AsmParser::ParseDirectiveIrp(SMLoc DirectiveLoc) { + std::vector Parameters; + StringRef Parameter; + + if (ParseIdentifier(Parameter)) + return TokError("expected identifier in '.irp' directive"); + + Parameters.push_back(Parameter); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("expected comma in '.irp' directive"); + + Lex(); + + std::vector A; + if (ParseMacroArguments(0, A)) + return true; + + // Eat the end of statement. + Lex(); + + // Lex the irp definition. + Macro *M = ParseMacroLikeBody(DirectiveLoc); + if (!M) + return true; + + // Macro instantiation is lexical, unfortunately. We construct a new buffer + // to hold the macro body with substitutions. + SmallString<256> Buf; + raw_svector_ostream OS(Buf); + + for (std::vector::iterator i = A.begin(), e = A.end(); i != e; + ++i) { + std::vector Args; + Args.push_back(*i); + + if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc())) + return true; + } + + InstantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + bool AsmParser::ParseDirectiveEndr(SMLoc DirectiveLoc) { if (ActiveMacros.empty()) return TokError("unexpected '.endr' directive, no current .rept"); diff --git a/test/MC/AsmParser/macro-err1.s b/test/MC/AsmParser/macro-err1.s new file mode 100644 index 00000000000..924deb0cf6e --- /dev/null +++ b/test/MC/AsmParser/macro-err1.s @@ -0,0 +1,10 @@ +// RUN: not llvm-mc -triple x86_64-unknown-unknown %s 2> %t +// RUN: FileCheck < %t %s + +.macro foo bar + .long \bar +.endm + +foo 42, 42 + +// CHECK: Too many arguments diff --git a/test/MC/AsmParser/macro-irp.s b/test/MC/AsmParser/macro-irp.s new file mode 100644 index 00000000000..a368b7446dc --- /dev/null +++ b/test/MC/AsmParser/macro-irp.s @@ -0,0 +1,8 @@ +// RUN: llvm-mc -triple x86_64-unknown-unknown %s | FileCheck %s + +.irp reg,%eax,%ebx + pushl \reg +.endr + +// CHECK: pushl %eax +// CHECK: pushl %ebx -- 2.34.1