rerererereeeeee
This commit is contained in:
parent
8a1dd20bd9
commit
e30c147da4
@ -15,15 +15,18 @@ $$
|
|||||||
\end{cases} \\
|
\end{cases} \\
|
||||||
[\text{BinExpr}]
|
[\text{BinExpr}]
|
||||||
\begin{cases}
|
\begin{cases}
|
||||||
[\text[{Expr}] * \text{[Expr]}] &prec=3\\
|
[\text[{Expr}]!] &prec=3\\
|
||||||
[\text[{Expr}] \div \text{[Expr]}] &prec=2\\
|
[\text[{Expr}] ^ \text{[Expr]}] &prec=2\\
|
||||||
[\text[{Expr}] + \text{[Expr]}] &prec=1\\
|
[\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\\
|
[\text[{Expr}] - \text{[Expr]}] &prec=0\\
|
||||||
\end{cases} \\
|
\end{cases} \\
|
||||||
[\text{Term}] &\to
|
[\text{Term}] &\to
|
||||||
\begin{cases}
|
\begin{cases}
|
||||||
\text{int\_lit} \\
|
\text{int\_lit} \\
|
||||||
\text{ident} \\
|
\text{ident} \\
|
||||||
|
(\text{Expr}) \\
|
||||||
\end{cases} \\
|
\end{cases} \\
|
||||||
\end{align}
|
\end{align}
|
||||||
$$
|
$$
|
||||||
|
|||||||
@ -5,7 +5,6 @@ Here's a simple hello world:
|
|||||||
```java
|
```java
|
||||||
include <io> // This is where all basic I/O functions live
|
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
|
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
|
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.
|
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.
|
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.)
|
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.
|
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
|
### Compact Source File Hello World
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
var x = 69 + 69 + 42;
|
var x = 1 + 1 + 1;
|
||||||
exit(x + 2);
|
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 << "]";
|
offset << "QWORD [rsp + " << (gen->m_stack_size - var.stack_loc - 1) * 8 << "]";
|
||||||
gen->push(offset.str());
|
gen->push(offset.str());
|
||||||
}
|
}
|
||||||
|
void operator()(const node::TermParen* term_paren) const {
|
||||||
|
gen->gen_expr(term_paren->expr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
TermVisitor visitor ({.gen = this});
|
TermVisitor visitor ({.gen = this});
|
||||||
std::visit(visitor, term->var);
|
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) {
|
void gen_expr(const node::Expr* expr) {
|
||||||
struct ExprVisitor {
|
struct ExprVisitor {
|
||||||
Generator* gen;
|
Generator* gen;
|
||||||
@ -70,12 +117,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const node::BinExpr* bin_expr) const {
|
void operator()(const node::BinExpr* bin_expr) const {
|
||||||
gen->gen_expr(bin_expr->var->lhs);
|
gen->gen_bin_expr(bin_expr);
|
||||||
gen->gen_expr(bin_expr->var->rhs);
|
|
||||||
gen->pop("rax");
|
|
||||||
gen->pop("rbx");
|
|
||||||
gen->m_output << " add rax, rbx\n";
|
|
||||||
gen->push("rax");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
130
src/parser.hxx
130
src/parser.hxx
@ -9,6 +9,8 @@
|
|||||||
#include "arena.hxx"
|
#include "arena.hxx"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
struct Expr;
|
||||||
|
|
||||||
struct TermIntLit {
|
struct TermIntLit {
|
||||||
Token int_lit;
|
Token int_lit;
|
||||||
};
|
};
|
||||||
@ -17,24 +19,36 @@ namespace node {
|
|||||||
Token ident;
|
Token ident;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Expr;
|
struct TermParen {
|
||||||
|
Expr* expr;
|
||||||
|
};
|
||||||
|
|
||||||
struct BinExprAdd {
|
struct BinExprAdd {
|
||||||
Expr* lhs;
|
Expr* lhs;
|
||||||
Expr* rhs;
|
Expr* rhs;
|
||||||
};
|
};
|
||||||
|
|
||||||
// struct BinExprMul {
|
struct BinExprMul {
|
||||||
// Expr* lhs;
|
Expr* lhs;
|
||||||
// Expr* rhs;
|
Expr* rhs;
|
||||||
// };
|
};
|
||||||
|
|
||||||
|
struct BinExprSub {
|
||||||
|
Expr* lhs;
|
||||||
|
Expr* rhs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BinExprDiv {
|
||||||
|
Expr* lhs;
|
||||||
|
Expr* rhs;
|
||||||
|
};
|
||||||
|
|
||||||
struct BinExpr {
|
struct BinExpr {
|
||||||
BinExprAdd* var;
|
std::variant<BinExprAdd*, BinExprMul*, BinExprSub*, BinExprDiv*> var;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Term {
|
struct Term {
|
||||||
std::variant<TermIntLit*, TermIdent*> var;
|
std::variant<TermIntLit*, TermIdent*, TermParen*> var;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
@ -80,37 +94,89 @@ public:
|
|||||||
auto term = m_allocator.alloc<node::Term>();
|
auto term = m_allocator.alloc<node::Term>();
|
||||||
term->var = term_ident;
|
term->var = term_ident;
|
||||||
return term;
|
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 {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<node::Expr*> parse_expr() {
|
std::optional<node::Expr*> parse_expr(int min_prec = 0) {
|
||||||
if (auto term = parse_term()) {
|
std::optional<node::Term*> term_lhs = parse_term();
|
||||||
if (try_consume(TokenType::add).has_value()) {
|
if (!term_lhs.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 {
|
|
||||||
return {};
|
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() {
|
std::optional<node::Stmt*> parse_stmt() {
|
||||||
@ -144,7 +210,7 @@ public:
|
|||||||
err::expression({});
|
err::expression({});
|
||||||
}
|
}
|
||||||
try_consume(TokenType::semi, ";");
|
try_consume(TokenType::semi, ";");
|
||||||
|
|
||||||
auto stmt = m_allocator.alloc<node::Stmt>();
|
auto stmt = m_allocator.alloc<node::Stmt>();
|
||||||
stmt->var = stmt_var;
|
stmt->var = stmt_var;
|
||||||
return stmt;
|
return stmt;
|
||||||
|
|||||||
@ -17,12 +17,26 @@ enum class TokenType {
|
|||||||
ident,
|
ident,
|
||||||
var,
|
var,
|
||||||
equals,
|
equals,
|
||||||
add,
|
plus,
|
||||||
mul,
|
star,
|
||||||
div,
|
slash,
|
||||||
sub
|
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 {
|
struct Token {
|
||||||
TokenType type;
|
TokenType type;
|
||||||
std::optional<std::string> value {};
|
std::optional<std::string> value {};
|
||||||
@ -47,15 +61,12 @@ public:
|
|||||||
if (buffer == "exit") {
|
if (buffer == "exit") {
|
||||||
tokens.push_back({.type = TokenType::exit});
|
tokens.push_back({.type = TokenType::exit});
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
continue;
|
|
||||||
} else if (buffer == "var") {
|
} else if (buffer == "var") {
|
||||||
tokens.push_back({.type = TokenType::var});
|
tokens.push_back({.type = TokenType::var});
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
continue;
|
|
||||||
} else {
|
} else {
|
||||||
tokens.push_back({.type = TokenType::ident, .value = buffer});
|
tokens.push_back({.type = TokenType::ident, .value = buffer});
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else if (std::isdigit(peek().value())) {
|
} else if (std::isdigit(peek().value())) {
|
||||||
buffer.push_back(consume());
|
buffer.push_back(consume());
|
||||||
@ -64,43 +75,39 @@ public:
|
|||||||
}
|
}
|
||||||
tokens.push_back({.type = TokenType::int_lit, .value = buffer});
|
tokens.push_back({.type = TokenType::int_lit, .value = buffer});
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
continue;
|
|
||||||
} else if (peek().value() == '(') {
|
} else if (peek().value() == '(') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::open_paren});
|
tokens.push_back({.type = TokenType::open_paren});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == ')') {
|
} else if (peek().value() == ')') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::close_paren});
|
tokens.push_back({.type = TokenType::close_paren});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == ';') {
|
} else if (peek().value() == ';') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::semi});
|
tokens.push_back({.type = TokenType::semi});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == '=') {
|
} else if (peek().value() == '=') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::equals});
|
tokens.push_back({.type = TokenType::equals});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == '+') {
|
} else if (peek().value() == '+') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::add});
|
tokens.push_back({.type = TokenType::plus});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == '*') {
|
} else if (peek().value() == '*') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::mul});
|
tokens.push_back({.type = TokenType::star});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == '-') {
|
} else if (peek().value() == '-') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::sub});
|
tokens.push_back({.type = TokenType::minus});
|
||||||
continue;
|
|
||||||
} else if (peek().value() == '/') {
|
} else if (peek().value() == '/') {
|
||||||
consume();
|
consume();
|
||||||
tokens.push_back({.type = TokenType::div});
|
tokens.push_back({.type = TokenType::slash});
|
||||||
continue;
|
} 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())) {
|
} else if (std::isspace(peek().value())) {
|
||||||
consume();
|
consume();
|
||||||
continue;
|
} else {
|
||||||
} else {
|
|
||||||
err::unknowntype(buffer);
|
err::unknowntype(buffer);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user