From 724162f42eb7068b2f1df575c02dfe3410f526e1 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Tue, 20 Jan 2026 19:55:38 +1100 Subject: [PATCH 01/11] Refactor fn arg checking --- src/interpreter.c | 6 ++++-- src/types.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/types.h | 7 +++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index 5e6ac0a..fe76d0c 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -1753,7 +1753,8 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop if (in->args.args[i + 1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction); } - if (in->args.args[i + 1].value.value.type != function->args[i].type) { + //if (in->args.args[i + 1].value.value.type != function->args[i].type) { + if (!checkFnTypes(&in->args.args[i + 1].value.value, &function->args[i])) { runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction); } appendToList(&argsList, in->args.args[i + 1].value.value); @@ -1781,7 +1782,8 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop if (in->args.args[i + 1].type != VALUE) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction); } - if (in->args.args[i + 1].value.value.type != function->args[i].type) { + //if (in->args.args[i + 1].value.value.type != function->args[i].type) { + if (!checkFnTypes(&in->args.args[i + 1].value.value, &function->args[i])) { runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction); } addVariable(newScope.variables, function->args[i].name, in->args.args[i + 1].value.value); diff --git a/src/types.c b/src/types.c index 01becb4..4a55807 100644 --- a/src/types.c +++ b/src/types.c @@ -582,3 +582,43 @@ GroundError createGroundError(char* what, char* type, GroundInstruction* where, return ge; } + +bool checkFnTypes(GroundValue* left, GroundFunctionArgs* right) { + if (left->type != right->type) { + return false; + } + if (left->type == CUSTOM) { + if (left->customType->size != right->customType->size) { + return false; + } + for (size_t i = 0; i < left->customType->size; i++) { + if (strcmp(left->customType->fields[i].id, right->customType->fields[i].id) != 0) { + return false; + } + if (!checkTypes(&left->customType->fields[i].value, &right->customType->fields[i].value)) { + return false; + } + } + } + return true; +} + +bool checkTypes(GroundValue* left, GroundValue* right) { + if (left->type != right->type) { + return false; + } + if (left->type == CUSTOM) { + if (left->customType->size != right->customType->size) { + return false; + } + for (size_t i = 0; i < left->customType->size; i++) { + if (strcmp(left->customType->fields[i].id, right->customType->fields[i].id) != 0) { + return false; + } + if (!checkTypes(&left->customType->fields[i].value, &right->customType->fields[i].value)) { + return false; + } + } + } + return true; +} diff --git a/src/types.h b/src/types.h index 0b3c903..a24ab32 100644 --- a/src/types.h +++ b/src/types.h @@ -62,6 +62,7 @@ typedef struct GroundError { */ typedef struct GroundValue { GroundValueType type; + struct GroundStruct* customType; union { int64_t intVal; double doubleVal; @@ -125,6 +126,7 @@ typedef struct GroundProgram { */ typedef struct GroundFunctionArgs { GroundValueType type; + struct GroundStruct* customType; char* name; } GroundFunctionArgs; @@ -276,6 +278,11 @@ void freeGroundObject(GroundObject* object); // Creates a GroundError. GroundError createGroundError(char* what, char* type, GroundInstruction* where, size_t* line); +// Compares types of a value and function args. +bool checkFnTypes(GroundValue* left, GroundFunctionArgs* arg); + +// Compares types of two values. +bool checkTypes(GroundValue* left, GroundValue* right); #endif -- 2.47.3 From ec23d55f9dc9ccc786b1e97d550e25444cd98c57 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Tue, 20 Jan 2026 19:57:49 +1100 Subject: [PATCH 02/11] Fix bug about passing objs to functions --- src/interpreter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/interpreter.c b/src/interpreter.c index fe76d0c..0e98a30 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -382,6 +382,7 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs gv.type = CUSTOM; gv.data.customVal = malloc(sizeof(GroundObject)); *gv.data.customVal = createObject(*gstruct); + gv.customType = gstruct; break; } case NONE: { @@ -1981,6 +1982,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop gv.type = CUSTOM; gv.data.customVal = malloc(sizeof(GroundObject)); *gv.data.customVal = createObject(*gstruct); + gv.customType = gstruct; break; } case NONE: { -- 2.47.3 From c6762a796600c5fde68b7ebbdbd24ba9ca8045b9 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Tue, 20 Jan 2026 21:26:40 +1100 Subject: [PATCH 03/11] extlibs can now add variables and structs! --- src/interface.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/interpreter.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/interface.c b/src/interface.c index 280c885..e97e9b9 100644 --- a/src/interface.c +++ b/src/interface.c @@ -1,4 +1,3 @@ -#include "lexer.h" #include "parser.h" #include "interpreter.h" #include "types.h" @@ -68,11 +67,34 @@ GroundValue groundCreateValue(GroundValueType type, ...) { return createListGroundValue(va_arg(args, List)); break; } - default: { + case FUNCTION: { + return createFunctionGroundValue(va_arg(args, GroundFunction*)); + break; + } + case STRUCTVAL: { + GroundValue gv; + gv.type = STRUCTVAL; + gv.data.structVal = malloc(sizeof(GroundStruct)); + *gv.data.structVal = va_arg(args, GroundStruct); + return gv; + } + case CUSTOM: { + // FIXME do this later lmao return createNoneGroundValue(); + break; + } + case ERROR: { + return createErrorGroundValue(va_arg(args, GroundError)); + break; + } + case NONE: { + return createNoneGroundValue(); + break; } } + return createNoneGroundValue(); + va_end(args); } @@ -90,3 +112,18 @@ void groundPrintProgram(GroundProgram* program) { GroundProgram groundParseFile(const char* code) { return parseFile(code); } + +GroundStruct groundCreateStruct() { + GroundStruct gs; + gs.size = 0; + gs.fields = malloc(sizeof(GroundStructField)); + return gs; +} + +void groundAddValueToScope(GroundScope* gs, const char* name, GroundValue value) { + addVariable(gs->variables, name, value); +} + +void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) { + addFieldToStruct(gstruct, name, field); +} diff --git a/src/interpreter.h b/src/interpreter.h index cde1fff..ae78460 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -42,6 +42,7 @@ GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); +void addVariable(GroundVariable **head, const char *id, GroundValue data); -- 2.47.3 From d3c03b49879f2081247c84811f6218ebb15ac4ba Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 11:17:19 +1100 Subject: [PATCH 04/11] Better cmdline args, start work on compiler --- src/compiler.c | 29 ++++++++++++++++++++++++++ src/compiler.h | 3 +++ src/include/estr.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++ src/interpreter.c | 2 +- src/main.c | 46 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/compiler.c create mode 100644 src/compiler.h create mode 100644 src/include/estr.h diff --git a/src/compiler.c b/src/compiler.c new file mode 100644 index 0000000..6934c41 --- /dev/null +++ b/src/compiler.c @@ -0,0 +1,29 @@ +#include "compiler.h" +#include "types.h" +#include "include/estr.h" + +char* compileGroundProgram(GroundProgram* program) { + Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n"); + Estr data = CREATE_ESTR("section .rodata\n"); + + for (size_t i = 0; i < program->size; i++) { + switch (program->instructions[i].type) { + case END: { + APPEND_ESTR(start, " mov rax, 60\n"); + APPEND_ESTR(start, " mov rdi, 0\n"); + APPEND_ESTR(start, " syscall\n"); + break; + } + default: { + printf("no\n"); + exit(1); + } + } + } + + Estr complete = CREATE_ESTR(""); + APPEND_ESTR(complete, start.str); + APPEND_ESTR(complete, data.str) + + return complete.str; +} diff --git a/src/compiler.h b/src/compiler.h new file mode 100644 index 0000000..366671e --- /dev/null +++ b/src/compiler.h @@ -0,0 +1,3 @@ +#include "types.h" + +char* compileGroundProgram(GroundProgram* program); diff --git a/src/include/estr.h b/src/include/estr.h new file mode 100644 index 0000000..df5d172 --- /dev/null +++ b/src/include/estr.h @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#ifndef ESTR_H +#define ESTR_H + +/* + + estr.h - Easy string manipulation + This library has macros to allow easier manipulation of strings. No longer shall + you have to malloc and realloc away to keep adding to your strings. + + Usage: + + Estr myString = CREATE_ESTR("my awesome string"); + APPEND_ESTR(myString, " is so cool"); + printf("%s\n", myString.str); + +*/ + +#define CREATE_ESTR(instr) \ + (Estr) { \ + .str = instr,\ + .size = strlen(instr),\ + .shouldBeFreed = 0, \ + .destroyed = 0 \ + } + +#define APPEND_ESTR(estr, instr) { \ + estr.size = estr.size + strlen(instr); \ + char* tmp_ptr = malloc(estr.size + 1); \ + if (tmp_ptr == NULL) printf("WARNING: Could not realloc estr " #estr "\n"); \ + else { \ + snprintf(tmp_ptr, estr.size + 1, "%s%s", estr.str, instr); \ + if (estr.shouldBeFreed > 0) free(estr.str); \ + estr.shouldBeFreed = 1; \ + estr.str = tmp_ptr; \ + } \ +} + +#define DESTROY_ESTR(estr) if (estr.shouldBeFreed > 0 && estr.destroyed < 1) free(estr.str); + +typedef struct Estr { + char* str; + size_t size; + int8_t shouldBeFreed; + int8_t destroyed; +} Estr; + +#endif // ESTR_H diff --git a/src/interpreter.c b/src/interpreter.c index 7516c75..0dbb3ca 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -352,7 +352,7 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs GroundValue gv; - switch (stringToValueType(in->instructions[i].args.args[0].value.refName)) { + switch (stringToValueType(in->instructions[i].args.args[1].value.refName)) { case INT: { gv = createIntGroundValue(0); break; diff --git a/src/main.c b/src/main.c index 85ebc42..2bdd63e 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include "parser.h" #include "interpreter.h" +#include "compiler.h" #include char* getFileContents(const char* filename) { @@ -39,6 +40,7 @@ char* getFileContents(const char* filename) { } int main(int argc, char** argv) { + /* if (argc < 2) { printf("Usage: ground [file]\n"); exit(1); @@ -46,5 +48,49 @@ int main(int argc, char** argv) { char* file = getFileContents(argv[1]); GroundProgram program = parseFile(file); free(file); + char* compiled = compileGroundProgram(&program); + printf("%s\n", compiled); interpretGroundProgram(&program, NULL); + */ + + if (argc < 2) { + printf("Usage: %s [-c] [--compile] [-h] [--help]\n", argv[0]); + exit(1); + } + + bool compile = false; + char* fileName = NULL; + + for (int i = 1; i < argc; i++) { + if (strcmp("--compile", argv[i]) == 0 || strcmp("-c", argv[i]) == 0) { + compile = true; + } + else if (strcmp("--help", argv[i]) == 0 || strcmp("-h", argv[i]) == 0) { + printf("GroundVM help\n"); + printf("Usage: %s [-c] [--compile] [-h] [--help]\n", argv[0]); + printf("Options:\n"); + printf(" -c or --compile: Outputs Linux x86_64 assembly instead of interpreting (WIP)\n"); + printf(" -h or --help: Shows this help message\n"); + exit(0); + } else { + fileName = argv[i]; + } + } + + if (fileName == NULL) { + printf("Usage: %s [-c] [--compile] [-h] [--help]\n", argv[0]); + printf("Error: No file name provided\n"); + exit(1); + } + + char* file = getFileContents(fileName); + GroundProgram program = parseFile(file); + free(file); + + if (compile) { + char* compiled = compileGroundProgram(&program); + printf("%s\n", compiled); + } else { + interpretGroundProgram(&program, NULL); + } } -- 2.47.3 From dac983b68470412214ca821d6018e63c58b05845 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 11:38:37 +1100 Subject: [PATCH 05/11] Update compiler --- src/compiler.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/compiler.h | 2 ++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/compiler.c b/src/compiler.c index 6934c41..10f5fdb 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1,16 +1,53 @@ #include "compiler.h" +#include "interpreter.h" #include "types.h" #include "include/estr.h" +#include char* compileGroundProgram(GroundProgram* program) { Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n"); Estr data = CREATE_ESTR("section .rodata\n"); + // Create data section for (size_t i = 0; i < program->size; i++) { - switch (program->instructions[i].type) { + + } + + // Generate assembly + for (size_t i = 0; i < program->size; i++) { + GroundInstruction gi = program->instructions[i]; + switch (gi.type) { case END: { + if (gi.args.length < 1) { + runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); + } + if (gi.args.length > 1) { + runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i); + } + if (gi.args.args[0].value.value.type != INT) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i); + } + + int64_t bigretint = gi.args.args[0].value.value.data.intVal; + int retint; + if (bigretint > 255) { + retint = 255; + } + else if (bigretint < 0) { + retint = 0; + } + else { + retint = bigretint; + } + char retstr[8]; + snprintf(retstr, sizeof(retstr), "%d", retint); APPEND_ESTR(start, " mov rax, 60\n"); - APPEND_ESTR(start, " mov rdi, 0\n"); + APPEND_ESTR(start, " mov rdi, "); + APPEND_ESTR(start, retstr); + APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " syscall\n"); break; } diff --git a/src/compiler.h b/src/compiler.h index 366671e..ffda11e 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,3 +1,5 @@ #include "types.h" +#include "interpreter.h" char* compileGroundProgram(GroundProgram* program); +[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine); -- 2.47.3 From 31577fcc624f10ff4b25b14015a3eeac16c21849 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 13:25:13 +1100 Subject: [PATCH 06/11] Add set to compiler --- src/compiler.c | 134 ++++++++++++++++++++++++++++++++++++++++--------- src/compiler.h | 13 +++++ 2 files changed, 124 insertions(+), 23 deletions(-) diff --git a/src/compiler.c b/src/compiler.c index 10f5fdb..d0bc121 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -3,20 +3,126 @@ #include "types.h" #include "include/estr.h" #include +#include + +VariableTable createVariableTable() { + VariableTable vt; + vt.capacity = 16; + vt.count = 0; + vt.vars = malloc(sizeof(VariableInfo) * vt.capacity); + return vt; +} + +void addVtVariable(VariableTable* vt, const char* name) { + // check if it already exists + for (size_t i = 0; i < vt->count; i++) { + if (strcmp(vt->vars[i].name, name) == 0) { + return; + } + } + + // increase capacity + if (vt->count >= vt->capacity) { + vt->capacity *= 2; + vt->vars = realloc(vt->vars, sizeof(VariableInfo) * vt->capacity); + } + + // add the variable + strcpy(vt->vars[vt->count].name, name); + vt->vars[vt->count].offset = vt->count * 8; + vt->count++; +} + +int getVariablePos(VariableTable* vt, const char* name) { + for (size_t i = 0; i < vt->count; i++) { + if (strcmp(vt->vars[i].name, name) == 0) { + return vt->vars[i].offset; + } + } + return -1; +} + +char* processValueString(GroundArg arg) { + if (arg.type == VALREF) { + char* buf = malloc(sizeof(char) * 260); + snprintf(buf, sizeof(char) * 260, "[%s]", arg.value.refName); + return buf; + } + if (arg.type == VALUE) { + if (arg.value.value.type != INT) { + printf("Only int is supported right now"); + exit(1); + } + char* buf = malloc(sizeof(char) * 64); + snprintf(buf, sizeof(char) * 260, "%" PRId64, arg.value.value.data.intVal); + return buf; + } + return NULL; +} char* compileGroundProgram(GroundProgram* program) { Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n"); - Estr data = CREATE_ESTR("section .rodata\n"); + Estr data = CREATE_ESTR("section .bss\n"); + + VariableTable varTable = createVariableTable(); + + // Allocate a spot for all direct references + for (size_t i = 0; i < program->size; i++) { + GroundInstruction gi = program->instructions[i]; + for (size_t j = 0; j < gi.args.length; j++) { + if (gi.args.args[j].type == DIRREF) { + addVtVariable(&varTable, gi.args.args[j].value.refName); + } + } + } // Create data section for (size_t i = 0; i < program->size; i++) { - + if (strcmp(varTable.vars[i].name, "") == 0) { + continue; + } + APPEND_ESTR(data, " "); + APPEND_ESTR(data, varTable.vars[i].name); + APPEND_ESTR(data, " resq 1\n"); } // Generate assembly for (size_t i = 0; i < program->size; i++) { GroundInstruction gi = program->instructions[i]; switch (gi.type) { + case SET: { + if (gi.args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &gi, i); + } + if (gi.args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &gi, i); + } + if (gi.args.args[0].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", &gi, i); + } + + char* varName= gi.args.args[0].value.refName; + GroundValue val = gi.args.args[1].value.value; + + if (val.type != INT) { + runtimeError(ARG_TYPE_MISMATCH, "For now only ints are supported", &gi, i); + } + + char valueStr[32]; + snprintf(valueStr, sizeof(valueStr), "%" PRId64, val.data.intVal); + APPEND_ESTR(start, " ; set\n") + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, valueStr); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + + break; + } case END: { if (gi.args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); @@ -24,29 +130,10 @@ char* compileGroundProgram(GroundProgram* program) { if (gi.args.length > 1) { runtimeError(TOO_MANY_ARGS, "Expecting 1 arg for end instruction", &gi, i); } - if (gi.args.args[0].type != VALUE) { - runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i); - } - if (gi.args.args[0].value.value.type != INT) { - runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for end instruction", &gi, i); - } - - int64_t bigretint = gi.args.args[0].value.value.data.intVal; - int retint; - if (bigretint > 255) { - retint = 255; - } - else if (bigretint < 0) { - retint = 0; - } - else { - retint = bigretint; - } - char retstr[8]; - snprintf(retstr, sizeof(retstr), "%d", retint); + APPEND_ESTR(start, " ; end\n"); APPEND_ESTR(start, " mov rax, 60\n"); APPEND_ESTR(start, " mov rdi, "); - APPEND_ESTR(start, retstr); + APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " syscall\n"); break; @@ -60,6 +147,7 @@ char* compileGroundProgram(GroundProgram* program) { Estr complete = CREATE_ESTR(""); APPEND_ESTR(complete, start.str); + APPEND_ESTR(complete, " ; End of program\n mov rax, 60\n mov rdi, 0\n syscall\n"); APPEND_ESTR(complete, data.str) return complete.str; diff --git a/src/compiler.h b/src/compiler.h index ffda11e..4e5e37f 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -3,3 +3,16 @@ char* compileGroundProgram(GroundProgram* program); [[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine); + +typedef struct VariableInfo { + char name[256]; + int offset; +} VariableInfo; + +typedef struct VariableTable { + VariableInfo* vars; + size_t count; + size_t capacity; +} VariableTable; + + -- 2.47.3 From bf68f1500c0e90db502c396bd864cfe13f8abc62 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 13:50:54 +1100 Subject: [PATCH 07/11] Add add instruction to compiler --- README.md | 11 +++++++++++ src/compiler.c | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7cd9ef5..e2a35bd 100644 --- a/README.md +++ b/README.md @@ -98,3 +98,14 @@ Commands: * eval (code): Runs Ground code in the current scope * help: Shows a help message +## Compiler + +CGround now includes an experimental Ground -> x86_64 Linux ASM compiler. You can try it by adding the `-c` flag when running Ground. This will print the generated ASM to the console. + +At present only the `int` data type is supported. + +Supported instructions so far: + +* set +* add +* end diff --git a/src/compiler.c b/src/compiler.c index d0bc121..49e725e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -105,17 +105,10 @@ char* compileGroundProgram(GroundProgram* program) { } char* varName= gi.args.args[0].value.refName; - GroundValue val = gi.args.args[1].value.value; - if (val.type != INT) { - runtimeError(ARG_TYPE_MISMATCH, "For now only ints are supported", &gi, i); - } - - char valueStr[32]; - snprintf(valueStr, sizeof(valueStr), "%" PRId64, val.data.intVal); APPEND_ESTR(start, " ; set\n") APPEND_ESTR(start, " mov rax, "); - APPEND_ESTR(start, valueStr); + APPEND_ESTR(start, processValueString(gi.args.args[1])); APPEND_ESTR(start, "\n"); APPEND_ESTR(start, " mov ["); APPEND_ESTR(start, varName); @@ -123,6 +116,36 @@ char* compileGroundProgram(GroundProgram* program) { break; } + case ADD: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for add instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for add instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; add\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " add rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } case END: { if (gi.args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); -- 2.47.3 From e3c8a2f4531740f68f86c726f16b5d569d94481d Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 14:02:05 +1100 Subject: [PATCH 08/11] Add multiply and subtract --- README.md | 2 ++ src/compiler.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/README.md b/README.md index e2a35bd..d84216b 100644 --- a/README.md +++ b/README.md @@ -108,4 +108,6 @@ Supported instructions so far: * set * add +* subtract +* multiply * end diff --git a/src/compiler.c b/src/compiler.c index 49e725e..96fb7d5 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -146,6 +146,66 @@ char* compileGroundProgram(GroundProgram* program) { APPEND_ESTR(start, "], rax\n"); break; } + case SUBTRACT: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for subtract instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for subtract instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; subtract\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " sub rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } + case MULTIPLY: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for multiply instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for multiply instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; add\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " imul rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } case END: { if (gi.args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); -- 2.47.3 From c728801bc32f7a0e8257c386d97b3a06d918fa9a Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 14:10:34 +1100 Subject: [PATCH 09/11] Add comparisons --- README.md | 4 ++ src/compiler.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d84216b..389f882 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,8 @@ Supported instructions so far: * add * subtract * multiply +* equal +* inequal +* greater +* lesser * end diff --git a/src/compiler.c b/src/compiler.c index 96fb7d5..84fac2e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -194,7 +194,7 @@ char* compileGroundProgram(GroundProgram* program) { } char* varName= gi.args.args[2].value.refName; - APPEND_ESTR(start, " ; add\n"); + APPEND_ESTR(start, " ; multiply\n"); APPEND_ESTR(start, " mov rax, "); APPEND_ESTR(start, processValueString(gi.args.args[0])); APPEND_ESTR(start, "\n"); @@ -206,6 +206,134 @@ char* compileGroundProgram(GroundProgram* program) { APPEND_ESTR(start, "], rax\n"); break; } + case EQUAL: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for equal instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for equal instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; equal\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " cmp rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " sete al\n"); + APPEND_ESTR(start, " movzx rax, al\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } + case INEQUAL: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for inequal instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for inequal instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; inequal\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " cmp rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " setne al\n"); + APPEND_ESTR(start, " movzx rax, al\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } + case GREATER: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for greater instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for greater instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; greater\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " cmp rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " setg al\n"); + APPEND_ESTR(start, " movzx rax, al\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } + case LESSER: { + if (gi.args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args for lesser instruction", &gi, i); + } + if (gi.args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args for lesser instruction", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 1", &gi, i); + } + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", &gi, i); + } + if (gi.args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", &gi, i); + } + + char* varName= gi.args.args[2].value.refName; + APPEND_ESTR(start, " ; lesser\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " cmp rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[1])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " setl al\n"); + APPEND_ESTR(start, " movzx rax, al\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + break; + } case END: { if (gi.args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); -- 2.47.3 From 51639e904d48c1f5fac6d7e7ec32c21271d5308e Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 14:35:48 +1100 Subject: [PATCH 10/11] Add control flow --- README.md | 3 +++ src/compiler.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 389f882..9aad1e8 100644 --- a/README.md +++ b/README.md @@ -114,4 +114,7 @@ Supported instructions so far: * inequal * greater * lesser +* jump +* if +* @ (label creation) * end diff --git a/src/compiler.c b/src/compiler.c index 84fac2e..8e31730 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -90,6 +90,11 @@ char* compileGroundProgram(GroundProgram* program) { for (size_t i = 0; i < program->size; i++) { GroundInstruction gi = program->instructions[i]; switch (gi.type) { + case CREATELABEL: { + APPEND_ESTR(start, gi.args.args[0].value.refName); + APPEND_ESTR(start, ":\n"); + break; + } case SET: { if (gi.args.length < 2) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &gi, i); @@ -100,7 +105,7 @@ char* compileGroundProgram(GroundProgram* program) { if (gi.args.args[0].type != DIRREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &gi, i); } - if (gi.args.args[1].type != VALUE) { + if (gi.args.args[1].type != VALUE && gi.args.args[1].type != VALREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", &gi, i); } @@ -116,6 +121,53 @@ char* compileGroundProgram(GroundProgram* program) { break; } + case JUMP: { + if (gi.args.length < 1) { + runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &gi, i); + } + if (gi.args.length > 1) { + runtimeError(TOO_MANY_ARGS, "Expecting 1 arg", &gi, i); + } + if (gi.args.args[0].type != LINEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a LineRef", &gi, i); + } + + char* labelName = gi.args.args[0].value.refName; + + APPEND_ESTR(start, " ; jump\n"); + APPEND_ESTR(start, " jmp "); + APPEND_ESTR(start, labelName); + APPEND_ESTR(start, "\n"); + + break; + } + case IF: { + if (gi.args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &gi, i); + } + if (gi.args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int (for now) for arg 1", &gi, i); + } + if (gi.args.args[1].type != LINEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a LineRef", &gi, i); + } + + char* labelName = gi.args.args[1].value.refName; + + APPEND_ESTR(start, " ; if\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " test rax, rax\n"); + APPEND_ESTR(start, " jnz "); + APPEND_ESTR(start, labelName); + APPEND_ESTR(start, "\n"); + + break; + } case ADD: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for add instruction", &gi, i); -- 2.47.3 From 07474d431733864f3a3888da01d5f21da6290ac7 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 15:20:00 +1100 Subject: [PATCH 11/11] Add print and println to compiler --- README.md | 2 + src/compiler.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9aad1e8..9240c35 100644 --- a/README.md +++ b/README.md @@ -117,4 +117,6 @@ Supported instructions so far: * jump * if * @ (label creation) +* print +* println * end diff --git a/src/compiler.c b/src/compiler.c index 8e31730..716aed9 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -50,7 +50,7 @@ char* processValueString(GroundArg arg) { } if (arg.type == VALUE) { if (arg.value.value.type != INT) { - printf("Only int is supported right now"); + printf("Only int is supported right now\n"); exit(1); } char* buf = malloc(sizeof(char) * 64); @@ -63,6 +63,59 @@ char* processValueString(GroundArg arg) { char* compileGroundProgram(GroundProgram* program) { Estr start = CREATE_ESTR("global _start\nsection .text\n_start:\n"); Estr data = CREATE_ESTR("section .bss\n"); + Estr helpers = CREATE_ESTR(""); + + APPEND_ESTR(helpers, "\n; Helper: Print integer in rax\n"); + APPEND_ESTR(helpers, "print_int:\n"); + APPEND_ESTR(helpers, " push rbp\n"); + APPEND_ESTR(helpers, " mov rbp, rsp\n"); + APPEND_ESTR(helpers, " sub rsp, 32 ; Allocate buffer on stack\n"); + APPEND_ESTR(helpers, " mov rdi, rsp ; RDI = buffer pointer\n"); + APPEND_ESTR(helpers, " add rdi, 31 ; Point to end of buffer\n"); + APPEND_ESTR(helpers, " mov byte [rdi], 0 ; Null terminator\n"); + APPEND_ESTR(helpers, " dec rdi\n"); + APPEND_ESTR(helpers, " mov rbx, 10 ; Divisor\n"); + APPEND_ESTR(helpers, " test rax, rax\n"); + APPEND_ESTR(helpers, " jns .positive\n"); + APPEND_ESTR(helpers, " neg rax ; Make positive\n"); + APPEND_ESTR(helpers, " push rax\n"); + APPEND_ESTR(helpers, " mov byte [rdi], '-'\n"); + APPEND_ESTR(helpers, " dec rdi\n"); + APPEND_ESTR(helpers, " pop rax\n"); + APPEND_ESTR(helpers, ".positive:\n"); + APPEND_ESTR(helpers, " xor rcx, rcx ; Digit counter\n"); + APPEND_ESTR(helpers, ".convert_loop:\n"); + APPEND_ESTR(helpers, " xor rdx, rdx\n"); + APPEND_ESTR(helpers, " div rbx ; rax = rax/10, rdx = remainder\n"); + APPEND_ESTR(helpers, " add dl, '0' ; Convert to ASCII\n"); + APPEND_ESTR(helpers, " mov [rdi], dl\n"); + APPEND_ESTR(helpers, " dec rdi\n"); + APPEND_ESTR(helpers, " inc rcx\n"); + APPEND_ESTR(helpers, " test rax, rax\n"); + APPEND_ESTR(helpers, " jnz .convert_loop\n"); + APPEND_ESTR(helpers, " inc rdi ; Point back to first digit\n"); + APPEND_ESTR(helpers, " ; Now print the string\n"); + APPEND_ESTR(helpers, " mov rax, 1 ; sys_write\n"); + APPEND_ESTR(helpers, " mov rsi, rdi ; Buffer\n"); + APPEND_ESTR(helpers, " mov rdx, rcx ; Length\n"); + APPEND_ESTR(helpers, " mov rdi, 1 ; stdout\n"); + APPEND_ESTR(helpers, " syscall\n"); + APPEND_ESTR(helpers, " mov rsp, rbp\n"); + APPEND_ESTR(helpers, " pop rbp\n"); + APPEND_ESTR(helpers, " ret\n"); + + APPEND_ESTR(helpers, "\n; Helper: Print string at address in rax, length in rbx\n"); + APPEND_ESTR(helpers, "print_string:\n"); + APPEND_ESTR(helpers, " push rax\n"); + APPEND_ESTR(helpers, " push rbx\n"); + APPEND_ESTR(helpers, " mov rdi, 1 ; stdout\n"); + APPEND_ESTR(helpers, " mov rsi, rax ; String address\n"); + APPEND_ESTR(helpers, " mov rdx, rbx ; Length\n"); + APPEND_ESTR(helpers, " mov rax, 1 ; sys_write\n"); + APPEND_ESTR(helpers, " syscall\n"); + APPEND_ESTR(helpers, " pop rbx\n"); + APPEND_ESTR(helpers, " pop rax\n"); + APPEND_ESTR(helpers, " ret\n"); VariableTable varTable = createVariableTable(); @@ -77,7 +130,7 @@ char* compileGroundProgram(GroundProgram* program) { } // Create data section - for (size_t i = 0; i < program->size; i++) { + for (size_t i = 0; i < varTable.count; i++) { if (strcmp(varTable.vars[i].name, "") == 0) { continue; } @@ -386,6 +439,42 @@ char* compileGroundProgram(GroundProgram* program) { APPEND_ESTR(start, "], rax\n"); break; } + case PRINT: + case PRINTLN: { + if (gi.args.length < 1) { + runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &gi, i); + } + + for (size_t j = 0; j < gi.args.length; j++) { + if (gi.args.args[j].type != VALUE && gi.args.args[j].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", &gi, i); + } + if (j > 0) { + // Print space between arguments + APPEND_ESTR(start, " ; print space\n"); + APPEND_ESTR(start, " mov rax, 1\n"); + APPEND_ESTR(start, " mov rdi, 1\n"); + APPEND_ESTR(start, " lea rsi, [rel space_char]\n"); + APPEND_ESTR(start, " mov rdx, 1\n"); + APPEND_ESTR(start, " syscall\n"); + } + APPEND_ESTR(start, " ; print int\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[j])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " call print_int\n"); + } + + if (gi.type == PRINTLN) { + APPEND_ESTR(start, " ; print newline\n"); + APPEND_ESTR(start, " mov rax, 1\n"); + APPEND_ESTR(start, " mov rdi, 1\n"); + APPEND_ESTR(start, " lea rsi, [rel newline_char]\n"); + APPEND_ESTR(start, " mov rdx, 1\n"); + APPEND_ESTR(start, " syscall\n"); + } + break; + } case END: { if (gi.args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg for end instruction", &gi, i); @@ -401,6 +490,10 @@ char* compileGroundProgram(GroundProgram* program) { APPEND_ESTR(start, " syscall\n"); break; } + case DROP: { + // Drop does nothing in ground->asm as we use the stack + break; + } default: { printf("no\n"); exit(1); @@ -411,6 +504,10 @@ char* compileGroundProgram(GroundProgram* program) { Estr complete = CREATE_ESTR(""); APPEND_ESTR(complete, start.str); APPEND_ESTR(complete, " ; End of program\n mov rax, 60\n mov rdi, 0\n syscall\n"); + APPEND_ESTR(complete, helpers.str); + APPEND_ESTR(complete, "\nsection .rodata\n"); + APPEND_ESTR(complete, "newline_char: db 10\n"); + APPEND_ESTR(complete, "space_char: db 32\n"); APPEND_ESTR(complete, data.str) return complete.str; -- 2.47.3