From ce81cb7f28d42f0f5677471bed3cc6afeb91ff6f Mon Sep 17 00:00:00 2001 From: Xircon Date: Sat, 1 Aug 2026 17:08:50 -0400 Subject: [PATCH] yummy --- documentation/lang/Grammar.md | 17 ++++---- examples/compact/exitall.x | 9 +++- src/error.hxx | 9 ++++ src/generation.hxx | 59 +++++++++++++++++++++++---- src/parser.hxx | 56 +++++++++++++++++++++++-- src/tokenization.hxx | 77 ++++++++++++++++++----------------- 6 files changed, 172 insertions(+), 55 deletions(-) diff --git a/documentation/lang/Grammar.md b/documentation/lang/Grammar.md index dd7948c..f764dd1 100644 --- a/documentation/lang/Grammar.md +++ b/documentation/lang/Grammar.md @@ -2,18 +2,21 @@ Basically just an outline of how to type things out and how things work syntactically. $$ \begin{align} - [\text{prog}] &\to [\text{stmt}]^* \\ - [\text{stmt}]^* &\to + [\text{Prog}] &\to [\text{Stmt}]^* \\ + [\text{Stmt}]^* &\to \begin{cases} - \text{exit}([\text{expr}]); \\ - \text{var}\space\text{ident} = [\text{expr}]; \\ + \text{exit}([\text{Expr}]); \\ + \text{var}\space\text{ident} = [\text{Expr}]; \\ + \text{if}\ ([\text{Expr}])\ [\text{Scope}] \\ + [\text{Scope}] \\ \end{cases} \\ - [\text{expr}] &\to + [\text{Expr}] &\to \begin{cases} - \text{[Term]} + \text{[Term]} \\ \text{[BinExpr]} \\ \end{cases} \\ - [\text{BinExpr}] + [\text{Scope}] &\to \{[\text{Stmt}]^*\} \\ + [\text{BinExpr}] &\to \begin{cases} [\text[{Expr}]!] &prec=3\\ [\text[{Expr}] ^ \text{[Expr]}] &prec=2\\ diff --git a/examples/compact/exitall.x b/examples/compact/exitall.x index b6b5786..003b6fb 100644 --- a/examples/compact/exitall.x +++ b/examples/compact/exitall.x @@ -1,4 +1,11 @@ var x = 1 + 2 * 3; +{ + var z = 2; + var y = 2; +} var y = x - 3; var z = (3*5) / 3; -exit(y + z); \ No newline at end of file +if (x) { + exit(y + z); +} +exit (1); \ No newline at end of file diff --git a/src/error.hxx b/src/error.hxx index 0003abf..59ff908 100644 --- a/src/error.hxx +++ b/src/error.hxx @@ -4,6 +4,7 @@ #include namespace err { + // Compiler Errors inline void syntax(std::optional err) { std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mexpected '" << err.value() << "'\033[0m" << std::endl; } @@ -40,6 +41,12 @@ namespace err { std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mundeclared varible '" << err.value() << "'\033[0m" << std::endl; } + inline void scope() { + std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37minvalid scope\033[0m" << std::endl; + } + + + // Operator errors inline void nofile() { std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mno input files\033[0m" << std::endl; } @@ -47,4 +54,6 @@ namespace err { inline void help() { std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mhelp no implemented... just... uhm... look at main.cxx?\033[0m" << std::endl; } + + } \ No newline at end of file diff --git a/src/generation.hxx b/src/generation.hxx index f9f6ecb..d7a2a01 100644 --- a/src/generation.hxx +++ b/src/generation.hxx @@ -3,7 +3,6 @@ #include #include #include -#include #include "parser.hxx" @@ -13,6 +12,14 @@ public: // Erm!!! } + void gen_scope(const node::Scope* scope) { + begin_scope(); + for (const node::Stmt* stmt : scope->stmts) { + gen_stmt(stmt); + } + end_scope(); + } + void gen_stmt(const node::Stmt* stmt) { struct StmtVisitor { // Visiting the homies Generator* gen; @@ -24,13 +31,28 @@ public: } void operator()(const node::StmtVar* stmt_var) { - if (gen->m_vars.contains(stmt_var->ident.value.value())) { + auto it = std::find_if(gen->m_vars.cbegin(), gen->m_vars.cend(), [&](const Var& var){return var.name == stmt_var->ident.value.value();}); + if (it != gen->m_vars.cend()) { err::redefine(stmt_var->ident.value.value()); exit(EXIT_FAILURE); } - gen->m_vars.insert({stmt_var->ident.value.value(), Var {.stack_loc = gen->m_stack_size}}); + gen->m_vars.push_back({.name = stmt_var->ident.value.value(), .stack_loc = gen->m_stack_size}); gen->gen_expr(stmt_var->expr); } + + void operator()(const node::StmtIf* stmt_if) const { + gen->gen_expr(stmt_if->expr); + gen->pop("rax"); + 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); + gen->m_output << "\n" << label << ":\n"; + } + + void operator()(const node::Scope* scope) { + gen->gen_scope(scope); + } }; StmtVisitor visitor {.gen = this}; @@ -47,13 +69,13 @@ public: } void operator()(const node::TermIdent* term_ident) const { - if (!gen->m_vars.contains(term_ident->ident.value.value())) { + auto it = std::find_if(gen->m_vars.cbegin(), gen->m_vars.cend(), [&](const Var& var){return var.name == term_ident->ident.value.value();}); + if (it == gen->m_vars.cend()) { err::undeclared(term_ident->ident.value.value()); exit(EXIT_FAILURE); } - const auto& var = gen->m_vars.at(term_ident->ident.value.value()); std::stringstream offset; - offset << "QWORD [rsp + " << (gen->m_stack_size - var.stack_loc - 1) * 8 << "]"; + offset << "QWORD [rsp + " << (gen->m_stack_size - (*it).stack_loc - 1) * 8 << "]"; gen->push(offset.str()); } void operator()(const node::TermParen* term_paren) const { @@ -139,6 +161,26 @@ public: } private: + void begin_scope() { + m_scopes.push_back(m_vars.size()); + } + + void end_scope(){ + size_t pop_count = m_vars.size() - m_scopes.back(); + m_output << " add rsp, " << pop_count * 8 << "\n"; + m_stack_size -= pop_count; + for (int 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(); + } + void push(const std::string& reg) { m_output << " push " << reg << "\n"; m_stack_size++; @@ -150,11 +192,14 @@ private: } struct Var { + std::string name; size_t stack_loc; }; const node::Prog m_prog; std::stringstream m_output; size_t m_stack_size = 0; - std::map m_vars {}; + std::vector m_vars {}; + std::vector m_scopes {}; + int m_label_count = 0; }; \ No newline at end of file diff --git a/src/parser.hxx b/src/parser.hxx index 1f2bd05..2c30e34 100644 --- a/src/parser.hxx +++ b/src/parser.hxx @@ -10,6 +10,7 @@ namespace node { struct Expr; + struct Stmt; struct TermIntLit { Token int_lit; @@ -55,6 +56,10 @@ namespace node { std::variant var; }; + struct Scope { + std::vector stmts; + }; + struct StmtExit { Expr* expr; }; @@ -64,8 +69,13 @@ namespace node { Expr* expr; }; + struct StmtIf { + Expr* expr; + Scope* scope; + }; + struct Stmt { - std::variant var; + std::variant var; }; struct Prog { @@ -163,7 +173,7 @@ public: sub->lhs = expr_lhs2; sub->rhs = expr_rhs.value(); expr->var = sub; - } else if (op.type == TokenType::slash) { + } else if (op.type == TokenType::fslash) { auto div = m_allocator.alloc(); expr_lhs->var = term_lhs.value(); expr_lhs2->var = expr_lhs->var; @@ -179,6 +189,18 @@ public: return expr_lhs; } + std::optional parse_scope() { + if (!try_consume(TokenType::open_curly).has_value()) { + return {}; + } + auto scope = m_allocator.alloc(); + while (auto stmt = parse_stmt()) { + scope->stmts.push_back(stmt.value()); + } + try_consume(TokenType::close_curly, "}"); + return scope; + } + std::optional parse_stmt() { if (peek().has_value() && peek().value().type == TokenType::exit && peek(1).has_value() && peek(1).value().type == TokenType::open_paren) { consume(); @@ -187,7 +209,7 @@ public: if (auto node_expr = parse_expr()) { stmt_exit->expr = node_expr.value(); } else { - err::expression({}); + err::expression("exit"); exit(EXIT_FAILURE); } @@ -214,6 +236,34 @@ public: auto stmt = m_allocator.alloc(); stmt->var = stmt_var; return stmt; + } else if (peek().has_value() && peek().value().type == TokenType::open_curly) { + if (auto scope = parse_scope()) { + auto stmt = m_allocator.alloc(); + stmt->var = scope.value(); + return stmt; + } else { + err::scope(); + exit(EXIT_FAILURE); + } + } else if (auto if_ = try_consume(TokenType::if_)) { + try_consume(TokenType::open_paren, "("); + auto stmt_if = m_allocator.alloc(); + if (auto expr = parse_expr()) { + stmt_if->expr = expr.value(); + } else { + err::expression("if"); + exit(EXIT_FAILURE); + } + try_consume(TokenType::close_paren, ")"); + if (auto scope = parse_scope()) { + stmt_if->scope = scope.value(); + } else { + err::scope(); + exit(EXIT_FAILURE); + } + auto stmt = m_allocator.alloc(); + stmt->var = stmt_if; + return stmt; } else { return {}; } diff --git a/src/tokenization.hxx b/src/tokenization.hxx index 87a134a..4d81ae5 100644 --- a/src/tokenization.hxx +++ b/src/tokenization.hxx @@ -5,6 +5,7 @@ #include #include #include +#include #include "error.hxx" @@ -19,16 +20,21 @@ enum class TokenType { equals, plus, star, - slash, + fslash, minus, carrot, excl, + open_curly, + close_curly, + open_bracket, + close_bracket, + if_, }; std::optional bin_prec(TokenType type) { switch (type) { case TokenType::star: - case TokenType::slash: + case TokenType::fslash: return 1; case TokenType::plus: case TokenType::minus: @@ -51,7 +57,6 @@ public: inline std::vector tokenize() { std::vector tokens; std::string buffer; - while (peek().has_value()) { if (std::isalpha(peek().value())) { buffer.push_back(consume()); @@ -64,6 +69,9 @@ public: } else if (buffer == "var") { tokens.push_back({.type = TokenType::var}); buffer.clear(); + } else if (buffer == "if") { + tokens.push_back({.type = TokenType::if_}); + buffer.clear(); } else { tokens.push_back({.type = TokenType::ident, .value = buffer}); buffer.clear(); @@ -75,42 +83,33 @@ public: } tokens.push_back({.type = TokenType::int_lit, .value = buffer}); buffer.clear(); - } else if (peek().value() == '(') { - consume(); - tokens.push_back({.type = TokenType::open_paren}); - } else if (peek().value() == ')') { - consume(); - tokens.push_back({.type = TokenType::close_paren}); - } else if (peek().value() == ';') { - consume(); - tokens.push_back({.type = TokenType::semi}); - } else if (peek().value() == '=') { - consume(); - tokens.push_back({.type = TokenType::equals}); - } else if (peek().value() == '+') { - consume(); - tokens.push_back({.type = TokenType::plus}); - } else if (peek().value() == '*') { - consume(); - tokens.push_back({.type = TokenType::star}); - } else if (peek().value() == '-') { - consume(); - tokens.push_back({.type = TokenType::minus}); - } else if (peek().value() == '/') { - consume(); - tokens.push_back({.type = TokenType::slash}); - } else if (peek().value() == '^') { - consume(); - tokens.push_back({.type = TokenType::carrot}); - } else if (peek().value() == '!') { - consume(); - tokens.push_back({.type = TokenType::excl}); } else if (std::isspace(peek().value())) { consume(); - } else { - err::unknowntype(buffer); - exit(EXIT_FAILURE); - } + } else { + char c = peek().has_value() ? *peek() : -1; + if (c != -1) { + switch(c) { + case '(': tokens.push_back({.type = TokenType::open_paren}); break; + case ')': tokens.push_back({.type = TokenType::close_paren}); break; + case ';': tokens.push_back({.type = TokenType::semi}); break; + case '=': tokens.push_back({.type = TokenType::equals}); break; + case '+': tokens.push_back({.type = TokenType::plus}); break; + case '*': tokens.push_back({.type = TokenType::star}); break; + case '-': tokens.push_back({.type = TokenType::minus}); break; + case '/': tokens.push_back({.type = TokenType::fslash}); break; + case '^': tokens.push_back({.type = TokenType::carrot}); break; + case '!': tokens.push_back({.type = TokenType::excl}); break; + case '{': tokens.push_back({.type = TokenType::open_curly}); break; + case '}': tokens.push_back({.type = TokenType::close_curly}); break; + case '[': tokens.push_back({.type = TokenType::open_bracket}); break; + case ']': tokens.push_back({.type = TokenType::close_bracket}); break; + default: + err::unknowntype(buffer); + exit(EXIT_FAILURE); + } + consume(); + } + } } // Return mah shit m_index = 0; @@ -130,6 +129,10 @@ private: return m_src.at(m_index++); } + constexpr unsigned int string_hash(const char* str, int h = 0) { + return !str[h] ? 5381 : (string_hash(str, h + 1) * 33) ^ str[h]; + } + const std::string m_src; size_t m_index = 0; }; \ No newline at end of file