From f1b156ce4d9b084680c20db93f8c0a22f85d91f3 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 13 Dec 2025 18:07:26 +1100 Subject: [PATCH] Initial commit --- .gitignore | 1 + src/main.cpp | 162 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/print.hg | 1 + 3 files changed, 164 insertions(+) create mode 100644 .gitignore create mode 100644 src/main.cpp create mode 100644 tests/print.hg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbb0de2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +hg diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..40e54ca --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace HighGround { + + namespace Parser { + + enum class HGNodeType { + Add, Subtract, Equal, Set, While, If, None, Root, CodeBlock + }; + + class HGNode; + + class HGNode { + HGNodeType nodeType = HGNodeType::None; + std::vector children; + public: + HGNode(HGNodeType nodeType) : nodeType(nodeType) {} + HGNode() = default; + void addNode(HGNode in) { + children.push_back(in); + } + std::vector generateCode() { + std::vector code; + return code; + } + }; + + } // namespace Parser + + class Lexer { + std::string input; + size_t size; + size_t current; + + std::optional peek(int ahead = 1) { + if (current + ahead < size) { + return input[current + ahead]; + } else { + return {}; + } + } + + std::optional consume() { + if (current < size) { + return input[current++]; + } else { + return {}; + } + } + + public: + Lexer(std::string in) : input(in), size(in.size()) {}; + std::vector lex() { + current = 0; + std::vector tokens; + std::string buf; + while (auto copt = consume()) { + char c = copt.value(); + switch (c) { + // tokens which are not followed by anything + case '(': + case ')': + case '{': + case '}': + { + if (!buf.empty()) { + tokens.push_back(buf); + buf.clear(); + } + tokens.push_back(std::string(1, c)); + break; + } + // tokens which may be followed by either themselves + // or an equals sign + case '+': + case '-': + { + std::string newToken(1, c); + auto tokenopt = peek(); + if (tokenopt) { + char token = tokenopt.value(); + if (token == c || token == '=') { + newToken += token; + consume(); + } + } + if (!buf.empty()) { + tokens.push_back(buf); + buf.clear(); + } + tokens.push_back(newToken); + break; + } + // tokens which may be followed by an equals sign + case '*': + case '/': + case '=': + { + std::string newToken(1, c); + auto tokenopt = peek(); + if (tokenopt) { + char token = tokenopt.value(); + if (token == '=') { + newToken += token; + consume(); + } + } + if (!buf.empty()) { + tokens.push_back(buf); + buf.clear(); + } + tokens.push_back(newToken); + break; + } + // tokens which do not need to be included + case ' ': + case '\n': + { + if (!buf.empty()) { + tokens.push_back(buf); + buf.clear(); + } + break; + } + default: + { + buf += c; + } + } + } + + if (!buf.empty()) { + tokens.push_back(buf); + } + return tokens; + } + + }; + + +} // namespace HighGround + + +int main(int argc, char** argv) { + if (argc < 2) { + std::cout << "Usage: " << argv[0] << " (file)\n"; + exit(1); + } + std::ifstream file(argv[1]); + std::ostringstream ss; + ss << file.rdbuf(); + auto lexed = HighGround::Lexer(ss.str()).lex(); + for (const std::string& str : lexed) { + std::cout << str << "\n"; + } +} diff --git a/tests/print.hg b/tests/print.hg new file mode 100644 index 0000000..8900c63 --- /dev/null +++ b/tests/print.hg @@ -0,0 +1 @@ +println("dingus")