#include #include #include #include #include #include #include #include #include #include namespace HighGround { int tmpIdIterator = 0; namespace Parser { enum class HGNodeType { Add, Subtract, Equal, Set, While, If, Value, Identifier, None, Root, CodeBlock }; enum class HGDataType { Int, String, Double, Bool, Char, None }; class HGNode; class HGGroundCodeBlock { public: std::vector code; HGGroundCodeBlock() = default; }; class HGData { std::variant data; public: HGDataType type = HGDataType::Int; HGData() = default; HGData(int64_t in) : data(in) {} std::optional getInt() { if (type == HGDataType::Int) { return std::get(data); } else { return {}; } } }; class HGNode { HGNodeType nodeType = HGNodeType::None; HGData data; std::vector children; public: std::string outputId; HGNode(HGNodeType nodeType) : nodeType(nodeType) {} HGNode(HGNodeType nodeType, HGData data) : nodeType(nodeType), data(data) {} HGNode() = default; void addNode(HGNode in) { children.push_back(in); } void setValue(HGData in) { data = in; } const std::vector generateCode() { std::vector code; for (auto& child : children) { auto childCode = child.generateCode(); code.insert(code.end(), childCode.begin(), childCode.end()); } switch (nodeType) { case HGNodeType::Value: { outputId = "tmp_" + std::to_string(tmpIdIterator++); HGGroundCodeBlock codeBlock; GroundInstruction gi = groundCreateInstruction(SET); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data())); switch (data.type) { case HGDataType::Int: { auto dataopt = data.getInt(); if (dataopt) { groundAddValueToInstruction(&gi, groundCreateValue(INT, dataopt.value())); } } } codeBlock.code.push_back(gi); code.push_back(codeBlock); break; } default: { std::cout << "Not implemented yet\n"; } } return code; } }; class Parser { std::vector tokensToParse; size_t current; size_t size; std::optional peek(int ahead = 1) { if (current + ahead < size) { return tokensToParse[current + ahead]; } else { return {}; } } std::optional consume() { if (current < size) { return tokensToParse[current++]; } else { return {}; } } bool isInt(std::string in) { for (const char& c : in) { if (!std::isdigit(c)) { return false; } } return true; } bool isDouble(std::string in) { bool foundDot = false; for (const char& c : in) { if (!std::isdigit(c)) { if (!foundDot && c == '.') { foundDot = true; continue; } return false; } } return true; } HGDataType getDataType(std::string in) { if (isInt(in)) { return HGDataType::Int; } if (isDouble(in)) { return HGDataType::Double; } return HGDataType::None; } HGNodeType getNodeType(std::string in) { if (getDataType(in) != HGDataType::None) { return HGNodeType::Value; } return HGNodeType::None; } public: Parser(std::vector in) : tokensToParse(in) {} HGNode parse() { current = 0; size = tokensToParse.size(); HGNode rootNode(HGNodeType::Root); while (auto tokenopt = consume()) { std::string token = tokenopt.value(); switch (getNodeType(token)) { case HGNodeType::Value: { switch (getDataType(token)) { case HGDataType::Int: { std::cout << "We have an int\n"; HGNode intNode(HGNodeType::Value); intNode.setValue(std::stoll(token)); rootNode.addNode(intNode); break; } } break; } } } return rootNode; } }; GroundProgram assembleProgram(HGNode& rootNode) { GroundProgram gp = groundCreateProgram(); auto code = rootNode.generateCode(); for (int i = 0; i < code.size(); i++) { for (const auto& inst : code[i].code) { groundAddInstructionToProgram(&gp, inst); } } groundAddInstructionToProgram(&gp, groundCreateInstruction(PAUSE)); return gp; } } // 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(); auto parsed = HighGround::Parser::Parser(lexed).parse(); GroundProgram program = HighGround::Parser::assembleProgram(parsed); groundRunProgram(&program); }