aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/MIR/MILexer.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 06:19:30 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 06:19:30 +0800
commitd62f022c92fcc3ebe2269273628943a0089683fd (patch)
tree92d13e4888b095cca71a0ac8b9b9eb99cc845596 /backend/lib/MIR/MILexer.cpp
parent236082a0fe4dcd0362c5c74923a93e3db6a01291 (diff)
downloadrcc-project-d62f022c92fcc3ebe2269273628943a0089683fd.tar.gz
rcc-project-d62f022c92fcc3ebe2269273628943a0089683fd.tar.xz
[CodeGen] Align MIR parser and printer ownership
Diffstat (limited to 'backend/lib/MIR/MILexer.cpp')
-rw-r--r--backend/lib/MIR/MILexer.cpp964
1 files changed, 0 insertions, 964 deletions
diff --git a/backend/lib/MIR/MILexer.cpp b/backend/lib/MIR/MILexer.cpp
deleted file mode 100644
index f568cef..0000000
--- a/backend/lib/MIR/MILexer.cpp
+++ /dev/null
@@ -1,964 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "rcc/MIR/MILexer.h"
-
-#include <algorithm>
-#include <array>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <iomanip>
-#include <optional>
-#include <ranges>
-#include <sstream>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-namespace rcc::mir {
-namespace {
-
-template <std::size_t Size>
-[[nodiscard]] consteval std::array<std::string_view, Size>
-sortSpellings(std::array<std::string_view, Size> Spellings) {
- for (std::size_t Left = 0; Left < Spellings.size(); ++Left) {
- for (std::size_t Right = Left + 1; Right < Spellings.size(); ++Right) {
- if (Spellings[Right] < Spellings[Left])
- std::swap(Spellings[Left], Spellings[Right]);
- }
- }
- return Spellings;
-}
-
-template <std::size_t Size>
-[[nodiscard]] consteval bool
-hasUniqueSpellings(const std::array<std::string_view, Size> &Spellings) {
- for (std::size_t Index = 1; Index < Spellings.size(); ++Index) {
- if (Spellings[Index - 1] == Spellings[Index])
- return false;
- }
- return true;
-}
-
-constexpr auto Keywords = sortSpellings(std::array{
- std::string_view{"addrspace"},
- std::string_view{"adjust_cfa_offset"},
- std::string_view{"afn"},
- std::string_view{"align"},
- std::string_view{"arcp"},
- std::string_view{"basealign"},
- std::string_view{"bb_id"},
- std::string_view{"bbsections"},
- std::string_view{"bfloat"},
- std::string_view{"blockaddress"},
- std::string_view{"call-entry"},
- std::string_view{"call-frame-size"},
- std::string_view{"cfi-type"},
- std::string_view{"constant-pool"},
- std::string_view{"contract"},
- std::string_view{"custom"},
- std::string_view{"dead"},
- std::string_view{"deactivation-symbol"},
- std::string_view{"debug-instr-number"},
- std::string_view{"debug-location"},
- std::string_view{"debug-use"},
- std::string_view{"dbg-instr-ref"},
- std::string_view{"def"},
- std::string_view{"def_cfa"},
- std::string_view{"def_cfa_offset"},
- std::string_view{"def_cfa_register"},
- std::string_view{"dereferenceable"},
- std::string_view{"disjoint"},
- std::string_view{"distinct"},
- std::string_view{"double"},
- std::string_view{"early-clobber"},
- std::string_view{"ehfunclet-entry"},
- std::string_view{"ehscope-entry"},
- std::string_view{"escape"},
- std::string_view{"exact"},
- std::string_view{"float"},
- std::string_view{"floatpred"},
- std::string_view{"fp128"},
- std::string_view{"frame-destroy"},
- std::string_view{"frame-setup"},
- std::string_view{"got"},
- std::string_view{"half"},
- std::string_view{"heap-alloc-marker"},
- std::string_view{"implicit"},
- std::string_view{"implicit-def"},
- std::string_view{"inbounds"},
- std::string_view{"inlineasm-br-indirect-target"},
- std::string_view{"internal"},
- std::string_view{"intpred"},
- std::string_view{"intrinsic"},
- std::string_view{"invariant"},
- std::string_view{"ir-block-address-taken"},
- std::string_view{"jump-table"},
- std::string_view{"killed"},
- std::string_view{"landing-pad"},
- std::string_view{"lanemask"},
- std::string_view{"liveins"},
- std::string_view{"liveout"},
- std::string_view{"llvm_def_aspace_cfa"},
- std::string_view{"llvm_register_pair"},
- std::string_view{"llvm_vector_offset"},
- std::string_view{"llvm_vector_register_mask"},
- std::string_view{"llvm_vector_registers"},
- std::string_view{"machine-block-address-taken"},
- std::string_view{"mmra"},
- std::string_view{"negate_ra_sign_state"},
- std::string_view{"negate_ra_sign_state_with_pc"},
- std::string_view{"ninf"},
- std::string_view{"nnan"},
- std::string_view{"noconvergent"},
- std::string_view{"nofpexcept"},
- std::string_view{"non-temporal"},
- std::string_view{"nneg"},
- std::string_view{"nsw"},
- std::string_view{"nsz"},
- std::string_view{"nusw"},
- std::string_view{"nuw"},
- std::string_view{"offset"},
- std::string_view{"pcsections"},
- std::string_view{"post-instr-symbol"},
- std::string_view{"ppc_fp128"},
- std::string_view{"pre-instr-symbol"},
- std::string_view{"reassoc"},
- std::string_view{"rel_offset"},
- std::string_view{"remember_state"},
- std::string_view{"renamable"},
- std::string_view{"register"},
- std::string_view{"restore"},
- std::string_view{"restore_state"},
- std::string_view{"same_value"},
- std::string_view{"samesign"},
- std::string_view{"shufflemask"},
- std::string_view{"stack"},
- std::string_view{"successors"},
- std::string_view{"target-flags"},
- std::string_view{"target-index"},
- std::string_view{"tied-def"},
- std::string_view{"undef"},
- std::string_view{"undefined"},
- std::string_view{"unknown-address"},
- std::string_view{"unknown-size"},
- std::string_view{"unpredictable"},
- std::string_view{"volatile"},
- std::string_view{"window_save"},
- std::string_view{"x86_fp80"},
-});
-
-constexpr auto MetadataKeywords = sortSpellings(std::array{
- std::string_view{"!DIExpression"},
- std::string_view{"!DILocation"},
- std::string_view{"!alias.scope"},
- std::string_view{"!noalias"},
- std::string_view{"!noalias.addrspace"},
- std::string_view{"!range"},
- std::string_view{"!tbaa"},
-});
-
-static_assert(hasUniqueSpellings(Keywords));
-static_assert(hasUniqueSpellings(MetadataKeywords));
-
-[[nodiscard]] constexpr bool isASCIIAlpha(char Character) noexcept {
- return (Character >= 'a' && Character <= 'z') || (Character >= 'A' && Character <= 'Z');
-}
-
-[[nodiscard]] constexpr bool isASCIIDigit(char Character) noexcept {
- return Character >= '0' && Character <= '9';
-}
-
-[[nodiscard]] constexpr bool isASCIIHexDigit(char Character) noexcept {
- return isASCIIDigit(Character) || (Character >= 'a' && Character <= 'f') ||
- (Character >= 'A' && Character <= 'F');
-}
-
-[[nodiscard]] constexpr unsigned hexDigitValue(char Character) noexcept {
- if (isASCIIDigit(Character))
- return static_cast<unsigned>(Character - '0');
- if (Character >= 'a' && Character <= 'f')
- return static_cast<unsigned>(Character - 'a' + 10);
- return static_cast<unsigned>(Character - 'A' + 10);
-}
-
-[[nodiscard]] constexpr bool isIdentifierCharacter(char Character) noexcept {
- return isASCIIAlpha(Character) || isASCIIDigit(Character) || Character == '_' ||
- Character == '-' || Character == '.' || Character == '$';
-}
-
-[[nodiscard]] constexpr bool isRegisterCharacter(char Character) noexcept {
- return isIdentifierCharacter(Character) && Character != '.';
-}
-
-[[nodiscard]] constexpr bool isHorizontalWhitespace(char Character) noexcept {
- return Character == ' ' || Character == '\t';
-}
-
-[[nodiscard]] constexpr bool isNewlineCharacter(char Character) noexcept {
- return Character == '\n' || Character == '\r';
-}
-
-[[nodiscard]] constexpr bool isHexFloatingPointPrefix(char Character) noexcept {
- return Character == 'H' || Character == 'K' || Character == 'L' || Character == 'M' ||
- Character == 'R';
-}
-
-[[nodiscard]] std::string unexpectedCharacterMessage(unsigned char Character) {
- if (Character >= 0x20U && Character <= 0x7EU) {
- return "unexpected character '" + std::string(1, static_cast<char>(Character)) + "'";
- }
- std::ostringstream Message;
- Message << "unexpected byte 0x" << std::uppercase << std::hex << std::setw(2) << std::setfill('0')
- << static_cast<unsigned>(Character);
- return Message.str();
-}
-
-} // namespace
-
-std::string_view getMITokenKindName(MITokenKind Kind) noexcept {
- switch (Kind) {
- case MITokenKind::EndOfFile:
- return "end-of-file";
- case MITokenKind::Error:
- return "error";
- case MITokenKind::Newline:
- return "newline";
- case MITokenKind::Comma:
- return "comma";
- case MITokenKind::Equal:
- return "equal";
- case MITokenKind::Underscore:
- return "underscore";
- case MITokenKind::Colon:
- return "colon";
- case MITokenKind::DoubleColon:
- return "double-colon";
- case MITokenKind::Dot:
- return "dot";
- case MITokenKind::Exclaim:
- return "exclaim";
- case MITokenKind::LeftParen:
- return "left-paren";
- case MITokenKind::RightParen:
- return "right-paren";
- case MITokenKind::LeftBrace:
- return "left-brace";
- case MITokenKind::RightBrace:
- return "right-brace";
- case MITokenKind::Plus:
- return "plus";
- case MITokenKind::Minus:
- return "minus";
- case MITokenKind::Less:
- return "less";
- case MITokenKind::Greater:
- return "greater";
- case MITokenKind::Keyword:
- return "keyword";
- case MITokenKind::MetadataKeyword:
- return "metadata-keyword";
- case MITokenKind::Identifier:
- return "identifier";
- case MITokenKind::NamedRegister:
- return "named-register";
- case MITokenKind::NamedVirtualRegister:
- return "named-virtual-register";
- case MITokenKind::MachineBasicBlockLabel:
- return "machine-basic-block-label";
- case MITokenKind::MachineBasicBlock:
- return "machine-basic-block";
- case MITokenKind::StackObject:
- return "stack-object";
- case MITokenKind::FixedStackObject:
- return "fixed-stack-object";
- case MITokenKind::NamedGlobalValue:
- return "named-global-value";
- case MITokenKind::GlobalValue:
- return "global-value";
- case MITokenKind::ExternalSymbol:
- return "external-symbol";
- case MITokenKind::MCSymbol:
- return "mc-symbol";
- case MITokenKind::IntegerLiteral:
- return "integer-literal";
- case MITokenKind::FloatingPointLiteral:
- return "floating-point-literal";
- case MITokenKind::HexLiteral:
- return "hex-literal";
- case MITokenKind::VirtualRegister:
- return "virtual-register";
- case MITokenKind::ConstantPoolItem:
- return "constant-pool-item";
- case MITokenKind::JumpTableIndex:
- return "jump-table-index";
- case MITokenKind::NamedIRBlock:
- return "named-ir-block";
- case MITokenKind::IRBlock:
- return "ir-block";
- case MITokenKind::NamedIRValue:
- return "named-ir-value";
- case MITokenKind::IRValue:
- return "ir-value";
- case MITokenKind::QuotedIRValue:
- return "quoted-ir-value";
- case MITokenKind::SubRegisterIndex:
- return "subregister-index";
- case MITokenKind::StringConstant:
- return "string-constant";
- }
- return "unknown";
-}
-
-bool isMIKeyword(std::string_view Spelling) noexcept {
- return std::ranges::binary_search(Keywords, Spelling);
-}
-
-bool isMIMetadataKeyword(std::string_view Spelling) noexcept {
- return std::ranges::binary_search(MetadataKeywords, Spelling);
-}
-
-std::string_view MIToken::stringValue() const noexcept {
- if (const auto *View = std::get_if<std::string_view>(&StringValue))
- return *View;
- if (const auto *Owned = std::get_if<std::string>(&StringValue))
- return *Owned;
- return {};
-}
-
-bool MIToken::isRegister() const noexcept {
- return Kind == MITokenKind::NamedRegister || Kind == MITokenKind::NamedVirtualRegister ||
- Kind == MITokenKind::VirtualRegister || Kind == MITokenKind::Underscore;
-}
-
-bool MIToken::isRegisterFlag() const noexcept {
- return isKeyword("implicit") || isKeyword("implicit-def") || isKeyword("def") ||
- isKeyword("dead") || isKeyword("killed") || isKeyword("undef") || isKeyword("internal") ||
- isKeyword("early-clobber") || isKeyword("debug-use") || isKeyword("renamable");
-}
-
-bool MIToken::isMemoryOperandFlag() const noexcept {
- return isKeyword("volatile") || isKeyword("non-temporal") || isKeyword("dereferenceable") ||
- isKeyword("invariant") || Kind == MITokenKind::StringConstant;
-}
-
-MIToken MILexer::makeToken(MITokenKind Kind, TextRange Range, std::string_view Spelling,
- std::string_view IntegerValue) {
- return MIToken(Kind, Range, Spelling, {}, IntegerValue);
-}
-
-MIToken MILexer::makeStringToken(MITokenKind Kind, TextRange Range, std::string_view Spelling,
- std::string_view StringValue, std::string_view IntegerValue) {
- return MIToken(Kind, Range, Spelling, StringValue, IntegerValue);
-}
-
-MIToken MILexer::makeOwnedStringToken(MITokenKind Kind, TextRange Range, std::string_view Spelling,
- std::string StringValue, std::string_view IntegerValue) {
- return MIToken(Kind, Range, Spelling, std::move(StringValue), IntegerValue);
-}
-
-class MILexer::Impl final {
-public:
- Impl(std::string SourceName, std::string SourceText, MILexerOptions Options)
- : Source(std::move(SourceName), std::move(SourceText)), Options(Options) {}
-
- [[nodiscard]] MIToken next() {
- if (Failed)
- return token(MITokenKind::EndOfFile, Offset, Offset);
-
- if (auto TriviaError = skipTrivia())
- return std::move(*TriviaError);
-
- if (atEnd())
- return token(MITokenKind::EndOfFile, Offset, Offset);
-
- const std::size_t Begin = Offset;
- MIToken Result = lexToken();
- if (Result.kind() == MITokenKind::Error)
- return Result;
-
- if (Options.MaximumTokenLength != 0 &&
- Result.range().End.Offset - Result.range().Begin.Offset > Options.MaximumTokenLength) {
- return fail(Begin, Offset, "machine instruction token exceeds the configured length limit");
- }
- if (Options.MaximumTokens != 0 && TokenCount >= Options.MaximumTokens) {
- return fail(Begin, Offset, "machine instruction token count exceeds the configured limit");
- }
- ++TokenCount;
- return Result;
- }
-
- [[nodiscard]] const TextSource &source() const noexcept {
- return Source;
- }
-
- [[nodiscard]] std::span<const TextDiagnostic> diagnostics() const noexcept {
- return Diagnostics;
- }
-
- [[nodiscard]] bool failed() const noexcept {
- return Failed;
- }
-
- [[nodiscard]] std::size_t tokenCount() const noexcept {
- return TokenCount;
- }
-
-private:
- struct QuotedValue final {
- std::size_t End = 0;
- std::string Value;
- };
-
- [[nodiscard]] std::string_view text() const noexcept {
- return Source.text();
- }
-
- [[nodiscard]] bool atEnd(std::size_t Lookahead = 0) const noexcept {
- return Offset >= text().size() || Lookahead >= text().size() - Offset;
- }
-
- [[nodiscard]] char peek(std::size_t Lookahead = 0) const noexcept {
- if (Offset >= text().size() || Lookahead >= text().size() - Offset)
- return '\0';
- return text()[Offset + Lookahead];
- }
-
- [[nodiscard]] bool startsWith(std::string_view Prefix) const noexcept {
- return text().substr(Offset).starts_with(Prefix);
- }
-
- [[nodiscard]] std::string_view slice(std::size_t Begin, std::size_t End) const noexcept {
- assert(Begin <= End && End <= text().size());
- return text().substr(Begin, End - Begin);
- }
-
- [[nodiscard]] MIToken token(MITokenKind Kind, std::size_t Begin, std::size_t End,
- std::string_view IntegerValue = {}) const {
- return MILexer::makeToken(Kind, Source.range(Begin, End), slice(Begin, End), IntegerValue);
- }
-
- [[nodiscard]] MIToken stringToken(MITokenKind Kind, std::size_t Begin, std::size_t End,
- std::string_view Value,
- std::string_view IntegerValue = {}) const {
- return MILexer::makeStringToken(Kind, Source.range(Begin, End), slice(Begin, End), Value,
- IntegerValue);
- }
-
- [[nodiscard]] MIToken ownedStringToken(MITokenKind Kind, std::size_t Begin, std::size_t End,
- std::string Value,
- std::string_view IntegerValue = {}) const {
- return MILexer::makeOwnedStringToken(Kind, Source.range(Begin, End), slice(Begin, End),
- std::move(Value), IntegerValue);
- }
-
- [[nodiscard]] MIToken fail(std::size_t Begin, std::size_t End, std::string Message) {
- End = std::clamp(End, Begin, text().size());
- Diagnostics.push_back(TextDiagnostic{
- .Severity = DiagnosticSeverity::Error,
- .Category = "mir-lexer",
- .Message = std::move(Message),
- .SourceName = std::string(Source.name()),
- .Range = Source.range(Begin, End),
- });
- Failed = true;
- return token(MITokenKind::Error, Begin, End);
- }
-
- [[nodiscard]] std::optional<MIToken> skipTrivia() {
- while (true) {
- while (!atEnd() && isHorizontalWhitespace(peek()))
- ++Offset;
-
- if (peek() == ';') {
- while (!atEnd() && !isNewlineCharacter(peek()))
- ++Offset;
- continue;
- }
-
- if (!startsWith("/*"))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset += 2;
- while (!atEnd() && !startsWith("*/"))
- ++Offset;
- if (atEnd()) {
- return fail(Begin, Offset,
- "end of machine instruction input reached before the closing '*/'");
- }
- Offset += 2;
- }
- }
-
- [[nodiscard]] std::optional<QuotedValue> scanQuotedString(std::size_t QuoteOffset) {
- assert(QuoteOffset < text().size() && text()[QuoteOffset] == '"');
- std::size_t Cursor = QuoteOffset + 1;
- while (Cursor < text().size() && text()[Cursor] != '"') {
- if (isNewlineCharacter(text()[Cursor])) {
- Offset = Cursor;
- static_cast<void>(fail(QuoteOffset, Cursor,
- "end of machine instruction reached before the closing '\"'"));
- return std::nullopt;
- }
- ++Cursor;
- }
- if (Cursor == text().size()) {
- Offset = Cursor;
- static_cast<void>(
- fail(QuoteOffset, Cursor, "end of machine instruction reached before the closing '\"'"));
- return std::nullopt;
- }
-
- std::string Value;
- Value.reserve(Cursor - QuoteOffset - 1);
- for (std::size_t Index = QuoteOffset + 1; Index < Cursor; ++Index) {
- const char Character = text()[Index];
- if (Character == '\\' && Index + 1 < Cursor && text()[Index + 1] == '\\') {
- Value.push_back('\\');
- ++Index;
- continue;
- }
- if (Character == '\\' && Index + 2 < Cursor && isASCIIHexDigit(text()[Index + 1]) &&
- isASCIIHexDigit(text()[Index + 2])) {
- const unsigned Decoded =
- hexDigitValue(text()[Index + 1]) * 16U + hexDigitValue(text()[Index + 2]);
- Value.push_back(static_cast<char>(Decoded));
- Index += 2;
- continue;
- }
- Value.push_back(Character);
- }
- return QuotedValue{.End = Cursor + 1, .Value = std::move(Value)};
- }
-
- [[nodiscard]] MIToken lexName(MITokenKind Kind, std::size_t PrefixLength) {
- const std::size_t Begin = Offset;
- Offset += PrefixLength;
- if (peek() == '"') {
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- return ownedStringToken(Kind, Begin, Offset, std::move(Quoted->Value));
- }
-
- const std::size_t ValueBegin = Offset;
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- return stringToken(Kind, Begin, Offset, slice(ValueBegin, Offset));
- }
-
- [[nodiscard]] std::optional<MIToken> lexMachineBasicBlock() {
- const bool IsReference = startsWith("%bb.");
- if (!IsReference && !startsWith("bb."))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- const std::size_t PrefixLength = IsReference ? 4 : 3;
- Offset += PrefixLength;
- if (!isASCIIDigit(peek())) {
- return fail(Offset, std::min(Offset + 1, text().size()),
- "expected a decimal block number after '" +
- std::string(IsReference ? "%bb.'" : "bb.'"));
- }
-
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- const std::string_view Number = slice(NumberBegin, Offset);
-
- if (peek() != '.') {
- return stringToken(IsReference ? MITokenKind::MachineBasicBlock
- : MITokenKind::MachineBasicBlockLabel,
- Begin, Offset, {}, Number);
- }
-
- ++Offset;
- const std::size_t NameBegin = Offset;
- if (peek() == '"') {
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- return ownedStringToken(IsReference ? MITokenKind::MachineBasicBlock
- : MITokenKind::MachineBasicBlockLabel,
- Begin, Offset, std::move(Quoted->Value), Number);
- }
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- return stringToken(IsReference ? MITokenKind::MachineBasicBlock
- : MITokenKind::MachineBasicBlockLabel,
- Begin, Offset, slice(NameBegin, Offset), Number);
- }
-
- [[nodiscard]] std::optional<MIToken> lexIndex(std::string_view Prefix, MITokenKind Kind,
- bool HasOptionalName) {
- if (!startsWith(Prefix) || !isASCIIDigit(peek(Prefix.size())))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset += Prefix.size();
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- const std::string_view Number = slice(NumberBegin, Offset);
-
- if (!HasOptionalName)
- return token(Kind, Begin, Offset, Number);
-
- if (peek() != '.')
- return stringToken(Kind, Begin, Offset, {}, Number);
-
- ++Offset;
- const std::size_t NameBegin = Offset;
- if (peek() == '"') {
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- return ownedStringToken(Kind, Begin, Offset, std::move(Quoted->Value), Number);
- }
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- return stringToken(Kind, Begin, Offset, slice(NameBegin, Offset), Number);
- }
-
- [[nodiscard]] std::optional<MIToken>
- lexIRReference(std::string_view Prefix, MITokenKind NumericKind, MITokenKind NamedKind) {
- if (!startsWith(Prefix))
- return std::nullopt;
- if (isASCIIDigit(peek(Prefix.size())))
- return lexIndex(Prefix, NumericKind, false);
- return lexName(NamedKind, Prefix.size());
- }
-
- [[nodiscard]] std::optional<MIToken> lexRegister() {
- if (peek() != '%' && peek() != '$')
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- const char Prefix = peek();
- ++Offset;
- if (Prefix == '%' && isASCIIDigit(peek())) {
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- return token(MITokenKind::VirtualRegister, Begin, Offset, slice(NumberBegin, Offset));
- }
-
- if (Prefix == '%' && !isRegisterCharacter(peek())) {
- Offset = Begin;
- return std::nullopt;
- }
-
- const std::size_t NameBegin = Offset;
- while (!atEnd() && isRegisterCharacter(peek()))
- ++Offset;
- return stringToken(Prefix == '%' ? MITokenKind::NamedVirtualRegister
- : MITokenKind::NamedRegister,
- Begin, Offset, slice(NameBegin, Offset));
- }
-
- [[nodiscard]] std::optional<MIToken> lexGlobalValue() {
- if (peek() != '@')
- return std::nullopt;
- if (!isASCIIDigit(peek(1)))
- return lexName(MITokenKind::NamedGlobalValue, 1);
-
- const std::size_t Begin = Offset++;
- const std::size_t NumberBegin = Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- return token(MITokenKind::GlobalValue, Begin, Offset, slice(NumberBegin, Offset));
- }
-
- [[nodiscard]] std::optional<MIToken> lexMCSymbol() {
- constexpr std::string_view Prefix = "<mcsymbol ";
- if (!startsWith(Prefix))
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset += Prefix.size();
- if (peek() != '"') {
- const std::size_t NameBegin = Offset;
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- const std::string_view Name = slice(NameBegin, Offset);
- if (peek() != '>') {
- return fail(Begin, Offset, "expected the '<mcsymbol ...' operand to be closed by '>'");
- }
- ++Offset;
- return stringToken(MITokenKind::MCSymbol, Begin, Offset, Name);
- }
-
- auto Quoted = scanQuotedString(Offset);
- if (!Quoted)
- return token(MITokenKind::Error, Begin, Offset);
- Offset = Quoted->End;
- if (peek() != '>') {
- return fail(Begin, Offset, "expected the '<mcsymbol ...' operand to be closed by '>'");
- }
- ++Offset;
- return ownedStringToken(MITokenKind::MCSymbol, Begin, Offset, std::move(Quoted->Value));
- }
-
- [[nodiscard]] std::optional<MIToken> lexFloatHexBits() {
- if (!startsWith("f0x") && !startsWith("f0X"))
- return std::nullopt;
- std::size_t End = Offset + 3;
- while (End < text().size() && isASCIIHexDigit(text()[End]))
- ++End;
- if (End == Offset + 3)
- return std::nullopt;
- const std::size_t Begin = Offset;
- Offset = End;
- return token(MITokenKind::FloatingPointLiteral, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexHexadecimalLiteral() {
- if (peek() != '0' || (peek(1) != 'x' && peek(1) != 'X'))
- return std::nullopt;
-
- std::size_t End = Offset + 2;
- bool IsFloatingPoint = false;
- if (End < text().size() && isHexFloatingPointPrefix(text()[End])) {
- IsFloatingPoint = true;
- ++End;
- }
- const std::size_t DigitsBegin = End;
- while (End < text().size() && isASCIIHexDigit(text()[End]))
- ++End;
- if (End == DigitsBegin)
- return std::nullopt;
-
- const std::size_t Begin = Offset;
- Offset = End;
- return token(IsFloatingPoint ? MITokenKind::FloatingPointLiteral : MITokenKind::HexLiteral,
- Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexNumericalLiteral() {
- if (!isASCIIDigit(peek()) && (peek() != '-' || !isASCIIDigit(peek(1)))) {
- return std::nullopt;
- }
-
- const std::size_t Begin = Offset;
- if (peek() == '-')
- ++Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
-
- if (peek() != '.') {
- return token(MITokenKind::IntegerLiteral, Begin, Offset, slice(Begin, Offset));
- }
-
- ++Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- if ((peek() == 'e' || peek() == 'E') &&
- (isASCIIDigit(peek(1)) || ((peek(1) == '-' || peek(1) == '+') && isASCIIDigit(peek(2))))) {
- ++Offset;
- if (peek() == '-' || peek() == '+')
- ++Offset;
- while (!atEnd() && isASCIIDigit(peek()))
- ++Offset;
- }
- return token(MITokenKind::FloatingPointLiteral, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexExclaim() {
- if (peek() != '!')
- return std::nullopt;
-
- const std::size_t Begin = Offset++;
- if (isASCIIDigit(peek()) || !isIdentifierCharacter(peek()))
- return token(MITokenKind::Exclaim, Begin, Offset);
-
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- const std::string_view Spelling = slice(Begin, Offset);
- if (!isMIMetadataKeyword(Spelling)) {
- return fail(Begin, Offset, "use of unknown metadata keyword '" + std::string(Spelling) + "'");
- }
- return stringToken(MITokenKind::MetadataKeyword, Begin, Offset, Spelling);
- }
-
- [[nodiscard]] std::optional<MIToken> lexSymbol() {
- const std::size_t Begin = Offset;
- if (startsWith("::")) {
- Offset += 2;
- return token(MITokenKind::DoubleColon, Begin, Offset);
- }
-
- MITokenKind Kind = MITokenKind::Error;
- switch (peek()) {
- case ',':
- Kind = MITokenKind::Comma;
- break;
- case '=':
- Kind = MITokenKind::Equal;
- break;
- case ':':
- Kind = MITokenKind::Colon;
- break;
- case '.':
- Kind = MITokenKind::Dot;
- break;
- case '(':
- Kind = MITokenKind::LeftParen;
- break;
- case ')':
- Kind = MITokenKind::RightParen;
- break;
- case '{':
- Kind = MITokenKind::LeftBrace;
- break;
- case '}':
- Kind = MITokenKind::RightBrace;
- break;
- case '+':
- Kind = MITokenKind::Plus;
- break;
- case '-':
- Kind = MITokenKind::Minus;
- break;
- case '<':
- Kind = MITokenKind::Less;
- break;
- case '>':
- Kind = MITokenKind::Greater;
- break;
- default:
- return std::nullopt;
- }
- ++Offset;
- return token(Kind, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexNewline() {
- if (!isNewlineCharacter(peek()))
- return std::nullopt;
- const std::size_t Begin = Offset++;
- if (text()[Begin] == '\r' && peek() == '\n')
- ++Offset;
- return token(MITokenKind::Newline, Begin, Offset);
- }
-
- [[nodiscard]] std::optional<MIToken> lexQuotedIRValue() {
- if (peek() != '`')
- return std::nullopt;
-
- const std::size_t Begin = Offset++;
- const std::size_t ValueBegin = Offset;
- while (!atEnd() && peek() != '`' && !isNewlineCharacter(peek()))
- ++Offset;
- if (atEnd() || isNewlineCharacter(peek())) {
- return fail(Begin, Offset, "end of machine instruction reached before the closing '`'");
- }
- const std::size_t ValueEnd = Offset++;
- return stringToken(MITokenKind::QuotedIRValue, Begin, Offset, slice(ValueBegin, ValueEnd));
- }
-
- [[nodiscard]] MIToken lexToken() {
- if (auto Result = lexMachineBasicBlock())
- return std::move(*Result);
- if (auto Result = lexFloatHexBits())
- return std::move(*Result);
-
- if (isASCIIAlpha(peek()) || peek() == '_') {
- const std::size_t Begin = Offset;
- while (!atEnd() && isIdentifierCharacter(peek()))
- ++Offset;
- const std::string_view Value = slice(Begin, Offset);
- if (Value == "_")
- return token(MITokenKind::Underscore, Begin, Offset);
- return stringToken(isMIKeyword(Value) ? MITokenKind::Keyword : MITokenKind::Identifier, Begin,
- Offset, Value);
- }
-
- if (auto Result = lexIndex("%jump-table.", MITokenKind::JumpTableIndex, false))
- return std::move(*Result);
- if (auto Result = lexIndex("%stack.", MITokenKind::StackObject, true))
- return std::move(*Result);
- if (auto Result = lexIndex("%fixed-stack.", MITokenKind::FixedStackObject, false))
- return std::move(*Result);
- if (auto Result = lexIndex("%const.", MITokenKind::ConstantPoolItem, false))
- return std::move(*Result);
- if (startsWith("%subreg."))
- return lexName(MITokenKind::SubRegisterIndex, 8);
- if (auto Result = lexIRReference("%ir-block.", MITokenKind::IRBlock, MITokenKind::NamedIRBlock))
- return std::move(*Result);
- if (auto Result = lexIRReference("%ir.", MITokenKind::IRValue, MITokenKind::NamedIRValue))
- return std::move(*Result);
- if (auto Result = lexRegister())
- return std::move(*Result);
- if (auto Result = lexGlobalValue())
- return std::move(*Result);
- if (peek() == '&')
- return lexName(MITokenKind::ExternalSymbol, 1);
- if (auto Result = lexMCSymbol())
- return std::move(*Result);
- if (auto Result = lexHexadecimalLiteral())
- return std::move(*Result);
- if (auto Result = lexNumericalLiteral())
- return std::move(*Result);
- if (auto Result = lexExclaim())
- return std::move(*Result);
- if (auto Result = lexSymbol())
- return std::move(*Result);
- if (auto Result = lexNewline())
- return std::move(*Result);
- if (auto Result = lexQuotedIRValue())
- return std::move(*Result);
- if (peek() == '"')
- return lexName(MITokenKind::StringConstant, 0);
-
- const std::size_t Begin = Offset++;
- return fail(Begin, Offset,
- unexpectedCharacterMessage(static_cast<unsigned char>(text()[Begin])));
- }
-
- TextSource Source;
- MILexerOptions Options;
- std::size_t Offset = 0;
- std::size_t TokenCount = 0;
- bool Failed = false;
- std::vector<TextDiagnostic> Diagnostics;
-};
-
-MILexer::MILexer(std::string SourceName, std::string SourceText, MILexerOptions Options)
- : Implementation(
- std::make_unique<Impl>(std::move(SourceName), std::move(SourceText), Options)) {}
-
-MILexer::MILexer(MILexer &&) noexcept = default;
-MILexer &MILexer::operator=(MILexer &&) noexcept = default;
-MILexer::~MILexer() = default;
-
-MIToken MILexer::next() {
- assert(Implementation != nullptr);
- return Implementation->next();
-}
-
-const TextSource &MILexer::source() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->source();
-}
-
-std::span<const TextDiagnostic> MILexer::diagnostics() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->diagnostics();
-}
-
-bool MILexer::failed() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->failed();
-}
-
-std::size_t MILexer::tokenCount() const noexcept {
- assert(Implementation != nullptr);
- return Implementation->tokenCount();
-}
-
-} // namespace rcc::mir