diff --git a/docs/grammar.md b/docs/grammar.md deleted file mode 100644 index ff54f93..0000000 --- a/docs/grammar.md +++ /dev/null @@ -1,38 +0,0 @@ -$$ -\begin{align} - [\text{Prog}] &\to [\text{Stmt}]^* \\ - [\text{Stmt}] &\to - \begin{cases} - \text{exit}([\text{Expr}]); \\ - \text{let}\space\text{ident} = [\text{Expr}]; \\ - \text{ident} = \text{[Expr]}; \\ - \text{if} ([\text{Expr}])[\text{Scope}]\text{[IfPred]}\\ - [\text{Scope}] - \end{cases} \\ - \text{[Scope]} &\to \{[\text{Stmt}]^*\} \\ - \text{[IfPred]} &\to - \begin{cases} - \text{elif}(\text{[Expr]})\text{[Scope]}\text{[IfPred]} \\ - \text{else}\text{[Scope]} \\ - \epsilon - \end{cases} \\ - [\text{Expr}] &\to - \begin{cases} - [\text{Term}] \\ - [\text{BinExpr}] - \end{cases} \\ - [\text{BinExpr}] &\to - \begin{cases} - [\text{Expr}] * [\text{Expr}] & \text{prec} = 1 \\ - [\text{Expr}] / [\text{Expr}] & \text{prec} = 1 \\ - [\text{Expr}] + [\text{Expr}] & \text{prec} = 0 \\ - [\text{Expr}] - [\text{Expr}] & \text{prec} = 0 \\ - \end{cases} \\ - [\text{Term}] &\to - \begin{cases} - \text{int\_lit} \\ - \text{ident} \\ - ([\text{Expr}]) - \end{cases} -\end{align} -$$ diff --git a/src/arena.hpp b/src/arena.hpp deleted file mode 100644 index f659de1..0000000 --- a/src/arena.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include -#include -#include - -class ArenaAllocator { -public: - explicit ArenaAllocator(const size_t max_num_bytes) - : m_size { max_num_bytes } - , m_buffer { new std::byte[max_num_bytes] } - , m_offset { m_buffer } - { - } - - ArenaAllocator(const ArenaAllocator&) = delete; - ArenaAllocator& operator=(const ArenaAllocator&) = delete; - - ArenaAllocator(ArenaAllocator&& other) noexcept - : m_size { std::exchange(other.m_size, 0) } - , m_buffer { std::exchange(other.m_buffer, nullptr) } - , m_offset { std::exchange(other.m_offset, nullptr) } - { - } - - ArenaAllocator& operator=(ArenaAllocator&& other) noexcept - { - std::swap(m_size, other.m_size); - std::swap(m_buffer, other.m_buffer); - std::swap(m_offset, other.m_offset); - return *this; - } - - template - [[nodiscard]] T* alloc() - { - size_t remaining_num_bytes = m_size - static_cast(m_offset - m_buffer); - auto pointer = static_cast(m_offset); - const auto aligned_address = std::align(alignof(T), sizeof(T), pointer, remaining_num_bytes); - if (aligned_address == nullptr) { - throw std::bad_alloc {}; - } - m_offset = static_cast(aligned_address) + sizeof(T); - return static_cast(aligned_address); - } - - template - [[nodiscard]] T* emplace(Args&&... args) - { - const auto allocated_memory = alloc(); - return new (allocated_memory) T { std::forward(args)... }; - } - - ~ArenaAllocator() - { - // No destructors are called for the stored objects. Thus, memory - // leaks are possible (e.g. when storing std::vector objects or - // other non-trivially destructable objects in the allocator). - // Although this could be changed, it would come with additional - // runtime overhead and therefore is not implemented. - delete[] m_buffer; - } - -private: - size_t m_size; - std::byte* m_buffer; - std::byte* m_offset; -}; \ No newline at end of file diff --git a/src/generation.hpp b/src/generation.hpp deleted file mode 100644 index 64d9084..0000000 --- a/src/generation.hpp +++ /dev/null @@ -1,302 +0,0 @@ -#pragma once - -#include -#include - -#include "parser.hpp" - -class Generator { -public: - explicit Generator(NodeProg prog) - : m_prog(std::move(prog)) - { - } - - void gen_term(const NodeTerm* term) - { - struct TermVisitor { - Generator& gen; - - void operator()(const NodeTermIntLit* term_int_lit) const - { - gen.m_output << " mov rax, " << term_int_lit->int_lit.value.value() << "\n"; - gen.push("rax"); - } - - void operator()(const NodeTermIdent* term_ident) const - { - const auto it = std::ranges::find_if(std::as_const(gen.m_vars), [&](const Var& var) { - return var.name == term_ident->ident.value.value(); - }); - if (it == gen.m_vars.cend()) { - std::cerr << "Undeclared identifier: " << term_ident->ident.value.value() << std::endl; - exit(EXIT_FAILURE); - } - std::stringstream offset; - offset << "QWORD [rsp + " << (gen.m_stack_size - it->stack_loc - 1) * 8 << "]"; - gen.push(offset.str()); - } - - void operator()(const NodeTermParen* term_paren) const - { - gen.gen_expr(term_paren->expr); - } - }; - TermVisitor visitor({ .gen = *this }); - std::visit(visitor, term->var); - } - - void gen_bin_expr(const NodeBinExpr* bin_expr) - { - struct BinExprVisitor { - Generator& gen; - - void operator()(const NodeBinExprSub* sub) const - { - gen.gen_expr(sub->rhs); - gen.gen_expr(sub->lhs); - gen.pop("rax"); - gen.pop("rbx"); - gen.m_output << " sub rax, rbx\n"; - gen.push("rax"); - } - - void operator()(const NodeBinExprAdd* add) const - { - gen.gen_expr(add->rhs); - gen.gen_expr(add->lhs); - gen.pop("rax"); - gen.pop("rbx"); - gen.m_output << " add rax, rbx\n"; - gen.push("rax"); - } - - void operator()(const NodeBinExprMulti* multi) const - { - gen.gen_expr(multi->rhs); - gen.gen_expr(multi->lhs); - gen.pop("rax"); - gen.pop("rbx"); - gen.m_output << " mul rbx\n"; - gen.push("rax"); - } - - void operator()(const NodeBinExprDiv* div) const - { - gen.gen_expr(div->rhs); - gen.gen_expr(div->lhs); - gen.pop("rax"); - gen.pop("rbx"); - gen.m_output << " div rbx\n"; - gen.push("rax"); - } - }; - - BinExprVisitor visitor { .gen = *this }; - std::visit(visitor, bin_expr->var); - } - - void gen_expr(const NodeExpr* expr) - { - struct ExprVisitor { - Generator& gen; - - void operator()(const NodeTerm* term) const - { - gen.gen_term(term); - } - - void operator()(const NodeBinExpr* bin_expr) const - { - gen.gen_bin_expr(bin_expr); - } - }; - - ExprVisitor visitor { .gen = *this }; - std::visit(visitor, expr->var); - } - - void gen_scope(const NodeScope* scope) - { - begin_scope(); - for (const NodeStmt* stmt : scope->stmts) { - gen_stmt(stmt); - } - end_scope(); - } - - void gen_if_pred(const NodeIfPred* pred, const std::string& end_label) - { - struct PredVisitor { - Generator& gen; - const std::string& end_label; - - void operator()(const NodeIfPredElif* elif) const - { - gen.m_output << " ;; elif\n"; - gen.gen_expr(elif->expr); - gen.pop("rax"); - const std::string label = gen.create_label(); - gen.m_output << " test rax, rax\n"; - gen.m_output << " jz " << label << "\n"; - gen.gen_scope(elif->scope); - gen.m_output << " jmp " << end_label << "\n"; - if (elif->pred.has_value()) { - gen.m_output << label << ":\n"; - gen.gen_if_pred(elif->pred.value(), end_label); - } - } - - void operator()(const NodeIfPredElse* else_) const - { - gen.m_output << " ;; else\n"; - gen.gen_scope(else_->scope); - } - }; - - PredVisitor visitor { .gen = *this, .end_label = end_label }; - std::visit(visitor, pred->var); - } - - void gen_stmt(const NodeStmt* stmt) - { - struct StmtVisitor { - Generator& gen; - - void operator()(const NodeStmtExit* stmt_exit) const - { - gen.m_output << " ;; exit\n"; - gen.gen_expr(stmt_exit->expr); - gen.m_output << " mov rax, 60\n"; - gen.pop("rdi"); - gen.m_output << " syscall\n"; - gen.m_output << " ;; /exit\n"; - } - - void operator()(const NodeStmtLet* stmt_let) const - { - gen.m_output << " ;; let\n"; - if (std::ranges::find_if( - std::as_const(gen.m_vars), - [&](const Var& var) { return var.name == stmt_let->ident.value.value(); }) - != gen.m_vars.cend()) { - std::cerr << "Identifier already used: " << stmt_let->ident.value.value() << std::endl; - exit(EXIT_FAILURE); - } - gen.m_vars.push_back({ .name = stmt_let->ident.value.value(), .stack_loc = gen.m_stack_size }); - gen.gen_expr(stmt_let->expr); - gen.m_output << " ;; /let\n"; - } - - void operator()(const NodeStmtAssign* stmt_assign) const - { - const auto it = std::ranges::find_if(gen.m_vars, [&](const Var& var) { - return var.name == stmt_assign->ident.value.value(); - }); - if (it == gen.m_vars.end()) { - std::cerr << "Undeclared identifier: " << stmt_assign->ident.value.value() << std::endl; - exit(EXIT_FAILURE); - } - gen.gen_expr(stmt_assign->expr); - gen.pop("rax"); - gen.m_output << " mov [rsp + " << (gen.m_stack_size - it->stack_loc - 1) * 8 << "], rax\n"; - } - - void operator()(const NodeScope* scope) const - { - gen.m_output << " ;; scope\n"; - gen.gen_scope(scope); - gen.m_output << " ;; /scope\n"; - } - - void operator()(const NodeStmtIf* stmt_if) const - { - gen.m_output << " ;; if\n"; - gen.gen_expr(stmt_if->expr); - gen.pop("rax"); - const std::string label = gen.create_label(); - gen.m_output << " test rax, rax\n"; - gen.m_output << " jz " << label << "\n"; - gen.gen_scope(stmt_if->scope); - if (stmt_if->pred.has_value()) { - const std::string end_label = gen.create_label(); - gen.m_output << " jmp " << end_label << "\n"; - gen.m_output << label << ":\n"; - gen.gen_if_pred(stmt_if->pred.value(), end_label); - gen.m_output << end_label << ":\n"; - } - else { - gen.m_output << label << ":\n"; - } - gen.m_output << " ;; /if\n"; - } - }; - - StmtVisitor visitor { .gen = *this }; - std::visit(visitor, stmt->var); - } - - [[nodiscard]] std::string gen_prog() - { - m_output << "global _start\n_start:\n"; - - for (const NodeStmt* stmt : m_prog.stmts) { - gen_stmt(stmt); - } - - m_output << " mov rax, 60\n"; - m_output << " mov rdi, 0\n"; - m_output << " syscall\n"; - return m_output.str(); - } - -private: - void push(const std::string& reg) - { - m_output << " push " << reg << "\n"; - m_stack_size++; - } - - void pop(const std::string& reg) - { - m_output << " pop " << reg << "\n"; - m_stack_size--; - } - - void begin_scope() - { - m_scopes.push_back(m_vars.size()); - } - - void end_scope() - { - const size_t pop_count = m_vars.size() - m_scopes.back(); - if (pop_count != 0) { - m_output << " add rsp, " << pop_count * 8 << "\n"; - } - m_stack_size -= pop_count; - for (size_t i = 0; i < pop_count; i++) { - m_vars.pop_back(); - } - m_scopes.pop_back(); - } - - std::string create_label() - { - std::stringstream ss; - ss << "label" << m_label_count++; - return ss.str(); - } - - struct Var { - std::string name; - size_t stack_loc; - }; - - const NodeProg m_prog; - std::stringstream m_output; - size_t m_stack_size = 0; - std::vector m_vars {}; - std::vector m_scopes {}; - int m_label_count = 0; -}; diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index bd9a6e6..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include -#include - -#include "generation.hpp" - -int main(int argc, char* argv[]) -{ - if (argc != 2) { - std::cerr << "Incorrect usage. Correct usage is..." << std::endl; - std::cerr << "hydro " << std::endl; - return EXIT_FAILURE; - } - - std::string contents; - { - std::stringstream contents_stream; - std::fstream input(argv[1], std::ios::in); - contents_stream << input.rdbuf(); - contents = contents_stream.str(); - } - - Tokenizer tokenizer(std::move(contents)); - std::vector tokens = tokenizer.tokenize(); - - Parser parser(std::move(tokens)); - std::optional prog = parser.parse_prog(); - - if (!prog.has_value()) { - std::cerr << "Invalid program" << std::endl; - exit(EXIT_FAILURE); - } - - { - Generator generator(prog.value()); - std::fstream file("out.asm", std::ios::out); - file << generator.gen_prog(); - } - - system("nasm -felf64 out.asm"); - system("ld -o out out.o"); - - return EXIT_SUCCESS; -} diff --git a/src/parser.hpp b/src/parser.hpp deleted file mode 100644 index c6c9280..0000000 --- a/src/parser.hpp +++ /dev/null @@ -1,379 +0,0 @@ -#pragma once - -#include -#include - -#include "arena.hpp" -#include "tokenization.hpp" - -struct NodeTermIntLit { - Token int_lit; -}; - -struct NodeTermIdent { - Token ident; -}; - -struct NodeExpr; - -struct NodeTermParen { - NodeExpr* expr; -}; - -struct NodeBinExprAdd { - NodeExpr* lhs; - NodeExpr* rhs; -}; - -struct NodeBinExprMulti { - NodeExpr* lhs; - NodeExpr* rhs; -}; - -struct NodeBinExprSub { - NodeExpr* lhs; - NodeExpr* rhs; -}; - -struct NodeBinExprDiv { - NodeExpr* lhs; - NodeExpr* rhs; -}; - -struct NodeBinExpr { - std::variant var; -}; - -struct NodeTerm { - std::variant var; -}; - -struct NodeExpr { - std::variant var; -}; - -struct NodeStmtExit { - NodeExpr* expr; -}; - -struct NodeStmtLet { - Token ident; - NodeExpr* expr {}; -}; - -struct NodeStmt; - -struct NodeScope { - std::vector stmts; -}; - -struct NodeIfPred; - -struct NodeIfPredElif { - NodeExpr* expr {}; - NodeScope* scope {}; - std::optional pred; -}; - -struct NodeIfPredElse { - NodeScope* scope; -}; - -struct NodeIfPred { - std::variant var; -}; - -struct NodeStmtIf { - NodeExpr* expr {}; - NodeScope* scope {}; - std::optional pred; -}; - -struct NodeStmtAssign { - Token ident; - NodeExpr* expr {}; -}; - -struct NodeStmt { - std::variant var; -}; - -struct NodeProg { - std::vector stmts; -}; - -class Parser { -public: - explicit Parser(std::vector tokens) - : m_tokens(std::move(tokens)) - , m_allocator(1024 * 1024 * 4) // 4 mb - { - } - - void error_expected(const std::string& msg) const - { - std::cerr << "[Parse Error] Expected " << msg << " on line " << peek(-1).value().line << std::endl; - exit(EXIT_FAILURE); - } - - std::optional parse_term() // NOLINT(*-no-recursion) - { - if (auto int_lit = try_consume(TokenType::int_lit)) { - auto term_int_lit = m_allocator.emplace(int_lit.value()); - auto term = m_allocator.emplace(term_int_lit); - return term; - } - if (auto ident = try_consume(TokenType::ident)) { - auto expr_ident = m_allocator.emplace(ident.value()); - auto term = m_allocator.emplace(expr_ident); - return term; - } - if (const auto open_paren = try_consume(TokenType::open_paren)) { - auto expr = parse_expr(); - if (!expr.has_value()) { - error_expected("expression"); - } - try_consume_err(TokenType::close_paren); - auto term_paren = m_allocator.emplace(expr.value()); - auto term = m_allocator.emplace(term_paren); - return term; - } - return {}; - } - - std::optional parse_expr(const int min_prec = 0) // NOLINT(*-no-recursion) - { - std::optional term_lhs = parse_term(); - if (!term_lhs.has_value()) { - return {}; - } - auto expr_lhs = m_allocator.emplace(term_lhs.value()); - - while (true) { - std::optional curr_tok = peek(); - std::optional prec; - if (curr_tok.has_value()) { - prec = bin_prec(curr_tok->type); - if (!prec.has_value() || prec < min_prec) { - break; - } - } - else { - break; - } - const auto [type, line, value] = consume(); - const int next_min_prec = prec.value() + 1; - auto expr_rhs = parse_expr(next_min_prec); - if (!expr_rhs.has_value()) { - error_expected("expression"); - } - auto expr = m_allocator.emplace(); - auto expr_lhs2 = m_allocator.emplace(); - if (type == TokenType::plus) { - expr_lhs2->var = expr_lhs->var; - auto add = m_allocator.emplace(expr_lhs2, expr_rhs.value()); - expr->var = add; - } - else if (type == TokenType::star) { - expr_lhs2->var = expr_lhs->var; - auto multi = m_allocator.emplace(expr_lhs2, expr_rhs.value()); - expr->var = multi; - } - else if (type == TokenType::minus) { - expr_lhs2->var = expr_lhs->var; - auto sub = m_allocator.emplace(expr_lhs2, expr_rhs.value()); - expr->var = sub; - } - else if (type == TokenType::fslash) { - expr_lhs2->var = expr_lhs->var; - auto div = m_allocator.emplace(expr_lhs2, expr_rhs.value()); - expr->var = div; - } - else { - assert(false); // Unreachable; - } - expr_lhs->var = expr; - } - return expr_lhs; - } - - std::optional parse_scope() // NOLINT(*-no-recursion) - { - if (!try_consume(TokenType::open_curly).has_value()) { - return {}; - } - auto scope = m_allocator.emplace(); - while (auto stmt = parse_stmt()) { - scope->stmts.push_back(stmt.value()); - } - try_consume_err(TokenType::close_curly); - return scope; - } - - std::optional parse_if_pred() // NOLINT(*-no-recursion) - { - if (try_consume(TokenType::elif)) { - try_consume_err(TokenType::open_paren); - const auto elif = m_allocator.alloc(); - if (const auto expr = parse_expr()) { - elif->expr = expr.value(); - } - else { - error_expected("expression"); - } - try_consume_err(TokenType::close_paren); - if (const auto scope = parse_scope()) { - elif->scope = scope.value(); - } - else { - error_expected("scope"); - } - elif->pred = parse_if_pred(); - auto pred = m_allocator.emplace(elif); - return pred; - } - if (try_consume(TokenType::else_)) { - auto else_ = m_allocator.alloc(); - if (const auto scope = parse_scope()) { - else_->scope = scope.value(); - } - else { - error_expected("scope"); - } - auto pred = m_allocator.emplace(else_); - return pred; - } - return {}; - } - - std::optional parse_stmt() // NOLINT(*-no-recursion) - { - if (peek().has_value() && peek().value().type == TokenType::exit && peek(1).has_value() - && peek(1).value().type == TokenType::open_paren) { - consume(); - consume(); - auto stmt_exit = m_allocator.emplace(); - if (const auto node_expr = parse_expr()) { - stmt_exit->expr = node_expr.value(); - } - else { - error_expected("expression"); - } - try_consume_err(TokenType::close_paren); - try_consume_err(TokenType::semi); - auto stmt = m_allocator.emplace(); - stmt->var = stmt_exit; - return stmt; - } - if (peek().has_value() && peek().value().type == TokenType::let && peek(1).has_value() - && peek(1).value().type == TokenType::ident && peek(2).has_value() - && peek(2).value().type == TokenType::eq) { - consume(); - auto stmt_let = m_allocator.emplace(); - stmt_let->ident = consume(); - consume(); - if (const auto expr = parse_expr()) { - stmt_let->expr = expr.value(); - } - else { - error_expected("expression"); - } - try_consume_err(TokenType::semi); - auto stmt = m_allocator.emplace(); - stmt->var = stmt_let; - return stmt; - } - if (peek().has_value() && peek().value().type == TokenType::ident && peek(1).has_value() - && peek(1).value().type == TokenType::eq) { - const auto assign = m_allocator.alloc(); - assign->ident = consume(); - consume(); - if (const auto expr = parse_expr()) { - assign->expr = expr.value(); - } - else { - error_expected("expression"); - } - try_consume_err(TokenType::semi); - auto stmt = m_allocator.emplace(assign); - return stmt; - } - if (peek().has_value() && peek().value().type == TokenType::open_curly) { - if (auto scope = parse_scope()) { - auto stmt = m_allocator.emplace(scope.value()); - return stmt; - } - error_expected("scope"); - } - if (auto if_ = try_consume(TokenType::if_)) { - try_consume_err(TokenType::open_paren); - auto stmt_if = m_allocator.emplace(); - if (const auto expr = parse_expr()) { - stmt_if->expr = expr.value(); - } - else { - error_expected("expression"); - } - try_consume_err(TokenType::close_paren); - if (const auto scope = parse_scope()) { - stmt_if->scope = scope.value(); - } - else { - error_expected("scope"); - } - stmt_if->pred = parse_if_pred(); - auto stmt = m_allocator.emplace(stmt_if); - return stmt; - } - return {}; - } - - std::optional parse_prog() - { - NodeProg prog; - while (peek().has_value()) { - if (auto stmt = parse_stmt()) { - prog.stmts.push_back(stmt.value()); - } - else { - error_expected("statement"); - } - } - return prog; - } - -private: - [[nodiscard]] std::optional peek(const int offset = 0) const - { - if (m_index + offset >= m_tokens.size()) { - return {}; - } - return m_tokens.at(m_index + offset); - } - - Token consume() - { - return m_tokens.at(m_index++); - } - - Token try_consume_err(const TokenType type) - { - if (peek().has_value() && peek().value().type == type) { - return consume(); - } - error_expected(to_string(type)); - return {}; - } - - std::optional try_consume(const TokenType type) - { - if (peek().has_value() && peek().value().type == type) { - return consume(); - } - return {}; - } - - const std::vector m_tokens; - size_t m_index = 0; - ArenaAllocator m_allocator; -}; diff --git a/src/tokenization.hpp b/src/tokenization.hpp deleted file mode 100644 index 9fa7d6f..0000000 --- a/src/tokenization.hpp +++ /dev/null @@ -1,233 +0,0 @@ -#pragma once - -#include -#include - -enum class TokenType { - exit, - int_lit, - semi, - open_paren, - close_paren, - ident, - let, - eq, - plus, - star, - minus, - fslash, - open_curly, - close_curly, - if_, - elif, - else_, -}; - -inline std::string to_string(const TokenType type) -{ - switch (type) { - case TokenType::exit: - return "`exit`"; - case TokenType::int_lit: - return "int literal"; - case TokenType::semi: - return "`;`"; - case TokenType::open_paren: - return "`(`"; - case TokenType::close_paren: - return "`)`"; - case TokenType::ident: - return "identifier"; - case TokenType::let: - return "`let`"; - case TokenType::eq: - return "`=`"; - case TokenType::plus: - return "`+`"; - case TokenType::star: - return "`*`"; - case TokenType::minus: - return "`-`"; - case TokenType::fslash: - return "`/`"; - case TokenType::open_curly: - return "`{`"; - case TokenType::close_curly: - return "`}`"; - case TokenType::if_: - return "`if`"; - case TokenType::elif: - return "`elif`"; - case TokenType::else_: - return "`else`"; - } - assert(false); -} - -inline std::optional bin_prec(const TokenType type) -{ - switch (type) { - case TokenType::minus: - case TokenType::plus: - return 0; - case TokenType::fslash: - case TokenType::star: - return 1; - default: - return {}; - } -} - -struct Token { - TokenType type; - int line; - std::optional value {}; -}; - -class Tokenizer { -public: - explicit Tokenizer(std::string src) - : m_src(std::move(src)) - { - } - - std::vector tokenize() - { - std::vector tokens; - std::string buf; - int line_count = 1; - while (peek().has_value()) { - if (std::isalpha(peek().value())) { - buf.push_back(consume()); - while (peek().has_value() && std::isalnum(peek().value())) { - buf.push_back(consume()); - } - if (buf == "exit") { - tokens.push_back({ TokenType::exit, line_count }); - buf.clear(); - } - else if (buf == "let") { - tokens.push_back({ TokenType::let, line_count }); - buf.clear(); - } - else if (buf == "if") { - tokens.push_back({ TokenType::if_, line_count }); - buf.clear(); - } - else if (buf == "elif") { - tokens.push_back({ TokenType::elif, line_count }); - buf.clear(); - } - else if (buf == "else") { - tokens.push_back({ TokenType::else_, line_count }); - buf.clear(); - } - else { - tokens.push_back({ TokenType::ident, line_count, buf }); - buf.clear(); - } - } - else if (std::isdigit(peek().value())) { - buf.push_back(consume()); - while (peek().has_value() && std::isdigit(peek().value())) { - buf.push_back(consume()); - } - tokens.push_back({ TokenType::int_lit, line_count, buf }); - buf.clear(); - } - else if (peek().value() == '/' && peek(1).has_value() && peek(1).value() == '/') { - consume(); - consume(); - while (peek().has_value() && peek().value() != '\n') { - consume(); - } - } - else if (peek().value() == '/' && peek(1).has_value() && peek(1).value() == '*') { - consume(); - consume(); - while (peek().has_value()) { - if (peek().value() == '*' && peek(1).has_value() && peek(1).value() == '/') { - break; - } - consume(); - } - if (peek().has_value()) { - consume(); - } - if (peek().has_value()) { - consume(); - } - } - else if (peek().value() == '(') { - consume(); - tokens.push_back({ TokenType::open_paren, line_count }); - } - else if (peek().value() == ')') { - consume(); - tokens.push_back({ TokenType::close_paren, line_count }); - } - else if (peek().value() == ';') { - consume(); - tokens.push_back({ TokenType::semi, line_count }); - } - else if (peek().value() == '=') { - consume(); - tokens.push_back({ TokenType::eq, line_count }); - } - else if (peek().value() == '+') { - consume(); - tokens.push_back({ TokenType::plus, line_count }); - } - else if (peek().value() == '*') { - consume(); - tokens.push_back({ TokenType::star, line_count }); - } - else if (peek().value() == '-') { - consume(); - tokens.push_back({ TokenType::minus, line_count }); - } - else if (peek().value() == '/') { - consume(); - tokens.push_back({ TokenType::fslash, line_count }); - } - else if (peek().value() == '{') { - consume(); - tokens.push_back({ TokenType::open_curly, line_count }); - } - else if (peek().value() == '}') { - consume(); - tokens.push_back({ TokenType::close_curly, line_count }); - } - else if (peek().value() == '\n') { - consume(); - line_count++; - } - else if (std::isspace(peek().value())) { - consume(); - } - else { - std::cerr << "Invalid token" << std::endl; - exit(EXIT_FAILURE); - } - } - m_index = 0; - return tokens; - } - -private: - [[nodiscard]] std::optional peek(const size_t offset = 0) const - { - if (m_index + offset >= m_src.length()) { - return {}; - } - return m_src.at(m_index + offset); - } - - char consume() - { - return m_src.at(m_index++); - } - - const std::string m_src; - size_t m_index = 0; -}; diff --git a/test.hy b/test.hy deleted file mode 100644 index 2942041..0000000 --- a/test.hy +++ /dev/null @@ -1,16 +0,0 @@ -let y = (10 - 2 * 3) / 2; -let x = 7; // first -// first -if (0) { - x = 1; -} elif (0) { - x = 2; -} else { - x = 3; -} - -exit(x); - -/* -exit(4); -*/