MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {}
namespace {
-
/// \brief Helper types for tracking macro definitions.
typedef std::vector<AsmToken> MCAsmMacroArgument;
typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
-typedef std::pair<StringRef, MCAsmMacroArgument> MCAsmMacroParameter;
+
+struct MCAsmMacroParameter {
+ StringRef Name;
+ MCAsmMacroArgument Value;
+ bool Required;
+
+ MCAsmMacroParameter() : Required(false) { }
+};
+
typedef std::vector<MCAsmMacroParameter> MCAsmMacroParameters;
struct MCAsmMacro {
MCAsmMacroParameters Parameters;
public:
- MCAsmMacro(StringRef N, StringRef B, const MCAsmMacroParameters &P) :
+ MCAsmMacro(StringRef N, StringRef B, ArrayRef<MCAsmMacroParameter> P) :
Name(N), Body(B), Parameters(P) {}
-
- MCAsmMacro(const MCAsmMacro& Other)
- : Name(Other.Name), Body(Other.Body), Parameters(Other.Parameters) {}
};
/// \brief Helper class for storing information about an active macro
bool parseCppHashLineFilenameComment(const SMLoc &L);
void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body,
- MCAsmMacroParameters Parameters);
+ ArrayRef<MCAsmMacroParameter> Parameters);
bool expandMacro(raw_svector_ostream &OS, StringRef Body,
- const MCAsmMacroParameters &Parameters,
- const MCAsmMacroArguments &A,
+ ArrayRef<MCAsmMacroParameter> Parameters,
+ ArrayRef<MCAsmMacroArgument> A,
const SMLoc &L);
/// \brief Are macros enabled in the parser?
} else if (MAI.doesAllowAtInName() && !MAI.useParensForSymbolVariant()) {
Variant = MCSymbolRefExpr::VK_None;
} else {
- Variant = MCSymbolRefExpr::VK_None;
return Error(SMLoc::getFromPointer(Split.second.begin()),
"invalid variant '" + Split.second + "'");
}
}
bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
- const MCAsmMacroParameters &Parameters,
- const MCAsmMacroArguments &A, const SMLoc &L) {
+ ArrayRef<MCAsmMacroParameter> Parameters,
+ ArrayRef<MCAsmMacroArgument> A, const SMLoc &L) {
unsigned NParameters = Parameters.size();
- if (NParameters != 0 && NParameters != A.size())
+ if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
return Error(L, "Wrong number of arguments");
// A macro without parameters is handled differently on Darwin:
std::size_t End = Body.size(), Pos = 0;
for (; Pos != End; ++Pos) {
// Check for a substitution or escape.
- if (!NParameters) {
+ if (IsDarwin && !NParameters) {
// This macro has no parameters, look for $0, $1, etc.
if (Body[Pos] != '$' || Pos + 1 == End)
continue;
if (Pos == End)
break;
- if (!NParameters) {
+ if (IsDarwin && !NParameters) {
switch (Body[Pos + 1]) {
// $$ => $
case '$':
StringRef Argument(Begin, I - (Pos + 1));
unsigned Index = 0;
for (; Index < NParameters; ++Index)
- if (Parameters[Index].first == Argument)
+ if (Parameters[Index].Name == Argument)
break;
if (Index == NParameters) {
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);
+ 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) {
- MCAsmMacroArgument MA;
+ SMLoc IDLoc = Lexer.getLoc();
+ MCAsmMacroParameter FA;
+
+ if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) {
+ if (parseIdentifier(FA.Name)) {
+ Error(IDLoc, "invalid argument identifier for formal argument");
+ eatToEndOfStatement();
+ return true;
+ }
+
+ if (!Lexer.is(AsmToken::Equal)) {
+ TokError("expected '=' after formal parameter identifier");
+ eatToEndOfStatement();
+ return true;
+ }
+ Lex();
- if (parseMacroArgument(MA))
+ NamedParametersFound = true;
+ }
+
+ if (NamedParametersFound && FA.Name.empty()) {
+ Error(IDLoc, "cannot mix positional and keyword arguments");
+ eatToEndOfStatement();
return true;
+ }
- if (!MA.empty() || (!NParameters && !Lexer.is(AsmToken::EndOfStatement)))
- A.push_back(MA);
- else if (NParameters) {
- if (!M->Parameters[Parameter].second.empty())
- A.push_back(M->Parameters[Parameter].second);
- else
- A.push_back(MA);
+ if (parseMacroArgument(FA.Value))
+ return true;
+
+ unsigned PI = Parameter;
+ if (!FA.Name.empty()) {
+ unsigned FAI = 0;
+ for (FAI = 0; FAI < NParameters; ++FAI)
+ if (M->Parameters[FAI].Name == FA.Name)
+ break;
+
+ if (FAI >= NParameters) {
+ Error(IDLoc,
+ "parameter named '" + FA.Name + "' does not exist for macro '" +
+ M->Name + "'");
+ return true;
+ }
+ PI = FAI;
+ }
+
+ if (!FA.Value.empty()) {
+ 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)) {
- if (NParameters && Parameter < NParameters - 1) {
- continue;
+ 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 false;
+ return Failure;
}
if (Lexer.is(AsmToken::Comma))
Lex();
}
- return TokError("Too many arguments");
+
+ return TokError("too many positional arguments");
}
const MCAsmMacro *AsmParser::lookupMacro(StringRef Name) {
if (Lexer.isNot(AsmToken::EndOfStatement))
return TokError("unexpected token in assignment");
- // Error on assignment to '.'.
- if (Name == ".") {
- return Error(EqualLoc, ("assignment to pseudo-symbol '.' is unsupported "
- "(use '.space' or '.org').)"));
- }
-
// Eat the end of statement marker.
Lex();
// Don't count these checks as uses.
Sym->setUsed(false);
+ } else if (Name == ".") {
+ if (Out.EmitValueToOffset(Value, 0)) {
+ Error(EqualLoc, "expected absolute expression");
+ eatToEndOfStatement();
+ }
+ return false;
} else
Sym = getContext().GetOrCreateSymbol(Name);
- // FIXME: Handle '.'.
-
// Do the assignment.
Out.EmitAssignment(Sym, Value);
if (NoDeadStrip)
}
/// parseDirectiveMacro
-/// ::= .macro name [parameters]
+/// ::= .macro name[,] [parameters]
bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
StringRef Name;
if (parseIdentifier(Name))
return TokError("expected identifier in '.macro' directive");
+ if (getLexer().is(AsmToken::Comma))
+ Lex();
+
MCAsmMacroParameters Parameters;
while (getLexer().isNot(AsmToken::EndOfStatement)) {
MCAsmMacroParameter Parameter;
- if (parseIdentifier(Parameter.first))
+ 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();
- if (parseMacroArgument(Parameter.second))
+
+ 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);
Lex();
AsmToken EndToken, StartToken = getTok();
+ unsigned MacroDepth = 0;
// Lex the macro definition.
for (;;) {
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;
+ if (getLexer().is(AsmToken::Identifier)) {
+ if (getTok().getIdentifier() == ".endm" ||
+ getTok().getIdentifier() == ".endmacro") {
+ if (MacroDepth == 0) { // Outermost macro.
+ EndToken = getTok();
+ Lex();
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '" + EndToken.getIdentifier() +
+ "' directive");
+ break;
+ } else {
+ // Otherwise we just found the end of an inner macro.
+ --MacroDepth;
+ }
+ } else if (getTok().getIdentifier() == ".macro") {
+ // We allow nested macros. Those aren't instantiated until the outermost
+ // macro is expanded so just ignore them for now.
+ ++MacroDepth;
+ }
}
// Otherwise, scan til the end of the statement.
/// and the strings like $1 are infact to simply to be passed trough unchanged.
void AsmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,
StringRef Body,
- MCAsmMacroParameters Parameters) {
+ ArrayRef<MCAsmMacroParameter> Parameters) {
// If this macro is not defined with named parameters the warning we are
// checking for here doesn't apply.
unsigned NParameters = Parameters.size();
StringRef Argument(Begin, I - (Pos + 1));
unsigned Index = 0;
for (; Index < NParameters; ++Index)
- if (Parameters[Index].first == Argument)
+ if (Parameters[Index].Name == Argument)
break;
if (Index == NParameters) {
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
// We Are Anonymous.
- StringRef Name;
- MCAsmMacroParameters Parameters;
- MacroLikeBodies.push_back(MCAsmMacro(Name, Body, Parameters));
+ MacroLikeBodies.push_back(MCAsmMacro(StringRef(), Body, None));
return &MacroLikeBodies.back();
}
// Macro instantiation is lexical, unfortunately. We construct a new buffer
// to hold the macro body with substitutions.
SmallString<256> Buf;
- MCAsmMacroParameters Parameters;
- MCAsmMacroArguments A;
raw_svector_ostream OS(Buf);
while (Count--) {
- if (expandMacro(OS, M->Body, Parameters, A, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, None, None, getTok().getLoc()))
return true;
}
instantiateMacroLikeBody(M, DirectiveLoc, OS);
/// parseDirectiveIrp
/// ::= .irp symbol,values
bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {
- MCAsmMacroParameters Parameters;
MCAsmMacroParameter Parameter;
- if (parseIdentifier(Parameter.first))
+ if (parseIdentifier(Parameter.Name))
return TokError("expected identifier in '.irp' directive");
- Parameters.push_back(Parameter);
-
if (Lexer.isNot(AsmToken::Comma))
return TokError("expected comma in '.irp' directive");
raw_svector_ostream OS(Buf);
for (MCAsmMacroArguments::iterator i = A.begin(), e = A.end(); i != e; ++i) {
- MCAsmMacroArguments Args;
- Args.push_back(*i);
-
- if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, Parameter, *i, getTok().getLoc()))
return true;
}
/// parseDirectiveIrpc
/// ::= .irpc symbol,values
bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {
- MCAsmMacroParameters Parameters;
MCAsmMacroParameter Parameter;
- if (parseIdentifier(Parameter.first))
+ if (parseIdentifier(Parameter.Name))
return TokError("expected identifier in '.irpc' directive");
- Parameters.push_back(Parameter);
-
if (Lexer.isNot(AsmToken::Comma))
return TokError("expected comma in '.irpc' directive");
raw_svector_ostream OS(Buf);
StringRef Values = A.front().front().getString();
- std::size_t I, End = Values.size();
- for (I = 0; I < End; ++I) {
+ for (std::size_t I = 0, End = Values.size(); I != End; ++I) {
MCAsmMacroArgument Arg;
Arg.push_back(AsmToken(AsmToken::Identifier, Values.slice(I, I + 1)));
- MCAsmMacroArguments Args;
- Args.push_back(Arg);
-
- if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, Parameter, Arg, getTok().getLoc()))
return true;
}