diff --git a/src/argparser.cpp b/src/argparser.cpp index 764a671..04383f1 100644 --- a/src/argparser.cpp +++ b/src/argparser.cpp @@ -5,6 +5,8 @@ #include "argparser.h" namespace ArgParser { + + bool nostdlib = false; void printHelp() { std::cout << "Solstice compiler\n"; @@ -20,7 +22,14 @@ namespace ArgParser { std::cout << " -t type or --type type\n"; std::cout << " Specifies the type of output.\n"; std::cout << " Currently supported options:\n"; - std::cout << " text\n"; + std::cout << " ground, native (BETA) (Requires --nostdlib)\n"; + std::cout << " Choosing the 'ground' option outputs the compiled program as a .grnd textual representation file.\n"; + std::cout << " Choosing the 'native' option uses Ground's ground->asm compiler to create a native executable.\n"; + std::cout << " This feature is currently in beta, as Ground's ground->asm compiler is not fully complete.\n"; + std::cout << " This feature requires the '--nostdlib' flag as Ground's ground->asm compiler does not support functions.\n"; + std::cout << " See https://sols.dev/docs#nativecompiler for more details\n"; + std::cout << " --nostdlib\n"; + std::cout << " Excludes the Solstice stdlib from compilation.\n"; } Args parseArgs(int argc, char** argv) { @@ -35,13 +44,12 @@ namespace ArgParser { printHelp(); exit(1); } - if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) { + else if (strcmp(argv[i], "--nostdlib") == 0) { + nostdlib = true; + } + else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) { i++; if (i < argc) { - if (args.output.has_value()) { - std::cout << "(error) Multiple output values provided\n"; - exit(1); - } args.output = Argument(ArgType::OUTPUT, std::string(argv[i])); continue; } else { @@ -52,10 +60,6 @@ namespace ArgParser { else if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--type") == 0) { i++; if (i < argc) { - if (args.output.has_value()) { - std::cout << "(error) Multiple type values provided\n"; - exit(1); - } args.outputtype = Argument(ArgType::OUTPUTTYPE, std::string(argv[i])); continue; } else { diff --git a/src/argparser.h b/src/argparser.h index 1ebb625..6fb92c7 100644 --- a/src/argparser.h +++ b/src/argparser.h @@ -4,6 +4,8 @@ #include namespace ArgParser { + + extern bool nostdlib; enum class ArgType { FILE, OUTPUT, OUTPUTTYPE diff --git a/src/main.cpp b/src/main.cpp index 5cc8a52..384768c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "lexer.h" #include "parser.h" @@ -31,32 +32,51 @@ int main(int argc, char** argv) { GroundProgram program = Solstice::Parser::assembleProgram(parsed); Solstice::Error::summariseErrors(); if (args.output.has_value()) { - std::FILE* originalStdout = stdout; - std::FILE* tmp = std::tmpfile(); - if (!tmp) { - std::cout << "Failed to create tmp file\n"; - exit(1); - } - stdout = tmp; - groundPrintProgram(&program); - std::fflush(tmp); - std::fseek(tmp, 0, SEEK_END); - long size = std::ftell(tmp); - std::fseek(tmp, 0, SEEK_SET); - - std::string result(size, '\0'); - std::fread(&result[0], 1, size, tmp); + if (!args.outputtype.has_value() || args.outputtype.value().value == "ground") { + std::FILE* originalStdout = stdout; + std::FILE* tmp = std::tmpfile(); + if (!tmp) { + std::cout << "Failed to create tmp file\n"; + exit(1); + } + stdout = tmp; + groundPrintProgram(&program); + std::fflush(tmp); + std::fseek(tmp, 0, SEEK_END); + long size = std::ftell(tmp); + std::fseek(tmp, 0, SEEK_SET); + + std::string result(size, '\0'); + std::fread(&result[0], 1, size, tmp); - stdout = originalStdout; - std::fclose(tmp); + stdout = originalStdout; + std::fclose(tmp); - std::ofstream outputFile(args.output.value().value); - if (!outputFile) { - std::cout << "Failed to write to " << args.output.value().value << "\n"; + std::ofstream outputFile(args.output.value().value); + if (!outputFile) { + std::cout << "Failed to write to " << args.output.value().value << "\n"; + } + outputFile << result; + outputFile.close(); + exit(0); + } else if (args.outputtype.value().value == "native") { + std::string assembly(groundCompileProgram(&program)); + std::string folder = "." + args.output.value().value + "_solsbuild"; + std::filesystem::create_directory(folder); + std::ofstream asmfile(folder + "/program.s"); + if (asmfile) { + asmfile << assembly; + asmfile.close(); + } else { + std::cout << "Failed to create temporary file for assembly\n"; + exit(1); + } + std::string command = "nasm -f elf64 -o " + folder + "/program.o " + folder + "/program.s"; + std::system(command.c_str()); + command = "ld -o " + args.output.value().value + " " + folder + "/program.o"; + std::system(command.c_str()); + exit(0); } - outputFile << result; - outputFile.close(); - exit(0); } else { GroundValue gv = groundRunProgram(&program); if (gv.type == INT) { diff --git a/src/parser.cpp b/src/parser.cpp index e9e66dc..e5ba11f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2,6 +2,7 @@ #include "error.h" #include "lexer.h" #include "solstice_stdlib.h" +#include "argparser.h" #include #include #include @@ -209,9 +210,11 @@ namespace Solstice { std::vector code; if (nodeType == SolNodeType::Root) { // Compile and insert standard library - auto parsedStdlib = Parser(Lexer(getStdLib()).lex()).parse(); - parsedStdlib.nodeType = SolNodeType::None; - code = parsedStdlib.generateCode(); + if (!ArgParser::nostdlib) { + auto parsedStdlib = Parser(Lexer(getStdLib()).lex()).parse(); + parsedStdlib.nodeType = SolNodeType::None; + code = parsedStdlib.generateCode(); + } } if (nodeType != SolNodeType::If && nodeType != SolNodeType::While) for (auto& child : children) { auto childCode = child.generateCode();