Command line argument parsing

This commit is contained in:
2026-03-04 12:25:59 +11:00
parent cfca3c1d7a
commit f1eee4f6a8

View File

@@ -2,10 +2,88 @@
#include "lexer/lexer.h"
#include "parser/parser.h"
#include "codegen/codegen.h"
#include "include/error.h"
#include "include/estr.h"
#include <stdio.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <sys/stat.h>
#endif
#include <groundvm.h>
typedef enum SolsAction {
SA_PRINT, SA_EXEC, SA_BYTECODE, SA_COMPILE
} SolsAction;
typedef struct Args {
SolsAction action;
char* inputFile;
char* outputFile;
} Args;
Args parseArgs(int argc, char** argv) {
Args args = {
.action = SA_EXEC,
.inputFile = NULL,
.outputFile = NULL
};
for (int i = 0; i < argc; i++) {
if (strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
printf("Solstice programming language\n");
printf("Usage: %s <file> [-h] [--help] [-p] [--print] [-b <file>] [--bytecode <file>] [-c <file>] [--compile <file>]\n", argv[0]);
printf("Args:\n");
printf(" <file>: Solstice source file\n");
printf(" -h or --help: Prints this help message and exits\n");
printf(" -p or --print: Prints textual version of Ground bytecode to console\n");
printf(" -b <file> or --bytecode <file>: Generates Ground bytecode (.grbc) and saves it to the provided filename\n");
printf(" -c <file> or --compile <file>: Compiles Ground to Linux x86_64 assembly, outputs a binary to the provided filename (experimental)\n");
printf(" If no extra arguments are provided, the generated Ground bytecode will be executed.\n");
exit(0);
}
else if (strcmp("-p", argv[i]) == 0 || strcmp("--print", argv[i]) == 0) {
args.action = SA_PRINT;
}
else if (strcmp("-b", argv[i]) == 0 || strcmp("--bytecode", argv[i]) == 0) {
if (args.action != SA_EXEC) {
printf("Expecting only one action\n");
exit(1);
}
args.action = SA_BYTECODE;
if (i + 1 >= argc) {
printf("Expecting file name after %s\n", argv[i]);
exit(1);
}
i++;
args.outputFile = argv[i];
}
else if (strcmp("-c", argv[i]) == 0 || strcmp("--compile", argv[i]) == 0) {
if (args.action != SA_EXEC) {
printf("Expecting only one action\n");
exit(1);
}
args.action = SA_COMPILE;
if (i + 1 >= argc) {
printf("Expecting file name after %s\n", argv[i]);
exit(1);
}
i++;
args.outputFile = argv[i];
}
else {
args.inputFile = argv[i];
}
}
if (args.inputFile == NULL) {
printf("Usage: %s <file> [-h] [--help] [-p] [--print] [-b <file>] [--bytecode <file>] [-c <file>] [--compile <file>]\n", argv[0]);
exit(1);
}
return args;
}
char* getFileContents(const char* filename) {
// https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c
FILE* fp;
@@ -41,24 +119,8 @@ char* getFileContents(const char* filename) {
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: %s [file]\n", argv[0]);
exit(1);
}
char* fileContents = NULL;
bool printProgram = false;
if (strcmp(argv[1], "-p") == 0) {
if (argc < 3) {
printf("Usage: %s -p [file]\n", argv[0]);
exit(1);
}
printProgram = true;
fileContents = getFileContents(argv[2]);
} else {
fileContents = getFileContents(argv[1]);
}
Args args = parseArgs(argc, argv);
char* fileContents = getFileContents(args.inputFile);
if (fileContents == NULL) {
printf("Couldn't read that file :(\n");
@@ -102,16 +164,81 @@ int main(int argc, char** argv) {
exit(1);
}
if (printProgram) {
switch (args.action) {
case SA_PRINT: {
groundPrintProgram(&codegen.as.success);
exit(0);
break;
}
// Run program on GroundVM
case SA_EXEC: {
GroundValue retval = groundRunProgram(&codegen.as.success);
if (retval.type == INT) {
return retval.data.intVal;
} else {
return 0;
}
break;
}
case SA_BYTECODE: {
serializeProgramToFile(args.outputFile, &codegen.as.success);
break;
}
case SA_COMPILE: {
char* compiled = groundCompileProgram(&codegen.as.success);
// Make work directory
Estr dir = CREATE_ESTR(".solsbuild_");
APPEND_ESTR(dir, args.outputFile);
#ifdef _WIN32
int dirstatus = _mkdir(estr.str);
#else
int dirstatus = mkdir(dir.str, 0755);
#endif
if (dirstatus != 0) {
printf("Couldn't create temporary work directory\n");
exit(1);
}
// Write generated asm to .s
Estr tmpasm = CREATE_ESTR(dir.str);
APPEND_ESTR(tmpasm, "/generated.s");
FILE* file = fopen(tmpasm.str, "w");
if (file == NULL) {
printf("Couldn't write to temporary assembly file");
}
fprintf(file, "%s", compiled);
fclose(file);
// Assemble with nasm
Estr nasmcmd = CREATE_ESTR("nasm -f elf64 -o ");
APPEND_ESTR(nasmcmd, dir.str);
APPEND_ESTR(nasmcmd, "/generated.o ");
APPEND_ESTR(nasmcmd, tmpasm.str);
int nasmstatus = system(nasmcmd.str);
if (nasmstatus != 0) {
printf("command \"%s\" exited with code %d\n", nasmcmd.str, nasmstatus);
exit(1);
}
// Link with ld
Estr ldcmd = CREATE_ESTR("ld -o ");
APPEND_ESTR(ldcmd, args.outputFile);
APPEND_ESTR(ldcmd, " ");
APPEND_ESTR(ldcmd, dir.str);
APPEND_ESTR(ldcmd, "/generated.o");
int ldstatus = system(ldcmd.str);
if (ldstatus != 0) {
printf("command \"%s\" exited with code %d\n", ldcmd.str, ldstatus);
exit(1);
}
// Yay we compiled it
break;
}
}
return 0;
}