yummy
This commit is contained in:
parent
34b8d1ed39
commit
ce81cb7f28
@ -2,18 +2,21 @@
|
|||||||
Basically just an outline of how to type things out and how things work syntactically.
|
Basically just an outline of how to type things out and how things work syntactically.
|
||||||
$$
|
$$
|
||||||
\begin{align}
|
\begin{align}
|
||||||
[\text{prog}] &\to [\text{stmt}]^* \\
|
[\text{Prog}] &\to [\text{Stmt}]^* \\
|
||||||
[\text{stmt}]^* &\to
|
[\text{Stmt}]^* &\to
|
||||||
\begin{cases}
|
\begin{cases}
|
||||||
\text{exit}([\text{expr}]); \\
|
\text{exit}([\text{Expr}]); \\
|
||||||
\text{var}\space\text{ident} = [\text{expr}]; \\
|
\text{var}\space\text{ident} = [\text{Expr}]; \\
|
||||||
|
\text{if}\ ([\text{Expr}])\ [\text{Scope}] \\
|
||||||
|
[\text{Scope}] \\
|
||||||
\end{cases} \\
|
\end{cases} \\
|
||||||
[\text{expr}] &\to
|
[\text{Expr}] &\to
|
||||||
\begin{cases}
|
\begin{cases}
|
||||||
\text{[Term]}
|
\text{[Term]} \\
|
||||||
\text{[BinExpr]} \\
|
\text{[BinExpr]} \\
|
||||||
\end{cases} \\
|
\end{cases} \\
|
||||||
[\text{BinExpr}]
|
[\text{Scope}] &\to \{[\text{Stmt}]^*\} \\
|
||||||
|
[\text{BinExpr}] &\to
|
||||||
\begin{cases}
|
\begin{cases}
|
||||||
[\text[{Expr}]!] &prec=3\\
|
[\text[{Expr}]!] &prec=3\\
|
||||||
[\text[{Expr}] ^ \text{[Expr]}] &prec=2\\
|
[\text[{Expr}] ^ \text{[Expr]}] &prec=2\\
|
||||||
|
|||||||
@ -1,4 +1,11 @@
|
|||||||
var x = 1 + 2 * 3;
|
var x = 1 + 2 * 3;
|
||||||
|
{
|
||||||
|
var z = 2;
|
||||||
|
var y = 2;
|
||||||
|
}
|
||||||
var y = x - 3;
|
var y = x - 3;
|
||||||
var z = (3*5) / 3;
|
var z = (3*5) / 3;
|
||||||
exit(y + z);
|
if (x) {
|
||||||
|
exit(y + z);
|
||||||
|
}
|
||||||
|
exit (1);
|
||||||
@ -4,6 +4,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace err {
|
namespace err {
|
||||||
|
// Compiler Errors
|
||||||
inline void syntax(std::optional<std::string> err) {
|
inline void syntax(std::optional<std::string> err) {
|
||||||
std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mexpected '" << err.value() << "'\033[0m" << std::endl;
|
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;
|
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() {
|
inline void nofile() {
|
||||||
std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mno input files\033[0m" << std::endl;
|
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() {
|
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;
|
std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mhelp no implemented... just... uhm... look at main.cxx?\033[0m" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,7 +3,6 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "parser.hxx"
|
#include "parser.hxx"
|
||||||
|
|
||||||
@ -13,6 +12,14 @@ public:
|
|||||||
// Erm!!!
|
// 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) {
|
void gen_stmt(const node::Stmt* stmt) {
|
||||||
struct StmtVisitor { // Visiting the homies
|
struct StmtVisitor { // Visiting the homies
|
||||||
Generator* gen;
|
Generator* gen;
|
||||||
@ -24,13 +31,28 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const node::StmtVar* stmt_var) {
|
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());
|
err::redefine(stmt_var->ident.value.value());
|
||||||
exit(EXIT_FAILURE);
|
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);
|
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};
|
StmtVisitor visitor {.gen = this};
|
||||||
@ -47,13 +69,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void operator()(const node::TermIdent* term_ident) const {
|
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());
|
err::undeclared(term_ident->ident.value.value());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
const auto& var = gen->m_vars.at(term_ident->ident.value.value());
|
|
||||||
std::stringstream offset;
|
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());
|
gen->push(offset.str());
|
||||||
}
|
}
|
||||||
void operator()(const node::TermParen* term_paren) const {
|
void operator()(const node::TermParen* term_paren) const {
|
||||||
@ -139,6 +161,26 @@ public:
|
|||||||
}
|
}
|
||||||
private:
|
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) {
|
void push(const std::string& reg) {
|
||||||
m_output << " push " << reg << "\n";
|
m_output << " push " << reg << "\n";
|
||||||
m_stack_size++;
|
m_stack_size++;
|
||||||
@ -150,11 +192,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Var {
|
struct Var {
|
||||||
|
std::string name;
|
||||||
size_t stack_loc;
|
size_t stack_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
const node::Prog m_prog;
|
const node::Prog m_prog;
|
||||||
std::stringstream m_output;
|
std::stringstream m_output;
|
||||||
size_t m_stack_size = 0;
|
size_t m_stack_size = 0;
|
||||||
std::map<std::string, Var> m_vars {};
|
std::vector<Var> m_vars {};
|
||||||
|
std::vector<size_t> m_scopes {};
|
||||||
|
int m_label_count = 0;
|
||||||
};
|
};
|
||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
struct Expr;
|
struct Expr;
|
||||||
|
struct Stmt;
|
||||||
|
|
||||||
struct TermIntLit {
|
struct TermIntLit {
|
||||||
Token int_lit;
|
Token int_lit;
|
||||||
@ -55,6 +56,10 @@ namespace node {
|
|||||||
std::variant<Term*, BinExpr*> var;
|
std::variant<Term*, BinExpr*> var;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Scope {
|
||||||
|
std::vector<Stmt*> stmts;
|
||||||
|
};
|
||||||
|
|
||||||
struct StmtExit {
|
struct StmtExit {
|
||||||
Expr* expr;
|
Expr* expr;
|
||||||
};
|
};
|
||||||
@ -64,8 +69,13 @@ namespace node {
|
|||||||
Expr* expr;
|
Expr* expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StmtIf {
|
||||||
|
Expr* expr;
|
||||||
|
Scope* scope;
|
||||||
|
};
|
||||||
|
|
||||||
struct Stmt {
|
struct Stmt {
|
||||||
std::variant<StmtExit*, StmtVar*> var;
|
std::variant<StmtExit*, StmtVar*, StmtIf*, Scope*> var;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Prog {
|
struct Prog {
|
||||||
@ -163,7 +173,7 @@ public:
|
|||||||
sub->lhs = expr_lhs2;
|
sub->lhs = expr_lhs2;
|
||||||
sub->rhs = expr_rhs.value();
|
sub->rhs = expr_rhs.value();
|
||||||
expr->var = sub;
|
expr->var = sub;
|
||||||
} else if (op.type == TokenType::slash) {
|
} else if (op.type == TokenType::fslash) {
|
||||||
auto div = m_allocator.alloc<node::BinExprDiv>();
|
auto div = m_allocator.alloc<node::BinExprDiv>();
|
||||||
expr_lhs->var = term_lhs.value();
|
expr_lhs->var = term_lhs.value();
|
||||||
expr_lhs2->var = expr_lhs->var;
|
expr_lhs2->var = expr_lhs->var;
|
||||||
@ -179,6 +189,18 @@ public:
|
|||||||
return expr_lhs;
|
return expr_lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<node::Scope*> parse_scope() {
|
||||||
|
if (!try_consume(TokenType::open_curly).has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto scope = m_allocator.alloc<node::Scope>();
|
||||||
|
while (auto stmt = parse_stmt()) {
|
||||||
|
scope->stmts.push_back(stmt.value());
|
||||||
|
}
|
||||||
|
try_consume(TokenType::close_curly, "}");
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<node::Stmt*> parse_stmt() {
|
std::optional<node::Stmt*> parse_stmt() {
|
||||||
if (peek().has_value() && peek().value().type == TokenType::exit && peek(1).has_value() && peek(1).value().type == TokenType::open_paren) {
|
if (peek().has_value() && peek().value().type == TokenType::exit && peek(1).has_value() && peek(1).value().type == TokenType::open_paren) {
|
||||||
consume();
|
consume();
|
||||||
@ -187,7 +209,7 @@ public:
|
|||||||
if (auto node_expr = parse_expr()) {
|
if (auto node_expr = parse_expr()) {
|
||||||
stmt_exit->expr = node_expr.value();
|
stmt_exit->expr = node_expr.value();
|
||||||
} else {
|
} else {
|
||||||
err::expression({});
|
err::expression("exit");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +236,34 @@ public:
|
|||||||
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;
|
||||||
|
} else if (peek().has_value() && peek().value().type == TokenType::open_curly) {
|
||||||
|
if (auto scope = parse_scope()) {
|
||||||
|
auto stmt = m_allocator.alloc<node::Stmt>();
|
||||||
|
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<node::StmtIf>();
|
||||||
|
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<node::Stmt>();
|
||||||
|
stmt->var = stmt_if;
|
||||||
|
return stmt;
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "error.hxx"
|
#include "error.hxx"
|
||||||
|
|
||||||
@ -19,16 +20,21 @@ enum class TokenType {
|
|||||||
equals,
|
equals,
|
||||||
plus,
|
plus,
|
||||||
star,
|
star,
|
||||||
slash,
|
fslash,
|
||||||
minus,
|
minus,
|
||||||
carrot,
|
carrot,
|
||||||
excl,
|
excl,
|
||||||
|
open_curly,
|
||||||
|
close_curly,
|
||||||
|
open_bracket,
|
||||||
|
close_bracket,
|
||||||
|
if_,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<int> bin_prec(TokenType type) {
|
std::optional<int> bin_prec(TokenType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TokenType::star:
|
case TokenType::star:
|
||||||
case TokenType::slash:
|
case TokenType::fslash:
|
||||||
return 1;
|
return 1;
|
||||||
case TokenType::plus:
|
case TokenType::plus:
|
||||||
case TokenType::minus:
|
case TokenType::minus:
|
||||||
@ -51,7 +57,6 @@ public:
|
|||||||
inline std::vector<Token> tokenize() {
|
inline std::vector<Token> tokenize() {
|
||||||
std::vector<Token> tokens;
|
std::vector<Token> tokens;
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
|
|
||||||
while (peek().has_value()) {
|
while (peek().has_value()) {
|
||||||
if (std::isalpha(peek().value())) {
|
if (std::isalpha(peek().value())) {
|
||||||
buffer.push_back(consume());
|
buffer.push_back(consume());
|
||||||
@ -64,6 +69,9 @@ public:
|
|||||||
} else if (buffer == "var") {
|
} else if (buffer == "var") {
|
||||||
tokens.push_back({.type = TokenType::var});
|
tokens.push_back({.type = TokenType::var});
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
|
} else if (buffer == "if") {
|
||||||
|
tokens.push_back({.type = TokenType::if_});
|
||||||
|
buffer.clear();
|
||||||
} else {
|
} else {
|
||||||
tokens.push_back({.type = TokenType::ident, .value = buffer});
|
tokens.push_back({.type = TokenType::ident, .value = buffer});
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
@ -75,41 +83,32 @@ public:
|
|||||||
}
|
}
|
||||||
tokens.push_back({.type = TokenType::int_lit, .value = buffer});
|
tokens.push_back({.type = TokenType::int_lit, .value = buffer});
|
||||||
buffer.clear();
|
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())) {
|
} else if (std::isspace(peek().value())) {
|
||||||
consume();
|
consume();
|
||||||
} else {
|
} else {
|
||||||
err::unknowntype(buffer);
|
char c = peek().has_value() ? *peek() : -1;
|
||||||
exit(EXIT_FAILURE);
|
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
|
// Return mah shit
|
||||||
@ -130,6 +129,10 @@ private:
|
|||||||
return m_src.at(m_index++);
|
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;
|
const std::string m_src;
|
||||||
size_t m_index = 0;
|
size_t m_index = 0;
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user