From 5cd0ea92060b9eabd95b6d5ac8bf30455844c16d Mon Sep 17 00:00:00 2001 From: Xircon Date: Thu, 30 Jul 2026 13:41:20 -0400 Subject: [PATCH] parsing my tree frfr --- src/generation.hxx | 24 +++++++++++++++ src/main.cxx | 33 ++++++++------------ src/parser.hxx | 71 ++++++++++++++++++++++++++++++++++++++++++++ src/tokenization.hxx | 20 ++++++------- 4 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 src/generation.hxx create mode 100644 src/parser.hxx diff --git a/src/generation.hxx b/src/generation.hxx new file mode 100644 index 0000000..49f6724 --- /dev/null +++ b/src/generation.hxx @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include "parser.hxx" + +class Generator { +public: + inline explicit Generator(node::Exit root) : m_root(std::move(root)) { + // Erm!!! + } + + [[nodiscard]] inline std::string generate() const { + std::stringstream output; + output << "global _start\n_start:\n"; + output << " mov rax, 60\n"; + output << " mov rdi, " << m_root.expr.int_lit.value.value() << "\n"; + output << " syscall\n"; + return output.str(); + } +private: + const node::Exit m_root; +}; \ No newline at end of file diff --git a/src/main.cxx b/src/main.cxx index cf011cb..89c2169 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -4,27 +4,10 @@ #include #include +#include "parser.hxx" +#include "generation.hxx" #include "tokenization.hxx" -std::string tokens_to_asm(std::vector& tokens) { - std::stringstream output; - output << "global _start\n_start:\n"; - for (int i = 0; i < tokens.size(); i++) { - const Token& token = tokens.at(i); - if (token.type == TokenType::exit) { - if (i + 1 < tokens.size() && tokens.at(i + 1).type == TokenType::int_lit) { - if (i + 2 < tokens.size() && tokens.at(i + 2).type == TokenType::semi) { - output << " mov rax, 60\n"; - output << " mov rdi, " << tokens.at(i + 1).value.value() << "\n"; - output << " syscall\n"; - } - } - } - } - - return output.str(); -} - int main(int argc, char* argv[]) { if (argc != 2) { std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mno input files\033[0m" << std::endl; // yes i spent 10 minutes to emulate clangs output... @@ -42,9 +25,19 @@ int main(int argc, char* argv[]) { Tokenizer tokenizer(std::move(contents)); std::vector tokens = tokenizer.tokenize(); + Parser parser(std::move(tokens)); + std::optional tree = parser.parse(); + + if (!tree.has_value()) { + std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37mparse tree has no value, possibly empty file?\033[0m" << std::endl; + exit(EXIT_FAILURE); + } + + Generator generator(tree.value()); + { std::fstream output("out.asm", std::ios::out); - output << tokens_to_asm(tokens); + output << generator.generate(); } system("nasm -felf64 out.asm"); diff --git a/src/parser.hxx b/src/parser.hxx new file mode 100644 index 0000000..8a94430 --- /dev/null +++ b/src/parser.hxx @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#include "tokenization.hxx" + +namespace node { + struct Expr { + Token int_lit; + }; + + struct Exit { + Expr expr; + }; +} + +class Parser { +public: + inline explicit Parser(std::vector tokens) : m_tokens(std::move(tokens)) { + // Erm! + } + + std::optional parse_expr() { + if(peek().has_value() && peek().value().type == TokenType::int_lit) { + return node::Expr{.int_lit = consume()}; + } else { + return {}; + } + } + + std::optional parse() { + std::optional exit_node; + while(peek().has_value()) { + if (peek().value().type == TokenType::exit) { + consume(); + if (auto node_expr = parse_expr()) { + exit_node = node::Exit {.expr = node_expr.value()}; + } else { + std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37minvalid expression\033[0m" << std::endl; + exit(EXIT_FAILURE); + } + + if (peek().has_value() && peek().value().type == TokenType::semi) { + consume(); + } else { + std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37minvalid syntax\033[0m" << std::endl; + exit(EXIT_FAILURE); + } + } + } + m_index = 0; + return exit_node; + } + +private: + [[nodiscard]] inline std::optional peek(int ahead = 1) const { + if (m_index + ahead > m_tokens.size()) { + return {}; + } else { + return m_tokens.at(m_index); + } + } + + inline Token consume() { + return m_tokens.at(m_index++); + } + + const std::vector m_tokens; + size_t m_index = 0; +}; \ No newline at end of file diff --git a/src/tokenization.hxx b/src/tokenization.hxx index 50c7a77..c62929a 100644 --- a/src/tokenization.hxx +++ b/src/tokenization.hxx @@ -27,10 +27,10 @@ public: std::vector tokens; std::string buffer; - while (peak().has_value()) { - if (std::isalpha(peak().value())) { + while (peek().has_value()) { + if (std::isalpha(peek().value())) { buffer.push_back(consume()); - while (peak().has_value() && std::isalnum(peak().value())) { + while (peek().has_value() && std::isalnum(peek().value())) { buffer.push_back(consume()); } if (buffer == "exit") { @@ -41,19 +41,19 @@ public: std::cerr << "xlang: \033[1;31merror:\033[0m \033[1;37munknown type name \'" << buffer << "\'\033[0m" << std::endl; exit(EXIT_FAILURE); } - } else if (std::isdigit(peak().value())) { + } else if (std::isdigit(peek().value())) { buffer.push_back(consume()); - while (peak().has_value() && std::isdigit(peak().value())) { + while (peek().has_value() && std::isdigit(peek().value())) { buffer.push_back(consume()); } tokens.push_back({.type = TokenType::int_lit, .value = buffer}); buffer.clear(); continue; - } else if (peak().value() == ';') { + } else if (peek().value() == ';') { consume(); tokens.push_back({.type = TokenType::semi}); continue; - } else if (std::isspace(peak().value())) { + } else if (std::isspace(peek().value())) { consume(); continue; } else { @@ -67,7 +67,7 @@ public: } private: - [[nodiscard]] std::optional peak(int ahead = 1) const { + [[nodiscard]] inline std::optional peek(int ahead = 1) const { if (m_index + ahead > m_src.length()) { return {}; } else { @@ -75,10 +75,10 @@ private: } } - char consume() { + inline char consume() { return m_src.at(m_index++); } const std::string m_src; - int m_index = 0; + size_t m_index = 0; }; \ No newline at end of file