forked from solstice/solstice
1641 lines
85 KiB
C++
1641 lines
85 KiB
C++
#include "parser.h"
|
|
#include "error.h"
|
|
#include "lexer.h"
|
|
#include "solstice_stdlib.h"
|
|
#include "argparser.h"
|
|
#include <groundvm.h>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
|
|
#define parseOneToken(token) Parser({token}).parse().children[0]
|
|
|
|
namespace Solstice {
|
|
namespace Parser {
|
|
|
|
char* copyString(std::string s) {
|
|
char* str = (char*) malloc(s.size() + 1);
|
|
strcpy(str, s.c_str());
|
|
return str;
|
|
}
|
|
|
|
bool isTemp(std::string id) {
|
|
return id.rfind("tmp_", 0) == 0;
|
|
}
|
|
|
|
std::map<std::string, std::string> variables;
|
|
|
|
std::string checkNodeReturnType(SolNode i) {
|
|
switch (i.nodeType) {
|
|
case SolNodeType::Identifier: {
|
|
if (variables.find(i.outputId) != variables.end()) {
|
|
return variables[i.outputId];
|
|
} else {
|
|
Error::syntaxError("Unknown variable " + i.outputId, i.line, i.lineContent);
|
|
}
|
|
break;
|
|
}
|
|
case SolNodeType::Value: {
|
|
return i.data.getTypeString();
|
|
}
|
|
case SolNodeType::Equal:
|
|
case SolNodeType::Inequal:
|
|
case SolNodeType::Greater:
|
|
case SolNodeType::Lesser:
|
|
case SolNodeType::EqGreater:
|
|
case SolNodeType::EqLesser:
|
|
return "bool";
|
|
break;
|
|
case SolNodeType::Add:
|
|
{
|
|
if (checkNodeReturnType(i.children[0]) == "string" && checkNodeReturnType(i.children[1]) == "string") {
|
|
return "string";
|
|
}
|
|
}
|
|
case SolNodeType::Subtract:
|
|
case SolNodeType::Multiply:
|
|
case SolNodeType::Divide:
|
|
{
|
|
if (checkNodeReturnType(i.children[0]) == "double") {
|
|
return "double";
|
|
}
|
|
if (checkNodeReturnType(i.children[1]) == "double") {
|
|
return "double";
|
|
}
|
|
return "int";
|
|
break;
|
|
}
|
|
case SolNodeType::FunctionCall: {
|
|
std::string funcName = i.children[0].outputId;
|
|
if (variables.find(funcName) == variables.end()) {
|
|
Error::syntaxError("Unknown function " + funcName, i.line, i.lineContent);
|
|
}
|
|
std::string signature = variables[funcName];
|
|
|
|
// Parse signature: fun(arg1, arg2) retType
|
|
if (signature.rfind("fun(", 0) != 0) {
|
|
// Not a function signature, maybe it's a variable being called?
|
|
Error::typingError(funcName + " is not a function", i.line, i.lineContent);
|
|
}
|
|
|
|
size_t endParen = signature.find(')');
|
|
if (endParen == std::string::npos) {
|
|
Error::typingError("Invalid function signature for " + funcName, i.line, i.lineContent);
|
|
}
|
|
|
|
std::string argsStr = signature.substr(4, endParen - 4);
|
|
std::string retType = signature.substr(endParen + 2); // skip ") "
|
|
|
|
std::vector<std::string> expectedArgs;
|
|
if (!argsStr.empty()) {
|
|
size_t start = 0;
|
|
size_t end = argsStr.find(", ");
|
|
while (end != std::string::npos) {
|
|
expectedArgs.push_back(argsStr.substr(start, end - start));
|
|
start = end + 2;
|
|
end = argsStr.find(", ", start);
|
|
}
|
|
expectedArgs.push_back(argsStr.substr(start));
|
|
}
|
|
|
|
// Check arguments
|
|
// children[0] is function name, children[1..] are args
|
|
if (i.children.size() - 1 != expectedArgs.size()) {
|
|
Error::typingError("Expected " + std::to_string(expectedArgs.size()) + " arguments for " + funcName + ", got " + std::to_string(i.children.size() - 1), i.line, i.lineContent);
|
|
return "none";
|
|
}
|
|
|
|
for (size_t k = 0; k < expectedArgs.size(); ++k) {
|
|
std::string argType = checkNodeReturnType(i.children[k + 1]);
|
|
if (argType != expectedArgs[k]) {
|
|
Error::typingError("Expected argument " + std::to_string(k + 1) + " of " + funcName + " to be " + expectedArgs[k] + ", got " + argType, i.children[k + 1].line, i.children[k + 1].lineContent);
|
|
}
|
|
}
|
|
|
|
return retType;
|
|
break;
|
|
}
|
|
case SolNodeType::Puts:
|
|
case SolNodeType::If:
|
|
case SolNodeType::While:
|
|
case SolNodeType::CodeBlock:
|
|
case SolNodeType::Set:
|
|
case SolNodeType::Root:
|
|
case SolNodeType::None:
|
|
case SolNodeType::FunctionDef:
|
|
return "none";
|
|
break;
|
|
}
|
|
return "none";
|
|
}
|
|
|
|
// 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) {}
|
|
SolData::SolData(SolFunction in) : data(in), type(SolDataType::Function) {}
|
|
|
|
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 {};
|
|
}
|
|
}
|
|
std::optional<SolFunction> SolData::getFunction() {
|
|
if (type == SolDataType::Function) {
|
|
return std::get<SolFunction>(data);
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
std::string SolData::getTypeString() {
|
|
switch (type) {
|
|
case SolDataType::Int: return "int";
|
|
case SolDataType::Double: return "double";
|
|
case SolDataType::String: return "string";
|
|
case SolDataType::Char: return "char";
|
|
case SolDataType::Bool: return "bool";
|
|
case SolDataType::Function: return "function";
|
|
case SolDataType::None: return "none";
|
|
}
|
|
return "none";
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
std::string currentFunctionRetType = "";
|
|
|
|
const std::vector<SolGroundCodeBlock> SolNode::generateCode() {
|
|
std::vector<SolGroundCodeBlock> code;
|
|
if (nodeType == SolNodeType::Root) {
|
|
// Compile and insert standard library
|
|
if (!ArgParser::nostdlib) {
|
|
auto parsedStdlib = Parser(Lexer(getStdLib()).lex()).parse();
|
|
parsedStdlib.nodeType = SolNodeType::None;
|
|
code = parsedStdlib.generateCode();
|
|
}
|
|
}
|
|
if (nodeType != SolNodeType::If && nodeType != SolNodeType::While && nodeType != SolNodeType::Struct) 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, copyString(outputId)));
|
|
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) {
|
|
char* str = (char*) malloc(dataopt.value().size() + 1);
|
|
strcpy(str, dataopt.value().c_str());
|
|
groundAddValueToInstruction(&gi, groundCreateValue(STRING, str));
|
|
}
|
|
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: {
|
|
ensure3(children[0], "int", "double", "string", "operator '+'");
|
|
ensure3(children[1], "int", "double", "string", "operator '+'");
|
|
ensuresame(children[0], children[1], "operator '+'");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(ADD);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to add", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Subtract: {
|
|
ensure2(children[0], "int", "double", "operator '-'");
|
|
ensure2(children[1], "int", "double", "operator '-'");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(SUBTRACT);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to subtract", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Multiply: {
|
|
ensure2(children[0], "int", "double", "operator '*'");
|
|
ensure2(children[1], "int", "double", "operator '*'");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(MULTIPLY);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to multiply", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Divide: {
|
|
ensure2(children[0], "int", "double", "operator '/'");
|
|
ensure2(children[1], "int", "double", "operator '/'");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(DIVIDE);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to divide", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Equal: {
|
|
ensuresame(children[0], children[1], "operator '=='");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(EQUAL);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to equal", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Inequal: {
|
|
ensuresame(children[0], children[1], "operator '!='");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(INEQUAL);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Greater: {
|
|
ensuresame(children[0], children[1], "operator '>'");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(GREATER);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to greater", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Lesser: {
|
|
ensuresame(children[0], children[1], "operator '<'");
|
|
SolGroundCodeBlock codeBlock;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
GroundInstruction gi = groundCreateInstruction(LESSER);
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to lesser", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::EqGreater: {
|
|
ensuresame(children[0], children[1], "operator '>='");
|
|
SolGroundCodeBlock codeBlock;
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent);
|
|
}
|
|
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, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
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, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
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, copyString(outputId)));
|
|
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, copyString(outputId)));
|
|
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false));
|
|
codeBlock.code.push_back(gi);
|
|
// @end
|
|
gi = groundCreateInstruction(CREATELABEL);
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::EqLesser: {
|
|
ensuresame(children[0], children[1], "operator '<='");
|
|
SolGroundCodeBlock codeBlock;
|
|
if (children.size() < 2) {
|
|
Error::typingError("Need more stuff to inequal", children[0].line, children[0].lineContent);
|
|
}
|
|
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, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
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, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
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, copyString(outputId)));
|
|
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, copyString(outputId)));
|
|
groundAddValueToInstruction(&gi, groundCreateValue(BOOL, false));
|
|
codeBlock.code.push_back(gi);
|
|
// @end
|
|
gi = groundCreateInstruction(CREATELABEL);
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(LABEL, endLabelId));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Puts: {
|
|
SolGroundCodeBlock codeBlock;
|
|
exists(children[0]);
|
|
GroundInstruction gi = groundCreateInstruction(PRINTLN);
|
|
if (children.size() < 1) {
|
|
Error::typingError("Need more stuff to puts", children[0].line, children[0].lineContent);
|
|
}
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::If: {
|
|
ensure(children[0], "bool", "if condition");
|
|
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);
|
|
if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId);
|
|
GroundInstruction gi = groundCreateInstruction(NOT);
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
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, copyString(outputId)));
|
|
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();
|
|
codeBlock.toBeDropped.clear();
|
|
GroundInstruction gi3 = groundCreateInstruction(CREATELABEL);
|
|
groundAddReferenceToInstruction(&gi3, groundCreateReference(LABEL, labelId));
|
|
codeBlock.code.push_back(gi3);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::While: {
|
|
ensure(children[0], "bool", "while condition");
|
|
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);
|
|
if (isTemp(children[0].outputId)) checkBlock.toBeDropped.push_back(children[0].outputId);
|
|
GroundInstruction gi = groundCreateInstruction(NOT);
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(outputId)));
|
|
checkBlock.code.push_back(gi);
|
|
GroundInstruction gi2 = groundCreateInstruction(IF);
|
|
groundAddReferenceToInstruction(&gi2, groundCreateReference(VALREF, copyString(outputId)));
|
|
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: {
|
|
if (variables.find(children[0].outputId) != variables.end()) {
|
|
if (variables[children[0].outputId] != checkNodeReturnType(children[1])) {
|
|
Error::typingError("Cannot change type of this variable", children[0].line, children[0].lineContent);
|
|
}
|
|
}
|
|
exists(children[1]);
|
|
SolGroundCodeBlock codeBlock;
|
|
GroundInstruction setInstruction = groundCreateInstruction(SET);
|
|
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(DIRREF, copyString(children[0].outputId)));
|
|
groundAddReferenceToInstruction(&setInstruction, groundCreateReference(VALREF, copyString(children[1].outputId)));
|
|
codeBlock.code.push_back(setInstruction);
|
|
if (isTemp(children[1].outputId)) codeBlock.toBeDropped.push_back(children[1].outputId);
|
|
code.push_back(codeBlock);
|
|
// Make sure we know what the variable type is
|
|
variables[children[0].outputId] = checkNodeReturnType(children[1]);
|
|
break;
|
|
}
|
|
case SolNodeType::FunctionCall: {
|
|
checkNodeReturnType(*this);
|
|
exists(children[0]);
|
|
std::string fnToCall = children[0].outputId;
|
|
outputId = "tmp_" + std::to_string(tmpIdIterator++);
|
|
SolGroundCodeBlock codeBlock;
|
|
GroundInstruction callInstruction = groundCreateInstruction(CALL);
|
|
groundAddReferenceToInstruction(&callInstruction, groundCreateReference(FNREF, copyString(children[0].outputId)));
|
|
for (int i = 1; i < children.size(); i++) {
|
|
groundAddReferenceToInstruction(&callInstruction, groundCreateReference(VALREF, copyString(children[i].outputId)));
|
|
}
|
|
groundAddReferenceToInstruction(&callInstruction, groundCreateReference(DIRREF, copyString(outputId)));
|
|
codeBlock.code.push_back(callInstruction);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Return: {
|
|
std::string retType = checkNodeReturnType(children[0]);
|
|
if (currentFunctionRetType != "" && retType != currentFunctionRetType) {
|
|
Error::typingError("Expected return type " + currentFunctionRetType + " but got " + retType, children[0].line, children[0].lineContent);
|
|
}
|
|
SolGroundCodeBlock codeBlock;
|
|
GroundInstruction returnInstruction = groundCreateInstruction(RETURN);
|
|
groundAddReferenceToInstruction(&returnInstruction, groundCreateReference(VALREF, copyString(children[0].outputId)));
|
|
codeBlock.code.push_back(returnInstruction);
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::FunctionDef: {
|
|
auto functionopt = data.getFunction();
|
|
if (functionopt.has_value()) {
|
|
SolFunction function = functionopt.value();
|
|
SolGroundCodeBlock codeBlock;
|
|
GroundInstruction inst = groundCreateInstruction(FUN);
|
|
char* fnName = (char*) malloc(sizeof(char) * (function.name.size() + 1));
|
|
strcpy(fnName, function.name.c_str());
|
|
char* retType = (char*) malloc(sizeof(char) * (function.returnType.size() + 1));
|
|
strcpy(retType, function.returnType.c_str());
|
|
groundAddReferenceToInstruction(&inst, groundCreateReference(FNREF, fnName));
|
|
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, retType));
|
|
|
|
// Scope Management
|
|
auto variablebackup = variables;
|
|
std::string oldRetType = currentFunctionRetType;
|
|
|
|
variables.clear();
|
|
currentFunctionRetType = function.returnType;
|
|
|
|
for (auto& pair : function.parameters) {
|
|
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, copyString(pair.second)));
|
|
groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, copyString(pair.first)));
|
|
variables[pair.first] = pair.second; // Correctly map Name -> Type
|
|
}
|
|
|
|
codeBlock.code.push_back(inst);
|
|
code.push_back(codeBlock);
|
|
codeBlock.code.clear();
|
|
|
|
// Generate body code with local variables visible
|
|
auto childCode = function.content->generateCode();
|
|
code.insert(code.end(), childCode.begin(), childCode.end());
|
|
|
|
codeBlock.code.push_back(groundCreateInstruction(ENDFUN));
|
|
code.push_back(codeBlock);
|
|
|
|
// Restore Scope
|
|
variables = variablebackup;
|
|
currentFunctionRetType = oldRetType;
|
|
}
|
|
break;
|
|
}
|
|
case SolNodeType::InlineGround: {
|
|
GroundProgram program = groundParseFile(ground.c_str());
|
|
SolGroundCodeBlock codeBlock;
|
|
for (size_t i = 0; i < program.size; i++) {
|
|
codeBlock.code.push_back(program.instructions[i]);
|
|
}
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
case SolNodeType::Struct: {
|
|
//SolGroundCodeBlock preProcessCodeBlock;
|
|
SolGroundCodeBlock codeBlock;
|
|
GroundInstruction gi = groundCreateInstruction(STRUCT);
|
|
|
|
// struct -name
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(TYPEREF, copyString(outputId)));
|
|
codeBlock.code.push_back(gi);
|
|
|
|
// contents of struct
|
|
for (SolNode& child : children) {
|
|
if (child.nodeType == SolNodeType::Identifier) {
|
|
gi = groundCreateInstruction(SET);
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, copyString(child.outputId)));
|
|
|
|
SolNode& valNode = child.children[0];
|
|
if (valNode.nodeType == SolNodeType::Value) {
|
|
GroundValue gv;
|
|
switch (valNode.data.type) {
|
|
case SolDataType::String: gv = groundCreateValue(STRING, copyString(valNode.data.getString().value())); break;
|
|
case SolDataType::Int: gv = groundCreateValue(INT, valNode.data.getInt().value()); break;
|
|
case SolDataType::Double: gv = groundCreateValue(DOUBLE, valNode.data.getDouble().value()); break;
|
|
case SolDataType::Char: gv = groundCreateValue(CHAR, valNode.data.getChar().value()); break;
|
|
case SolDataType::Bool: gv = groundCreateValue(BOOL, valNode.data.getBool().value()); break;
|
|
default: Error::syntaxError("Struct member must be assigned a value or identifier", valNode.line, valNode.lineContent); break;
|
|
}
|
|
groundAddValueToInstruction(&gi, gv);
|
|
} else if (child.nodeType == SolNodeType::Identifier) {
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(VALREF, copyString(valNode.outputId)));
|
|
} else {
|
|
Error::syntaxError("Struct member must be assigned a value or identifier", valNode.line, valNode.lineContent);
|
|
}
|
|
codeBlock.code.push_back(gi);
|
|
}
|
|
if (child.nodeType == SolNodeType::FunctionDef) {
|
|
auto fnBlock = child.generateCode();
|
|
for (const auto& code : fnBlock) {
|
|
codeBlock.code.insert(codeBlock.code.end(), code.code.begin(), code.code.end());
|
|
}
|
|
}
|
|
}
|
|
codeBlock.code.push_back(groundCreateInstruction(ENDSTRUCT));
|
|
code.push_back(codeBlock);
|
|
break;
|
|
}
|
|
default: {}
|
|
}
|
|
return code;
|
|
}
|
|
|
|
// Parser Implementation
|
|
Parser::Parser(std::vector<Token> in) : tokensToParse(in) {}
|
|
|
|
std::optional<Token> Parser::peek(int ahead) {
|
|
if (current + ahead < size) {
|
|
return tokensToParse[current + ahead];
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
std::optional<Token> 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::Subtract;
|
|
}
|
|
if (in == "*") {
|
|
return SolNodeType::Multiply;
|
|
}
|
|
if (in == "/") {
|
|
return SolNodeType::Divide;
|
|
}
|
|
if (in == "=" || in == ":") {
|
|
return SolNodeType::Set;
|
|
}
|
|
if (in == "==") {
|
|
return SolNodeType::Equal;
|
|
}
|
|
if (in == "!=") {
|
|
return SolNodeType::Inequal;
|
|
}
|
|
if (in == ">=") {
|
|
return SolNodeType::EqGreater;
|
|
}
|
|
if (in == "<=") {
|
|
return SolNodeType::EqLesser;
|
|
}
|
|
if (in == ">") {
|
|
return SolNodeType::Greater;
|
|
}
|
|
if (in == "<") {
|
|
return SolNodeType::Lesser;
|
|
}
|
|
if (in == "puts") {
|
|
return SolNodeType::Puts;
|
|
}
|
|
if (in == "if") {
|
|
return SolNodeType::If;
|
|
}
|
|
if (in == "while") {
|
|
return SolNodeType::While;
|
|
}
|
|
if (in == "def") {
|
|
return SolNodeType::FunctionDef;
|
|
}
|
|
if (in == "return") {
|
|
return SolNodeType::Return;
|
|
}
|
|
if (in == "ground") {
|
|
return SolNodeType::InlineGround;
|
|
}
|
|
if (in == "struct") {
|
|
return SolNodeType::Struct;
|
|
}
|
|
if (in == "new") {
|
|
return SolNodeType::New;
|
|
}
|
|
if (in == "{") {
|
|
return SolNodeType::CodeBlockStart;
|
|
}
|
|
if (in == "}") {
|
|
return SolNodeType::CodeBlockEnd;
|
|
}
|
|
if (in == "(") {
|
|
return SolNodeType::BracketStart;
|
|
}
|
|
if (in == ")") {
|
|
return SolNodeType::BracketEnd;
|
|
}
|
|
return SolNodeType::Identifier;
|
|
}
|
|
|
|
int Parser::getPrecedence(std::string token) {
|
|
if (token == "*" || token == "/") return 2;
|
|
if (token == "+" || token == "-") return 1;
|
|
return 0;
|
|
}
|
|
|
|
SolNode Parser::parsePrimary() {
|
|
auto tokenopt = consume();
|
|
if (!tokenopt) {
|
|
Error::syntaxError("Unexpected end of input");
|
|
}
|
|
Token tokenObj = tokenopt.value();
|
|
std::string token = tokenObj.value;
|
|
SolNodeType type = getNodeType(token);
|
|
|
|
if (type == SolNodeType::Value) {
|
|
SolNode node(SolNodeType::Value);
|
|
node.line = tokenObj.line;
|
|
node.lineContent = tokenObj.lineContent;
|
|
switch (getDataType(token)) {
|
|
case SolDataType::Int: node.setValue((int64_t) std::stoll(token)); break;
|
|
case SolDataType::Double: node.setValue(std::stod(token)); break;
|
|
case SolDataType::String: node.setValue(token.substr(1, token.size() - 2)); break;
|
|
case SolDataType::Char: node.setValue(token[1]); break;
|
|
case SolDataType::Bool: node.setValue(token == "true"); break;
|
|
default: break;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
if (type == SolNodeType::Identifier) {
|
|
SolNode idNode(SolNodeType::Identifier);
|
|
idNode.outputId = token;
|
|
idNode.line = tokenObj.line;
|
|
idNode.lineContent = tokenObj.lineContent;
|
|
|
|
auto peekOpt = peek();
|
|
if (peekOpt.has_value() && peekOpt.value().value == "(") {
|
|
consume(); // (
|
|
SolNode fnCallNode(SolNodeType::FunctionCall);
|
|
fnCallNode.line = tokenObj.line;
|
|
fnCallNode.lineContent = tokenObj.lineContent;
|
|
fnCallNode.addNode(idNode);
|
|
|
|
std::vector<Token> tokens;
|
|
size_t brackets = 1;
|
|
while (auto t = consume()) {
|
|
if (t.value().value == "(") brackets++;
|
|
if (t.value().value == ")") brackets--;
|
|
if (brackets == 0) break;
|
|
tokens.push_back(t.value());
|
|
}
|
|
if (brackets != 0) {
|
|
Error::syntaxError("Unclosed function call bracket", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
auto args = Parser(tokens).parse();
|
|
for(auto& child : args.children) fnCallNode.addNode(child);
|
|
return fnCallNode;
|
|
}
|
|
return idNode;
|
|
}
|
|
|
|
if (type == SolNodeType::BracketStart) {
|
|
std::vector<Token> tokens;
|
|
size_t brackets = 1;
|
|
while (auto t = consume()) {
|
|
if (t.value().value == "(") brackets++;
|
|
if (t.value().value == ")") brackets--;
|
|
if (brackets == 0) break;
|
|
tokens.push_back(t.value());
|
|
}
|
|
if (brackets != 0) {
|
|
Error::syntaxError("Unclosed bracket", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
auto inner = Parser(tokens).parse();
|
|
if (inner.children.size() > 0) return inner.children[0];
|
|
return SolNode(SolNodeType::None);
|
|
}
|
|
|
|
Error::syntaxError("Unexpected token in expression: " + token, tokenObj.line, tokenObj.lineContent);
|
|
return SolNode(SolNodeType::None);
|
|
}
|
|
|
|
SolNode Parser::parseExpression(int minPrec) {
|
|
SolNode lhs = parsePrimary();
|
|
while(true) {
|
|
auto opOpt = peek();
|
|
if (!opOpt) break;
|
|
Token opToken = opOpt.value();
|
|
std::string op = opToken.value;
|
|
int prec = getPrecedence(op);
|
|
if (prec < minPrec) break;
|
|
|
|
consume();
|
|
SolNode rhs = parseExpression(prec + 1);
|
|
SolNode newNode(getNodeType(op));
|
|
newNode.line = opToken.line;
|
|
newNode.lineContent = opToken.lineContent;
|
|
newNode.addNode(lhs);
|
|
newNode.addNode(rhs);
|
|
lhs = newNode;
|
|
}
|
|
return lhs;
|
|
}
|
|
|
|
SolNode Parser::parse() {
|
|
current = 0;
|
|
size = tokensToParse.size();
|
|
SolNode rootNode(SolNodeType::Root);
|
|
while (auto tokenopt = consume()) {
|
|
Token tokenObj = tokenopt.value();
|
|
std::string token = tokenObj.value;
|
|
switch (getNodeType(token)) {
|
|
case SolNodeType::Value: {
|
|
switch (getDataType(token)) {
|
|
case SolDataType::Int: {
|
|
SolNode intNode(SolNodeType::Value);
|
|
intNode.setValue((int64_t) std::stoll(token));
|
|
intNode.line = tokenObj.line;
|
|
intNode.lineContent = tokenObj.lineContent;
|
|
rootNode.addNode(intNode);
|
|
break;
|
|
}
|
|
case SolDataType::Double: {
|
|
SolNode doubleNode(SolNodeType::Value);
|
|
doubleNode.setValue(std::stod(token));
|
|
doubleNode.line = tokenObj.line;
|
|
doubleNode.lineContent = tokenObj.lineContent;
|
|
rootNode.addNode(doubleNode);
|
|
break;
|
|
}
|
|
case SolDataType::String: {
|
|
SolNode stringNode(SolNodeType::Value);
|
|
stringNode.setValue(token.substr(1, token.size() - 2));
|
|
stringNode.line = tokenObj.line;
|
|
stringNode.lineContent = tokenObj.lineContent;
|
|
rootNode.addNode(stringNode);
|
|
break;
|
|
}
|
|
case SolDataType::Char: {
|
|
SolNode charNode(SolNodeType::Value);
|
|
charNode.setValue(token[1]);
|
|
charNode.line = tokenObj.line;
|
|
charNode.lineContent = tokenObj.lineContent;
|
|
rootNode.addNode(charNode);
|
|
break;
|
|
}
|
|
case SolDataType::Bool: {
|
|
SolNode boolNode(SolNodeType::Value);
|
|
boolNode.setValue(token == "true");
|
|
boolNode.line = tokenObj.line;
|
|
boolNode.lineContent = tokenObj.lineContent;
|
|
rootNode.addNode(boolNode);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SolNodeType::Add:
|
|
case SolNodeType::Subtract:
|
|
case SolNodeType::Multiply:
|
|
case SolNodeType::Divide:
|
|
{
|
|
SolNode opNode(getNodeType(token));
|
|
opNode.line = tokenObj.line;
|
|
opNode.lineContent = tokenObj.lineContent;
|
|
|
|
if (rootNode.children.empty()) {
|
|
Error::syntaxError("Expected operand before operator", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
opNode.addNode(rootNode.children.back());
|
|
rootNode.children.pop_back();
|
|
|
|
// Parse RHS with higher precedence
|
|
SolNode rhs = parseExpression(getPrecedence(token) + 1);
|
|
opNode.addNode(rhs);
|
|
|
|
rootNode.addNode(opNode);
|
|
break;
|
|
}
|
|
case SolNodeType::Equal:
|
|
case SolNodeType::Inequal:
|
|
case SolNodeType::Lesser:
|
|
case SolNodeType::Greater:
|
|
case SolNodeType::EqLesser:
|
|
case SolNodeType::EqGreater:
|
|
{
|
|
SolNode equalNode(getNodeType(token));
|
|
equalNode.line = tokenObj.line;
|
|
equalNode.lineContent = tokenObj.lineContent;
|
|
|
|
if (rootNode.children.empty()) {
|
|
Error::syntaxError("Expected operand before comparison", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
equalNode.addNode(rootNode.children.back());
|
|
rootNode.children.pop_back();
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "\n") {
|
|
break;
|
|
}
|
|
tokens.push_back(tokenopt.value());
|
|
}
|
|
auto children = Parser(tokens).parse();
|
|
equalNode.addNode(children.children[0]);
|
|
rootNode.addNode(equalNode);
|
|
break;
|
|
}
|
|
case SolNodeType::Puts: {
|
|
SolNode putsNode(SolNodeType::Puts);
|
|
putsNode.line = tokenObj.line;
|
|
putsNode.lineContent = tokenObj.lineContent;
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().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);
|
|
ifNode.line = tokenObj.line;
|
|
ifNode.lineContent = tokenObj.lineContent;
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().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().value == "{") {
|
|
tokens.push_back(tokenopt.value());
|
|
while (auto tokenopt = consume()) {
|
|
tokens.push_back(tokenopt.value());
|
|
if (tokenopt.value().value == "{") {
|
|
brackets++;
|
|
}
|
|
if (tokenopt.value().value == "}") {
|
|
brackets--;
|
|
}
|
|
if (brackets == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (brackets != 0) {
|
|
Error::syntaxError("Unclosed code block", tokenopt.value().line, tokenopt.value().lineContent);
|
|
}
|
|
} else {
|
|
Error::syntaxError("I want a code block instead of a " + tokenopt.value().value, tokenopt.value().line, tokenopt.value().lineContent);
|
|
}
|
|
} else {
|
|
Error::syntaxError("Expected code block after if condition", ifNode.line, ifNode.lineContent);
|
|
}
|
|
auto childCodeBlock = Parser(tokens).parse();
|
|
ifNode.addNode(childCodeBlock.children[0]);
|
|
rootNode.addNode(ifNode);
|
|
break;
|
|
}
|
|
case SolNodeType::While: {
|
|
SolNode whileNode(SolNodeType::While);
|
|
whileNode.line = tokenObj.line;
|
|
whileNode.lineContent = tokenObj.lineContent;
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().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().value == "{") {
|
|
tokens.push_back(tokenopt.value());
|
|
while (auto tokenopt = consume()) {
|
|
tokens.push_back(tokenopt.value());
|
|
if (tokenopt.value().value == "{") {
|
|
brackets++;
|
|
}
|
|
if (tokenopt.value().value == "}") {
|
|
brackets--;
|
|
}
|
|
if (brackets == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (brackets != 0) {
|
|
Error::syntaxError("Unclosed code block", tokenopt.value().line, tokenopt.value().lineContent);
|
|
}
|
|
} else {
|
|
Error::syntaxError("I want a code block instead of a " + tokenopt.value().value, tokenopt.value().line, tokenopt.value().lineContent);
|
|
}
|
|
} else {
|
|
Error::syntaxError("Expected code block after while condition", whileNode.line, whileNode.lineContent);
|
|
}
|
|
auto childCodeBlock = Parser(tokens).parse();
|
|
whileNode.addNode(childCodeBlock.children[0]);
|
|
rootNode.addNode(whileNode);
|
|
break;
|
|
}
|
|
case SolNodeType::CodeBlockStart: {
|
|
SolNode codeBlockNode(SolNodeType::CodeBlock);
|
|
codeBlockNode.line = tokenObj.line;
|
|
codeBlockNode.lineContent = tokenObj.lineContent;
|
|
size_t brackets = 1;
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "{") {
|
|
brackets++;
|
|
}
|
|
if (tokenopt.value().value == "}") {
|
|
brackets--;
|
|
}
|
|
if (brackets == 0) {
|
|
break;
|
|
}
|
|
tokens.push_back(tokenopt.value());
|
|
}
|
|
if (brackets != 0) {
|
|
Error::syntaxError("Unclosed code block", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
codeBlockNode.children = Parser(tokens).parse().children;
|
|
rootNode.addNode(codeBlockNode);
|
|
break;
|
|
}
|
|
case SolNodeType::Identifier: {
|
|
SolNode idNode(SolNodeType::Identifier);
|
|
idNode.outputId = token;
|
|
idNode.line = tokenObj.line;
|
|
idNode.lineContent = tokenObj.lineContent;
|
|
rootNode.addNode(idNode);
|
|
break;
|
|
}
|
|
case SolNodeType::Set: {
|
|
SolNode setNode(SolNodeType::Set);
|
|
setNode.line = tokenObj.line;
|
|
setNode.lineContent = tokenObj.lineContent;
|
|
|
|
setNode.addNode(rootNode.children.back());
|
|
rootNode.children.pop_back();
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().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: {
|
|
// function call
|
|
if (!rootNode.children.empty() && rootNode.children.back().nodeType == SolNodeType::Identifier) {
|
|
SolNode fnCallNode(SolNodeType::FunctionCall);
|
|
fnCallNode.line = tokenObj.line;
|
|
fnCallNode.lineContent = tokenObj.lineContent;
|
|
fnCallNode.addNode(rootNode.children.back());
|
|
rootNode.children.pop_back();
|
|
std::vector<Token> tokens;
|
|
size_t brackets = 1;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "(") {
|
|
brackets++;
|
|
}
|
|
if (tokenopt.value().value == ")") {
|
|
brackets--;
|
|
}
|
|
// comma, eval statement here
|
|
if (tokenopt.value().value == "," && brackets == 1) {
|
|
auto node = Parser(tokens).parse();
|
|
if (!node.children.empty()) fnCallNode.children.push_back(node.children[0]);
|
|
else {
|
|
Error::syntaxError("dingus");
|
|
}
|
|
tokens.clear();
|
|
continue;
|
|
}
|
|
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<Token> tokens;
|
|
size_t brackets = 1;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "(") {
|
|
brackets++;
|
|
}
|
|
if (tokenopt.value().value == ")") {
|
|
brackets--;
|
|
}
|
|
if (brackets < 1) {
|
|
break;
|
|
}
|
|
tokens.push_back(tokenopt.value());
|
|
}
|
|
auto node = Parser(tokens).parse();
|
|
if (!node.children.empty()) {
|
|
rootNode.addNode(node.children.back());
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SolNodeType::FunctionDef: {
|
|
SolFunction fn;
|
|
auto nameTokenOpt = consume();
|
|
if (!nameTokenOpt || getNodeType(nameTokenOpt.value().value) != SolNodeType::Identifier) {
|
|
Error::syntaxError("Expected function name", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
fn.name = nameTokenOpt.value().value;
|
|
|
|
auto openParen = consume();
|
|
if (!openParen || openParen.value().value != "(") {
|
|
Error::syntaxError("Expected '(' after function name", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
|
|
std::string signature = "fun(";
|
|
|
|
bool first = true;
|
|
while (auto next = peek()) {
|
|
if (next.value().value == ")") {
|
|
consume();
|
|
break;
|
|
}
|
|
if (!first) {
|
|
auto comma = consume();
|
|
if (comma.value().value != ",") {
|
|
Error::syntaxError("Expected ',' between arguments", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
}
|
|
|
|
auto typeToken = consume();
|
|
if (!typeToken) Error::syntaxError("Expected type", tokenObj.line, tokenObj.lineContent);
|
|
std::string argType = typeToken.value().value;
|
|
|
|
auto argNameToken = consume();
|
|
if (!argNameToken) Error::syntaxError("Expected argument name", tokenObj.line, tokenObj.lineContent);
|
|
std::string argName = argNameToken.value().value;
|
|
|
|
fn.parameters.push_back({argName, argType});
|
|
|
|
if (!first) signature += ", ";
|
|
signature += argType;
|
|
first = false;
|
|
}
|
|
signature += ") ";
|
|
|
|
while (peek() && peek().value().value == "\n") consume();
|
|
|
|
auto next = peek();
|
|
if (next && next.value().value != "{") {
|
|
auto retTypeToken = consume();
|
|
fn.returnType = retTypeToken.value().value;
|
|
} else {
|
|
fn.returnType = "void";
|
|
}
|
|
signature += fn.returnType;
|
|
fn.signature = signature;
|
|
|
|
while (peek() && peek().value().value == "\n") consume();
|
|
|
|
auto brace = peek();
|
|
if (!brace || brace.value().value != "{") {
|
|
Error::syntaxError("Expected '{' starting function body", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
|
|
consume();
|
|
std::vector<Token> bodyTokens;
|
|
size_t brackets = 1;
|
|
while(auto t = consume()) {
|
|
if (t.value().value == "{") brackets++;
|
|
if (t.value().value == "}") brackets--;
|
|
if (brackets == 0) break;
|
|
bodyTokens.push_back(t.value());
|
|
}
|
|
if (brackets != 0) Error::syntaxError("Unclosed function body", tokenObj.line, tokenObj.lineContent);
|
|
|
|
auto parsedBody = Parser(bodyTokens).parse();
|
|
auto bodyNode = std::make_shared<SolNode>(SolNodeType::CodeBlock);
|
|
bodyNode->children = parsedBody.children;
|
|
|
|
fn.content = bodyNode;
|
|
|
|
SolNode fnNode(SolNodeType::FunctionDef);
|
|
fnNode.data = SolData(fn);
|
|
variables[fn.name] = signature;
|
|
|
|
rootNode.addNode(fnNode);
|
|
break;
|
|
}
|
|
case SolNodeType::Return: {
|
|
SolNode returnNode(SolNodeType::Return);
|
|
returnNode.line = tokenObj.line;
|
|
returnNode.lineContent = tokenObj.lineContent;
|
|
std::vector<Token> tokens;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "\n") {
|
|
break;
|
|
}
|
|
tokens.push_back(tokenopt.value());
|
|
}
|
|
auto children = Parser(tokens).parse();
|
|
for (auto& child : children.children) {
|
|
returnNode.addNode(child);
|
|
}
|
|
rootNode.addNode(returnNode);
|
|
break;
|
|
}
|
|
case SolNodeType::InlineGround: {
|
|
SolNode groundNode(SolNodeType::InlineGround);
|
|
consume(); // some funny token
|
|
consume(); // {
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "}") {
|
|
break;
|
|
}
|
|
groundNode.ground += tokenopt.value().value + " ";
|
|
}
|
|
rootNode.addNode(groundNode);
|
|
break;
|
|
}
|
|
case SolNodeType::Struct: {
|
|
SolNode structNode(SolNodeType::Struct);
|
|
structNode.line = tokenObj.line;
|
|
structNode.lineContent = tokenObj.lineContent;
|
|
|
|
auto nameopt = consume();
|
|
if (nameopt) {
|
|
structNode.outputId = nameopt.value().value;
|
|
}
|
|
|
|
while (peek() && peek().value().value == "\n") {
|
|
consume();
|
|
}
|
|
|
|
auto openBrace = consume();
|
|
if (!openBrace || openBrace.value().value != "{") {
|
|
Error::syntaxError("Expected '{' after struct name", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
|
|
std::vector<Token> tokens;
|
|
int count = 1;
|
|
while (auto tokenopt = consume()) {
|
|
if (tokenopt.value().value == "{") {
|
|
count++;
|
|
}
|
|
if (tokenopt.value().value == "}") {
|
|
count--;
|
|
}
|
|
if (count < 1) {
|
|
break;
|
|
}
|
|
tokens.push_back(tokenopt.value());
|
|
}
|
|
|
|
if (count != 0) {
|
|
Error::syntaxError("Unclosed struct body", tokenObj.line, tokenObj.lineContent);
|
|
}
|
|
|
|
for (size_t i = 0; i < tokens.size(); i++) {
|
|
Token token = tokens[i];
|
|
|
|
if (token.value == "\n") {
|
|
continue;
|
|
}
|
|
|
|
if (getNodeType(token.value) == SolNodeType::Identifier) {
|
|
if (i + 2 >= tokens.size()) {
|
|
Error::syntaxError("Expecting a value after the identifier", token.line, token.lineContent);
|
|
continue;
|
|
}
|
|
if (getNodeType(tokens[i + 1].value) != SolNodeType::Set) {
|
|
Error::syntaxError("Expected a set keyword ('=' or ':')", token.line, token.lineContent);
|
|
continue;
|
|
}
|
|
if (getNodeType(tokens[i + 2].value) != SolNodeType::Identifier &&
|
|
getNodeType(tokens[i + 2].value) != SolNodeType::Value) {
|
|
Error::syntaxError("Expected a value or identifier for default value", token.line, token.lineContent);
|
|
continue;
|
|
}
|
|
|
|
SolNode idNode(SolNodeType::Identifier);
|
|
idNode.outputId = token.value;
|
|
idNode.line = token.line;
|
|
idNode.lineContent = token.lineContent;
|
|
SolNode valueNode = Parser({tokens[i + 2]}).parse().children[0];
|
|
idNode.addNode(valueNode);
|
|
structNode.addNode(idNode);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
|
|
else if (getNodeType(token.value) == SolNodeType::FunctionDef) {
|
|
std::vector<Token> functionTokens;
|
|
functionTokens.push_back(token);
|
|
int funcCount = 0;
|
|
i++;
|
|
|
|
while (i < tokens.size()) {
|
|
functionTokens.push_back(tokens[i]);
|
|
|
|
if (tokens[i].value == "{") {
|
|
funcCount++;
|
|
}
|
|
if (tokens[i].value == "}") {
|
|
funcCount--;
|
|
if (funcCount == 0) {
|
|
break;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (funcCount != 0) {
|
|
Error::syntaxError("Unclosed function in struct", token.line, token.lineContent);
|
|
}
|
|
|
|
SolNode functionNode = Parser(functionTokens).parse().children[0];
|
|
structNode.addNode(functionNode);
|
|
} else {
|
|
Error::syntaxError("Structs only support set statements and function definition", token.line, token.lineContent);
|
|
}
|
|
}
|
|
|
|
rootNode.addNode(structNode);
|
|
break;
|
|
}
|
|
|
|
case SolNodeType::New: {
|
|
SolNode putsNode(SolNodeType::New);
|
|
putsNode.line = tokenObj.line;
|
|
putsNode.lineContent = tokenObj.lineContent;
|
|
auto typeopt = consume();
|
|
rootNode.addNode(putsNode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
char* droppedVar = (char*) malloc(tmpVar.size() + 1);
|
|
strcpy(droppedVar, tmpVar.c_str());
|
|
groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, droppedVar));
|
|
groundAddInstructionToProgram(&gp, gi);
|
|
}
|
|
}
|
|
return gp;
|
|
}
|
|
|
|
} // namespace Parser
|
|
|
|
}
|