aboutsummaryrefslogtreecommitdiffstats
path: root/lib/MC
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2012-06-15 14:02:34 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2012-06-15 14:02:34 +0000
commitaa7a2f2ba308656e206338fe65c422e0b6781c64 (patch)
tree0decf31bedfca33830c0e407a416c7610617ada8 /lib/MC
parent6207cb519bbe9ce31eaef9a835fe6bd57dbf0d0f (diff)
downloadexternal_llvm-aa7a2f2ba308656e206338fe65c422e0b6781c64.zip
external_llvm-aa7a2f2ba308656e206338fe65c422e0b6781c64.tar.gz
external_llvm-aa7a2f2ba308656e206338fe65c422e0b6781c64.tar.bz2
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
Diffstat (limited to 'lib/MC')
-rw-r--r--lib/MC/MCParser/AsmParser.cpp145
1 files changed, 115 insertions, 30 deletions
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 04603e9..f2618e1 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<MacroArgument> &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<MacroArgument> 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<MacroArgument> &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<MacroArgument> 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<StringRef> 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<MacroArgument> 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;
+}
+
bool AsmParser::ParseDirectiveEndr(SMLoc DirectiveLoc) {
if (ActiveMacros.empty())
return TokError("unexpected '.endr' directive, no current .rept");