This commit is contained in:
Xircon 2026-08-01 17:08:50 -04:00
parent 34b8d1ed39
commit ce81cb7f28
6 changed files with 172 additions and 55 deletions

View File

@ -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\\

View File

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

View File

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

View File

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

View File

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

View File

@ -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,42 +83,33 @@ 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
m_index = 0; m_index = 0;
@ -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;
}; };