Files
highground-fork/src/main.cpp

326 lines
11 KiB
C++
Raw Normal View History

2025-12-14 14:21:19 +11:00
#include <cctype>
#include <cstdint>
2025-12-13 18:07:26 +11:00
#include <groundvm.h>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <optional>
2025-12-14 14:21:19 +11:00
#include <variant>
2025-12-13 18:07:26 +11:00
namespace HighGround {
2025-12-14 14:21:19 +11:00
int tmpIdIterator = 0;
2025-12-13 18:07:26 +11:00
namespace Parser {
enum class HGNodeType {
2025-12-14 14:21:19 +11:00
Add, Subtract, Equal, Set, While, If, Value, Identifier, None, Root, CodeBlock
};
enum class HGDataType {
Int, String, Double, Bool, Char, None
2025-12-13 18:07:26 +11:00
};
class HGNode;
2025-12-14 14:21:19 +11:00
class HGGroundCodeBlock {
public:
std::vector<GroundInstruction> code;
HGGroundCodeBlock() = default;
};
class HGData {
std::variant<int64_t, std::string, double, bool, char> data;
public:
HGDataType type = HGDataType::Int;
HGData() = default;
HGData(int64_t in) : data(in) {}
std::optional<int64_t> getInt() {
if (type == HGDataType::Int) {
return std::get<int64_t>(data);
} else {
return {};
}
}
};
2025-12-13 18:07:26 +11:00
class HGNode {
HGNodeType nodeType = HGNodeType::None;
2025-12-14 14:21:19 +11:00
HGData data;
2025-12-13 18:07:26 +11:00
std::vector<HGNode> children;
public:
2025-12-14 14:21:19 +11:00
std::string outputId;
2025-12-13 18:07:26 +11:00
HGNode(HGNodeType nodeType) : nodeType(nodeType) {}
2025-12-14 14:21:19 +11:00
HGNode(HGNodeType nodeType, HGData data) : nodeType(nodeType), data(data) {}
2025-12-13 18:07:26 +11:00
HGNode() = default;
void addNode(HGNode in) {
children.push_back(in);
}
2025-12-14 14:21:19 +11:00
void setValue(HGData in) {
data = in;
}
const std::vector<HGGroundCodeBlock> generateCode() {
std::vector<HGGroundCodeBlock> 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";
}
}
2025-12-13 18:07:26 +11:00
return code;
}
2025-12-14 14:21:19 +11:00
2025-12-13 18:07:26 +11:00
};
2025-12-14 14:21:19 +11:00
class Parser {
std::vector<std::string> tokensToParse;
size_t current;
size_t size;
std::optional<std::string> peek(int ahead = 1) {
if (current + ahead < size) {
return tokensToParse[current + ahead];
} else {
return {};
}
}
std::optional<std::string> 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<std::string> 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;
}
2025-12-13 18:07:26 +11:00
} // namespace Parser
class Lexer {
std::string input;
size_t size;
size_t current;
std::optional<char> peek(int ahead = 1) {
if (current + ahead < size) {
return input[current + ahead];
} else {
return {};
}
}
std::optional<char> consume() {
if (current < size) {
return input[current++];
} else {
return {};
}
}
public:
Lexer(std::string in) : input(in), size(in.size()) {};
std::vector<std::string> lex() {
current = 0;
std::vector<std::string> 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();
2025-12-14 14:21:19 +11:00
auto parsed = HighGround::Parser::Parser(lexed).parse();
GroundProgram program = HighGround::Parser::assembleProgram(parsed);
groundRunProgram(&program);
2025-12-13 18:07:26 +11:00
}