From e30c147da480bb11769df18d1f015fbc2ba34a07 Mon Sep 17 00:00:00 2001 From: Xircon Date: Sat, 1 Aug 2026 03:05:45 -0400 Subject: [PATCH] rerererereeeeee --- documentation/lang/Grammar.md | 9 ++- documentation/lang/Main.md | 3 +- examples/compact/exitadd.x | 5 +- examples/compact/exitall.x | 4 ++ examples/compact/exitmul.x | 3 + examples/compact/exitsub.x | 1 + src/generation.hxx | 54 ++++++++++++-- src/parser.hxx | 130 +++++++++++++++++++++++++--------- src/tokenization.hxx | 51 +++++++------ 9 files changed, 193 insertions(+), 67 deletions(-) create mode 100644 examples/compact/exitall.x create mode 100644 examples/compact/exitmul.x create mode 100644 examples/compact/exitsub.x diff --git a/documentation/lang/Grammar.md b/documentation/lang/Grammar.md index a61599a..dd7948c 100644 --- a/documentation/lang/Grammar.md +++ b/documentation/lang/Grammar.md @@ -15,15 +15,18 @@ $$ \end{cases} \\ [\text{BinExpr}] \begin{cases} - [\text[{Expr}] * \text{[Expr]}] &prec=3\\ - [\text[{Expr}] \div \text{[Expr]}] &prec=2\\ - [\text[{Expr}] + \text{[Expr]}] &prec=1\\ + [\text[{Expr}]!] &prec=3\\ + [\text[{Expr}] ^ \text{[Expr]}] &prec=2\\ + [\text[{Expr}] \times \text{[Expr]}] &prec=1\\ + [\text[{Expr}] \div \text{[Expr]}] &prec=1\\ + [\text[{Expr}] + \text{[Expr]}] &prec=0\\ [\text[{Expr}] - \text{[Expr]}] &prec=0\\ \end{cases} \\ [\text{Term}] &\to \begin{cases} \text{int\_lit} \\ \text{ident} \\ + (\text{Expr}) \\ \end{cases} \\ \end{align} $$ diff --git a/documentation/lang/Main.md b/documentation/lang/Main.md index 8c45857..aab7489 100644 --- a/documentation/lang/Main.md +++ b/documentation/lang/Main.md @@ -5,7 +5,6 @@ Here's a simple hello world: ```java include // This is where all basic I/O functions live -! Main Function public static void main() { // Declare a function the exact same way as in java, does not HAVE to be public nor static, these are automatic io.println("Hi world!"); // Println works the same as its java counterpart return; // Return is not needed for void functions, but can still be used. @@ -15,7 +14,7 @@ public static void main() { // Declare a function the exact same way as in java, You'll notice the syntax is similar to that of Java, minus having to declare the class of course. As here theres no classes *just files* so no, you cannot have classes in classes... or can you? No, no you cannot. They're useful, but honestly i dislike them and find it makes things messy. (yes i like to have 3000 files how'd you know.) -Anyhow, Comments are the same as in C or Java, you can annotate a function to say its use via ! \[USAGE\] it basically just works like a comment, but is designed specifically for saying what a function does and can only be used before a function declaration. Going on with similarities, include carries over from C, except you do not need to add a file extension ***ever*** similar to how imports in java work, tho differing from that as there is *no* static imports. +Anyhow, Comments are the same as in C or Java, you can annotate a function similar to java with the `@` symbol. Going on with similarities, include carries over from C, except you do not need to add a file extension ***ever*** similar to how imports in java work, tho differing from that as there is *no* static imports. So like shown in the example to use something like println from the io package, you must type `io.println("");` and not `println("");` if something is inside the same file you do not need the package before it, but you can still do this it won't hurt anything. ### Compact Source File Hello World diff --git a/examples/compact/exitadd.x b/examples/compact/exitadd.x index 048a9ae..a0bccb0 100644 --- a/examples/compact/exitadd.x +++ b/examples/compact/exitadd.x @@ -1,2 +1,3 @@ -var x = 69 + 69 + 42; -exit(x + 2); \ No newline at end of file +var x = 1 + 1 + 1; +var y = 2 + 2; +exit(x + y); \ No newline at end of file diff --git a/examples/compact/exitall.x b/examples/compact/exitall.x new file mode 100644 index 0000000..b6b5786 --- /dev/null +++ b/examples/compact/exitall.x @@ -0,0 +1,4 @@ +var x = 1 + 2 * 3; +var y = x - 3; +var z = (3*5) / 3; +exit(y + z); \ No newline at end of file diff --git a/examples/compact/exitmul.x b/examples/compact/exitmul.x new file mode 100644 index 0000000..54e0789 --- /dev/null +++ b/examples/compact/exitmul.x @@ -0,0 +1,3 @@ +var x = 1 + 2 * 3; +var y = x + 5; +exit(y); \ No newline at end of file diff --git a/examples/compact/exitsub.x b/examples/compact/exitsub.x new file mode 100644 index 0000000..25f4021 --- /dev/null +++ b/examples/compact/exitsub.x @@ -0,0 +1 @@ +exit(11-4); \ No newline at end of file diff --git a/src/generation.hxx b/src/generation.hxx index aecb825..5b3e90e 100644 --- a/src/generation.hxx +++ b/src/generation.hxx @@ -56,11 +56,58 @@ public: offset << "QWORD [rsp + " << (gen->m_stack_size - var.stack_loc - 1) * 8 << "]"; gen->push(offset.str()); } + void operator()(const node::TermParen* term_paren) const { + gen->gen_expr(term_paren->expr); + } }; TermVisitor visitor ({.gen = this}); std::visit(visitor, term->var); } + void gen_bin_expr(const node::BinExpr* bin_expr) { + struct BinExprVisitor { + Generator* gen; + void operator()(const node::BinExprAdd* add) { + 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 node::BinExprMul* mul) { + gen->gen_expr(mul->rhs); + gen->gen_expr(mul->lhs); + gen->pop("rax"); + gen->pop("rbx"); + gen->m_output << " mul rbx\n"; + gen->push("rax"); + } + + void operator()(const node::BinExprSub* sub) { + 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 node::BinExprDiv* div) { + 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 node::Expr* expr) { struct ExprVisitor { Generator* gen; @@ -70,12 +117,7 @@ public: } void operator()(const node::BinExpr* bin_expr) const { - gen->gen_expr(bin_expr->var->lhs); - gen->gen_expr(bin_expr->var->rhs); - gen->pop("rax"); - gen->pop("rbx"); - gen->m_output << " add rax, rbx\n"; - gen->push("rax"); + gen->gen_bin_expr(bin_expr); } }; diff --git a/src/parser.hxx b/src/parser.hxx index 312195b..1f2bd05 100644 --- a/src/parser.hxx +++ b/src/parser.hxx @@ -9,6 +9,8 @@ #include "arena.hxx" namespace node { + struct Expr; + struct TermIntLit { Token int_lit; }; @@ -17,24 +19,36 @@ namespace node { Token ident; }; - struct Expr; + struct TermParen { + Expr* expr; + }; struct BinExprAdd { Expr* lhs; Expr* rhs; }; - // struct BinExprMul { - // Expr* lhs; - // Expr* rhs; - // }; + struct BinExprMul { + Expr* lhs; + Expr* rhs; + }; + + struct BinExprSub { + Expr* lhs; + Expr* rhs; + }; + + struct BinExprDiv { + Expr* lhs; + Expr* rhs; + }; struct BinExpr { - BinExprAdd* var; + std::variant var; }; struct Term { - std::variant var; + std::variant var; }; struct Expr { @@ -80,37 +94,89 @@ public: auto term = m_allocator.alloc(); term->var = term_ident; return term; + } else if(auto open_paren = try_consume(TokenType::open_paren)) { + auto expr = parse_expr(); + if (!expr.has_value()) { + err::expression({}); + exit(EXIT_FAILURE); + } + try_consume(TokenType::close_paren, ")"); + auto term_paren = m_allocator.alloc(); + term_paren->expr = expr.value(); + auto term = m_allocator.alloc(); + term->var = term_paren; + return term; } else { return {}; } } - std::optional parse_expr() { - if (auto term = parse_term()) { - if (try_consume(TokenType::add).has_value()) { - auto bin_expr = m_allocator.alloc(); - auto bin_expr_add = m_allocator.alloc(); - auto lhs_expr = m_allocator.alloc(); - lhs_expr->var = term.value(); - bin_expr_add->lhs = lhs_expr; - if (auto rhs = parse_expr()) { - bin_expr_add->rhs = rhs.value(); - bin_expr->var = bin_expr_add; - auto expr = m_allocator.alloc(); - expr->var = bin_expr; - return expr; - } else { - err::expression({}); - exit(EXIT_FAILURE); - } - } else { - auto expr = m_allocator.alloc(); - expr->var = term.value(); - return expr; - } - } else { + std::optional parse_expr(int min_prec = 0) { + std::optional term_lhs = parse_term(); + if (!term_lhs.has_value()) { return {}; } + + auto expr_lhs = m_allocator.alloc(); + expr_lhs->var = 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; // breaking bad + } + } else { + break; // breaking bad 2 + } + + Token op = consume(); + int next_min_prec = prec.value() + 1; + auto expr_rhs = parse_expr(next_min_prec); + if (!expr_rhs.has_value()) { + err::expression({}); + exit(EXIT_FAILURE); + } + + auto expr = m_allocator.alloc(); + auto expr_lhs2 = m_allocator.alloc(); // LHS two: The Sequel. + if (op.type == TokenType::plus) { + auto add = m_allocator.alloc(); + expr_lhs->var = term_lhs.value(); + expr_lhs2->var = expr_lhs->var; + add->lhs = expr_lhs2; + add->rhs = expr_rhs.value(); + expr->var = add; + } else if (op.type == TokenType::star) { + auto mul = m_allocator.alloc(); + expr_lhs->var = term_lhs.value(); + expr_lhs2->var = expr_lhs->var; + mul->lhs = expr_lhs2; + mul->rhs = expr_rhs.value(); + expr->var = mul; + } else if (op.type == TokenType::minus) { + auto sub = m_allocator.alloc(); + expr_lhs->var = term_lhs.value(); + expr_lhs2->var = expr_lhs->var; + sub->lhs = expr_lhs2; + sub->rhs = expr_rhs.value(); + expr->var = sub; + } else if (op.type == TokenType::slash) { + auto div = m_allocator.alloc(); + expr_lhs->var = term_lhs.value(); + expr_lhs2->var = expr_lhs->var; + div->lhs = expr_lhs2; + div->rhs = expr_rhs.value(); + expr->var = div; + } else { + err::syntax({}); + exit(EXIT_FAILURE); + } + expr_lhs->var = expr; + } + return expr_lhs; } std::optional parse_stmt() { @@ -144,7 +210,7 @@ public: err::expression({}); } try_consume(TokenType::semi, ";"); - + auto stmt = m_allocator.alloc(); stmt->var = stmt_var; return stmt; diff --git a/src/tokenization.hxx b/src/tokenization.hxx index fba07b2..87a134a 100644 --- a/src/tokenization.hxx +++ b/src/tokenization.hxx @@ -17,12 +17,26 @@ enum class TokenType { ident, var, equals, - add, - mul, - div, - sub + plus, + star, + slash, + minus, + carrot, + excl, }; +std::optional bin_prec(TokenType type) { + switch (type) { + case TokenType::star: + case TokenType::slash: + return 1; + case TokenType::plus: + case TokenType::minus: + return 0; + default: return {}; + } +} + struct Token { TokenType type; std::optional value {}; @@ -47,15 +61,12 @@ public: if (buffer == "exit") { tokens.push_back({.type = TokenType::exit}); buffer.clear(); - continue; } else if (buffer == "var") { tokens.push_back({.type = TokenType::var}); buffer.clear(); - continue; } else { tokens.push_back({.type = TokenType::ident, .value = buffer}); buffer.clear(); - continue; } } else if (std::isdigit(peek().value())) { buffer.push_back(consume()); @@ -64,43 +75,39 @@ public: } tokens.push_back({.type = TokenType::int_lit, .value = buffer}); buffer.clear(); - continue; } else if (peek().value() == '(') { consume(); tokens.push_back({.type = TokenType::open_paren}); - continue; } else if (peek().value() == ')') { consume(); tokens.push_back({.type = TokenType::close_paren}); - continue; } else if (peek().value() == ';') { consume(); tokens.push_back({.type = TokenType::semi}); - continue; } else if (peek().value() == '=') { consume(); tokens.push_back({.type = TokenType::equals}); - continue; } else if (peek().value() == '+') { consume(); - tokens.push_back({.type = TokenType::add}); - continue; + tokens.push_back({.type = TokenType::plus}); } else if (peek().value() == '*') { consume(); - tokens.push_back({.type = TokenType::mul}); - continue; + tokens.push_back({.type = TokenType::star}); } else if (peek().value() == '-') { consume(); - tokens.push_back({.type = TokenType::sub}); - continue; + tokens.push_back({.type = TokenType::minus}); } else if (peek().value() == '/') { consume(); - tokens.push_back({.type = TokenType::div}); - continue; + 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(); - continue; - } else { + } else { err::unknowntype(buffer); exit(EXIT_FAILURE); }