From: Daniel Dunbar Date: Sun, 18 Jul 2010 18:47:21 +0000 (+0000) Subject: MC/AsmParser: Add basic parsing support for .macro definitions. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=6d8cf082f643a585b82e8dd136641ee4638b8c7a;p=oota-llvm.git MC/AsmParser: Add basic parsing support for .macro definitions. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108652 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index d4db857a22c..eb39205336f 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -36,6 +36,15 @@ using namespace llvm; namespace { +/// \brief Helper class for tracking macro definitions. +struct Macro { + StringRef Name; + StringRef Body; + +public: + Macro(StringRef N, StringRef B) : Name(N), Body(B) {} +}; + /// \brief The concrete assembly parser instance. class AsmParser : public MCAsmParser { friend class GenericAsmParser; @@ -63,6 +72,9 @@ private: /// in the directive name and the location of the directive keyword. StringMap > DirectiveMap; + /// MacroMap - Map of currently defined macros. + StringMap MacroMap; + /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabled : 1; @@ -179,12 +191,21 @@ public: Parser.AddDirectiveHandler(this, ".macros_off", MCAsmParser::DirectiveHandler( &GenericAsmParser::ParseDirectiveMacrosOnOff)); + Parser.AddDirectiveHandler(this, ".macro", MCAsmParser::DirectiveHandler( + &GenericAsmParser::ParseDirectiveMacro)); + Parser.AddDirectiveHandler(this, ".endm", MCAsmParser::DirectiveHandler( + &GenericAsmParser::ParseDirectiveEndMacro)); + Parser.AddDirectiveHandler(this, ".endmacro", MCAsmParser::DirectiveHandler( + &GenericAsmParser::ParseDirectiveEndMacro)); } bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); }; } @@ -785,6 +806,17 @@ 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); @@ -1626,6 +1658,70 @@ bool GenericAsmParser::ParseDirectiveMacrosOnOff(StringRef Directive, return false; } +/// ParseDirectiveMacro +/// ::= .macro name +bool GenericAsmParser::ParseDirectiveMacro(StringRef Directive, + SMLoc DirectiveLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.macro' directive"); + + // Eat the end of statement. + Lex(); + + AsmToken EndToken, StartToken = getTok(); + + // Lex the macro definition. + for (;;) { + // Check whether we have reached the end of the file. + if (getLexer().is(AsmToken::Eof)) + return Error(DirectiveLoc, "no matching '.endmacro' in definition"); + + // Otherwise, check whether we have reach the .endmacro. + if (getLexer().is(AsmToken::Identifier) && + (getTok().getIdentifier() == ".endm" || + getTok().getIdentifier() == ".endmacro")) { + EndToken = getTok(); + Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + EndToken.getIdentifier() + + "' directive"); + break; + } + + // Otherwise, scan til the end of the statement. + getParser().EatToEndOfStatement(); + } + + if (getParser().MacroMap.lookup(Name)) { + return Error(DirectiveLoc, "macro '" + Name + "' is already defined"); + } + + const char *BodyStart = StartToken.getLoc().getPointer(); + const char *BodyEnd = EndToken.getLoc().getPointer(); + StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); + getParser().MacroMap[Name] = new Macro(Name, Body); + return false; +} + +/// ParseDirectiveEndMacro +/// ::= .endm +/// ::= .endmacro +bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, + SMLoc DirectiveLoc) { + 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. + return TokError("unexpected '" + Directive + "' in file, " + "no current macro definition"); +} + /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(const Target &T, SourceMgr &SM, MCContext &C, MCStreamer &Out, diff --git a/test/MC/AsmParser/macros-parsing.s b/test/MC/AsmParser/macros-parsing.s index 302baa03651..ad195053eb8 100644 --- a/test/MC/AsmParser/macros-parsing.s +++ b/test/MC/AsmParser/macros-parsing.s @@ -1,8 +1,23 @@ -// RUN: llvm-mc %s 2> %t.err +// RUN: not llvm-mc %s 2> %t.err // RUN: FileCheck --check-prefix=CHECK-ERRORS %s < %t.err -.macros_on +.macro .test0 +.endmacro + .macros_off +// 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 +.macro .test0 +.endmacro + +// CHECK-ERRORS: unexpected '.endmacro' in file +.endmacro + +// CHECK-ERRORS: no matching '.endmacro' in definition +.macro dummy -// CHECK-ERRORS: .abort '"end"' detected -.abort "end"