We can codegen now
This commit is contained in:
4
build.c
4
build.c
@@ -10,7 +10,7 @@ if [[ ! -v CFLAGS ]]; then
|
|||||||
CFLAGS="-O3 -Wall -Wextra -pedantic"
|
CFLAGS="-O3 -Wall -Wextra -pedantic"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
gcc "$0" -o "$OUTPUT" $CFLAGS
|
gcc "$0" -o "$OUTPUT" $CFLAGS -lgroundvm
|
||||||
|
|
||||||
if not [ $# -lt 1 ]; then
|
if not [ $# -lt 1 ]; then
|
||||||
exec "./$OUTPUT" "$@"
|
exec "./$OUTPUT" "$@"
|
||||||
@@ -43,7 +43,7 @@ exit
|
|||||||
#include "src/parser/parser.c"
|
#include "src/parser/parser.c"
|
||||||
|
|
||||||
// -- CODEGEN --
|
// -- CODEGEN --
|
||||||
|
#include "src/codegen/codegen.c"
|
||||||
|
|
||||||
// -- MAIN --
|
// -- MAIN --
|
||||||
#include "src/main.c"
|
#include "src/main.c"
|
||||||
|
|||||||
53
src/codegen/codegen.c
Normal file
53
src/codegen/codegen.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include "codegen.h"
|
||||||
|
|
||||||
|
#include <groundvm.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
28
src/codegen/codegen.h
Normal file
28
src/codegen/codegen.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef CODEGEN_H
|
||||||
|
#define CODEGEN_H
|
||||||
|
|
||||||
|
#include <groundvm.h>
|
||||||
|
#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
|
||||||
18
src/main.c
18
src/main.c
@@ -1,6 +1,9 @@
|
|||||||
#include "lexer/lexer.h"
|
#include "lexer/lexer.h"
|
||||||
#include "parser/parser.h"
|
#include "parser/parser.h"
|
||||||
|
#include "codegen/codegen.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <groundvm.h>
|
||||||
|
|
||||||
char* getFileContents(const char* filename) {
|
char* getFileContents(const char* filename) {
|
||||||
// https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c
|
// 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);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ typedef struct SolsNode {
|
|||||||
} children;
|
} children;
|
||||||
LineInfo line;
|
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;
|
GroundArg accessArg;
|
||||||
} SolsNode;
|
} SolsNode;
|
||||||
|
|
||||||
|
|||||||
@@ -155,6 +155,33 @@ static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
|
|||||||
return Error(Nothing, charptr, err.str);
|
return Error(Nothing, charptr, err.str);
|
||||||
}
|
}
|
||||||
node.as.success.line = peek.as.success.line;
|
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);
|
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||||
return Success(Nothing, charptr, {});
|
return Success(Nothing, charptr, {});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user