Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/MC/MCParser/MasmParser.cpp
Show First 20 Lines • Show All 605 Lines • ▼ Show 20 Lines | private: | ||||
/// | /// | ||||
/// \param InBuffer If not 0, should be the known buffer id that contains the | /// \param InBuffer If not 0, should be the known buffer id that contains the | ||||
/// location. | /// location. | ||||
void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0, | void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0, | ||||
bool EndStatementAtEOF = true); | bool EndStatementAtEOF = true); | ||||
/// Parse up to a token of kind \p EndTok and return the contents from the | /// Parse up to a token of kind \p EndTok and return the contents from the | ||||
/// current token up to (but not including) this token; the current token on | /// current token up to (but not including) this token; the current token on | ||||
/// exit will be either this kind or EOF. | /// exit will be either this kind or EOF. Reads through instantiated macro | ||||
StringRef parseStringTo(AsmToken::TokenKind EndTok); | /// functions and text macros. | ||||
SmallVector<StringRef, 1> parseStringRefsTo(AsmToken::TokenKind EndTok); | |||||
std::string parseStringTo(AsmToken::TokenKind EndTok); | |||||
/// Parse up to the end of statement and return the contents from the current | /// Parse up to the end of statement and return the contents from the current | ||||
/// token until the end of the statement; the current token on exit will be | /// token until the end of the statement; the current token on exit will be | ||||
/// either the EndOfStatement or EOF. | /// either the EndOfStatement or EOF. | ||||
StringRef parseStringToEndOfStatement() override { | StringRef parseStringToEndOfStatement() override; | ||||
return parseStringTo(AsmToken::EndOfStatement); | |||||
} | |||||
bool parseTextItem(std::string &Data); | bool parseTextItem(std::string &Data); | ||||
unsigned getBinOpPrecedence(AsmToken::TokenKind K, | unsigned getBinOpPrecedence(AsmToken::TokenKind K, | ||||
MCBinaryExpr::Opcode &Kind); | MCBinaryExpr::Opcode &Kind); | ||||
bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); | bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); | ||||
bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); | bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); | ||||
▲ Show 20 Lines • Show All 486 Lines • ▼ Show 20 Lines | if (getTok().is(AsmToken::EndOfStatement)) { | ||||
if (!getTok().getString().empty() && getTok().getString().front() != '\n' && | if (!getTok().getString().empty() && getTok().getString().front() != '\n' && | ||||
getTok().getString().front() != '\r' && MAI.preserveAsmComments()) | getTok().getString().front() != '\r' && MAI.preserveAsmComments()) | ||||
Out.addExplicitComment(Twine(getTok().getString())); | Out.addExplicitComment(Twine(getTok().getString())); | ||||
} | } | ||||
const AsmToken *tok = &Lexer.Lex(); | const AsmToken *tok = &Lexer.Lex(); | ||||
while (tok->is(AsmToken::Identifier)) { | while (tok->is(AsmToken::Identifier)) { | ||||
auto it = Variables.find(tok->getIdentifier()); | auto it = Variables.find(tok->getIdentifier().lower()); | ||||
Lint: Pre-merge checks: clang-tidy: warning: invalid case style for variable 'it' [readability-identifier-naming]… | |||||
const llvm::MCAsmMacro *M = | |||||
getContext().lookupMacro(tok->getIdentifier().lower()); | |||||
if (it != Variables.end() && it->second.IsText) { | if (it != Variables.end() && it->second.IsText) { | ||||
// This is a textmacro; expand it in place. | |||||
std::unique_ptr<MemoryBuffer> Instantiation = | std::unique_ptr<MemoryBuffer> Instantiation = | ||||
MemoryBuffer::getMemBufferCopy(it->second.TextValue, | MemoryBuffer::getMemBufferCopy(it->second.TextValue, | ||||
"<instantiation>"); | "<instantiation>"); | ||||
// Jump to the macro instantiation and prime the lexer. | // Jump to the macro instantiation and prime the lexer. | ||||
CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), | CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), | ||||
getTok().getEndLoc()); | getTok().getEndLoc()); | ||||
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr, | Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr, | ||||
/*EndStatementAtEOF=*/false); | /*EndStatementAtEOF=*/false); | ||||
EndStatementAtEOFStack.push_back(false); | EndStatementAtEOFStack.push_back(false); | ||||
tok = &Lexer.Lex(); | tok = &Lexer.Lex(); | ||||
} else if (M && M->Function && Lexer.peekTok().is(AsmToken::LParen)) { | |||||
// This is a macro function invocation; expand it in place. | |||||
const AsmToken MacroTok = *tok; | |||||
tok = &Lexer.Lex(); | |||||
if (handleMacroInvocation(M, MacroTok.getLoc())) { | |||||
Lexer.UnLex(AsmToken(AsmToken::Error, MacroTok.getIdentifier())); | |||||
tok = &Lexer.Lex(); | |||||
} | |||||
continue; | |||||
} else { | } else { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// Parse comments here to be deferred until end of next statement. | // Parse comments here to be deferred until end of next statement. | ||||
while (tok->is(AsmToken::Comment)) { | while (tok->is(AsmToken::Comment)) { | ||||
if (MAI.preserveAsmComments()) | if (MAI.preserveAsmComments()) | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | if (!ParsingMSInlineAsm && !getStreamer().getCurrentSectionOnly()) { | ||||
return Error(getTok().getLoc(), | return Error(getTok().getLoc(), | ||||
"expected section directive before assembly directive"); | "expected section directive before assembly directive"); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
/// Throw away the rest of the line for testing purposes. | /// Throw away the rest of the line for testing purposes. | ||||
void MasmParser::eatToEndOfStatement() { | void MasmParser::eatToEndOfStatement() { | ||||
while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) | while (Lexer.isNot(AsmToken::EndOfStatement)) { | ||||
if (Lexer.is(AsmToken::Eof)) { | |||||
SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); | |||||
if (ParentIncludeLoc == SMLoc()) { | |||||
break; | |||||
} | |||||
EndStatementAtEOFStack.pop_back(); | |||||
jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back()); | |||||
} | |||||
Lexer.Lex(); | Lexer.Lex(); | ||||
} | |||||
// Eat EOL. | // Eat EOL. | ||||
if (Lexer.is(AsmToken::EndOfStatement)) | if (Lexer.is(AsmToken::EndOfStatement)) | ||||
Lexer.Lex(); | Lexer.Lex(); | ||||
} | } | ||||
StringRef MasmParser::parseStringTo(AsmToken::TokenKind EndTok) { | SmallVector<StringRef, 1> | ||||
MasmParser::parseStringRefsTo(AsmToken::TokenKind EndTok) { | |||||
SmallVector<StringRef, 1> Refs; | |||||
const char *Start = getTok().getLoc().getPointer(); | const char *Start = getTok().getLoc().getPointer(); | ||||
while (Lexer.isNot(EndTok)) { | |||||
if (Lexer.is(AsmToken::Eof)) { | |||||
SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); | |||||
if (ParentIncludeLoc == SMLoc()) { | |||||
break; | |||||
} | |||||
Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start); | |||||
while (Lexer.isNot(EndTok) && Lexer.isNot(AsmToken::Eof)) | EndStatementAtEOFStack.pop_back(); | ||||
jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back()); | |||||
Lexer.Lex(); | |||||
Start = getTok().getLoc().getPointer(); | |||||
} else { | |||||
Lexer.Lex(); | |||||
} | |||||
} | |||||
Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start); | |||||
return Refs; | |||||
} | |||||
std::string MasmParser::parseStringTo(AsmToken::TokenKind EndTok) { | |||||
SmallVector<StringRef, 1> Refs = parseStringRefsTo(EndTok); | |||||
std::string Str; | |||||
for (StringRef S : Refs) { | |||||
Str.append(S.str()); | |||||
} | |||||
return Str; | |||||
} | |||||
StringRef MasmParser::parseStringToEndOfStatement() { | |||||
const char *Start = getTok().getLoc().getPointer(); | |||||
while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) | |||||
Lexer.Lex(); | Lexer.Lex(); | ||||
const char *End = getTok().getLoc().getPointer(); | const char *End = getTok().getLoc().getPointer(); | ||||
return StringRef(Start, End - Start); | return StringRef(Start, End - Start); | ||||
} | } | ||||
/// Parse a paren expression and return it. | /// Parse a paren expression and return it. | ||||
/// NOTE: This assumes the leading '(' has already been consumed. | /// NOTE: This assumes the leading '(' has already been consumed. | ||||
Show All 21 Lines | bool MasmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) { | ||||
EndLoc = getTok().getEndLoc(); | EndLoc = getTok().getEndLoc(); | ||||
if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression")) | if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression")) | ||||
return true; | return true; | ||||
return false; | return false; | ||||
} | } | ||||
/// Parse a primary expression and return it. | /// Parse a primary expression and return it. | ||||
/// primaryexpr ::= (parenexpr | /// primaryexpr ::= (parenexpr | ||||
/// primaryexpr ::= macro_function "(" macro_arguments ")" | |||||
/// primaryexpr ::= symbol | /// primaryexpr ::= symbol | ||||
/// primaryexpr ::= number | /// primaryexpr ::= number | ||||
/// primaryexpr ::= '.' | /// primaryexpr ::= '.' | ||||
/// primaryexpr ::= ~,+,-,'not' primaryexpr | /// primaryexpr ::= ~,+,-,'not' primaryexpr | ||||
/// primaryexpr ::= string | /// primaryexpr ::= string | ||||
/// (a string is interpreted as a 64-bit number in big-endian base-256) | /// (a string is interpreted as a 64-bit number in big-endian base-256) | ||||
bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, | bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, | ||||
AsmTypeInfo *TypeInfo) { | AsmTypeInfo *TypeInfo) { | ||||
Show All 34 Lines | case AsmToken::Identifier: { | ||||
} | } | ||||
// Parse named bitwise negation. | // Parse named bitwise negation. | ||||
if (Identifier.equals_lower("not")) { | if (Identifier.equals_lower("not")) { | ||||
if (parsePrimaryExpr(Res, EndLoc, nullptr)) | if (parsePrimaryExpr(Res, EndLoc, nullptr)) | ||||
return true; | return true; | ||||
Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); | Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); | ||||
return false; | return false; | ||||
} | } | ||||
// Parse macro function invocation. | |||||
if (const MCAsmMacro *M = getContext().lookupMacro(Identifier)) { | |||||
if (handleMacroInvocation(M, FirstTokenLoc)) | |||||
return true; | |||||
return parsePrimaryExpr(Res, EndLoc, nullptr); | |||||
} | |||||
// Parse symbol variant. | // Parse symbol variant. | ||||
std::pair<StringRef, StringRef> Split; | std::pair<StringRef, StringRef> Split; | ||||
if (!MAI.useParensForSymbolVariant()) { | if (!MAI.useParensForSymbolVariant()) { | ||||
if (FirstTokenKind == AsmToken::String) { | if (FirstTokenKind == AsmToken::String) { | ||||
if (Lexer.is(AsmToken::At)) { | if (Lexer.is(AsmToken::At)) { | ||||
Lex(); // eat @ | Lex(); // eat @ | ||||
SMLoc AtLoc = getLexer().getLoc(); | SMLoc AtLoc = getLexer().getLoc(); | ||||
StringRef VName; | StringRef VName; | ||||
▲ Show 20 Lines • Show All 662 Lines • ▼ Show 20 Lines | if (LocalLabelVal == -1) { | ||||
Sym = getContext().getOrCreateSymbol(IDVal); | Sym = getContext().getOrCreateSymbol(IDVal); | ||||
} else | } else | ||||
Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal); | Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal); | ||||
// End of Labels should be treated as end of line for lexing | // End of Labels should be treated as end of line for lexing | ||||
// purposes but that information is not available to the Lexer who | // purposes but that information is not available to the Lexer who | ||||
// does not understand Labels. This may cause us to see a Hash | // does not understand Labels. This may cause us to see a Hash | ||||
// here instead of a preprocessor line comment. | // here instead of a preprocessor line comment. | ||||
if (getTok().is(AsmToken::Hash)) { | if (getTok().is(AsmToken::Hash)) { | ||||
StringRef CommentStr = parseStringToEndOfStatement(); | std::string CommentStr = parseStringTo(AsmToken::EndOfStatement); | ||||
Lexer.Lex(); | Lexer.Lex(); | ||||
Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); | Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); | ||||
} | } | ||||
// Consume any end of statement token, if present, to avoid spurious | // Consume any end of statement token, if present, to avoid spurious | ||||
// AddBlankLine calls(). | // AddBlankLine calls(). | ||||
if (getTok().is(AsmToken::EndOfStatement)) { | if (getTok().is(AsmToken::EndOfStatement)) { | ||||
Lex(); | Lex(); | ||||
Show All 16 Lines | case AsmToken::Colon: { | ||||
return false; | return false; | ||||
} | } | ||||
default: // Normal instruction or directive. | default: // Normal instruction or directive. | ||||
break; | break; | ||||
} | } | ||||
// If macros are enabled, check to see if this is a macro instantiation. | // If macros are enabled, check to see if this is a macro instantiation. | ||||
if (const MCAsmMacro *M = getContext().lookupMacro(IDVal)) { | if (const MCAsmMacro *M = getContext().lookupMacro(IDVal.lower())) { | ||||
if (M->Function) { | |||||
return handleMacroInvocation(M, IDLoc); | |||||
} else { | |||||
return handleMacroEntry(M, IDLoc); | return handleMacroEntry(M, IDLoc); | ||||
} | } | ||||
} | |||||
// Otherwise, we have a normal instruction or directive. | // Otherwise, we have a normal instruction or directive. | ||||
if (DirKind != DK_NO_DIRECTIVE) { | if (DirKind != DK_NO_DIRECTIVE) { | ||||
// There are several entities interested in parsing directives: | // There are several entities interested in parsing directives: | ||||
// | // | ||||
// 1. Asm parser extensions. For example, platform-specific parsers | // 1. Asm parser extensions. For example, platform-specific parsers | ||||
// (like the ELF parser) register themselves as extensions. | // (like the ELF parser) register themselves as extensions. | ||||
▲ Show 20 Lines • Show All 582 Lines • ▼ Show 20 Lines | if (Pos == End) | ||||
break; | break; | ||||
unsigned I = Pos; | unsigned I = Pos; | ||||
bool InitialAmpersand = (Body[I] == '&'); | bool InitialAmpersand = (Body[I] == '&'); | ||||
if (InitialAmpersand) { | if (InitialAmpersand) { | ||||
++I; | ++I; | ||||
++Pos; | ++Pos; | ||||
} | } | ||||
while (isMacroParameterChar(Body[I]) && I + 1 != End) | while (I < End && isMacroParameterChar(Body[I])) | ||||
++I; | ++I; | ||||
const char *Begin = Body.data() + Pos; | const char *Begin = Body.data() + Pos; | ||||
StringRef Argument(Begin, I - Pos); | StringRef Argument(Begin, I - Pos); | ||||
unsigned Index = 0; | unsigned Index = 0; | ||||
for (; Index < NParameters; ++Index) | for (; Index < NParameters; ++Index) | ||||
if (Parameters[Index].Name == Argument) | if (Parameters[Index].Name == Argument) | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
} // end anonymous namespace | } // end anonymous namespace | ||||
bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP, | bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP, | ||||
MCAsmMacroArgument &MA, | MCAsmMacroArgument &MA, | ||||
AsmToken::TokenKind EndTok) { | AsmToken::TokenKind EndTok) { | ||||
if (MP && MP->Vararg) { | if (MP && MP->Vararg) { | ||||
if (Lexer.isNot(EndTok)) { | if (Lexer.isNot(EndTok)) { | ||||
StringRef Str = parseStringTo(EndTok); | SmallVector<StringRef, 1> Str = parseStringRefsTo(EndTok); | ||||
MA.emplace_back(AsmToken::String, Str); | for (StringRef S : Str) { | ||||
MA.emplace_back(AsmToken::String, S); | |||||
} | |||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
SMLoc StrLoc = Lexer.getLoc(), EndLoc; | SMLoc StrLoc = Lexer.getLoc(), EndLoc; | ||||
if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) { | if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) { | ||||
const char *StrChar = StrLoc.getPointer() + 1; | const char *StrChar = StrLoc.getPointer() + 1; | ||||
const char *EndChar = EndLoc.getPointer() - 1; | const char *EndChar = EndLoc.getPointer() - 1; | ||||
jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back()); | jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back()); | ||||
/// Eat from '<' to '>'. | /// Eat from '<' to '>'. | ||||
Lex(); | Lex(); | ||||
MA.emplace_back(AsmToken::String, StringRef(StrChar, EndChar - StrChar)); | MA.emplace_back(AsmToken::String, StringRef(StrChar, EndChar - StrChar)); | ||||
Show All 13 Lines | if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) | ||||
return TokError("unexpected token"); | return TokError("unexpected token"); | ||||
if (ParenLevel == 0) { | if (ParenLevel == 0) { | ||||
if (Lexer.is(AsmToken::Comma)) | if (Lexer.is(AsmToken::Comma)) | ||||
break; | break; | ||||
if (Lexer.is(AsmToken::Space)) { | if (Lexer.is(AsmToken::Space)) { | ||||
SpaceEaten = true; | SpaceEaten = true; | ||||
Lexer.Lex(); // Eat spaces. | Lex(); // Eat spaces. | ||||
} | } | ||||
// Spaces can delimit parameters, but could also be part an expression. | // Spaces can delimit parameters, but could also be part an expression. | ||||
// If the token after a space is an operator, add the token and the next | // If the token after a space is an operator, add the token and the next | ||||
// one into this argument | // one into this argument | ||||
if (!IsDarwin) { | if (!IsDarwin) { | ||||
if (isOperator(Lexer.getKind()) && Lexer.isNot(EndTok)) { | if (isOperator(Lexer.getKind()) && Lexer.isNot(EndTok)) { | ||||
MA.push_back(getTok()); | MA.push_back(getTok()); | ||||
Lexer.Lex(); | Lex(); | ||||
// Whitespace after an operator can be ignored. | // Whitespace after an operator can be ignored. | ||||
if (Lexer.is(AsmToken::Space)) | if (Lexer.is(AsmToken::Space)) | ||||
Lexer.Lex(); | Lex(); | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
if (SpaceEaten) | if (SpaceEaten) | ||||
break; | break; | ||||
} | } | ||||
// handleMacroEntry relies on not advancing the lexer here | // handleMacroEntry relies on not advancing the lexer here | ||||
// to be able to fill in the remaining default parameter values | // to be able to fill in the remaining default parameter values | ||||
if (Lexer.is(EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0)) | if (Lexer.is(EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0)) | ||||
break; | break; | ||||
// Adjust the current parentheses level. | // Adjust the current parentheses level. | ||||
if (Lexer.is(AsmToken::LParen)) | if (Lexer.is(AsmToken::LParen)) | ||||
++ParenLevel; | ++ParenLevel; | ||||
else if (Lexer.is(AsmToken::RParen) && ParenLevel) | else if (Lexer.is(AsmToken::RParen) && ParenLevel) | ||||
--ParenLevel; | --ParenLevel; | ||||
// Append the token to the current argument list. | // Append the token to the current argument list. | ||||
MA.push_back(getTok()); | MA.push_back(getTok()); | ||||
Lexer.Lex(); | Lex(); | ||||
} | } | ||||
if (ParenLevel != 0) | if (ParenLevel != 0) | ||||
return TokError("unbalanced parentheses in argument"); | return TokError("unbalanced parentheses in argument"); | ||||
if (MA.empty() && MP) { | if (MA.empty() && MP) { | ||||
if (MP->Required) { | if (MP->Required) { | ||||
return TokError("missing value for required parameter '" + MP->Name + | return TokError("missing value for required parameter '" + MP->Name + | ||||
▲ Show 20 Lines • Show All 2,625 Lines • ▼ Show 20 Lines | if (getLexer().is(AsmToken::Identifier)) { | ||||
++MacroDepth; | ++MacroDepth; | ||||
} | } | ||||
} | } | ||||
// Otherwise, scan til the end of the statement. | // Otherwise, scan til the end of the statement. | ||||
eatToEndOfStatement(); | eatToEndOfStatement(); | ||||
} | } | ||||
if (getContext().lookupMacro(Name)) { | if (getContext().lookupMacro(Name.lower())) { | ||||
return Error(NameLoc, "macro '" + Name + "' is already defined"); | return Error(NameLoc, "macro '" + Name + "' is already defined"); | ||||
} | } | ||||
const char *BodyStart = StartToken.getLoc().getPointer(); | const char *BodyStart = StartToken.getLoc().getPointer(); | ||||
const char *BodyEnd = EndToken.getLoc().getPointer(); | const char *BodyEnd = EndToken.getLoc().getPointer(); | ||||
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); | StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); | ||||
MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals), | MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals), | ||||
MacroFunction); | MacroFunction); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | while (true) { | ||||
SMLoc NameLoc; | SMLoc NameLoc; | ||||
if (parseTokenLoc(NameLoc) || | if (parseTokenLoc(NameLoc) || | ||||
check(parseIdentifier(Name), NameLoc, | check(parseIdentifier(Name), NameLoc, | ||||
"expected identifier in 'purge' directive")) | "expected identifier in 'purge' directive")) | ||||
return true; | return true; | ||||
DEBUG_WITH_TYPE("asm-macros", dbgs() | DEBUG_WITH_TYPE("asm-macros", dbgs() | ||||
<< "Un-defining macro: " << Name << "\n"); | << "Un-defining macro: " << Name << "\n"); | ||||
if (!getContext().lookupMacro(Name)) | if (!getContext().lookupMacro(Name.lower())) | ||||
return Error(NameLoc, "macro '" + Name + "' is not defined"); | return Error(NameLoc, "macro '" + Name + "' is not defined"); | ||||
getContext().undefineMacro(Name); | getContext().undefineMacro(Name.lower()); | ||||
if (!parseOptionalToken(AsmToken::Comma)) | if (!parseOptionalToken(AsmToken::Comma)) | ||||
break; | break; | ||||
parseOptionalToken(AsmToken::EndOfStatement); | parseOptionalToken(AsmToken::EndOfStatement); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | bool MasmParser::parseDirectiveComm(bool IsLocal) { | ||||
return false; | return false; | ||||
} | } | ||||
/// parseDirectiveComment | /// parseDirectiveComment | ||||
/// ::= comment delimiter [[text]] | /// ::= comment delimiter [[text]] | ||||
/// [[text]] | /// [[text]] | ||||
/// [[text]] delimiter [[text]] | /// [[text]] delimiter [[text]] | ||||
bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) { | bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) { | ||||
StringRef FirstLine = parseStringToEndOfStatement(); | std::string FirstLine = parseStringTo(AsmToken::EndOfStatement); | ||||
size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A "); | size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A "); | ||||
StringRef Delimiter = FirstLine.take_front(DelimiterEnd); | StringRef Delimiter = StringRef(FirstLine).take_front(DelimiterEnd); | ||||
if (Delimiter.empty()) | if (Delimiter.empty()) | ||||
return Error(DirectiveLoc, "no delimiter in 'comment' directive"); | return Error(DirectiveLoc, "no delimiter in 'comment' directive"); | ||||
do { | do { | ||||
if (getTok().is(AsmToken::Eof)) | if (getTok().is(AsmToken::Eof)) | ||||
return Error(DirectiveLoc, "unmatched delimiter in 'comment' directive"); | return Error(DirectiveLoc, "unmatched delimiter in 'comment' directive"); | ||||
Lex(); // eat end of statement | Lex(); // eat end of statement | ||||
} while (!parseStringToEndOfStatement().contains(Delimiter)); | } while ( | ||||
!StringRef(parseStringTo(AsmToken::EndOfStatement)).contains(Delimiter)); | |||||
return parseToken(AsmToken::EndOfStatement, | return parseToken(AsmToken::EndOfStatement, | ||||
"unexpected token in 'comment' directive"); | "unexpected token in 'comment' directive"); | ||||
} | } | ||||
/// parseDirectiveInclude | /// parseDirectiveInclude | ||||
/// ::= include <filename> | /// ::= include <filename> | ||||
/// | include filename | /// | include filename | ||||
bool MasmParser::parseDirectiveInclude() { | bool MasmParser::parseDirectiveInclude() { | ||||
// Allow the strings to have escaped octal character sequence. | // Allow the strings to have escaped octal character sequence. | ||||
std::string Filename; | std::string Filename; | ||||
SMLoc IncludeLoc = getTok().getLoc(); | SMLoc IncludeLoc = getTok().getLoc(); | ||||
if (!parseAngleBracketString(Filename)) | if (!parseAngleBracketString(Filename)) | ||||
Filename = parseStringToEndOfStatement().str(); | Filename = parseStringTo(AsmToken::EndOfStatement); | ||||
if (check(!Filename.empty(), "missing filename in 'include' directive") || | if (check(!Filename.empty(), "missing filename in 'include' directive") || | ||||
check(getTok().isNot(AsmToken::EndOfStatement), | check(getTok().isNot(AsmToken::EndOfStatement), | ||||
"unexpected token in 'include' directive") || | "unexpected token in 'include' directive") || | ||||
// Attempt to switch the lexer to the included file before consuming the | // Attempt to switch the lexer to the included file before consuming the | ||||
// end of statement to avoid losing it when we switch. | // end of statement to avoid losing it when we switch. | ||||
check(enterIncludeFile(Filename), IncludeLoc, | check(enterIncludeFile(Filename), IncludeLoc, | ||||
"Could not find include file '" + Filename + "'")) | "Could not find include file '" + Filename + "'")) | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 346 Lines • ▼ Show 20 Lines | |||||
bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) { | bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) { | ||||
if (!TheCondStack.empty()) { | if (!TheCondStack.empty()) { | ||||
if (TheCondStack.back().Ignore) { | if (TheCondStack.back().Ignore) { | ||||
eatToEndOfStatement(); | eatToEndOfStatement(); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
StringRef Message = ".err directive invoked in source file"; | std::string Message = ".err directive invoked in source file"; | ||||
if (Lexer.isNot(AsmToken::EndOfStatement)) | if (Lexer.isNot(AsmToken::EndOfStatement)) | ||||
Message = parseStringToEndOfStatement(); | Message = parseStringTo(AsmToken::EndOfStatement); | ||||
Lex(); | Lex(); | ||||
return Error(DirectiveLoc, Message); | return Error(DirectiveLoc, Message); | ||||
} | } | ||||
/// parseDirectiveErrorIfb | /// parseDirectiveErrorIfb | ||||
/// ::= .errb textitem[, message] | /// ::= .errb textitem[, message] | ||||
bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank) { | bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank) { | ||||
if (!TheCondStack.empty()) { | if (!TheCondStack.empty()) { | ||||
if (TheCondStack.back().Ignore) { | if (TheCondStack.back().Ignore) { | ||||
eatToEndOfStatement(); | eatToEndOfStatement(); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
std::string Text; | std::string Text; | ||||
if (parseTextItem(Text)) | if (parseTextItem(Text)) | ||||
return Error(getTok().getLoc(), "missing text item in '.errb' directive"); | return Error(getTok().getLoc(), "missing text item in '.errb' directive"); | ||||
StringRef Message = ".errb directive invoked in source file"; | std::string Message = ".errb directive invoked in source file"; | ||||
if (Lexer.isNot(AsmToken::EndOfStatement)) { | if (Lexer.isNot(AsmToken::EndOfStatement)) { | ||||
if (parseToken(AsmToken::Comma)) | if (parseToken(AsmToken::Comma)) | ||||
return addErrorSuffix(" in '.errb' directive"); | return addErrorSuffix(" in '.errb' directive"); | ||||
Message = parseStringToEndOfStatement(); | Message = parseStringTo(AsmToken::EndOfStatement); | ||||
} | } | ||||
Lex(); | Lex(); | ||||
if (Text.empty() == ExpectBlank) | if (Text.empty() == ExpectBlank) | ||||
return Error(DirectiveLoc, Message); | return Error(DirectiveLoc, Message); | ||||
return false; | return false; | ||||
} | } | ||||
Show All 21 Lines | if (!IsDefined) { | ||||
if (Variables.find(Name) != Variables.end()) { | if (Variables.find(Name) != Variables.end()) { | ||||
IsDefined = true; | IsDefined = true; | ||||
} else { | } else { | ||||
MCSymbol *Sym = getContext().lookupSymbol(Name); | MCSymbol *Sym = getContext().lookupSymbol(Name); | ||||
IsDefined = (Sym && !Sym->isUndefined(false)); | IsDefined = (Sym && !Sym->isUndefined(false)); | ||||
} | } | ||||
} | } | ||||
StringRef Message = ".errdef directive invoked in source file"; | std::string Message = ".errdef directive invoked in source file"; | ||||
if (Lexer.isNot(AsmToken::EndOfStatement)) { | if (Lexer.isNot(AsmToken::EndOfStatement)) { | ||||
if (parseToken(AsmToken::Comma)) | if (parseToken(AsmToken::Comma)) | ||||
return addErrorSuffix(" in '.errdef' directive"); | return addErrorSuffix(" in '.errdef' directive"); | ||||
Message = parseStringToEndOfStatement(); | Message = parseStringTo(AsmToken::EndOfStatement); | ||||
} | } | ||||
Lex(); | Lex(); | ||||
if (IsDefined == ExpectDefined) | if (IsDefined == ExpectDefined) | ||||
return Error(DirectiveLoc, Message); | return Error(DirectiveLoc, Message); | ||||
return false; | return false; | ||||
} | } | ||||
Show All 26 Lines | bool MasmParser::parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual, | ||||
Lex(); | Lex(); | ||||
if (parseTextItem(String2)) { | if (parseTextItem(String2)) { | ||||
if (ExpectEqual) | if (ExpectEqual) | ||||
return TokError("expected string parameter for '.erridn' directive"); | return TokError("expected string parameter for '.erridn' directive"); | ||||
return TokError("expected string parameter for '.errdif' directive"); | return TokError("expected string parameter for '.errdif' directive"); | ||||
} | } | ||||
StringRef Message; | std::string Message; | ||||
if (ExpectEqual) | if (ExpectEqual) | ||||
Message = ".erridn directive invoked in source file"; | Message = ".erridn directive invoked in source file"; | ||||
else | else | ||||
Message = ".errdif directive invoked in source file"; | Message = ".errdif directive invoked in source file"; | ||||
if (Lexer.isNot(AsmToken::EndOfStatement)) { | if (Lexer.isNot(AsmToken::EndOfStatement)) { | ||||
if (parseToken(AsmToken::Comma)) | if (parseToken(AsmToken::Comma)) | ||||
return addErrorSuffix(" in '.erridn' directive"); | return addErrorSuffix(" in '.erridn' directive"); | ||||
Message = parseStringToEndOfStatement(); | Message = parseStringTo(AsmToken::EndOfStatement); | ||||
} | } | ||||
Lex(); | Lex(); | ||||
if (CaseInsensitive) | if (CaseInsensitive) | ||||
TheCondState.CondMet = | TheCondState.CondMet = | ||||
ExpectEqual == (StringRef(String1).equals_lower(String2)); | ExpectEqual == (StringRef(String1).equals_lower(String2)); | ||||
else | else | ||||
TheCondState.CondMet = ExpectEqual == (String1 == String2); | TheCondState.CondMet = ExpectEqual == (String1 == String2); | ||||
Show All 15 Lines | if (TheCondStack.back().Ignore) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
int64_t ExprValue; | int64_t ExprValue; | ||||
if (parseAbsoluteExpression(ExprValue)) | if (parseAbsoluteExpression(ExprValue)) | ||||
return addErrorSuffix(" in '.erre' directive"); | return addErrorSuffix(" in '.erre' directive"); | ||||
StringRef Message = ".erre directive invoked in source file"; | std::string Message = ".erre directive invoked in source file"; | ||||
if (Lexer.isNot(AsmToken::EndOfStatement)) { | if (Lexer.isNot(AsmToken::EndOfStatement)) { | ||||
if (parseToken(AsmToken::Comma)) | if (parseToken(AsmToken::Comma)) | ||||
return addErrorSuffix(" in '.erre' directive"); | return addErrorSuffix(" in '.erre' directive"); | ||||
Message = parseStringToEndOfStatement(); | Message = parseStringTo(AsmToken::EndOfStatement); | ||||
} | } | ||||
Lex(); | Lex(); | ||||
if ((ExprValue == 0) == ExpectZero) | if ((ExprValue == 0) == ExpectZero) | ||||
return Error(DirectiveLoc, Message); | return Error(DirectiveLoc, Message); | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Lines | MCAsmMacro *MasmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { | ||||
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); | StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); | ||||
// We Are Anonymous. | // We Are Anonymous. | ||||
MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters()); | MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters()); | ||||
return &MacroLikeBodies.back(); | return &MacroLikeBodies.back(); | ||||
} | } | ||||
bool MasmParser::expandStatement(SMLoc Loc) { | bool MasmParser::expandStatement(SMLoc Loc) { | ||||
SMLoc StartLoc = getTok().getLoc(); | std::string Body = parseStringTo(AsmToken::EndOfStatement); | ||||
eatToEndOfStatement(); | |||||
SMLoc EndLoc = getTok().getLoc(); | SMLoc EndLoc = getTok().getLoc(); | ||||
StringRef Body = StringRef(StartLoc.getPointer(), | |||||
EndLoc.getPointer() - StartLoc.getPointer()); | |||||
MCAsmMacroParameters Parameters; | MCAsmMacroParameters Parameters; | ||||
MCAsmMacroArguments Arguments; | MCAsmMacroArguments Arguments; | ||||
for (const auto &V : Variables) { | for (const auto &V : Variables) { | ||||
const Variable &Var = V.getValue(); | const Variable &Var = V.getValue(); | ||||
if (Var.IsText) { | if (Var.IsText) { | ||||
Parameters.emplace_back(); | Parameters.emplace_back(); | ||||
Arguments.emplace_back(); | Arguments.emplace_back(); | ||||
MCAsmMacroParameter &P = Parameters.back(); | MCAsmMacroParameter &P = Parameters.back(); | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | if (check(parseIdentifier(Parameter.Name), | ||||
"expected identifier in '" + Directive + "' directive") || | "expected identifier in '" + Directive + "' directive") || | ||||
parseToken(AsmToken::Comma, | parseToken(AsmToken::Comma, | ||||
"expected comma in '" + Directive + "' directive")) | "expected comma in '" + Directive + "' directive")) | ||||
return true; | return true; | ||||
if (parseAngleBracketString(Argument)) { | if (parseAngleBracketString(Argument)) { | ||||
// Match ml64.exe; treat all characters to end of statement as a string, | // Match ml64.exe; treat all characters to end of statement as a string, | ||||
// ignoring comment markers, then discard anything following a space (using | // ignoring comment markers, then discard anything following a space (using | ||||
// the C locale). | // the C locale). | ||||
Argument = parseStringToEndOfStatement().str(); | Argument = parseStringTo(AsmToken::EndOfStatement); | ||||
if (getTok().is(AsmToken::EndOfStatement)) | if (getTok().is(AsmToken::EndOfStatement)) | ||||
Argument += getTok().getString(); | Argument += getTok().getString(); | ||||
size_t End = 0; | size_t End = 0; | ||||
for (; End < Argument.size(); ++End) { | for (; End < Argument.size(); ++End) { | ||||
if (isSpace(Argument[End])) | if (isSpace(Argument[End])) | ||||
break; | break; | ||||
} | } | ||||
Argument.resize(End); | Argument.resize(End); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (!isPowerOf2_64(IntValue)) | ||||
return Error(ExprLoc, "literal value not a power of two greater then zero"); | return Error(ExprLoc, "literal value not a power of two greater then zero"); | ||||
Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue)); | Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue)); | ||||
return false; | return false; | ||||
} | } | ||||
bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) { | bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) { | ||||
const SMLoc Loc = getLexer().getLoc(); | const SMLoc Loc = getLexer().getLoc(); | ||||
StringRef RadixString = parseStringToEndOfStatement().trim(); | std::string RadixStringRaw = parseStringTo(AsmToken::EndOfStatement); | ||||
StringRef RadixString = StringRef(RadixStringRaw).trim(); | |||||
unsigned Radix; | unsigned Radix; | ||||
if (RadixString.getAsInteger(10, Radix)) { | if (RadixString.getAsInteger(10, Radix)) { | ||||
return Error(Loc, | return Error(Loc, | ||||
"radix must be a decimal number in the range 2 to 16; was " + | "radix must be a decimal number in the range 2 to 16; was " + | ||||
RadixString); | RadixString); | ||||
} | } | ||||
if (Radix < 2 || Radix > 16) | if (Radix < 2 || Radix > 16) | ||||
return Error(Loc, "radix must be in the range 2 to 16; was " + | return Error(Loc, "radix must be in the range 2 to 16; was " + | ||||
std::to_string(Radix)); | std::to_string(Radix)); | ||||
getLexer().setMasmDefaultRadix(Radix); | getLexer().setMasmDefaultRadix(Radix); | ||||
return false; | return false; | ||||
} | } | ||||
/// parseDirectiveEcho | /// parseDirectiveEcho | ||||
/// ::= "echo" message | /// ::= "echo" message | ||||
bool MasmParser::parseDirectiveEcho() { | bool MasmParser::parseDirectiveEcho() { | ||||
// We're called before the directive is parsed, to avoid triggering lexical | // We're called before the directive is parsed, to avoid triggering lexical | ||||
// substitutions in the message. Assert that the next token is the directive, | // substitutions in the message. Assert that the next token is the directive, | ||||
// then eat it without using the Parser's Lex method. | // then eat it without using the Parser's Lex method. | ||||
assert(getTok().is(AsmToken::Identifier) && | assert(getTok().is(AsmToken::Identifier) && | ||||
getTok().getString().equals_lower("echo")); | getTok().getString().equals_lower("echo")); | ||||
Lexer.Lex(); | Lexer.Lex(); | ||||
SMLoc StartLoc = getTok().getLoc(); | std::string Message = parseStringTo(AsmToken::EndOfStatement); | ||||
eatToEndOfStatement(); | |||||
SMLoc EndLoc = getTok().getLoc(); | |||||
StringRef Message = StringRef(StartLoc.getPointer(), | |||||
EndLoc.getPointer() - StartLoc.getPointer()); | |||||
llvm::outs() << Message; | llvm::outs() << Message; | ||||
if (Message.back() != '\n') | if (!StringRef(Message).endswith("\n")) | ||||
llvm::outs() << '\n'; | llvm::outs() << '\n'; | ||||
return false; | return false; | ||||
} | } | ||||
// We are comparing pointers, but the pointers are relative to a single string. | // We are comparing pointers, but the pointers are relative to a single string. | ||||
// Thus, this should always be deterministic. | // Thus, this should always be deterministic. | ||||
static int rewritesSort(const AsmRewrite *AsmRewriteA, | static int rewritesSort(const AsmRewrite *AsmRewriteA, | ||||
const AsmRewrite *AsmRewriteB) { | const AsmRewrite *AsmRewriteB) { | ||||
▲ Show 20 Lines • Show All 392 Lines • Show Last 20 Lines |
clang-tidy: warning: invalid case style for variable 'it' [readability-identifier-naming]
not useful