mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
MC/AsmParser: Add basic support for macro instantiation.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108653 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6d8cf082f6
commit
c64a0d7c3e
@ -45,6 +45,25 @@ public:
|
|||||||
Macro(StringRef N, StringRef B) : Name(N), Body(B) {}
|
Macro(StringRef N, StringRef B) : Name(N), Body(B) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Helper class for storing information about an active macro
|
||||||
|
/// instantiation.
|
||||||
|
struct MacroInstantiation {
|
||||||
|
/// The macro being instantiated.
|
||||||
|
const Macro *TheMacro;
|
||||||
|
|
||||||
|
/// The macro instantiation with substitutions.
|
||||||
|
MemoryBuffer *Instantiation;
|
||||||
|
|
||||||
|
/// The location of the instantiation.
|
||||||
|
SMLoc InstantiationLoc;
|
||||||
|
|
||||||
|
/// The location where parsing should resume upon instantiation completion.
|
||||||
|
SMLoc ExitLoc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL);
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief The concrete assembly parser instance.
|
/// \brief The concrete assembly parser instance.
|
||||||
class AsmParser : public MCAsmParser {
|
class AsmParser : public MCAsmParser {
|
||||||
friend class GenericAsmParser;
|
friend class GenericAsmParser;
|
||||||
@ -75,6 +94,9 @@ private:
|
|||||||
/// MacroMap - Map of currently defined macros.
|
/// MacroMap - Map of currently defined macros.
|
||||||
StringMap<Macro*> MacroMap;
|
StringMap<Macro*> MacroMap;
|
||||||
|
|
||||||
|
/// ActiveMacros - Stack of active macro instantiations.
|
||||||
|
std::vector<MacroInstantiation*> ActiveMacros;
|
||||||
|
|
||||||
/// Boolean tracking whether macro substitution is enabled.
|
/// Boolean tracking whether macro substitution is enabled.
|
||||||
unsigned MacrosEnabled : 1;
|
unsigned MacrosEnabled : 1;
|
||||||
|
|
||||||
@ -115,11 +137,20 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool ParseStatement();
|
bool ParseStatement();
|
||||||
|
|
||||||
|
bool HandleMacroEntry(StringRef Name, SMLoc NameLoc, const Macro *M);
|
||||||
|
void HandleMacroExit();
|
||||||
|
|
||||||
|
void PrintMacroInstantiations();
|
||||||
void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const;
|
void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const;
|
||||||
|
|
||||||
/// EnterIncludeFile - Enter the specified file. This returns true on failure.
|
/// EnterIncludeFile - Enter the specified file. This returns true on failure.
|
||||||
bool EnterIncludeFile(const std::string &Filename);
|
bool EnterIncludeFile(const std::string &Filename);
|
||||||
|
|
||||||
|
/// \brief Reset the current lexer position to that given by \arg Loc. The
|
||||||
|
/// current token is not set; clients should ensure Lex() is called
|
||||||
|
/// subsequently.
|
||||||
|
void JumpToLoc(SMLoc Loc);
|
||||||
|
|
||||||
void EatToEndOfStatement();
|
void EatToEndOfStatement();
|
||||||
|
|
||||||
bool ParseAssignment(StringRef Name);
|
bool ParseAssignment(StringRef Name);
|
||||||
@ -247,12 +278,22 @@ AsmParser::~AsmParser() {
|
|||||||
delete GenericParser;
|
delete GenericParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsmParser::PrintMacroInstantiations() {
|
||||||
|
// Print the active macro instantiation stack.
|
||||||
|
for (std::vector<MacroInstantiation*>::const_reverse_iterator
|
||||||
|
it = ActiveMacros.rbegin(), ie = ActiveMacros.rend(); it != ie; ++it)
|
||||||
|
PrintMessage((*it)->InstantiationLoc, "while in macro instantiation",
|
||||||
|
"note");
|
||||||
|
}
|
||||||
|
|
||||||
void AsmParser::Warning(SMLoc L, const Twine &Msg) {
|
void AsmParser::Warning(SMLoc L, const Twine &Msg) {
|
||||||
PrintMessage(L, Msg.str(), "warning");
|
PrintMessage(L, Msg.str(), "warning");
|
||||||
|
PrintMacroInstantiations();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsmParser::Error(SMLoc L, const Twine &Msg) {
|
bool AsmParser::Error(SMLoc L, const Twine &Msg) {
|
||||||
PrintMessage(L, Msg.str(), "error");
|
PrintMessage(L, Msg.str(), "error");
|
||||||
|
PrintMacroInstantiations();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +313,12 @@ bool AsmParser::EnterIncludeFile(const std::string &Filename) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsmParser::JumpToLoc(SMLoc Loc) {
|
||||||
|
CurBuffer = SrcMgr.FindBufferContainingLoc(Loc);
|
||||||
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), Loc.getPointer());
|
||||||
|
}
|
||||||
|
|
||||||
const AsmToken &AsmParser::Lex() {
|
const AsmToken &AsmParser::Lex() {
|
||||||
const AsmToken *tok = &Lexer.Lex();
|
const AsmToken *tok = &Lexer.Lex();
|
||||||
|
|
||||||
@ -281,9 +327,7 @@ const AsmToken &AsmParser::Lex() {
|
|||||||
// include stack.
|
// include stack.
|
||||||
SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
|
SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
|
||||||
if (ParentIncludeLoc != SMLoc()) {
|
if (ParentIncludeLoc != SMLoc()) {
|
||||||
CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc);
|
JumpToLoc(ParentIncludeLoc);
|
||||||
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer),
|
|
||||||
ParentIncludeLoc.getPointer());
|
|
||||||
tok = &Lexer.Lex();
|
tok = &Lexer.Lex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -716,7 +760,12 @@ bool AsmParser::ParseStatement() {
|
|||||||
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 (MacrosEnabled)
|
||||||
|
if (const Macro *M = MacroMap.lookup(IDVal))
|
||||||
|
return HandleMacroEntry(IDVal, IDLoc, M);
|
||||||
|
|
||||||
// Otherwise, we have a normal instruction or directive.
|
// Otherwise, we have a normal instruction or directive.
|
||||||
if (IDVal[0] == '.') {
|
if (IDVal[0] == '.') {
|
||||||
// Assembler features
|
// Assembler features
|
||||||
@ -806,17 +855,6 @@ bool AsmParser::ParseStatement() {
|
|||||||
if (IDVal == ".include")
|
if (IDVal == ".include")
|
||||||
return ParseDirectiveInclude();
|
return ParseDirectiveInclude();
|
||||||
|
|
||||||
// If macros are enabled, check to see if this is a macro instantiation.
|
|
||||||
if (MacrosEnabled) {
|
|
||||||
if (const Macro *M = MacroMap.lookup(IDVal)) {
|
|
||||||
(void) M;
|
|
||||||
|
|
||||||
Error(IDLoc, "macros are not yet supported");
|
|
||||||
EatToEndOfStatement();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up the handler in the handler table.
|
// Look up the handler in the handler table.
|
||||||
std::pair<MCAsmParserExtension*, DirectiveHandler> Handler =
|
std::pair<MCAsmParserExtension*, DirectiveHandler> Handler =
|
||||||
DirectiveMap.lookup(IDVal);
|
DirectiveMap.lookup(IDVal);
|
||||||
@ -871,6 +909,54 @@ bool AsmParser::ParseStatement() {
|
|||||||
return HadError;
|
return HadError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL)
|
||||||
|
: TheMacro(M), InstantiationLoc(IL), ExitLoc(EL)
|
||||||
|
{
|
||||||
|
// Macro instantiation is lexical, unfortunately. We construct a new buffer
|
||||||
|
// to hold the macro body with substitutions.
|
||||||
|
llvm::SmallString<256> Buf;
|
||||||
|
Buf += M->Body;
|
||||||
|
|
||||||
|
// We include the .endmacro in the buffer as our queue to exit the macro
|
||||||
|
// instantiation.
|
||||||
|
Buf += ".endmacro\n";
|
||||||
|
|
||||||
|
Instantiation = MemoryBuffer::getMemBufferCopy(Buf, "<instantiation>");
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
EatToEndOfStatement();
|
||||||
|
|
||||||
|
// Create the macro instantiation object and add to the current macro
|
||||||
|
// instantiation stack.
|
||||||
|
MacroInstantiation *MI = new MacroInstantiation(M, NameLoc,
|
||||||
|
getTok().getLoc());
|
||||||
|
ActiveMacros.push_back(MI);
|
||||||
|
|
||||||
|
// Jump to the macro instantiation and prime the lexer.
|
||||||
|
CurBuffer = SrcMgr.AddNewSourceBuffer(MI->Instantiation, SMLoc());
|
||||||
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer));
|
||||||
|
Lex();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsmParser::HandleMacroExit() {
|
||||||
|
// Jump to the EndOfStatement we should return to, and consume it.
|
||||||
|
JumpToLoc(ActiveMacros.back()->ExitLoc);
|
||||||
|
Lex();
|
||||||
|
|
||||||
|
// Pop the instantiation entry.
|
||||||
|
delete ActiveMacros.back();
|
||||||
|
ActiveMacros.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
bool AsmParser::ParseAssignment(StringRef Name) {
|
bool AsmParser::ParseAssignment(StringRef Name) {
|
||||||
// FIXME: Use better location, we should use proper tokens.
|
// FIXME: Use better location, we should use proper tokens.
|
||||||
SMLoc EqualLoc = Lexer.getLoc();
|
SMLoc EqualLoc = Lexer.getLoc();
|
||||||
@ -1715,9 +1801,15 @@ bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive,
|
|||||||
if (getLexer().isNot(AsmToken::EndOfStatement))
|
if (getLexer().isNot(AsmToken::EndOfStatement))
|
||||||
return TokError("unexpected token in '" + Directive + "' directive");
|
return TokError("unexpected token in '" + Directive + "' directive");
|
||||||
|
|
||||||
// If we see a .endmacro directly, it is a stray entry in the file; well
|
// If we are inside a macro instantiation, terminate the current
|
||||||
// formed .endmacro directives are handled during the macro definition
|
// instantiation.
|
||||||
// parsing.
|
if (!getParser().ActiveMacros.empty()) {
|
||||||
|
getParser().HandleMacroExit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, this .endmacro is a stray entry in the file; well formed
|
||||||
|
// .endmacro directives are handled during the macro definition parsing.
|
||||||
return TokError("unexpected '" + Directive + "' in file, "
|
return TokError("unexpected '" + Directive + "' in file, "
|
||||||
"no current macro definition");
|
"no current macro definition");
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// CHECK-ERRORS: 9:1: warning: ignoring directive for now
|
// CHECK-ERRORS: 9:1: warning: ignoring directive for now
|
||||||
.test0
|
.test0
|
||||||
.macros_on
|
.macros_on
|
||||||
// CHECK-ERRORS: 12:1: error: macros are not yet supported
|
|
||||||
.test0
|
.test0
|
||||||
|
|
||||||
// CHECK-ERRORS: macro '.test0' is already defined
|
// CHECK-ERRORS: macro '.test0' is already defined
|
||||||
|
Loading…
Reference in New Issue
Block a user