From 0613fcd95794387087ebc496d168675934071109 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Tue, 24 Feb 2026 20:07:02 +1100 Subject: [PATCH] We can codegen now --- build.c | 4 ++-- src/codegen/codegen.c | 53 +++++++++++++++++++++++++++++++++++++++++++ src/codegen/codegen.h | 28 +++++++++++++++++++++++ src/main.c | 18 ++++++++++++++- src/parser/SolsNode.h | 2 +- src/parser/parser.c | 27 ++++++++++++++++++++++ 6 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/codegen/codegen.c create mode 100644 src/codegen/codegen.h diff --git a/build.c b/build.c index 30aa71f..943ba18 100755 --- a/build.c +++ b/build.c @@ -10,7 +10,7 @@ if [[ ! -v CFLAGS ]]; then CFLAGS="-O3 -Wall -Wextra -pedantic" fi -gcc "$0" -o "$OUTPUT" $CFLAGS +gcc "$0" -o "$OUTPUT" $CFLAGS -lgroundvm if not [ $# -lt 1 ]; then exec "./$OUTPUT" "$@" @@ -43,7 +43,7 @@ exit #include "src/parser/parser.c" // -- CODEGEN -- - +#include "src/codegen/codegen.c" // -- MAIN -- #include "src/main.c" diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c new file mode 100644 index 0000000..13a2469 --- /dev/null +++ b/src/codegen/codegen.c @@ -0,0 +1,53 @@ +#include "codegen.h" + +#include +#include "../parser/SolsNode.h" +#include "../include/estr.h" + +// FIXME add proper erroring function +char* createCodegenError(char* what) { + Estr estr = CREATE_ESTR(what); + APPEND_ESTR(estr, "\nthats an error"); + return estr.str; +} + +static inline ResultType(GroundProgram, charptr) generateLiteralNode(SolsNode* node) { + // We don't even need to do anything lmao + return Success(GroundProgram, charptr, groundCreateProgram()); +} + +static inline ResultType(GroundProgram, charptr) generatePutsNode(SolsNode* node) { + if (node->children.count < 1) { + return Error(GroundProgram, charptr, "puts requires arguments"); + } + GroundInstruction inst = groundCreateInstruction(PRINTLN); + for (size_t i = 0; i < node->children.count; i++) { + groundAddReferenceToInstruction(&inst, node->children.at[i].accessArg); + } + GroundProgram program = groundCreateProgram(); + groundAddInstructionToProgram(&program, inst); + return Success(GroundProgram, charptr, program); +} + +ResultType(GroundProgram, charptr) generateCode(SolsNode* node) { + + GroundProgram program = groundCreateProgram(); + + // Generate code for all children before generating this node's code + for (size_t i = 0; i < node->children.count; i++) { + ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i]); + if (generated.error) { + return Error(GroundProgram, charptr, createCodegenError(generated.as.error)); + } + for (size_t j = 0; j < generated.as.success.size; j++) { + groundAddInstructionToProgram(&program, generated.as.success.instructions[j]); + } + } + + // Now generate code for this node + switch (node->type) { + case SNT_PUTS: generate(Puts); + case SNT_LITERAL: generate(Literal); + } + return Success(GroundProgram, charptr, program); +} diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h new file mode 100644 index 0000000..27f26d3 --- /dev/null +++ b/src/codegen/codegen.h @@ -0,0 +1,28 @@ +#ifndef CODEGEN_H +#define CODEGEN_H + +#include +#include "../parser/SolsNode.h" + +Result(GroundProgram, charptr); + +// Generates a GroundProgram (from the Ground VM header) from +// a provided SolsNode. +// Returns: +// Success: Generated GroundProgram +// Failure: charptr detailing what happened +ResultType(GroundProgram, charptr) generateCode(SolsNode* node); + +// Macro to help with code generation (and soon error handling) +#define generate(nodetype) {\ + ResultType(GroundProgram, charptr) __result = generate##nodetype##Node(node);\ + if (__result.error) {\ + return Error(GroundProgram, charptr, __result.as.error);\ + }\ + for (size_t i = 0; i < __result.as.success.size; i++) {\ + groundAddInstructionToProgram(&program, __result.as.success.instructions[i]);\ + }\ + break;\ +} + +#endif diff --git a/src/main.c b/src/main.c index 0e12e59..e4626be 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,9 @@ #include "lexer/lexer.h" #include "parser/parser.h" +#include "codegen/codegen.h" + #include +#include char* getFileContents(const char* filename) { // https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c @@ -69,5 +72,18 @@ int main(int argc, char** argv) { exit(1); } - return 0; + // Do codegen on root node + ResultType(GroundProgram, charptr) codegen = generateCode(&parser.as.success.output); + if (codegen.error) { + printf("%s\n", codegen.as.error); + exit(1); + } + + // Run program on GroundVM + GroundValue retval = groundRunProgram(&codegen.as.success); + if (retval.type == INT) { + return retval.data.intVal; + } else { + return 0; + } } diff --git a/src/parser/SolsNode.h b/src/parser/SolsNode.h index 3cd3282..bf983b5 100644 --- a/src/parser/SolsNode.h +++ b/src/parser/SolsNode.h @@ -39,7 +39,7 @@ typedef struct SolsNode { } children; LineInfo line; - // Used by the code generator, do not use in the parser! + // Used by the code generator, unless value is a literal do not use in parser GroundArg accessArg; } SolsNode; diff --git a/src/parser/parser.c b/src/parser/parser.c index 6544b94..3e8e209 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -155,6 +155,33 @@ static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) { return Error(Nothing, charptr, err.str); } node.as.success.line = peek.as.success.line; + GroundValue value; + switch (peek.as.success.as.literal.type) { + case SLT_INT: { + value = groundCreateValue(INT, peek.as.success.as.literal.as.intv); + break; + } + case SLT_DOUBLE: { + value = groundCreateValue(DOUBLE, peek.as.success.as.literal.as.doublev); + break; + } + case SLT_STRING: { + value = groundCreateValue(STRING, peek.as.success.as.literal.as.stringv); + break; + } + case SLT_BOOL: { + value = groundCreateValue(BOOL, peek.as.success.as.literal.as.boolv); + break; + } + case SLT_CHAR: { + value = groundCreateValue(CHAR, peek.as.success.as.literal.as.charv); + break; + } + } + node.as.success.accessArg = (GroundArg) { + .type = VALUE, + .value.value = value + }; addChildToSolsNode(parser->currentParent, node.as.success); return Success(Nothing, charptr, {}); }