MCAsmParser: support required parameters

This enhances the macro parser to parse and handle parameter qualifications,
which is needed to support required formal parameters in macro definitions.  A
required parameter may not be defaulted (though providing a default value is
accepted with a warning).  This improves GAS compatibility.

Partially addresses PR9248.

llvm-svn: 201630
This commit is contained in:
Saleem Abdulrasool 2014-02-19 03:00:29 +00:00
parent a08585b233
commit f903a44728
3 changed files with 139 additions and 12 deletions

View File

@ -58,6 +58,9 @@ typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
struct MCAsmMacroParameter {
StringRef Name;
MCAsmMacroArgument Value;
bool Required;
MCAsmMacroParameter() : Required(false) { }
};
typedef std::vector<MCAsmMacroParameter> MCAsmMacroParameters;
@ -1940,26 +1943,23 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA) {
bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
MCAsmMacroArguments &A) {
const unsigned NParameters = M ? M->Parameters.size() : 0;
bool NamedParametersFound = false;
SmallVector<SMLoc, 4> FALocs;
A.resize(NParameters);
for (unsigned PI = 0; PI < NParameters; ++PI)
if (!M->Parameters[PI].Value.empty())
A[PI] = M->Parameters[PI].Value;
bool NamedParametersFound = false;
FALocs.resize(NParameters);
// 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) {
SMLoc IDLoc = Lexer.getLoc();
MCAsmMacroParameter FA;
SMLoc L;
if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) {
L = Lexer.getLoc();
if (parseIdentifier(FA.Name)) {
Error(L, "invalid argument identifier for formal argument");
Error(IDLoc, "invalid argument identifier for formal argument");
eatToEndOfStatement();
return true;
}
@ -1975,7 +1975,7 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
}
if (NamedParametersFound && FA.Name.empty()) {
Error(Lexer.getLoc(), "cannot mix positional and keyword arguments");
Error(IDLoc, "cannot mix positional and keyword arguments");
eatToEndOfStatement();
return true;
}
@ -1989,8 +1989,9 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
for (FAI = 0; FAI < NParameters; ++FAI)
if (M->Parameters[FAI].Name == FA.Name)
break;
if (FAI >= NParameters) {
Error(L,
Error(IDLoc,
"parameter named '" + FA.Name + "' does not exist for macro '" +
M->Name + "'");
return true;
@ -2002,13 +2003,33 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
if (A.size() <= PI)
A.resize(PI + 1);
A[PI] = FA.Value;
if (FALocs.size() <= PI)
FALocs.resize(PI + 1);
FALocs[PI] = Lexer.getLoc();
}
// At the end of the statement, fill in remaining arguments that have
// default values. If there aren't any, then the next argument is
// required but missing
if (Lexer.is(AsmToken::EndOfStatement))
return false;
if (Lexer.is(AsmToken::EndOfStatement)) {
bool Failure = false;
for (unsigned FAI = 0; FAI < NParameters; ++FAI) {
if (A[FAI].empty()) {
if (M->Parameters[FAI].Required) {
Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),
"missing value for required parameter "
"'" + M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");
Failure = true;
}
if (!M->Parameters[FAI].Value.empty())
A[FAI] = M->Parameters[FAI].Value;
}
}
return Failure;
}
if (Lexer.is(AsmToken::Comma))
Lex();
@ -3210,10 +3231,36 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
if (parseIdentifier(Parameter.Name))
return TokError("expected identifier in '.macro' directive");
if (Lexer.is(AsmToken::Colon)) {
Lex(); // consume ':'
SMLoc QualLoc;
StringRef Qualifier;
QualLoc = Lexer.getLoc();
if (parseIdentifier(Qualifier))
return Error(QualLoc, "missing parameter qualifier for "
"'" + Parameter.Name + "' in macro '" + Name + "'");
if (Qualifier == "req")
Parameter.Required = true;
else
return Error(QualLoc, Qualifier + " is not a valid parameter qualifier "
"for '" + Parameter.Name + "' in macro '" + Name + "'");
}
if (getLexer().is(AsmToken::Equal)) {
Lex();
SMLoc ParamLoc;
ParamLoc = Lexer.getLoc();
if (parseMacroArgument(Parameter.Value))
return true;
if (Parameter.Required)
Warning(ParamLoc, "pointless default value for required parameter "
"'" + Parameter.Name + "' in macro '" + Name + "'");
}
Parameters.push_back(Parameter);

View File

@ -0,0 +1,64 @@
# RUN: not llvm-mc -triple i386 -o /dev/null %s 2>&1 | FileCheck %s
.macro missing_qualifier parameter:
# CHECK: error: missing parameter qualifier for 'parameter' in macro 'missing_qualifier'
# CHECK: .macro missing_qualifier parameter:
# CHECK: ^
.macro non_identifier_qualifier parameter:0
# CHECK: error: missing parameter qualifier for 'parameter' in macro 'non_identifier_qualifier'
# CHECK: .macro non_identifier_qualifier parameter:0
# CHECK: ^
.macro invalid_qualifier parameter:invalid_qualifier
# CHECK: error: invalid_qualifier is not a valid parameter qualifier for 'parameter' in macro 'invalid_qualifier'
# CHECK: .macro invalid_qualifier parameter:invalid_qualifier
# CHECK: ^
.macro pointless_default parameter:req=default
.endm
# CHECK: warning: pointless default value for required parameter 'parameter' in macro 'pointless_default'
# CHECK: .macro pointless_default parameter:req=default
# CHECK: ^
.macro missing_required_parameter parameter:req
.endm
missing_required_parameter
# CHECK: error: missing value for required parameter 'parameter' in macro 'missing_required_parameter'
# CHECK: missing_required_parameter
# CHECK: ^
.macro missing_second_required_argument first=0 second:req
.endm
missing_second_required_argument
# CHECK: error: missing value for required parameter 'second' in macro 'missing_second_required_argument'
# CHECK: missing_second_required_argument
# CHECK: ^
.macro second_third_required first=0 second:req third:req
.endm
second_third_required 0
# CHECK: error: missing value for required parameter 'second' in macro 'second_third_required'
# CHECK: second_third_required 0
# CHECK: ^
# CHECK: error: missing value for required parameter 'third' in macro 'second_third_required'
# CHECK: second_third_required 0
# CHECK: ^
second_third_required third=3 first=1
# CHECK: error: missing value for required parameter 'second' in macro 'second_third_required'
# CHECK: second_third_required third=3 first=1
# CHECK: ^

View File

@ -0,0 +1,16 @@
# RUN: llvm-mc -triple i386 -o - %s | FileCheck %s
.macro required parameter:req
.long \parameter
.endm
required 0
# CHECK: .long 0
.macro required_with_default parameter:req=0
.long \parameter
.endm
required 1
# CHECK: .long 1