rerererereeeeee
This commit is contained in:
parent
8a1dd20bd9
commit
e30c147da4
@ -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}
|
||||
$$
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
var x = 69 + 69 + 42;
|
||||
exit(x + 2);
|
||||
var x = 1 + 1 + 1;
|
||||
var y = 2 + 2;
|
||||
exit(x + y);
|
||||
4
examples/compact/exitall.x
Normal file
4
examples/compact/exitall.x
Normal file
@ -0,0 +1,4 @@
|
||||
var x = 1 + 2 * 3;
|
||||
var y = x - 3;
|
||||
var z = (3*5) / 3;
|
||||
exit(y + z);
|
||||
3
examples/compact/exitmul.x
Normal file
3
examples/compact/exitmul.x
Normal file
@ -0,0 +1,3 @@
|
||||
var x = 1 + 2 * 3;
|
||||
var y = x + 5;
|
||||
exit(y);
|
||||
1
examples/compact/exitsub.x
Normal file
1
examples/compact/exitsub.x
Normal file
@ -0,0 +1 @@
|
||||
exit(11-4);
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
118
src/parser.hxx
118
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<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;
|
||||
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 {
|
||||
auto expr = m_allocator.alloc<node::Expr>();
|
||||
expr->var = term.value();
|
||||
return expr;
|
||||
err::syntax({});
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
return {};
|
||||
expr_lhs->var = expr;
|
||||
}
|
||||
return expr_lhs;
|
||||
}
|
||||
|
||||
std::optional<node::Stmt*> parse_stmt() {
|
||||
|
||||
@ -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,42 +75,38 @@ 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 {
|
||||
err::unknowntype(buffer);
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user