#include "parser.h" #include "error.h" #include #include #include #define parseOneToken(token) Parser({token.value()}).parse().children[0] namespace Solstice { namespace Parser { bool isTemp(std::string id) { return id.rfind("tmp_", 0) == 0; } std::map variables; SolDataType 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"); } break; } case SolNodeType::Equal: case SolNodeType::Inequal: case SolNodeType::Greater: case SolNodeType::Lesser: case SolNodeType::EqGreater: case SolNodeType::EqLesser: return SolDataType::Bool; break; case SolNodeType::Add: { if (checkNodeReturnType(i.children[0]) == SolDataType::String && checkNodeReturnType(i.children[1]) == SolDataType::String) { return SolDataType::String; } } case SolNodeType::Subtract: case SolNodeType::Multiply: case SolNodeType::Divide: { if (checkNodeReturnType(i.children[0]) == SolDataType::Double) { return SolDataType::Double; } if (checkNodeReturnType(i.children[1]) == SolDataType::Double) { return SolDataType::Double; } return SolDataType::Int; break; } case SolNodeType::Puts: case SolNodeType::If: case SolNodeType::While: case SolNodeType::CodeBlock: default: return SolDataType::None; break; } return SolDataType::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) {} std::optional SolData::getInt() { if (type == SolDataType::Int) { return std::get(data); } else { return {}; } } std::optional SolData::getDouble() { if (type == SolDataType::Double) { return std::get(data); } else { return {}; } } std::optional SolData::getString() { if (type == SolDataType::String) { return std::get(data); } else { return {}; } } std::optional SolData::getChar() { if (type == SolDataType::Char) { return std::get(data); } else { return {}; } } std::optional SolData::getBool() { if (type == SolDataType::Bool) { return std::get(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 SolNode::generateCode() { std::vector 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) { 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: { 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); 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: { 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); 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: { 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); 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: { 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); 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: { 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); 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: { 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); 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: { 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); 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; 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); if (isTemp(children[0].outputId)) codeBlock.toBeDropped.push_back(children[0].outputId); code.push_back(codeBlock); break; } case SolNodeType::If: { ensure(children[0], SolDataType::Bool); 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, 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(); 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], SolDataType::Bool); 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, 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: { if (variables.find(children[0].outputId) != variables.end()) { if (variables[children[0].outputId] != checkNodeReturnType(children[1])) { Error::typingError("Cannot change type of this variable"); } } 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); 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] = children[1].data.type; 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); if (isTemp(children[1].outputId)) inputCodeBlock.toBeDropped.push_back(children[1].outputId); } 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 in) : tokensToParse(in) {} std::optional Parser::peek(int ahead) { if (current + ahead < size) { return tokensToParse[current + ahead]; } else { return {}; } } std::optional 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; } 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 == "{") { 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; } 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"; exit(1); } equalNode.addNode(rootNode.children.back()); rootNode.children.pop_back(); std::vector tokens; while (auto tokenopt = consume()) { if (tokenopt.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); std::vector 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 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 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 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 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 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 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); char* droppedVar = (char*) malloc(tmpVar.size() + 1); strcpy(droppedVar, tmpVar.c_str()); groundAddReferenceToInstruction(&gi, groundCreateReference(DIRREF, droppedVar)); groundAddInstructionToProgram(&gp, gi); } } return gp; } } // namespace Parser }