From 654247c3ea3304b434cb3f0dcf69338073651158 Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Wed, 29 Jan 2014 18:57:46 +0000 Subject: MC: Better management of macro arguments The linux kernel makes uses of a GAS `feature' which substitutes nothing for macro arguments which aren't specified. Proper support for these kind of macro arguments necessitated a cleanup of differences between `GAS' and `Darwin' dialect macro processing. Differential Revision: http://llvm-reviews.chandlerc.com/D2634 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200409 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/MCParser/AsmParser.cpp | 77 +++++++++++---------------------------- test/MC/AsmParser/macros-darwin.s | 8 +--- test/MC/AsmParser/macros-gas.s | 28 +++++++------- 3 files changed, 38 insertions(+), 75 deletions(-) diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 91699983e2..3f813a73cc 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -287,11 +287,8 @@ private: /// \brief Handle exit from macro instantiation. void handleMacroExit(); - /// \brief Extract AsmTokens for a macro argument. If the argument delimiter - /// is initially unknown, set it to AsmToken::Eof. It will be set to the - /// correct delimiter by the method. - bool parseMacroArgument(MCAsmMacroArgument &MA, - AsmToken::TokenKind &ArgumentDelimiter); + /// \brief Extract AsmTokens for a macro argument. + bool parseMacroArgument(MCAsmMacroArgument &MA); /// \brief Parse all macro arguments for a given macro. bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A); @@ -1879,8 +1876,7 @@ private: }; } -bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, - AsmToken::TokenKind &ArgumentDelimiter) { +bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA) { unsigned ParenLevel = 0; unsigned AddTokens = 0; @@ -1891,14 +1887,8 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) return TokError("unexpected token in macro instantiation"); - if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) { - // Spaces and commas cannot be mixed to delimit parameters - if (ArgumentDelimiter == AsmToken::Eof) - ArgumentDelimiter = AsmToken::Comma; - else if (ArgumentDelimiter != AsmToken::Comma) - return TokError("expected ' ' for macro argument separator"); + if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) break; - } if (Lexer.is(AsmToken::Space)) { Lex(); // Eat spaces @@ -1906,8 +1896,7 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, // Spaces can delimit parameters, but could also be part an expression. // If the token after a space is an operator, add the token and the next // one into this argument - if (ArgumentDelimiter == AsmToken::Space || - ArgumentDelimiter == AsmToken::Eof) { + if (!IsDarwin) { if (isOperator(Lexer.getKind())) { // Check to see whether the token is used as an operator, // or part of an identifier @@ -1917,9 +1906,6 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, } if (!AddTokens && ParenLevel == 0) { - if (ArgumentDelimiter == AsmToken::Eof && - !isOperator(Lexer.getKind())) - ArgumentDelimiter = AsmToken::Space; break; } } @@ -1952,9 +1938,6 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool AsmParser::parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A) { const unsigned NParameters = M ? M->Parameters.size() : 0; - // Argument delimiter is initially unknown. It will be set by - // parseMacroArgument() - AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof; // Parse two kinds of macro invocations: // - macros defined without any parameters accept an arbitrary number of them @@ -1963,14 +1946,16 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, ++Parameter) { MCAsmMacroArgument MA; - if (parseMacroArgument(MA, ArgumentDelimiter)) + if (parseMacroArgument(MA)) return true; - if (!MA.empty() || !NParameters) + if (!MA.empty() || (!NParameters && !Lexer.is(AsmToken::EndOfStatement))) A.push_back(MA); else if (NParameters) { if (!M->Parameters[Parameter].second.empty()) A.push_back(M->Parameters[Parameter].second); + else + A.push_back(MA); } // At the end of the statement, fill in remaining arguments that have @@ -1978,12 +1963,7 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, // required but missing if (Lexer.is(AsmToken::EndOfStatement)) { if (NParameters && Parameter < NParameters - 1) { - if (M->Parameters[Parameter + 1].second.empty()) - return TokError("macro argument '" + - Twine(M->Parameters[Parameter + 1].first) + - "' is missing"); - else - continue; + continue; } return false; } @@ -2021,12 +2001,6 @@ bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { if (parseMacroArguments(M, A)) return true; - // Remove any trailing empty arguments. Do this after-the-fact as we have - // to keep empty arguments in the middle of the list or positionality - // gets off. e.g., "foo 1, , 2" vs. "foo 1, 2," - while (!A.empty() && A.back().empty()) - A.pop_back(); - // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. SmallString<256> Buf; @@ -3113,28 +3087,21 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { return TokError("expected identifier in '.macro' directive"); MCAsmMacroParameters Parameters; - // Argument delimiter is initially unknown. It will be set by - // parseMacroArgument() - AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - for (;;) { - MCAsmMacroParameter Parameter; - if (parseIdentifier(Parameter.first)) - return TokError("expected identifier in '.macro' directive"); + while (getLexer().isNot(AsmToken::EndOfStatement)) { + MCAsmMacroParameter Parameter; + if (parseIdentifier(Parameter.first)) + return TokError("expected identifier in '.macro' directive"); - if (getLexer().is(AsmToken::Equal)) { - Lex(); - if (parseMacroArgument(Parameter.second, ArgumentDelimiter)) - return true; - } + if (getLexer().is(AsmToken::Equal)) { + Lex(); + if (parseMacroArgument(Parameter.second)) + return true; + } - Parameters.push_back(Parameter); + Parameters.push_back(Parameter); - if (getLexer().is(AsmToken::Comma)) - Lex(); - else if (getLexer().is(AsmToken::EndOfStatement)) - break; - } + if (getLexer().is(AsmToken::Comma)) + Lex(); } // Eat the end of statement. diff --git a/test/MC/AsmParser/macros-darwin.s b/test/MC/AsmParser/macros-darwin.s index c4061f0663..e22038e7d1 100644 --- a/test/MC/AsmParser/macros-darwin.s +++ b/test/MC/AsmParser/macros-darwin.s @@ -86,12 +86,8 @@ test8 x - y, z, 1 // CHECK: .globl "1 2 3" test9 1, 2,3 +// CHECK: .globl "1,23," test8 1,2 3 -// CHECK-ERRORS: error: macro argument '_c' is missing -// CHECK-ERRORS-NEXT: test8 1,2 3 -// CHECK-ERRORS-NEXT: ^ +// CHECK: .globl "12,3," test8 1 2, 3 -// CHECK-ERRORS: error: macro argument '_c' is missing -// CHECK-ERRORS-NEXT:test8 1 2, 3 -// CHECK-ERRORS-NEXT: ^ diff --git a/test/MC/AsmParser/macros-gas.s b/test/MC/AsmParser/macros-gas.s index 39f654dd9a..6c75363b5e 100644 --- a/test/MC/AsmParser/macros-gas.s +++ b/test/MC/AsmParser/macros-gas.s @@ -32,17 +32,21 @@ test2 10 // CHECK: .ascii "1 2 3 \003" test3 1, 2, 3 -// FIXME: test3 1, 2 3 should be treated like test 1, 2, 3 +// CHECK: .ascii "1 2 3 \003" +test3 1, 2 3 + +.macro test3_prime _a _b _c +.ascii "\_a \_b \_c" +.endm -// FIXME: remove the n argument from the remaining test3 examples -// CHECK: .ascii "1 (23) n \n" -test3 1, (2 3), n +// CHECK: .ascii "1 (23) " +test3_prime 1, (2 3) -// CHECK: .ascii "1 (23) n \n" -test3 1 (2 3) n +// CHECK: .ascii "1 (23) " +test3_prime 1 (2 3) -// CHECK: .ascii "1 2 n \n" -test3 1 2 n +// CHECK: .ascii "1 2 " +test3_prime 1 2 .macro test5 _a .globl \_a @@ -82,12 +86,8 @@ test8 x - y z 1 // CHECK: .ascii "1 2 3" test9 1, 2,3 +// CHECK: .ascii "1,2,3" test8 1,2 3 -// CHECK-ERRORS: error: macro argument '_c' is missing -// CHECK-ERRORS-NEXT: test8 1,2 3 -// CHECK-ERRORS-NEXT: ^ +// CHECK: .ascii "1,2,3" test8 1 2, 3 -// CHECK-ERRORS: error: expected ' ' for macro argument separator -// CHECK-ERRORS-NEXT:test8 1 2, 3 -// CHECK-ERRORS-NEXT: ^ -- cgit v1.2.3