aboutsummaryrefslogtreecommitdiff
path: root/obc.c
diff options
context:
space:
mode:
authorAryadev Chavali <aryadev@aryadevchavali.com>2024-12-03 04:23:22 +0000
committerAryadev Chavali <aryadev@aryadevchavali.com>2024-12-03 04:23:22 +0000
commit2cbb2e9ffa75964b95d2e48c142f797352a0201a (patch)
tree211d9d4e8270eb83ee949402e990a7cd424c8d9c /obc.c
parent959b1f8b2c45d2687d1c322d78d21f1dac02ba15 (diff)
downloadobf-2cbb2e9ffa75964b95d2e48c142f797352a0201a.tar.gz
obf-2cbb2e9ffa75964b95d2e48c142f797352a0201a.tar.bz2
obf-2cbb2e9ffa75964b95d2e48c142f797352a0201a.zip
Implement compiler (obc)
Diffstat (limited to 'obc.c')
-rw-r--r--obc.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/obc.c b/obc.c
new file mode 100644
index 0000000..227f980
--- /dev/null
+++ b/obc.c
@@ -0,0 +1,121 @@
+/* obc.c
+ * Created: 2024-12-03
+ * Author: Aryadev Chavali
+ * Description: Entrypoint of compiler
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "./assembler.h"
+#include "./lib.h"
+#include "./parser.h"
+
+void usage(const char *name, FILE *fp)
+{
+ fprintf(
+ fp,
+ "Usage: %s [-s ASM-NAME | -c OBJ-NAME | -o EXEC-NAME] FILE\n"
+ "\tGiven BrainFuck source code FILE, compile it.\n"
+ "\tOptions:\n"
+ "\t\t-s ASM-NAME: Transpile to assembly, store in ASM-NAME\n"
+ "\t\t-c OBJ-NAME: Transpile and assemble, store in OBJ-NAME\n"
+ "\t\t-o EXEC-NAME: Transpile, assemble and link, store in EXEC-NAME\n",
+ name);
+}
+
+struct Config
+{
+ char *prog_name, *asm_name, *obj_name, *exec_name;
+};
+
+int parse_config(struct Config *config, int argc, char *argv[])
+{
+ for (int i = 1; i < argc; ++i)
+ {
+ size_t size = strlen(argv[i]);
+ if (argv[i][0] == '-')
+ {
+ if (size > 2 || !strspn(argv[i] + 1, "cso") || i == argc - 1)
+ return 0;
+ switch (argv[i][1])
+ {
+ case 's':
+ config->asm_name = argv[i + 1];
+ ++i;
+ break;
+ case 'c':
+ config->obj_name = argv[i + 1];
+ ++i;
+ break;
+ case 'o':
+ config->exec_name = argv[i + 1];
+ ++i;
+ break;
+ }
+ }
+ else
+ config->prog_name = argv[i];
+ }
+ if (!config->prog_name)
+ return 0;
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc == 1)
+ {
+ usage(argv[0], stderr);
+ return 1;
+ }
+
+ struct Config config = {0};
+ int ret = parse_config(&config, argc, argv);
+ if (!ret)
+ {
+ usage(argv[0], stderr);
+ goto end;
+ }
+ ret = 0;
+
+ char *file_data = NULL;
+ buffer_t *buffer = NULL, *asm_buffer = NULL;
+ struct PResult res = {0};
+
+ FILE *handle = fopen(config.prog_name, "r");
+ if (!handle)
+ {
+ fprintf(stderr, "ERROR: Could not open \"%s\"\n", config.prog_name);
+ ret = 1;
+ goto end;
+ }
+ file_data = fread_all(handle);
+ fclose(handle);
+ buffer = buffer_init_str(config.prog_name, file_data, strlen(file_data));
+ res = parse_buffer(buffer);
+
+ if (res.nodes == NULL)
+ {
+ fputs("[WARNING]: Empty source file.", stderr);
+ ret = 1;
+ goto end;
+ }
+
+ asm_setup_buffer(&asm_buffer, config.asm_name ? config.asm_name : "a.asm");
+ asm_translate_nodes(&asm_buffer, res, config.prog_name);
+ asm_write(&asm_buffer);
+ asm_assemble(asm_buffer->name, config.obj_name ? config.obj_name : "a.o");
+ asm_link(config.obj_name ? config.obj_name : "a.o",
+ config.exec_name ? config.exec_name : "a.out");
+end:
+ if (asm_buffer)
+ free(asm_buffer);
+ if (res.nodes)
+ free(res.nodes);
+ if (buffer)
+ free(buffer);
+ if (file_data)
+ free(file_data);
+ return ret;
+}