-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6d653ff
Showing
7 changed files
with
798 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea | ||
/cmake-build-debug |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
cmake_minimum_required(VERSION 3.20) | ||
project(mython) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
add_executable(mython main.cpp lexer.h lexer.cpp test_runner_p.h lexer_test_open.cpp) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#include "lexer.h" | ||
|
||
#include <algorithm> | ||
#include <charconv> | ||
#include <unordered_map> | ||
|
||
using namespace std; | ||
|
||
namespace parse { | ||
|
||
bool operator==(const Token& lhs, const Token& rhs) { | ||
using namespace token_type; | ||
|
||
if (lhs.index() != rhs.index()) { | ||
return false; | ||
} | ||
if (lhs.Is<Char>()) { | ||
return lhs.As<Char>().value == rhs.As<Char>().value; | ||
} | ||
if (lhs.Is<Number>()) { | ||
return lhs.As<Number>().value == rhs.As<Number>().value; | ||
} | ||
if (lhs.Is<String>()) { | ||
return lhs.As<String>().value == rhs.As<String>().value; | ||
} | ||
if (lhs.Is<Id>()) { | ||
return lhs.As<Id>().value == rhs.As<Id>().value; | ||
} | ||
return true; | ||
} | ||
|
||
bool operator!=(const Token& lhs, const Token& rhs) { | ||
return !(lhs == rhs); | ||
} | ||
|
||
std::ostream& operator<<(std::ostream& os, const Token& rhs) { | ||
using namespace token_type; | ||
|
||
#define VALUED_OUTPUT(type) \ | ||
if (auto p = rhs.TryAs<type>()) return os << #type << '{' << p->value << '}'; | ||
|
||
VALUED_OUTPUT(Number); | ||
VALUED_OUTPUT(Id); | ||
VALUED_OUTPUT(String); | ||
VALUED_OUTPUT(Char); | ||
|
||
#undef VALUED_OUTPUT | ||
|
||
#define UNVALUED_OUTPUT(type) \ | ||
if (rhs.Is<type>()) return os << #type; | ||
|
||
UNVALUED_OUTPUT(Class); | ||
UNVALUED_OUTPUT(Return); | ||
UNVALUED_OUTPUT(If); | ||
UNVALUED_OUTPUT(Else); | ||
UNVALUED_OUTPUT(Def); | ||
UNVALUED_OUTPUT(Newline); | ||
UNVALUED_OUTPUT(Print); | ||
UNVALUED_OUTPUT(Indent); | ||
UNVALUED_OUTPUT(Dedent); | ||
UNVALUED_OUTPUT(And); | ||
UNVALUED_OUTPUT(Or); | ||
UNVALUED_OUTPUT(Not); | ||
UNVALUED_OUTPUT(Eq); | ||
UNVALUED_OUTPUT(NotEq); | ||
UNVALUED_OUTPUT(LessOrEq); | ||
UNVALUED_OUTPUT(GreaterOrEq); | ||
UNVALUED_OUTPUT(None); | ||
UNVALUED_OUTPUT(True); | ||
UNVALUED_OUTPUT(False); | ||
UNVALUED_OUTPUT(Eof); | ||
|
||
#undef UNVALUED_OUTPUT | ||
|
||
return os << "Unknown token :("sv; | ||
} | ||
|
||
Lexer::Lexer(std::istream& /*input*/) { | ||
// Реализуйте конструктор самостоятельно | ||
} | ||
|
||
const Token& Lexer::CurrentToken() const { | ||
// Заглушка. Реализуйте метод самостоятельно | ||
throw std::logic_error("Not implemented"s); | ||
} | ||
|
||
Token Lexer::NextToken() { | ||
// Заглушка. Реализуйте метод самостоятельно | ||
throw std::logic_error("Not implemented"s); | ||
} | ||
|
||
} // namespace parse |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
#pragma once | ||
|
||
#include <iosfwd> | ||
#include <optional> | ||
#include <sstream> | ||
#include <stdexcept> | ||
#include <string> | ||
#include <variant> | ||
|
||
namespace parse { | ||
|
||
namespace token_type { | ||
struct Number { // Лексема «число» | ||
int value; // число | ||
}; | ||
|
||
struct Id { // Лексема «идентификатор» | ||
std::string value; // Имя идентификатора | ||
}; | ||
|
||
struct Char { // Лексема «символ» | ||
char value; // код символа | ||
}; | ||
|
||
struct String { // Лексема «строковая константа» | ||
std::string value; | ||
}; | ||
|
||
struct Class {}; // Лексема «class» | ||
struct Return {}; // Лексема «return» | ||
struct If {}; // Лексема «if» | ||
struct Else {}; // Лексема «else» | ||
struct Def {}; // Лексема «def» | ||
struct Newline {}; // Лексема «конец строки» | ||
struct Print {}; // Лексема «print» | ||
struct Indent {}; // Лексема «увеличение отступа», соответствует двум пробелам | ||
struct Dedent {}; // Лексема «уменьшение отступа» | ||
struct Eof {}; // Лексема «конец файла» | ||
struct And {}; // Лексема «and» | ||
struct Or {}; // Лексема «or» | ||
struct Not {}; // Лексема «not» | ||
struct Eq {}; // Лексема «==» | ||
struct NotEq {}; // Лексема «!=» | ||
struct LessOrEq {}; // Лексема «<=» | ||
struct GreaterOrEq {}; // Лексема «>=» | ||
struct None {}; // Лексема «None» | ||
struct True {}; // Лексема «True» | ||
struct False {}; // Лексема «False» | ||
} // namespace token_type | ||
|
||
using TokenBase | ||
= std::variant<token_type::Number, token_type::Id, token_type::Char, token_type::String, | ||
token_type::Class, token_type::Return, token_type::If, token_type::Else, | ||
token_type::Def, token_type::Newline, token_type::Print, token_type::Indent, | ||
token_type::Dedent, token_type::And, token_type::Or, token_type::Not, | ||
token_type::Eq, token_type::NotEq, token_type::LessOrEq, token_type::GreaterOrEq, | ||
token_type::None, token_type::True, token_type::False, token_type::Eof>; | ||
|
||
struct Token : TokenBase { | ||
using TokenBase::TokenBase; | ||
|
||
template <typename T> | ||
[[nodiscard]] bool Is() const { | ||
return std::holds_alternative<T>(*this); | ||
} | ||
|
||
template <typename T> | ||
[[nodiscard]] const T& As() const { | ||
return std::get<T>(*this); | ||
} | ||
|
||
template <typename T> | ||
[[nodiscard]] const T* TryAs() const { | ||
return std::get_if<T>(this); | ||
} | ||
}; | ||
|
||
bool operator==(const Token& lhs, const Token& rhs); | ||
bool operator!=(const Token& lhs, const Token& rhs); | ||
|
||
std::ostream& operator<<(std::ostream& os, const Token& rhs); | ||
|
||
class LexerError : public std::runtime_error { | ||
public: | ||
using std::runtime_error::runtime_error; | ||
}; | ||
|
||
class Lexer { | ||
public: | ||
explicit Lexer(std::istream& input); | ||
|
||
// Возвращает ссылку на текущий токен или token_type::Eof, если поток токенов закончился | ||
[[nodiscard]] const Token& CurrentToken() const; | ||
|
||
// Возвращает следующий токен, либо token_type::Eof, если поток токенов закончился | ||
Token NextToken(); | ||
|
||
// Если текущий токен имеет тип T, метод возвращает ссылку на него. | ||
// В противном случае метод выбрасывает исключение LexerError | ||
template <typename T> | ||
const T& Expect() const { | ||
using namespace std::literals; | ||
// Заглушка. Реализуйте метод самостоятельно | ||
throw LexerError("Not implemented"s); | ||
} | ||
|
||
// Метод проверяет, что текущий токен имеет тип T, а сам токен содержит значение value. | ||
// В противном случае метод выбрасывает исключение LexerError | ||
template <typename T, typename U> | ||
void Expect(const U& /*value*/) const { | ||
using namespace std::literals; | ||
// Заглушка. Реализуйте метод самостоятельно | ||
throw LexerError("Not implemented"s); | ||
} | ||
|
||
// Если следующий токен имеет тип T, метод возвращает ссылку на него. | ||
// В противном случае метод выбрасывает исключение LexerError | ||
template <typename T> | ||
const T& ExpectNext() { | ||
using namespace std::literals; | ||
// Заглушка. Реализуйте метод самостоятельно | ||
throw LexerError("Not implemented"s); | ||
} | ||
|
||
// Метод проверяет, что следующий токен имеет тип T, а сам токен содержит значение value. | ||
// В противном случае метод выбрасывает исключение LexerError | ||
template <typename T, typename U> | ||
void ExpectNext(const U& /*value*/) { | ||
using namespace std::literals; | ||
// Заглушка. Реализуйте метод самостоятельно | ||
throw LexerError("Not implemented"s); | ||
} | ||
|
||
private: | ||
// Реализуйте приватную часть самостоятельно | ||
}; | ||
|
||
} // namespace parse |
Oops, something went wrong.