rerererereeeeee

This commit is contained in:
Xircon 2026-08-01 03:05:45 -04:00
parent 8a1dd20bd9
commit e30c147da4
9 changed files with 193 additions and 67 deletions

View File

@ -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}
$$

View File

@ -5,7 +5,6 @@ Here's a simple hello world:
```java
include <io> // 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

View File

@ -1,2 +1,3 @@
var x = 69 + 69 + 42;
exit(x + 2);
var x = 1 + 1 + 1;
var y = 2 + 2;
exit(x + y);

View File

@ -0,0 +1,4 @@
var x = 1 + 2 * 3;
var y = x - 3;
var z = (3*5) / 3;
exit(y + z);

View File

@ -0,0 +1,3 @@
var x = 1 + 2 * 3;
var y = x + 5;
exit(y);

View File

@ -0,0 +1 @@
exit(11-4);

View File

@ -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);
}
};

View File

@ -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<BinExprAdd*, BinExprMul*, BinExprSub*, BinExprDiv*> var;
};
struct Term {
std::variant<TermIntLit*, TermIdent*> var;
std::variant<TermIntLit*, TermIdent*, TermParen*> var;
};
struct Expr {
@ -80,37 +94,89 @@ public:
auto term = m_allocator.alloc<node::Term>();
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<node::TermParen>();
term_paren->expr = expr.value();
auto term = m_allocator.alloc<node::Term>();
term->var = term_paren;
return term;
} else {
return {};
}
}
std::optional<node::Expr*> parse_expr() {
if (auto term = parse_term()) {
if (try_consume(TokenType::add).has_value()) {
auto bin_expr = m_allocator.alloc<node::BinExpr>();
auto bin_expr_add = m_allocator.alloc<node::BinExprAdd>();
auto lhs_expr = m_allocator.alloc<node::Expr>();
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<node::Expr>();
expr->var = bin_expr;
return expr;
} else {
err::expression({});
exit(EXIT_FAILURE);
}
} else {
auto expr = m_allocator.alloc<node::Expr>();
expr->var = term.value();
return expr;
}
} else {
std::optional<node::Expr*> parse_expr(int min_prec = 0) {
std::optional<node::Term*> term_lhs = parse_term();
if (!term_lhs.has_value()) {
return {};
}
auto expr_lhs = m_allocator.alloc<node::Expr>();
expr_lhs->var = term_lhs.value();
while (true) {
std::optional<Token> curr_tok = peek();
std::optional<int> 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<node::BinExpr>();
auto expr_lhs2 = m_allocator.alloc<node::Expr>(); // LHS two: The Sequel.
if (op.type == TokenType::plus) {
auto add = m_allocator.alloc<node::BinExprAdd>();
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<node::BinExprMul>();
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<node::BinExprSub>();
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<node::BinExprDiv>();
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<node::Stmt*> parse_stmt() {

View File

@ -17,12 +17,26 @@ enum class TokenType {
ident,
var,
equals,
add,
mul,
div,
sub
plus,
star,
slash,
minus,
carrot,
excl,
};
std::optional<int> 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<std::string> 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);
}