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.
|
||||
$$
|
||||
\begin{align}
|
||||
[\text{prog}] &\to [\text{stmt}]^* \\
|
||||
[\text{stmt}]^* &\to
|
||||
[\text{Prog}] &\to [\text{Stmt}]^* \\
|
||||
[\text{Stmt}]^* &\to
|
||||
\begin{cases}
|
||||
\text{exit}([\text{expr}]); \\
|
||||
\text{var}\space\text{ident} = [\text{expr}]; \\
|
||||
\text{exit}([\text{Expr}]); \\
|
||||
\text{var}\space\text{ident} = [\text{Expr}]; \\
|
||||
\text{if}\ ([\text{Expr}])\ [\text{Scope}] \\
|
||||
[\text{Scope}] \\
|
||||
\end{cases} \\
|
||||
[\text{expr}] &\to
|
||||
[\text{Expr}] &\to
|
||||
\begin{cases}
|
||||
\text{[Term]}
|
||||
\text{[Term]} \\
|
||||
\text{[BinExpr]} \\
|
||||
\end{cases} \\
|
||||
[\text{BinExpr}]
|
||||
[\text{Scope}] &\to \{[\text{Stmt}]^*\} \\
|
||||
[\text{BinExpr}] &\to
|
||||
\begin{cases}
|
||||
[\text[{Expr}]!] &prec=3\\
|
||||
[\text[{Expr}] ^ \text{[Expr]}] &prec=2\\
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
var x = 1 + 2 * 3;
|
||||
{
|
||||
var z = 2;
|
||||
var y = 2;
|
||||
}
|
||||
var y = x - 3;
|
||||
var z = (3*5) / 3;
|
||||
exit(y + z);
|
||||
if (x) {
|
||||
exit(y + z);
|
||||
}
|
||||
exit (1);
|
||||
@ -4,6 +4,7 @@
|
||||
#include <optional>
|
||||
|
||||
namespace err {
|
||||
// Compiler Errors
|
||||
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;
|
||||
}
|
||||
@ -40,6 +41,12 @@ namespace err {
|
||||
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() {
|
||||
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() {
|
||||
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 <vector>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
#include "parser.hxx"
|
||||
|
||||
@ -13,6 +12,14 @@ public:
|
||||
// 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) {
|
||||
struct StmtVisitor { // Visiting the homies
|
||||
Generator* gen;
|
||||
@ -24,13 +31,28 @@ public:
|
||||
}
|
||||
|
||||
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());
|
||||
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);
|
||||
}
|
||||
|
||||
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};
|
||||
@ -47,13 +69,13 @@ public:
|
||||
}
|
||||
|
||||
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());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
const auto& var = gen->m_vars.at(term_ident->ident.value.value());
|
||||
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());
|
||||
}
|
||||
void operator()(const node::TermParen* term_paren) const {
|
||||
@ -139,6 +161,26 @@ public:
|
||||
}
|
||||
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) {
|
||||
m_output << " push " << reg << "\n";
|
||||
m_stack_size++;
|
||||
@ -150,11 +192,14 @@ private:
|
||||
}
|
||||
|
||||
struct Var {
|
||||
std::string name;
|
||||
size_t stack_loc;
|
||||
};
|
||||
|
||||
const node::Prog m_prog;
|
||||
std::stringstream m_output;
|
||||
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 {
|
||||
struct Expr;
|
||||
struct Stmt;
|
||||
|
||||
struct TermIntLit {
|
||||
Token int_lit;
|
||||
@ -55,6 +56,10 @@ namespace node {
|
||||
std::variant<Term*, BinExpr*> var;
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
std::vector<Stmt*> stmts;
|
||||
};
|
||||
|
||||
struct StmtExit {
|
||||
Expr* expr;
|
||||
};
|
||||
@ -64,8 +69,13 @@ namespace node {
|
||||
Expr* expr;
|
||||
};
|
||||
|
||||
struct StmtIf {
|
||||
Expr* expr;
|
||||
Scope* scope;
|
||||
};
|
||||
|
||||
struct Stmt {
|
||||
std::variant<StmtExit*, StmtVar*> var;
|
||||
std::variant<StmtExit*, StmtVar*, StmtIf*, Scope*> var;
|
||||
};
|
||||
|
||||
struct Prog {
|
||||
@ -163,7 +173,7 @@ public:
|
||||
sub->lhs = expr_lhs2;
|
||||
sub->rhs = expr_rhs.value();
|
||||
expr->var = sub;
|
||||
} else if (op.type == TokenType::slash) {
|
||||
} else if (op.type == TokenType::fslash) {
|
||||
auto div = m_allocator.alloc<node::BinExprDiv>();
|
||||
expr_lhs->var = term_lhs.value();
|
||||
expr_lhs2->var = expr_lhs->var;
|
||||
@ -179,6 +189,18 @@ public:
|
||||
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() {
|
||||
if (peek().has_value() && peek().value().type == TokenType::exit && peek(1).has_value() && peek(1).value().type == TokenType::open_paren) {
|
||||
consume();
|
||||
@ -187,7 +209,7 @@ public:
|
||||
if (auto node_expr = parse_expr()) {
|
||||
stmt_exit->expr = node_expr.value();
|
||||
} else {
|
||||
err::expression({});
|
||||
err::expression("exit");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -214,6 +236,34 @@ public:
|
||||
auto stmt = m_allocator.alloc<node::Stmt>();
|
||||
stmt->var = stmt_var;
|
||||
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 {
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <sstream>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "error.hxx"
|
||||
|
||||
@ -19,16 +20,21 @@ enum class TokenType {
|
||||
equals,
|
||||
plus,
|
||||
star,
|
||||
slash,
|
||||
fslash,
|
||||
minus,
|
||||
carrot,
|
||||
excl,
|
||||
open_curly,
|
||||
close_curly,
|
||||
open_bracket,
|
||||
close_bracket,
|
||||
if_,
|
||||
};
|
||||
|
||||
std::optional<int> bin_prec(TokenType type) {
|
||||
switch (type) {
|
||||
case TokenType::star:
|
||||
case TokenType::slash:
|
||||
case TokenType::fslash:
|
||||
return 1;
|
||||
case TokenType::plus:
|
||||
case TokenType::minus:
|
||||
@ -51,7 +57,6 @@ public:
|
||||
inline std::vector<Token> tokenize() {
|
||||
std::vector<Token> tokens;
|
||||
std::string buffer;
|
||||
|
||||
while (peek().has_value()) {
|
||||
if (std::isalpha(peek().value())) {
|
||||
buffer.push_back(consume());
|
||||
@ -64,6 +69,9 @@ public:
|
||||
} else if (buffer == "var") {
|
||||
tokens.push_back({.type = TokenType::var});
|
||||
buffer.clear();
|
||||
} else if (buffer == "if") {
|
||||
tokens.push_back({.type = TokenType::if_});
|
||||
buffer.clear();
|
||||
} else {
|
||||
tokens.push_back({.type = TokenType::ident, .value = buffer});
|
||||
buffer.clear();
|
||||
@ -75,42 +83,33 @@ public:
|
||||
}
|
||||
tokens.push_back({.type = TokenType::int_lit, .value = buffer});
|
||||
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())) {
|
||||
consume();
|
||||
} else {
|
||||
char c = peek().has_value() ? *peek() : -1;
|
||||
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
|
||||
m_index = 0;
|
||||
@ -130,6 +129,10 @@ private:
|
||||
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;
|
||||
size_t m_index = 0;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user