Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dvshapkin committed Aug 16, 2021
0 parents commit 6d653ff
Show file tree
Hide file tree
Showing 7 changed files with 798 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
/cmake-build-debug
6 changes: 6 additions & 0 deletions CMakeLists.txt
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)
92 changes: 92 additions & 0 deletions lexer.cpp
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
138 changes: 138 additions & 0 deletions lexer.h
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
Loading

0 comments on commit 6d653ff

Please sign in to comment.