Files
highground-fork/src/parser.cpp

899 lines
47 KiB
C++
Raw Normal View History

2025-12-21 12:06:55 +11:00
#include "parser.h"
2025-12-22 13:49:44 +11:00
#include <groundvm.h>
2025-12-21 12:06:55 +11:00
#include <iostream>
#include <cstring>
#include <algorithm>
#define parseOneToken(token) Parser({token.value()}).parse().children[0]
namespace Solstice {
namespace Parser {
2025-12-22 19:38:06 +11:00
bool isTemp(std::string id) {
return id.rfind("tmp_", 0) == 0;
}
2025-12-21 12:06:55 +11:00
// SolData Implementation
SolData::SolData(int64_t in) : data(in), type(SolDataType::Int) {}
SolData::SolData(double in) : data(in), type(SolDataType::Double) {}
SolData::SolData(std::string in) : data(in), type(SolDataType::String) {}
SolData::SolData(char in) : data(in), type(SolDataType::Char) {}
SolData::SolData(bool in) : data(in), type(SolDataType::Bool) {}
std::optional<int64_t> SolData::getInt() {
if (type == SolDataType::Int) {
return std::get<int64_t>(data);
} else {
return {};
}
}
std::optional<double> SolData::getDouble() {
if (type == SolDataType::Double) {
return std::get<double>(data);
} else {
return {};
}
}
std::optional<std::string> SolData::getString() {
if (type == SolDataType::String) {
return std::get<std::string>(data);
} else {
return {};
}
}
std::optional<char> SolData::getChar() {
if (type == SolDataType::Char) {
return std::get<char>(data);
} else {
return {};
}
}
std::optional<bool> SolData::getBool() {
if (type == SolDataType::Bool) {
return std::get<bool>(data);
} else {
return {};
}
}
// SolNode Implementation
SolNode::SolNode(SolNodeType nodeType) : nodeType(nodeType) {}
SolNode::SolNode(SolNodeType nodeType, SolData data) : data(data), nodeType(nodeType) {}
void SolNode::addNode(SolNode in) {
children.push_back(in);
}
void SolNode::setValue(SolData in) {
data = in;
}
const std::vector<SolGroundCodeBlock> SolNode::generateCode() {
std::vector<SolGroundCodeBlock> code;
if (nodeType != SolNodeType::If && nodeType != SolNodeType::While) for (auto& child : children) {
auto childCode = child.generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
}
switch (nodeType) {
case SolNodeType::Value: {
outputId = "tmp_" + std::to_string(tmpIdIterator++);
SolGroundCodeBlock codeBlock;
GroundInstruction gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
switch (data.type) {
case SolDataType::Int: {
auto dataopt = data.getInt();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(INT, dataopt.value()));
}
break;
}
case SolDataType::Double: {
auto dataopt = data.getDouble();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(DOUBLE, dataopt.value()));
}
break;
}
case SolDataType::String: {
auto dataopt = data.getString();
if (dataopt) {
2025-12-22 19:38:06 +11:00
char* str = (char*) malloc(dataopt.value().size() + 1);
strcpy(str, dataopt.value().c_str());
groundAddValueToInstruction(&gi, groundCreateValue(STRING, str));
2025-12-21 12:06:55 +11:00
}
break;
}
case SolDataType::Char: {
auto dataopt = data.getChar();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(CHAR, dataopt.value()));
}
break;
}
case SolDataType::Bool: {
auto dataopt = data.getBool();
if (dataopt) {
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, dataopt.value()));
}
break;
}
}
codeBlock.code.push_back(gi);
code.push_back(codeBlock);
break;
}
case SolNodeType::Add: {
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(ADD);
if (children.size() < 2) {
std::cout << "Need more stuff to add\n";
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::Equal: {
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(EQUAL);
if (children.size() < 2) {
std::cout << "Need more stuff to equal\n";
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::Inequal: {
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(INEQUAL);
if (children.size() < 2) {
std::cout << "Need more stuff to inequal\n";
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
2025-12-22 13:49:44 +11:00
case SolNodeType::Greater: {
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(GREATER);
if (children.size() < 2) {
std::cout << "Need more stuff to greater\n";
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::Lesser: {
SolGroundCodeBlock codeBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
GroundInstruction gi = groundCreateInstruction(LESSER);
if (children.size() < 2) {
std::cout << "Need more stuff to lesser\n";
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::EqGreater: {
SolGroundCodeBlock codeBlock;
if (children.size() < 2) {
std::cout << "Need more stuff to inequal\n";
}
outputId = "tmp_" + std::to_string(tmpIdIterator++);
std::string trueLabelIdString = "internal_true" + std::to_string(labelIterator++);
std::string falseLabelIdString = "internal_false" + std::to_string(labelIterator);
std::string endLabelIdString = "internal_end" + std::to_string(labelIterator);
char* trueLabelId = (char*) malloc(sizeof(char) * (trueLabelIdString.size() + 1));
strcpy(trueLabelId, trueLabelIdString.data());
char* falseLabelId = (char*) malloc(sizeof(char) * (falseLabelIdString.size() + 1));
strcpy(falseLabelId, falseLabelIdString.data());
char* endLabelId = (char*) malloc(sizeof(char) * (endLabelIdString.size() + 1));
strcpy(endLabelId, endLabelIdString.data());
// greater $tmp_0 $tmp_1 &cond
GroundInstruction gi = groundCreateInstruction(GREATER);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond0"));
codeBlock.code.push_back(gi);
// if &cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond0"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// equal $tmp_0 $tmp_1 &cond
gi = groundCreateInstruction(EQUAL);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond1"));
codeBlock.code.push_back(gi);
// if $cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond1"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// jump %false
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, falseLabelId));
codeBlock.code.push_back(gi);
// @true
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, trueLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x true
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, true));
codeBlock.code.push_back(gi);
// jump %end
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, endLabelId));
codeBlock.code.push_back(gi);
// @false
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, falseLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x false
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false));
codeBlock.code.push_back(gi);
// @end
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::EqLesser: {
SolGroundCodeBlock codeBlock;
if (children.size() < 2) {
std::cout << "Need more stuff to inequal\n";
}
outputId = "tmp_" + std::to_string(tmpIdIterator++);
std::string trueLabelIdString = "internal_true" + std::to_string(labelIterator++);
std::string falseLabelIdString = "internal_false" + std::to_string(labelIterator);
std::string endLabelIdString = "internal_end" + std::to_string(labelIterator);
char* trueLabelId = (char*) malloc(sizeof(char) * (trueLabelIdString.size() + 1));
strcpy(trueLabelId, trueLabelIdString.data());
char* falseLabelId = (char*) malloc(sizeof(char) * (falseLabelIdString.size() + 1));
strcpy(falseLabelId, falseLabelIdString.data());
char* endLabelId = (char*) malloc(sizeof(char) * (endLabelIdString.size() + 1));
strcpy(endLabelId, endLabelIdString.data());
// lesser $tmp_0 $tmp_1 &cond
GroundInstruction gi = groundCreateInstruction(LESSER);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond0"));
codeBlock.code.push_back(gi);
// if &cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond0"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// equal $tmp_0 $tmp_1 &cond
gi = groundCreateInstruction(EQUAL);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[1].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, (char*) "internal_cond1"));
codeBlock.code.push_back(gi);
// if $cond %true
gi = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, (char*) "internal_cond1"));
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, trueLabelId));
codeBlock.code.push_back(gi);
// jump %false
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, falseLabelId));
codeBlock.code.push_back(gi);
// @true
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, trueLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x true
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, true));
codeBlock.code.push_back(gi);
// jump %end
gi = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi, groundCreateReference(LINEREF, endLabelId));
codeBlock.code.push_back(gi);
// @false
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, falseLabelId));
codeBlock.code.push_back(gi);
// set &tmp_x false
gi = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false));
codeBlock.code.push_back(gi);
// @end
gi = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-22 13:49:44 +11:00
code.push_back(codeBlock);
break;
}
2025-12-21 12:06:55 +11:00
case SolNodeType::Puts: {
SolGroundCodeBlock codeBlock;
GroundInstruction gi = groundCreateInstruction(PRINTLN);
if (children.size() < 1) {
std::cout << "Need more stuff to puts\n";
}
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
codeBlock.code.push_back(gi);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::If: {
auto conditionCode = children[0].generateCode();
code.insert(code.end(), conditionCode.begin(), conditionCode.end());
outputId = "tmp_" + std::to_string(tmpIdIterator++);
SolGroundCodeBlock codeBlock;
codeBlock.toBeDropped.push_back(outputId);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction(NOT);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
codeBlock.code.push_back(gi);
std::string labelIdString = "if_" + std::to_string(labelIterator++);
char* labelId = (char*) malloc(sizeof(char) * labelIdString.size() + 1);
strcpy(labelId, labelIdString.data());
GroundInstruction gi2 = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi2, groundCreateReference(VALREF, outputId.data()));
groundAddReferenceToInstruction(&gi2, groundCreateReference(LINEREF, labelId));
codeBlock.code.push_back(gi2);
code.push_back(codeBlock);
for (size_t i = 1; i < children.size(); i++) {
auto childCode = children[i].generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
}
codeBlock.code.clear();
2025-12-22 19:38:06 +11:00
codeBlock.toBeDropped.clear();
2025-12-21 12:06:55 +11:00
GroundInstruction gi3 = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi3, groundCreateReference(LABEL, labelId));
codeBlock.code.push_back(gi3);
code.push_back(codeBlock);
break;
}
case SolNodeType::While: {
SolGroundCodeBlock startLabelBlock;
std::string startLabelIdString = "whilestart_" + std::to_string(labelIterator++);
std::string endLabelIdString = "whileend_" + std::to_string(labelIterator);
char* startLabelId = (char*) malloc(sizeof(char) * (startLabelIdString.size() + 1));
strcpy(startLabelId, startLabelIdString.data());
char* endLabelId = (char*) malloc(sizeof(char) * (endLabelIdString.size() + 1));
strcpy(endLabelId, endLabelIdString.data());
GroundInstruction startLabel = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&startLabel, groundCreateReference(LABEL, startLabelId));
startLabelBlock.code.push_back(startLabel);
code.push_back(startLabelBlock);
auto conditionCode = children[0].generateCode();
code.insert(code.end(), conditionCode.begin(), conditionCode.end());
SolGroundCodeBlock checkBlock;
outputId = "tmp_" + std::to_string(tmpIdIterator++);
checkBlock.toBeDropped.push_back(outputId);
2025-12-22 19:38:06 +11:00
if (isTemp(children[0].outputId)) checkBlock.toBeDropped.push_back(children[0].outputId);
2025-12-21 12:06:55 +11:00
GroundInstruction gi = groundCreateInstruction(NOT);
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, outputId.data()));
checkBlock.code.push_back(gi);
GroundInstruction gi2 = groundCreateInstruction(IF);
groundAddReferenceToInstruction(&gi2, groundCreateReference(VALREF, outputId.data()));
groundAddReferenceToInstruction(&gi2, groundCreateReference(LINEREF, endLabelId));
checkBlock.code.push_back(gi2);
code.push_back(checkBlock);
for (size_t i = 1; i < children.size(); i++) {
auto childCode = children[i].generateCode();
code.insert(code.end(), childCode.begin(), childCode.end());
}
SolGroundCodeBlock endBlock;
GroundInstruction gi3 = groundCreateInstruction(JUMP);
groundAddReferenceToInstruction(&gi3, groundCreateReference(LINEREF, startLabelId));
endBlock.code.push_back(gi3);
GroundInstruction gi4 = groundCreateInstruction(CREATELABEL);
groundAddReferenceToInstruction(&gi4, groundCreateReference(LABEL, endLabelId));
endBlock.code.push_back(gi4);
code.push_back(endBlock);
break;
}
case SolNodeType::Identifier: {
break;
}
case SolNodeType::Set: {
SolGroundCodeBlock codeBlock;
GroundInstruction setInstruction = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(DIRREF, children[0].outputId.data()));
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(VALREF, children[1].outputId.data()));
codeBlock.code.push_back(setInstruction);
2025-12-22 19:38:06 +11:00
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
code.push_back(codeBlock);
break;
}
case SolNodeType::FunctionCall: {
// Take care of in built functions
if (children[0].outputId == "input") {
SolGroundCodeBlock inputCodeBlock;
if (children.size() > 1) {
GroundInstruction printInstruction = groundCreateInstruction(PRINT);
groundAddReferenceToInstruction(&printInstruction, groundCreateReference(VALREF, children[1].outputId.data()));
inputCodeBlock.code.push_back(printInstruction);
2025-12-22 19:38:06 +11:00
if (isTemp(children[1].outputId)) inputCodeBlock.toBeDropped.push_back(children[1].outputId);
2025-12-21 12:06:55 +11:00
}
GroundInstruction inputInstruction = groundCreateInstruction(INPUT);
outputId = "tmp_" + std::to_string(tmpIdIterator++);
groundAddReferenceToInstruction(&inputInstruction, groundCreateReference(DIRREF, outputId.data()));
inputCodeBlock.code.push_back(inputInstruction);
code.push_back(inputCodeBlock);
break;
}
break;
}
default: {}
}
return code;
}
// Parser Implementation
Parser::Parser(std::vector<std::string> in) : tokensToParse(in) {}
std::optional<std::string> Parser::peek(int ahead) {
if (current + ahead < size) {
return tokensToParse[current + ahead];
} else {
return {};
}
}
std::optional<std::string> Parser::consume() {
if (current < size) {
return tokensToParse[current++];
} else {
return {};
}
}
// Helper functions
bool Parser::isInt(std::string in) {
for (const char& c : in) {
if (!std::isdigit(c)) {
return false;
}
}
return true;
}
bool Parser::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;
}
bool Parser::isString(std::string in) {
if (in.size() > 1 && in[0] == '"' && in.back() == '"') {
return true;
}
return false;
}
bool Parser::isChar(std::string in) {
if (in.size() == 3 && in[0] == '\'' && in.back() == '\'') {
return true;
}
return false;
}
bool Parser::isBool(std::string in) {
if (in == "true" || in == "false") {
return true;
}
return false;
}
SolDataType Parser::getDataType(std::string in) {
if (isInt(in)) {
return SolDataType::Int;
}
if (isDouble(in)) {
return SolDataType::Double;
}
if (isString(in)) {
return SolDataType::String;
}
if (isChar(in)) {
return SolDataType::Char;
}
if (isBool(in)) {
return SolDataType::Bool;
}
return SolDataType::None;
}
SolNodeType Parser::getNodeType(std::string in) {
if (getDataType(in) != SolDataType::None) {
return SolNodeType::Value;
}
if (in == "+") {
return SolNodeType::Add;
}
if (in == "=") {
return SolNodeType::Set;
}
if (in == "==") {
return SolNodeType::Equal;
}
if (in == "!=") {
return SolNodeType::Inequal;
}
2025-12-22 13:49:44 +11:00
if (in == ">=") {
return SolNodeType::EqGreater;
}
if (in == "<=") {
return SolNodeType::EqLesser;
}
if (in == ">") {
return SolNodeType::Greater;
}
if (in == "<") {
return SolNodeType::Lesser;
}
2025-12-21 12:06:55 +11:00
if (in == "puts") {
return SolNodeType::Puts;
}
if (in == "if") {
return SolNodeType::If;
}
if (in == "while") {
return SolNodeType::While;
}
if (in == "{") {
return SolNodeType::CodeBlockStart;
}
if (in == "}") {
return SolNodeType::CodeBlockEnd;
}
if (in == "(") {
return SolNodeType::BracketStart;
}
if (in == ")") {
return SolNodeType::BracketEnd;
}
return SolNodeType::Identifier;
}
SolNode Parser::parse() {
current = 0;
size = tokensToParse.size();
SolNode rootNode(SolNodeType::Root);
while (auto tokenopt = consume()) {
std::string token = tokenopt.value();
switch (getNodeType(token)) {
case SolNodeType::Value: {
switch (getDataType(token)) {
case SolDataType::Int: {
SolNode intNode(SolNodeType::Value);
intNode.setValue((int64_t) std::stoll(token));
rootNode.addNode(intNode);
break;
}
case SolDataType::Double: {
SolNode doubleNode(SolNodeType::Value);
doubleNode.setValue(std::stod(token));
rootNode.addNode(doubleNode);
break;
}
case SolDataType::String: {
SolNode stringNode(SolNodeType::Value);
stringNode.setValue(token.substr(1, token.size() - 2));
rootNode.addNode(stringNode);
break;
}
case SolDataType::Char: {
SolNode charNode(SolNodeType::Value);
charNode.setValue(token[1]);
rootNode.addNode(charNode);
break;
}
case SolDataType::Bool: {
SolNode boolNode(SolNodeType::Value);
boolNode.setValue(token == "true");
rootNode.addNode(boolNode);
break;
}
}
break;
}
case SolNodeType::Add: {
SolNode addNode(SolNodeType::Add);
addNode.addNode(rootNode.children.back());
rootNode.children.pop_back();
auto tokenopt = consume();
if (tokenopt) {
addNode.addNode(parseOneToken(tokenopt));
} else {
std::cout << "FEED ME MORE TOKENS\n";
exit(1);
}
rootNode.addNode(addNode);
break;
}
2025-12-22 13:49:44 +11:00
case SolNodeType::Equal:
case SolNodeType::Inequal:
case SolNodeType::Lesser:
case SolNodeType::Greater:
case SolNodeType::EqLesser:
case SolNodeType::EqGreater:
{
SolNode equalNode(getNodeType(token));
if (rootNode.children.empty()) {
std::cout << "ah dingus\n";
2025-12-21 12:06:55 +11:00
exit(1);
}
2025-12-22 13:49:44 +11:00
equalNode.addNode(rootNode.children.back());
2025-12-21 12:06:55 +11:00
rootNode.children.pop_back();
2025-12-22 13:49:44 +11:00
std::vector<std::string> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "\n") {
break;
}
tokens.push_back(tokenopt.value());
2025-12-21 12:06:55 +11:00
}
2025-12-22 13:49:44 +11:00
auto children = Parser(tokens).parse();
equalNode.addNode(children.children[0]);
rootNode.addNode(equalNode);
2025-12-21 12:06:55 +11:00
break;
}
case SolNodeType::Puts: {
SolNode putsNode(SolNodeType::Puts);
std::vector<std::string> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "\n") {
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
for (auto& child : children.children) {
putsNode.addNode(child);
}
rootNode.addNode(putsNode);
break;
}
case SolNodeType::If: {
SolNode ifNode(SolNodeType::If);
std::vector<std::string> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "\n") {
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
ifNode.addNode(children.children[0]);
tokens.clear();
size_t brackets = 1;
auto tokenopt = consume();
if (tokenopt) {
if (tokenopt.value() == "{") {
tokens.push_back(tokenopt.value());
while (auto tokenopt = consume()) {
tokens.push_back(tokenopt.value());
if (tokenopt.value() == "{") {
brackets++;
}
if (tokenopt.value() == "}") {
brackets--;
}
if (brackets == 0) {
break;
}
}
} else {
std::cout << "I want a code block instead of a " + tokenopt.value() + "\n";
exit(1);
}
} else {
std::cout << "FEED ME MORE TOKENSSSSS\n";
exit(1);
}
auto childCodeBlock = Parser(tokens).parse();
ifNode.addNode(childCodeBlock.children[0]);
rootNode.addNode(ifNode);
break;
}
case SolNodeType::While: {
SolNode whileNode(SolNodeType::While);
std::vector<std::string> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "\n") {
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
whileNode.addNode(children.children[0]);
tokens.clear();
size_t brackets = 1;
auto tokenopt = consume();
if (tokenopt) {
if (tokenopt.value() == "{") {
tokens.push_back(tokenopt.value());
while (auto tokenopt = consume()) {
tokens.push_back(tokenopt.value());
if (tokenopt.value() == "{") {
brackets++;
}
if (tokenopt.value() == "}") {
brackets--;
}
if (brackets == 0) {
break;
}
}
} else {
std::cout << "I want a code block instead of a " + tokenopt.value() + "\n";
exit(1);
}
} else {
std::cout << "FEED ME MORE TOKENSSSSS\n";
exit(1);
}
auto childCodeBlock = Parser(tokens).parse();
whileNode.addNode(childCodeBlock.children[0]);
rootNode.addNode(whileNode);
break;
}
case SolNodeType::CodeBlockStart: {
SolNode codeBlockNode(SolNodeType::CodeBlock);
size_t brackets = 1;
std::vector<std::string> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "{") {
brackets++;
}
if (tokenopt.value() == "}") {
brackets--;
}
if (brackets == 0) {
break;
}
tokens.push_back(tokenopt.value());
}
codeBlockNode.children = Parser(tokens).parse().children;
rootNode.addNode(codeBlockNode);
break;
}
case SolNodeType::Identifier: {
SolNode idNode(SolNodeType::Identifier);
idNode.outputId = token;
rootNode.addNode(idNode);
break;
}
case SolNodeType::Set: {
SolNode setNode(SolNodeType::Set);
setNode.addNode(rootNode.children.back());
rootNode.children.pop_back();
std::vector<std::string> tokens;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "\n") {
break;
}
tokens.push_back(tokenopt.value());
}
auto children = Parser(tokens).parse();
setNode.addNode(children.children[0]);
rootNode.addNode(setNode);
break;
}
case SolNodeType::BracketStart: {
if (rootNode.children.back().nodeType == SolNodeType::Identifier) {
SolNode fnCallNode(SolNodeType::FunctionCall);
fnCallNode.addNode(rootNode.children.back());
rootNode.children.pop_back();
std::vector<std::string> tokens;
size_t brackets = 1;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "(") {
brackets++;
}
if (tokenopt.value() == ")") {
brackets--;
}
if (brackets < 1) {
break;
}
tokens.push_back(tokenopt.value());
}
auto node = Parser(tokens).parse();
fnCallNode.children.insert(fnCallNode.children.end(), node.children.begin(), node.children.end());
rootNode.addNode(fnCallNode);
} else {
std::vector<std::string> tokens;
size_t brackets = 1;
while (auto tokenopt = consume()) {
if (tokenopt.value() == "(") {
brackets++;
}
if (tokenopt.value() == ")") {
brackets--;
}
if (brackets < 1) {
break;
}
tokens.push_back(tokenopt.value());
}
auto node = Parser(tokens).parse();
node.nodeType = SolNodeType::Expression;
rootNode.addNode(node);
}
}
}
}
return rootNode;
}
GroundProgram assembleProgram(SolNode& 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);
}
for (auto& tmpVar : code[i].toBeDropped) {
GroundInstruction gi = groundCreateInstruction(DROP);
2025-12-22 19:38:06 +11:00
char* droppedVar = (char*) malloc(tmpVar.size() + 1);
strcpy(droppedVar, tmpVar.c_str());
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, droppedVar));
groundAddInstructionToProgram(&gp, gi);
}
2025-12-21 12:06:55 +11:00
}
return gp;
}
} // namespace Parser
2025-12-22 13:49:44 +11:00
}