mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
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. llvm-svn: 158523
This commit is contained in:
parent
33d8ca2ddc
commit
9efec1f548
@ -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,6 +1543,66 @@ MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL,
|
||||
{
|
||||
}
|
||||
|
||||
/// 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 (;;) {
|
||||
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;
|
||||
|
||||
// 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 (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
|
||||
@ -1544,37 +1610,9 @@ bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc,
|
||||
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());
|
||||
unsigned ParenLevel = 0;
|
||||
for (;;) {
|
||||
if (Lexer.is(AsmToken::Eof))
|
||||
return TokError("unexpected token in macro instantiation");
|
||||
if (Lexer.is(AsmToken::EndOfStatement))
|
||||
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());
|
||||
}
|
||||
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 (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");
|
||||
|
10
test/MC/AsmParser/macro-err1.s
Normal file
10
test/MC/AsmParser/macro-err1.s
Normal file
@ -0,0 +1,10 @@
|
||||
// RUN: not llvm-mc -triple x86_64-unknown-unknown %s 2> %t
|
||||
// RUN: FileCheck < %t %s
|
||||
|
||||
.macro foo bar
|
||||
.long \bar
|
||||
.endm
|
||||
|
||||
foo 42, 42
|
||||
|
||||
// CHECK: Too many arguments
|
8
test/MC/AsmParser/macro-irp.s
Normal file
8
test/MC/AsmParser/macro-irp.s
Normal file
@ -0,0 +1,8 @@
|
||||
// RUN: llvm-mc -triple x86_64-unknown-unknown %s | FileCheck %s
|
||||
|
||||
.irp reg,%eax,%ebx
|
||||
pushl \reg
|
||||
.endr
|
||||
|
||||
// CHECK: pushl %eax
|
||||
// CHECK: pushl %ebx
|
Loading…
Reference in New Issue
Block a user