From c64a0d7c3e55cf7d8bc8b49dcc447a3d809b11c8 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sun, 18 Jul 2010 18:54:11 +0000 Subject: [PATCH] MC/AsmParser: Add basic support for macro instantiation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108653 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/MCParser/AsmParser.cpp | 132 ++++++++++++++++++++++++----- test/MC/AsmParser/macros-parsing.s | 2 +- 2 files changed, 113 insertions(+), 21 deletions(-) diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index eb39205336f..69f71304bbe 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -45,6 +45,25 @@ public: Macro(StringRef N, StringRef B) : Name(N), Body(B) {} }; +/// \brief Helper class for storing information about an active macro +/// instantiation. +struct MacroInstantiation { + /// The macro being instantiated. + const Macro *TheMacro; + + /// The macro instantiation with substitutions. + MemoryBuffer *Instantiation; + + /// The location of the instantiation. + SMLoc InstantiationLoc; + + /// The location where parsing should resume upon instantiation completion. + SMLoc ExitLoc; + +public: + MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL); +}; + /// \brief The concrete assembly parser instance. class AsmParser : public MCAsmParser { friend class GenericAsmParser; @@ -75,6 +94,9 @@ private: /// MacroMap - Map of currently defined macros. StringMap MacroMap; + /// ActiveMacros - Stack of active macro instantiations. + std::vector ActiveMacros; + /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabled : 1; @@ -115,11 +137,20 @@ public: private: bool ParseStatement(); + bool HandleMacroEntry(StringRef Name, SMLoc NameLoc, const Macro *M); + void HandleMacroExit(); + + void PrintMacroInstantiations(); void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const; /// EnterIncludeFile - Enter the specified file. This returns true on failure. bool EnterIncludeFile(const std::string &Filename); - + + /// \brief Reset the current lexer position to that given by \arg Loc. The + /// current token is not set; clients should ensure Lex() is called + /// subsequently. + void JumpToLoc(SMLoc Loc); + void EatToEndOfStatement(); bool ParseAssignment(StringRef Name); @@ -247,12 +278,22 @@ AsmParser::~AsmParser() { delete GenericParser; } +void AsmParser::PrintMacroInstantiations() { + // Print the active macro instantiation stack. + for (std::vector::const_reverse_iterator + it = ActiveMacros.rbegin(), ie = ActiveMacros.rend(); it != ie; ++it) + PrintMessage((*it)->InstantiationLoc, "while in macro instantiation", + "note"); +} + void AsmParser::Warning(SMLoc L, const Twine &Msg) { PrintMessage(L, Msg.str(), "warning"); + PrintMacroInstantiations(); } bool AsmParser::Error(SMLoc L, const Twine &Msg) { PrintMessage(L, Msg.str(), "error"); + PrintMacroInstantiations(); return true; } @@ -272,7 +313,12 @@ bool AsmParser::EnterIncludeFile(const std::string &Filename) { return false; } - + +void AsmParser::JumpToLoc(SMLoc Loc) { + CurBuffer = SrcMgr.FindBufferContainingLoc(Loc); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), Loc.getPointer()); +} + const AsmToken &AsmParser::Lex() { const AsmToken *tok = &Lexer.Lex(); @@ -281,9 +327,7 @@ const AsmToken &AsmParser::Lex() { // include stack. SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); if (ParentIncludeLoc != SMLoc()) { - CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), - ParentIncludeLoc.getPointer()); + JumpToLoc(ParentIncludeLoc); tok = &Lexer.Lex(); } } @@ -716,7 +760,12 @@ bool AsmParser::ParseStatement() { default: // Normal instruction or directive. break; } - + + // If macros are enabled, check to see if this is a macro instantiation. + if (MacrosEnabled) + if (const Macro *M = MacroMap.lookup(IDVal)) + return HandleMacroEntry(IDVal, IDLoc, M); + // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.') { // Assembler features @@ -806,17 +855,6 @@ bool AsmParser::ParseStatement() { if (IDVal == ".include") return ParseDirectiveInclude(); - // If macros are enabled, check to see if this is a macro instantiation. - if (MacrosEnabled) { - if (const Macro *M = MacroMap.lookup(IDVal)) { - (void) M; - - Error(IDLoc, "macros are not yet supported"); - EatToEndOfStatement(); - return false; - } - } - // Look up the handler in the handler table. std::pair Handler = DirectiveMap.lookup(IDVal); @@ -871,6 +909,54 @@ bool AsmParser::ParseStatement() { return HadError; } +MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL) + : 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; + + // We include the .endmacro in the buffer as our queue to exit the macro + // instantiation. + Buf += ".endmacro\n"; + + Instantiation = MemoryBuffer::getMemBufferCopy(Buf, ""); +} + +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"); + + EatToEndOfStatement(); + + // Create the macro instantiation object and add to the current macro + // instantiation stack. + MacroInstantiation *MI = new MacroInstantiation(M, NameLoc, + getTok().getLoc()); + ActiveMacros.push_back(MI); + + // Jump to the macro instantiation and prime the lexer. + CurBuffer = SrcMgr.AddNewSourceBuffer(MI->Instantiation, SMLoc()); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + Lex(); + + return false; +} + +void AsmParser::HandleMacroExit() { + // Jump to the EndOfStatement we should return to, and consume it. + JumpToLoc(ActiveMacros.back()->ExitLoc); + Lex(); + + // Pop the instantiation entry. + delete ActiveMacros.back(); + ActiveMacros.pop_back(); +} + bool AsmParser::ParseAssignment(StringRef Name) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); @@ -1715,9 +1801,15 @@ bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + Directive + "' directive"); - // If we see a .endmacro directly, it is a stray entry in the file; well - // formed .endmacro directives are handled during the macro definition - // parsing. + // If we are inside a macro instantiation, terminate the current + // instantiation. + if (!getParser().ActiveMacros.empty()) { + getParser().HandleMacroExit(); + return false; + } + + // Otherwise, this .endmacro is a stray entry in the file; well formed + // .endmacro directives are handled during the macro definition parsing. return TokError("unexpected '" + Directive + "' in file, " "no current macro definition"); } diff --git a/test/MC/AsmParser/macros-parsing.s b/test/MC/AsmParser/macros-parsing.s index ad195053eb8..cac67aac232 100644 --- a/test/MC/AsmParser/macros-parsing.s +++ b/test/MC/AsmParser/macros-parsing.s @@ -8,7 +8,7 @@ // CHECK-ERRORS: 9:1: warning: ignoring directive for now .test0 .macros_on -// CHECK-ERRORS: 12:1: error: macros are not yet supported + .test0 // CHECK-ERRORS: macro '.test0' is already defined -- 2.34.1