diff options
Diffstat (limited to 'lib/MC/MCParser/AsmParser.cpp')
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 511 |
1 files changed, 448 insertions, 63 deletions
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 8aef43c..b67c769 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -45,13 +45,18 @@ FatalAssemblerWarnings("fatal-assembler-warnings", namespace { /// \brief Helper class for tracking macro definitions. +typedef std::vector<AsmToken> MacroArgument; +typedef std::vector<MacroArgument> MacroArguments; +typedef StringRef MacroParameter; +typedef std::vector<MacroParameter> MacroParameters; + struct Macro { StringRef Name; StringRef Body; - std::vector<StringRef> Parameters; + MacroParameters Parameters; public: - Macro(StringRef N, StringRef B, const std::vector<StringRef> &P) : + Macro(StringRef N, StringRef B, const MacroParameters &P) : Name(N), Body(B), Parameters(P) {} }; @@ -178,9 +183,9 @@ private: bool ParseCppHashLineFilenameComment(const SMLoc &L); bool HandleMacroEntry(StringRef Name, SMLoc NameLoc, const Macro *M); - bool expandMacro(SmallString<256> &Buf, StringRef Body, - const std::vector<StringRef> &Parameters, - const std::vector<std::vector<AsmToken> > &A, + bool expandMacro(raw_svector_ostream &OS, StringRef Body, + const MacroParameters &Parameters, + const MacroArguments &A, const SMLoc &L); void HandleMacroExit(); @@ -204,11 +209,18 @@ private: void EatToEndOfStatement(); + bool ParseMacroArgument(MacroArgument &MA); + bool ParseMacroArguments(const Macro *M, MacroArguments &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. StringRef ParseStringToEndOfStatement(); + /// \brief Parse until the end of a statement or a comma is encountered, + /// return the contents from the current token up to the end or comma. + StringRef ParseStringToComma(); + bool ParseAssignment(StringRef Name, bool allow_redef); bool ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); @@ -245,6 +257,10 @@ private: bool ParseDirectiveIncbin(); // ".incbin" bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" + // ".ifb" or ".ifnb", depending on ExpectBlank. + bool ParseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank); + // ".ifc" or ".ifnc", depending on ExpectEqual. + bool ParseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual); // ".ifdef" or ".ifndef", depending on expect_defined bool ParseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined); bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" @@ -257,6 +273,15 @@ private: const MCExpr *ApplyModifierToExpr(const MCExpr *E, MCSymbolRefExpr::VariantKind Variant); + + // Macro-like directives + Macro *ParseMacroLikeBody(SMLoc DirectiveLoc); + void InstantiateMacroLikeBody(Macro *M, SMLoc DirectiveLoc, + raw_svector_ostream &OS); + bool ParseDirectiveRept(SMLoc DirectiveLoc); // ".rept" + bool ParseDirectiveIrp(SMLoc DirectiveLoc); // ".irp" + bool ParseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc" + bool ParseDirectiveEndr(SMLoc DirectiveLoc); // ".endr" }; /// \brief Generic implementations of directive handling, etc. which is shared @@ -328,6 +353,7 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacro>(".macro"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endm"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endmacro"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectivePurgeMacro>(".purgem"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".sleb128"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".uleb128"); @@ -359,6 +385,7 @@ public: bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); + bool ParseDirectivePurgeMacro(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLEB128(StringRef, SMLoc); }; @@ -456,7 +483,7 @@ bool AsmParser::EnterIncludeFile(const std::string &Filename) { } /// Process the specified .incbin file by seaching for it in the include paths -/// then just emiting the byte contents of the file to the streamer. This +/// then just emitting the byte contents of the file to the streamer. This /// returns true on failure. bool AsmParser::ProcessIncbinFile(const std::string &Filename) { std::string IncludedFile; @@ -602,6 +629,18 @@ StringRef AsmParser::ParseStringToEndOfStatement() { return StringRef(Start, End - Start); } +StringRef AsmParser::ParseStringToComma() { + const char *Start = getTok().getLoc().getPointer(); + + while (Lexer.isNot(AsmToken::EndOfStatement) && + Lexer.isNot(AsmToken::Comma) && + Lexer.isNot(AsmToken::Eof)) + Lex(); + + const char *End = getTok().getLoc().getPointer(); + return StringRef(Start, End - Start); +} + /// ParseParenExpr - Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. /// @@ -700,7 +739,7 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { IDVal == "f" ? 1 : 0); Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); - if(IDVal == "b" && Sym->isUndefined()) + if (IDVal == "b" && Sym->isUndefined()) return Error(Loc, "invalid reference to undefined symbol"); EndLoc = Lexer.getLoc(); Lex(); // Eat identifier. @@ -1042,6 +1081,14 @@ bool AsmParser::ParseStatement() { // example. if (IDVal == ".if") return ParseDirectiveIf(IDLoc); + if (IDVal == ".ifb") + return ParseDirectiveIfb(IDLoc, true); + if (IDVal == ".ifnb") + return ParseDirectiveIfb(IDLoc, false); + if (IDVal == ".ifc") + return ParseDirectiveIfc(IDLoc, true); + if (IDVal == ".ifnc") + return ParseDirectiveIfc(IDLoc, false); if (IDVal == ".ifdef") return ParseDirectiveIfdef(IDLoc, true); if (IDVal == ".ifndef" || IDVal == ".ifnotdef") @@ -1123,6 +1170,11 @@ bool AsmParser::ParseStatement() { // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.' && IDVal != ".") { + + // Target hook for parsing target specific directives. + if (!getTargetParser().ParseDirective(ID)) + return false; + // Assembler features if (IDVal == ".set" || IDVal == ".equ") return ParseDirectiveSet(IDVal, true); @@ -1192,6 +1244,10 @@ bool AsmParser::ParseStatement() { // Symbol attribute directives + if (IDVal == ".extern") { + EatToEndOfStatement(); // .extern is the default, ignore it. + return false; + } if (IDVal == ".globl" || IDVal == ".global") return ParseDirectiveSymbolAttribute(MCSA_Global); if (IDVal == ".indirect_symbol") @@ -1225,22 +1281,27 @@ bool AsmParser::ParseStatement() { if (IDVal == ".incbin") return ParseDirectiveIncbin(); - if (IDVal == ".code16") + if (IDVal == ".code16" || IDVal == ".code16gcc") return TokError(Twine(IDVal) + " not supported yet"); + // Macro-like directives + if (IDVal == ".rept") + return ParseDirectiveRept(IDLoc); + if (IDVal == ".irp") + return ParseDirectiveIrp(IDLoc); + if (IDVal == ".irpc") + return ParseDirectiveIrpc(IDLoc); + if (IDVal == ".endr") + return ParseDirectiveEndr(IDLoc); + // Look up the handler in the handler table. std::pair<MCAsmParserExtension*, DirectiveHandler> Handler = DirectiveMap.lookup(IDVal); if (Handler.first) return (*Handler.second)(Handler.first, IDVal, IDLoc); - // Target hook for parsing target specific directives. - if (!getTargetParser().ParseDirective(ID)) - return false; - bool retval = Warning(IDLoc, "ignoring directive for now"); - EatToEndOfStatement(); - return retval; + return Error(IDLoc, "unknown directive"); } CheckForValidSection(); @@ -1339,7 +1400,7 @@ bool AsmParser::ParseCppHashLineFilenameComment(const SMLoc &L) { return false; } -/// DiagHandler - will use the the last parsed cpp hash line filename comment +/// DiagHandler - will use the last parsed cpp hash line filename comment /// for the Filename and LineNo if any in the diagnostic. void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { const AsmParser *Parser = static_cast<const AsmParser*>(Context); @@ -1393,11 +1454,10 @@ void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { NewDiag.print(0, OS); } -bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body, - const std::vector<StringRef> &Parameters, - const std::vector<std::vector<AsmToken> > &A, +bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, + const MacroParameters &Parameters, + const MacroArguments &A, const SMLoc &L) { - raw_svector_ostream OS(Buf); unsigned NParameters = Parameters.size(); if (NParameters != 0 && NParameters != A.size()) return Error(L, "Wrong number of arguments"); @@ -1449,7 +1509,7 @@ bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body, break; // Otherwise substitute with the token values, with spaces eliminated. - for (std::vector<AsmToken>::const_iterator it = A[Index].begin(), + for (MacroArgument::const_iterator it = A[Index].begin(), ie = A[Index].end(); it != ie; ++it) OS << it->getString(); break; @@ -1472,7 +1532,7 @@ bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body, if (Index == NParameters) return Error(L, "Parameter not found"); - for (std::vector<AsmToken>::const_iterator it = A[Index].begin(), + for (MacroArgument::const_iterator it = A[Index].begin(), ie = A[Index].end(); it != ie; ++it) OS << it->getString(); @@ -1482,9 +1542,6 @@ bool AsmParser::expandMacro(SmallString<256> &Buf, StringRef Body, Body = Body.substr(Pos); } - // We include the .endmacro in the buffer as our queue to exit the macro - // instantiation. - OS << ".endmacro\n"; return false; } @@ -1494,55 +1551,97 @@ 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<std::vector<AsmToken> > MacroArguments; - MacroArguments.push_back(std::vector<AsmToken>()); +/// 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(std::vector<AsmToken>()); - } 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, MacroArguments &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; + + 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"); + + MacroArguments A; + 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; StringRef Body = M->Body; + raw_svector_ostream OS(Buf); - if (expandMacro(Buf, Body, M->Parameters, MacroArguments, getTok().getLoc())) + if (expandMacro(OS, Body, M->Parameters, A, getTok().getLoc())) return true; + // We include the .endmacro in the buffer as our queue to exit the macro + // instantiation. + OS << ".endmacro\n"; + MemoryBuffer *Instantiation = - MemoryBuffer::getMemBufferCopy(Buf.str(), "<instantiation>"); + MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>"); // Create the macro instantiation object and add to the current macro // instantiation stack. @@ -2295,10 +2394,9 @@ bool AsmParser::ParseDirectiveIncbin() { bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { TheCondStack.push_back(TheCondState); TheCondState.TheCond = AsmCond::IfCond; - if(TheCondState.Ignore) { + if (TheCondState.Ignore) { EatToEndOfStatement(); - } - else { + } else { int64_t ExprValue; if (ParseAbsoluteExpression(ExprValue)) return true; @@ -2315,6 +2413,61 @@ bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { return false; } +/// ParseDirectiveIfb +/// ::= .ifb string +bool AsmParser::ParseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) { + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + EatToEndOfStatement(); + } else { + StringRef Str = ParseStringToEndOfStatement(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.ifb' directive"); + + Lex(); + + TheCondState.CondMet = ExpectBlank == Str.empty(); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// ParseDirectiveIfc +/// ::= .ifc string1, string2 +bool AsmParser::ParseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) { + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + EatToEndOfStatement(); + } else { + StringRef Str1 = ParseStringToComma(); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.ifc' directive"); + + Lex(); + + StringRef Str2 = ParseStringToEndOfStatement(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.ifc' directive"); + + Lex(); + + TheCondState.CondMet = ExpectEqual == (Str1 == Str2); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// ParseDirectiveIfdef +/// ::= .ifdef symbol bool AsmParser::ParseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { StringRef Name; TheCondStack.push_back(TheCondState); @@ -2853,7 +3006,7 @@ bool GenericAsmParser::ParseDirectiveCFISameValue(StringRef IDVal, /// ParseDirectiveCFIRestore /// ::= .cfi_restore register bool GenericAsmParser::ParseDirectiveCFIRestore(StringRef IDVal, - SMLoc DirectiveLoc) { + SMLoc DirectiveLoc) { int64_t Register = 0; if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) return true; @@ -2866,7 +3019,7 @@ bool GenericAsmParser::ParseDirectiveCFIRestore(StringRef IDVal, /// ParseDirectiveCFIEscape /// ::= .cfi_escape expression[,...] bool GenericAsmParser::ParseDirectiveCFIEscape(StringRef IDVal, - SMLoc DirectiveLoc) { + SMLoc DirectiveLoc) { std::string Values; int64_t CurrValue; if (getParser().ParseAbsoluteExpression(CurrValue)) @@ -2922,7 +3075,7 @@ bool GenericAsmParser::ParseDirectiveMacro(StringRef Directive, if (getParser().ParseIdentifier(Name)) return TokError("expected identifier in directive"); - std::vector<StringRef> Parameters; + MacroParameters Parameters; if (getLexer().isNot(AsmToken::EndOfStatement)) { for(;;) { StringRef Parameter; @@ -2981,7 +3134,7 @@ bool GenericAsmParser::ParseDirectiveMacro(StringRef Directive, /// ::= .endm /// ::= .endmacro bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, - SMLoc DirectiveLoc) { + SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + Directive + "' directive"); @@ -2998,6 +3151,27 @@ bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, "no current macro definition"); } +/// ParseDirectivePurgeMacro +/// ::= .purgem +bool GenericAsmParser::ParseDirectivePurgeMacro(StringRef Directive, + SMLoc DirectiveLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in '.purgem' directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.purgem' directive"); + + StringMap<Macro*>::iterator I = getParser().MacroMap.find(Name); + if (I == getParser().MacroMap.end()) + return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); + + // Undefine the macro. + delete I->getValue(); + getParser().MacroMap.erase(I); + return false; +} + bool GenericAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { getParser().CheckForValidSection(); @@ -3017,6 +3191,217 @@ bool GenericAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { return false; } +Macro *AsmParser::ParseMacroLikeBody(SMLoc DirectiveLoc) { + AsmToken EndToken, StartToken = getTok(); + + unsigned NestLevel = 0; + for (;;) { + // Check whether we have reached the end of the file. + if (getLexer().is(AsmToken::Eof)) { + Error(DirectiveLoc, "no matching '.endr' in definition"); + return 0; + } + + if (Lexer.is(AsmToken::Identifier) && + (getTok().getIdentifier() == ".rept")) { + ++NestLevel; + } + + // Otherwise, check whether we have reached the .endr. + if (Lexer.is(AsmToken::Identifier) && + getTok().getIdentifier() == ".endr") { + if (NestLevel == 0) { + EndToken = getTok(); + Lex(); + if (Lexer.isNot(AsmToken::EndOfStatement)) { + TokError("unexpected token in '.endr' directive"); + return 0; + } + break; + } + --NestLevel; + } + + // Otherwise, scan till the end of the statement. + EatToEndOfStatement(); + } + + const char *BodyStart = StartToken.getLoc().getPointer(); + const char *BodyEnd = EndToken.getLoc().getPointer(); + StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); + + // We Are Anonymous. + StringRef Name; + MacroParameters Parameters; + return new Macro(Name, Body, Parameters); +} + +void AsmParser::InstantiateMacroLikeBody(Macro *M, SMLoc DirectiveLoc, + raw_svector_ostream &OS) { + OS << ".endr\n"; + + MemoryBuffer *Instantiation = + MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>"); + + // Create the macro instantiation object and add to the current macro + // instantiation stack. + MacroInstantiation *MI = new MacroInstantiation(M, DirectiveLoc, + getTok().getLoc(), + Instantiation); + 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(); +} + +bool AsmParser::ParseDirectiveRept(SMLoc DirectiveLoc) { + int64_t Count; + if (ParseAbsoluteExpression(Count)) + return TokError("unexpected token in '.rept' directive"); + + if (Count < 0) + return TokError("Count is negative"); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.rept' directive"); + + // Eat the end of statement. + Lex(); + + // Lex the rept 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; + MacroParameters Parameters; + MacroArguments A; + raw_svector_ostream OS(Buf); + while (Count--) { + if (expandMacro(OS, M->Body, Parameters, A, getTok().getLoc())) + return true; + } + InstantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + +/// ParseDirectiveIrp +/// ::= .irp symbol,values +bool AsmParser::ParseDirectiveIrp(SMLoc DirectiveLoc) { + MacroParameters Parameters; + MacroParameter 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(); + + MacroArguments 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<MacroArgument>::iterator i = A.begin(), e = A.end(); i != e; + ++i) { + std::vector<MacroArgument> Args; + Args.push_back(*i); + + if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc())) + return true; + } + + InstantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + +/// ParseDirectiveIrpc +/// ::= .irpc symbol,values +bool AsmParser::ParseDirectiveIrpc(SMLoc DirectiveLoc) { + MacroParameters Parameters; + MacroParameter Parameter; + + if (ParseIdentifier(Parameter)) + return TokError("expected identifier in '.irpc' directive"); + + Parameters.push_back(Parameter); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("expected comma in '.irpc' directive"); + + Lex(); + + MacroArguments A; + if (ParseMacroArguments(0, A)) + return true; + + if (A.size() != 1 || A.front().size() != 1) + return TokError("unexpected token in '.irpc' directive"); + + // Eat the end of statement. + Lex(); + + // Lex the irpc 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); + + StringRef Values = A.front().front().getString(); + std::size_t I, End = Values.size(); + for (I = 0; I < End; ++I) { + MacroArgument Arg; + Arg.push_back(AsmToken(AsmToken::Identifier, Values.slice(I, I+1))); + + MacroArguments Args; + Args.push_back(Arg); + + 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"); + + // The only .repl that should get here are the ones created by + // InstantiateMacroLikeBody. + assert(getLexer().is(AsmToken::EndOfStatement)); + + HandleMacroExit(); + return false; +} /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, |