diff --git a/include/ground.h b/include/ground.h index eecab56..4863539 100644 --- a/include/ground.h +++ b/include/ground.h @@ -23,6 +23,7 @@ typedef struct GroundState GroundState; typedef struct GroundBytecodeProgram GroundBytecodeProgram; typedef struct GroundBytecodeInstruction GroundBytecodeInstruction; typedef struct GroundBytecodeHeap GroundBytecodeHeap; +typedef struct GroundBytecode GroundBytecode; // --- Literal types --- @@ -267,7 +268,7 @@ struct GroundBytecodeProgram { }; struct GroundBytecodeInstruction { - GroundInstruction instruction; + enum GroundInstructionType type; struct { GroundSize* at; GroundSize capacity; @@ -278,9 +279,13 @@ struct GroundBytecodeInstruction { struct GroundBytecodeHeap { GroundValue* heap; GroundSize capacity; - GroundSize count; + GroundSize len; }; +struct GroundBytecode { + GroundBytecodeProgram program; + GroundBytecodeHeap heap; +}; // // INTERFACE @@ -335,6 +340,8 @@ struct _Ground { GroundIdentifier* (*Identifier) (const char* id); + GroundBytecode (*Bytecode) (GroundProgram* program, GroundState* state); + } New; // Frees the memory held by the specified struct @@ -406,7 +413,7 @@ struct _Ground { } Internal; struct { - void (*Error) (const char* message); + void (*Error) (const char* message); void (*Warning) (const char* message); void (*printErrors)(); @@ -422,8 +429,13 @@ struct _Ground { void (*execute) (GroundBytecodeProgram* program, GroundBytecodeHeap* heap); void (*optimise) (GroundBytecodeProgram* program); } Program; - struct {} Instruction; - struct {} Heap; + struct { + int64_t (*execute) (GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap); + } Instruction; + struct { + void (*set) (GroundBytecodeHeap* heap, GroundSize idx, GroundValue value); + GroundValue* (*get) (GroundBytecodeHeap* heap, GroundSize idx); + } Heap; } Bytecode; }; diff --git a/meson.build b/meson.build index dd74707..f55101d 100644 --- a/meson.build +++ b/meson.build @@ -3,6 +3,13 @@ project('ground', 'c', version : '0.1.0') pkg = import('pkgconfig') sources = files( + + 'src/Bytecode/Heap/get.c', + 'src/Bytecode/Heap/set.c', + 'src/Bytecode/Instruction/execute.c', + 'src/Bytecode/Program/execute.c', + 'src/Bytecode/Program/optimise.c', + 'src/Copy/Arg.c', 'src/Copy/Function.c', 'src/Copy/Instruction.c', @@ -64,6 +71,8 @@ sources = files( 'src/New/Identifier.c', + 'src/New/Bytecode.c', + 'src/New/NativeFunction.c', 'src/New/Instruction.c', diff --git a/src/Bytecode/Heap/get.c b/src/Bytecode/Heap/get.c new file mode 100644 index 0000000..e0faaca --- /dev/null +++ b/src/Bytecode/Heap/get.c @@ -0,0 +1,5 @@ +#include "../../../include/ground.h" + +GroundValue* _GroundBytecodeHeapGet(GroundBytecodeHeap* heap, GroundSize idx) { + return &heap->heap[idx]; +} diff --git a/src/Bytecode/Heap/set.c b/src/Bytecode/Heap/set.c new file mode 100644 index 0000000..f7ce37d --- /dev/null +++ b/src/Bytecode/Heap/set.c @@ -0,0 +1,5 @@ +#include "../../../include/ground.h" + +void _GroundBytecodeHeapSet(GroundBytecodeHeap* heap, GroundSize idx, GroundValue value) { + heap->heap[idx] = value; +} diff --git a/src/Bytecode/Instruction/execute.c b/src/Bytecode/Instruction/execute.c new file mode 100644 index 0000000..3dfa8a5 --- /dev/null +++ b/src/Bytecode/Instruction/execute.c @@ -0,0 +1,600 @@ +#include "../../../include/ground.h" +#include +#include + +int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap) { + + static const void* jumpTable[] = { + &&IF, &&JUMP, &&END, + &&INPUT, &&PRINT, &&PRINTLN, + &&SET, &&GETTYPE, &&EXISTS, + &&SETLIST, &&SETLISTAT, &&GETLISTAT, &&GETLISTSIZE, &&LISTAPPEND, + &&GETSTRSIZE, &&GETSTRCHARAT, + &&ADD, &&SUBTRACT, &&MULTIPLY, &&DIVIDE, + &&EQUAL, &&INEQUAL, &&NOT, &&GREATER, &&LESSER, + &&AND, &&OR, &&XOR, &&NEG, &&SHIFT, + &&STOI, &&STOD, &&ITOC, &&CTOI, &&TOSTRING, + &&FUN, &&RETURN, &&ENDFUN, &&CALL, &&CALLMETHOD, + &&STRUCT, &&ENDSTRUCT, &&INIT, &&GETFIELD, &&SETFIELD, + &&USE, &&EXTERN, &&CREATELABEL, + &&PAUSE, &&DROP, &&LICENSE, &&ERRORCMD, &&THROW, &&CATCH + }; + + // Jump to the spot + goto *jumpTable[instruction->type]; + + IF: { + return -1; + } + JUMP: { + return -1; + } + END: { + return -2; + } + INPUT: { + return -1; + } + PRINT: { + for (GroundSize i = 0; i < instruction->args.len; i++) { + GroundValue* val = Ground.Bytecode.Heap.get(heap, instruction->args.at[i]); + switch (val->type.type) { + case GroundType_Int: + printf("%" PRId64, val->as.Int); + break; + + case GroundType_Double: + printf("%f", val->as.Double); + break; + + case GroundType_Bool: + printf(val->as.Bool ? "true" : "false"); + break; + + case GroundType_Char: + printf("%c", val->as.Char); + break; + + case GroundType_String: + printf("%s", val->as.String.cstr); + break; + + default: + printf(""); + break; + } + } + return -1; + } + PRINTLN: { + for (GroundSize i = 0; i < instruction->args.len; i++) { + GroundValue* val = Ground.Bytecode.Heap.get(heap, instruction->args.at[i]); + switch (val->type.type) { + case GroundType_Int: + printf("%" PRId64, val->as.Int); + break; + + case GroundType_Double: + printf("%f", val->as.Double); + break; + + case GroundType_Bool: + printf(val->as.Bool ? "true" : "false"); + break; + + case GroundType_Char: + printf("%c", val->as.Char); + break; + + case GroundType_String: + printf("%s", val->as.String.cstr); + break; + + default: + printf(""); + break; + } + } + printf("\n"); + return -1; + } + SET: { + Ground.Bytecode.Heap.set(heap, instruction->args.at[0], *Ground.Bytecode.Heap.get(heap, instruction->args.at[1])); + return -1; + } + GETTYPE: { + Ground.Log.Warning("GETTYPE is deprecated"); + return -1; + } + EXISTS: { + Ground.Log.Warning("EXISTS is deprecated"); + return -1; + } + SETLIST: { + return -1; + } + SETLISTAT: { + return -1; + } + GETLISTAT: { + return -1; + } + GETLISTSIZE: { + return -1; + } + LISTAPPEND: { + return -1; + } + GETSTRSIZE: { + return -1; + } + GETSTRCHARAT: { + return -1; + } + ADD: { + GroundValue* final = Ground.Bytecode.Heap.get(heap, instruction->args.at[2]); + GroundValue* left = Ground.Bytecode.Heap.get(heap, instruction->args.at[0]); + GroundValue* right = Ground.Bytecode.Heap.get(heap, instruction->args.at[1]); + + switch (left->type.type) { + case GroundType_Int: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Int(left->as.Int + right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Int + right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + case GroundType_Double: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Double(left->as.Double + right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Double + right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + case GroundType_String: { + switch (right->type.type) { + case GroundType_String: { + char* buf = malloc(sizeof(char) * (left->as.String.len + right->as.String.len + 1)); + if (buf == NULL) { + Ground.Log.Error("malloc failed (instruction ADD{string, string, dirref}) in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + sprintf(buf, "%s%s", left->as.String.cstr, right->as.String.cstr); + *final = Ground.New.Value.String(Ground.New.String(buf)); + break; + } + default: { + Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + } + default: { + Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + return -1; + } + SUBTRACT: { + GroundValue* final = Ground.Bytecode.Heap.get(heap, instruction->args.at[2]); + GroundValue* left = Ground.Bytecode.Heap.get(heap, instruction->args.at[0]); + GroundValue* right = Ground.Bytecode.Heap.get(heap, instruction->args.at[1]); + + switch (left->type.type) { + case GroundType_Int: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Int(left->as.Int - right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Int - right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + case GroundType_Double: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Double(left->as.Double - right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Double - right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + return -1; + } + MULTIPLY: { + GroundValue* final = Ground.Bytecode.Heap.get(heap, instruction->args.at[2]); + GroundValue* left = Ground.Bytecode.Heap.get(heap, instruction->args.at[0]); + GroundValue* right = Ground.Bytecode.Heap.get(heap, instruction->args.at[1]); + + switch (left->type.type) { + case GroundType_Int: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Int(left->as.Int * right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Int * right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + case GroundType_Double: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Double(left->as.Double * right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Double * right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + return -1; + } + DIVIDE: { + GroundValue* final = Ground.Bytecode.Heap.get(heap, instruction->args.at[2]); + GroundValue* left = Ground.Bytecode.Heap.get(heap, instruction->args.at[0]); + GroundValue* right = Ground.Bytecode.Heap.get(heap, instruction->args.at[1]); + + switch (left->type.type) { + case GroundType_Int: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Int(left->as.Int / right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Int / right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + case GroundType_Double: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Double(left->as.Double / right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Double(left->as.Double / right->as.Double); + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + break; + } + default: { + Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); + Ground.Flags.error = true; + break; + } + } + return -1; + } + EQUAL: { + GroundValue* final = Ground.Bytecode.Heap.get(heap, instruction->args.at[2]); + GroundValue* left = Ground.Bytecode.Heap.get(heap, instruction->args.at[0]); + GroundValue* right = Ground.Bytecode.Heap.get(heap, instruction->args.at[1]); + + switch (left->type.type) { + case GroundType_Int: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Bool(left->as.Int == right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Bool(left->as.Int == right->as.Double); + break; + } + default: { + *final = Ground.New.Value.Bool(false); + break; + } + } + break; + } + case GroundType_Double: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Bool(left->as.Double == right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Bool(left->as.Double == right->as.Double); + break; + } + default: { + *final = Ground.New.Value.Bool(false); + break; + } + } + break; + } + case GroundType_Char: { + if (right->type.type == GroundType_Char) { + *final = Ground.New.Value.Bool(left->as.Char == right->as.Char); + } else { + *final = Ground.New.Value.Bool(false); + } + break; + } + case GroundType_Bool: { + if (right->type.type == GroundType_Bool) { + *final = Ground.New.Value.Bool(left->as.Bool == right->as.Bool); + } else { + *final = Ground.New.Value.Bool(false); + } + break; + } + case GroundType_String: { + if (right->type.type == GroundType_String) { + *final = Ground.New.Value.Bool(strcmp(left->as.String.cstr, right->as.String.cstr)); + } else { + *final = Ground.New.Value.Bool(false); + } + break; + } + default: { + // FIXME implement for complex types + *final = Ground.New.Value.Bool(false); + break; + } + } + return -1; + } + INEQUAL: { + GroundValue* final = Ground.Bytecode.Heap.get(heap, instruction->args.at[2]); + GroundValue* left = Ground.Bytecode.Heap.get(heap, instruction->args.at[0]); + GroundValue* right = Ground.Bytecode.Heap.get(heap, instruction->args.at[1]); + + switch (left->type.type) { + case GroundType_Int: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Bool(left->as.Int != right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Bool(left->as.Int != right->as.Double); + break; + } + default: { + *final = Ground.New.Value.Bool(true); + break; + } + } + break; + } + case GroundType_Double: { + switch (right->type.type) { + case GroundType_Int: { + *final = Ground.New.Value.Bool(left->as.Double != right->as.Int); + break; + } + case GroundType_Double: { + *final = Ground.New.Value.Bool(left->as.Double != right->as.Double); + break; + } + default: { + *final = Ground.New.Value.Bool(true); + break; + } + } + break; + } + case GroundType_Char: { + if (right->type.type == GroundType_Char) { + *final = Ground.New.Value.Bool(left->as.Char != right->as.Char); + } else { + *final = Ground.New.Value.Bool(true); + } + break; + } + case GroundType_Bool: { + if (right->type.type == GroundType_Bool) { + *final = Ground.New.Value.Bool(left->as.Bool != right->as.Bool); + } else { + *final = Ground.New.Value.Bool(true); + } + break; + } + case GroundType_String: { + if (right->type.type == GroundType_String) { + *final = Ground.New.Value.Bool(!strcmp(left->as.String.cstr, right->as.String.cstr)); + } else { + *final = Ground.New.Value.Bool(true); + } + break; + } + default: { + // FIXME implement for complex types + *final = Ground.New.Value.Bool(false); + break; + } + } + return -1; + } + NOT: { + Ground.Bytecode.Heap.set(heap, instruction->args.at[1], Ground.New.Value.Bool(!Ground.Bytecode.Heap.get(heap, instruction->args.at[0])->as.Bool)); + return -1; + } + GREATER: { + return -1; + } + LESSER: { + return -1; + } + AND: { + return -1; + } + OR: { + return -1; + } + XOR: { + return -1; + } + NEG: { + return -1; + } + SHIFT: { + return -1; + } + STOI: { + return -1; + } + STOD: { + return -1; + } + ITOC: { + return -1; + } + CTOI: { + return -1; + } + TOSTRING: { + return -1; + } + FUN: { + return -1; + } + RETURN: { + return -1; + } + ENDFUN: { + return -1; + } + CALL: { + return -1; + } + CALLMETHOD: { + return -1; + } + STRUCT: { + return -1; + } + ENDSTRUCT: { + return -1; + } + INIT: { + return -1; + } + GETFIELD: { + return -1; + } + SETFIELD: { + return -1; + } + USE: { + return -1; + } + EXTERN: { + return -1; + } + CREATELABEL: { + return -1; + } + PAUSE: { + return -1; + } + DROP: { + return -1; + } + LICENSE: { + return -1; + } + ERRORCMD: { + return -1; + } + THROW: { + return -1; + } + CATCH: { + return -1; + } + + Ground.Log.Error("operation fell through in Ground.Instruction.execute()"); + Ground.Flags.error = true; + + return -1; +} diff --git a/src/Bytecode/Program/execute.c b/src/Bytecode/Program/execute.c new file mode 100644 index 0000000..eb0a10a --- /dev/null +++ b/src/Bytecode/Program/execute.c @@ -0,0 +1,17 @@ +#include "../../../include/ground.h" +#include + +void _GroundBytecodeProgramExecute(GroundBytecodeProgram* program, GroundBytecodeHeap* heap) { + for (GroundSize i = 0; i < program->len; i++) { + int64_t status = Ground.Bytecode.Instruction.execute(&program->at[i], heap); + if (Ground.Flags.error) { + return; + } + + switch (status) { + case -1: break; + case -2: return; + default: i = status; break; + } + } +} diff --git a/src/Bytecode/Program/optimise.c b/src/Bytecode/Program/optimise.c new file mode 100644 index 0000000..9df305f --- /dev/null +++ b/src/Bytecode/Program/optimise.c @@ -0,0 +1,5 @@ +#include "../../../include/ground.h" + +void _GroundBytecodeProgramOptimise(GroundBytecodeProgram* program) { + // TODO: Implement optimisation +} diff --git a/src/Instruction/execute.c b/src/Instruction/execute.c index d4a9e40..f431859 100644 --- a/src/Instruction/execute.c +++ b/src/Instruction/execute.c @@ -11,617 +11,5 @@ */ int64_t _GroundInstructionExecute(GroundInstruction* instruction, GroundValue* heap) { - - static const void* jumpTable[] = { - &&IF, &&JUMP, &&END, - &&INPUT, &&PRINT, &&PRINTLN, - &&SET, &&GETTYPE, &&EXISTS, - &&SETLIST, &&SETLISTAT, &&GETLISTAT, &&GETLISTSIZE, &&LISTAPPEND, - &&GETSTRSIZE, &&GETSTRCHARAT, - &&ADD, &&SUBTRACT, &&MULTIPLY, &&DIVIDE, - &&EQUAL, &&INEQUAL, &&NOT, &&GREATER, &&LESSER, - &&AND, &&OR, &&XOR, &&NEG, &&SHIFT, - &&STOI, &&STOD, &&ITOC, &&CTOI, &&TOSTRING, - &&FUN, &&RETURN, &&ENDFUN, &&CALL, &&CALLMETHOD, - &&STRUCT, &&ENDSTRUCT, &&INIT, &&GETFIELD, &&SETFIELD, - &&USE, &&EXTERN, &&CREATELABEL, - &&PAUSE, &&DROP, &&LICENSE, &&ERRORCMD, &&THROW, &&CATCH - }; - - // Preprocess any ValueRefs - for (GroundSize i = 0; i < instruction->args.len; i++) { - if (instruction->args.at[i].type == GroundArg_ValueRef) { - GroundSize offset = instruction->args.at[i]._offset; - instruction->args.at[i] = Ground.New.Arg.Value(heap[offset]); - } - } - - // Jump to the spot - goto *jumpTable[instruction->type]; - - IF: { - if (instruction->args.at[0].as.value.as.Bool) { - return instruction->args.at[1]._offset; - } - return -1; - } - JUMP: { - return instruction->args.at[0]._offset; - } - END: { - return -2; - } - INPUT: { - char input[2048]; - fgets(input, sizeof(input) - 1, stdin); - input[2047] = '\0'; - - GroundString string = Ground.New.String(input); - GroundValue value = Ground.New.Value.String(string); - heap[instruction->args.at[0]._offset] = value; - return -1; - } - PRINT: { - for (GroundSize i = 0; i < instruction->args.len; i++) { - GroundValue* val = &instruction->args.at[i].as.value; - switch (val->type.type) { - case GroundType_Int: - printf("%" PRId64, val->as.Int); - break; - - case GroundType_Double: - printf("%f", val->as.Double); - break; - - case GroundType_Bool: - printf(val->as.Bool ? "true" : "false"); - break; - - case GroundType_Char: - printf("%c", val->as.Char); - break; - - case GroundType_String: - printf("%s", val->as.String.cstr); - break; - - default: - printf(""); - break; - } - } - return -1; - } - PRINTLN: { - for (GroundSize i = 0; i < instruction->args.len; i++) { - GroundValue* val = &instruction->args.at[i].as.value; - switch (val->type.type) { - case GroundType_Int: - printf("%" PRId64, val->as.Int); - break; - - case GroundType_Double: - printf("%f", val->as.Double); - break; - - case GroundType_Bool: - printf(val->as.Bool ? "true" : "false"); - break; - - case GroundType_Char: - printf("%c", val->as.Char); - break; - - case GroundType_String: - printf("%s", val->as.String.cstr); - break; - - default: - printf(""); - break; - } - } - printf("\n"); - return -1; - } - SET: { - GroundSize offset = instruction->args.at[0]._offset; - heap[offset] = instruction->args.at[1].as.value; - return -1; - } - GETTYPE: { - Ground.Log.Warning("GETTYPE is deprecated"); - return -1; - } - EXISTS: { - Ground.Log.Warning("EXISTS is deprecated"); - return -1; - } - SETLIST: { - return -1; - } - SETLISTAT: { - return -1; - } - GETLISTAT: { - return -1; - } - GETLISTSIZE: { - return -1; - } - LISTAPPEND: { - return -1; - } - GETSTRSIZE: { - return -1; - } - GETSTRCHARAT: { - return -1; - } - ADD: { - GroundValue* final = &heap[instruction->args.at[2]._offset]; - GroundValue* left = &instruction->args.at[0].as.value; - GroundValue* right = &instruction->args.at[1].as.value; - - switch (left->type.type) { - case GroundType_Int: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Int(left->as.Int + right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Int + right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - case GroundType_Double: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Double(left->as.Double + right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Double + right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - case GroundType_String: { - switch (right->type.type) { - case GroundType_String: { - char* buf = malloc(sizeof(char) * (left->as.String.len + right->as.String.len + 1)); - if (buf == NULL) { - Ground.Log.Error("malloc failed (instruction ADD{string, string, dirref}) in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - sprintf(buf, "%s%s", left->as.String.cstr, right->as.String.cstr); - *final = Ground.New.Value.String(Ground.New.String(buf)); - break; - } - default: { - Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - } - default: { - Ground.Log.Error("invalid add operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - return -1; - } - SUBTRACT: { - GroundValue* final = &heap[instruction->args.at[2]._offset]; - GroundValue* left = &instruction->args.at[0].as.value; - GroundValue* right = &instruction->args.at[1].as.value; - - switch (left->type.type) { - case GroundType_Int: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Int(left->as.Int - right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Int - right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - case GroundType_Double: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Double(left->as.Double - right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Double - right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - return -1; - } - MULTIPLY: { - GroundValue* final = &heap[instruction->args.at[2]._offset]; - GroundValue* left = &instruction->args.at[0].as.value; - GroundValue* right = &instruction->args.at[1].as.value; - - switch (left->type.type) { - case GroundType_Int: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Int(left->as.Int * right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Int * right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - case GroundType_Double: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Double(left->as.Double * right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Double * right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - return -1; - } - DIVIDE: { - GroundValue* final = &heap[instruction->args.at[2]._offset]; - GroundValue* left = &instruction->args.at[0].as.value; - GroundValue* right = &instruction->args.at[1].as.value; - - switch (left->type.type) { - case GroundType_Int: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Int(left->as.Int / right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Int / right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - case GroundType_Double: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Double(left->as.Double / right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Double(left->as.Double / right->as.Double); - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - break; - } - default: { - Ground.Log.Error("invalid subtract operation in Ground.Instruction.execute()"); - Ground.Flags.error = true; - break; - } - } - return -1; - } - EQUAL: { - GroundValue* final = &heap[instruction->args.at[2]._offset]; - GroundValue* left = &instruction->args.at[0].as.value; - GroundValue* right = &instruction->args.at[1].as.value; - - switch (left->type.type) { - case GroundType_Int: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Bool(left->as.Int == right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Bool(left->as.Int == right->as.Double); - break; - } - default: { - *final = Ground.New.Value.Bool(false); - break; - } - } - break; - } - case GroundType_Double: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Bool(left->as.Double == right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Bool(left->as.Double == right->as.Double); - break; - } - default: { - *final = Ground.New.Value.Bool(false); - break; - } - } - break; - } - case GroundType_Char: { - if (right->type.type == GroundType_Char) { - *final = Ground.New.Value.Bool(left->as.Char == right->as.Char); - } else { - *final = Ground.New.Value.Bool(false); - } - break; - } - case GroundType_Bool: { - if (right->type.type == GroundType_Bool) { - *final = Ground.New.Value.Bool(left->as.Bool == right->as.Bool); - } else { - *final = Ground.New.Value.Bool(false); - } - break; - } - case GroundType_String: { - if (right->type.type == GroundType_String) { - *final = Ground.New.Value.Bool(strcmp(left->as.String.cstr, right->as.String.cstr)); - } else { - *final = Ground.New.Value.Bool(false); - } - break; - } - default: { - // FIXME implement for complex types - *final = Ground.New.Value.Bool(false); - break; - } - } - return -1; - } - INEQUAL: { - GroundValue* final = &heap[instruction->args.at[2]._offset]; - GroundValue* left = &instruction->args.at[0].as.value; - GroundValue* right = &instruction->args.at[1].as.value; - - switch (left->type.type) { - case GroundType_Int: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Bool(left->as.Int != right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Bool(left->as.Int != right->as.Double); - break; - } - default: { - *final = Ground.New.Value.Bool(true); - break; - } - } - break; - } - case GroundType_Double: { - switch (right->type.type) { - case GroundType_Int: { - *final = Ground.New.Value.Bool(left->as.Double != right->as.Int); - break; - } - case GroundType_Double: { - *final = Ground.New.Value.Bool(left->as.Double != right->as.Double); - break; - } - default: { - *final = Ground.New.Value.Bool(true); - break; - } - } - break; - } - case GroundType_Char: { - if (right->type.type == GroundType_Char) { - *final = Ground.New.Value.Bool(left->as.Char != right->as.Char); - } else { - *final = Ground.New.Value.Bool(true); - } - break; - } - case GroundType_Bool: { - if (right->type.type == GroundType_Bool) { - *final = Ground.New.Value.Bool(left->as.Bool != right->as.Bool); - } else { - *final = Ground.New.Value.Bool(true); - } - break; - } - case GroundType_String: { - if (right->type.type == GroundType_String) { - *final = Ground.New.Value.Bool(!strcmp(left->as.String.cstr, right->as.String.cstr)); - } else { - *final = Ground.New.Value.Bool(true); - } - break; - } - default: { - // FIXME implement for complex types - *final = Ground.New.Value.Bool(false); - break; - } - } - return -1; - } - NOT: { - heap[instruction->args.at[1]._offset] = Ground.New.Value.Bool(!instruction->args.at[0].as.value.as.Bool); - return -1; - } - GREATER: { - return -1; - } - LESSER: { - return -1; - } - AND: { - return -1; - } - OR: { - return -1; - } - XOR: { - return -1; - } - NEG: { - return -1; - } - SHIFT: { - return -1; - } - STOI: { - return -1; - } - STOD: { - return -1; - } - ITOC: { - return -1; - } - CTOI: { - return -1; - } - TOSTRING: { - return -1; - } - FUN: { - return -1; - } - RETURN: { - return -1; - } - ENDFUN: { - return -1; - } - CALL: { - return -1; - } - CALLMETHOD: { - return -1; - } - STRUCT: { - return -1; - } - ENDSTRUCT: { - return -1; - } - INIT: { - return -1; - } - GETFIELD: { - return -1; - } - SETFIELD: { - return -1; - } - USE: { - return -1; - } - EXTERN: { - return -1; - } - CREATELABEL: { - return -1; - } - PAUSE: { - return -1; - } - DROP: { - return -1; - } - LICENSE: { - return -1; - } - ERRORCMD: { - return -1; - } - THROW: { - return -1; - } - CATCH: { - return -1; - } - - Ground.Log.Error("operation fell through in Ground.Instruction.execute()"); - Ground.Flags.error = true; - return -1; } diff --git a/src/Internal/run.c b/src/Internal/run.c index 50ccb0c..5bd8d3e 100644 --- a/src/Internal/run.c +++ b/src/Internal/run.c @@ -1,148 +1,15 @@ #include "../../include/ground.h" -#include -#include -#include - -static inline void doLabels(GroundProgram* program, GroundState* state) { - - for (GroundSize i = 0; i < program->len; i++) { - GroundInstruction* instruction = &program->at[i]; - if (instruction->type == GroundInstruction_CREATELABEL) { - if (instruction->args.len > 0) { - GroundArg* arg = &instruction->args.at[0]; - GroundLabel* label = NULL; - HASH_FIND_STR(state->labels, arg->as.ref->string, label); - - if (label == NULL) { - label = malloc(sizeof(GroundLabel)); - if (label == NULL) { - Ground.Log.Error("malloc failed in Ground.Internal.run()"); - Ground.Flags.error = true; - return; - } - strncpy(label->name, arg->as.ref->string, 2047); - label->name[2047] = '\0'; - label->lineNum = i; - HASH_ADD_STR(state->labels, name, label); - } - } - } - } - - for (GroundSize i = 0; i < program->len; i++) { - GroundInstruction* instruction = &program->at[i]; - if (instruction->type == GroundInstruction_JUMP) { - GroundArg* arg = &instruction->args.at[0]; - GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); - if (line == NULL) { - char buf[2048]; - snprintf(buf, 2047, "couldn't find label '%s' (instruction JUMP at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); - Ground.Log.Error(buf); - Ground.Flags.error = true; - return; - } - - arg->_offset = *line; - - } else if (instruction->type == GroundInstruction_IF) { - GroundArg* arg = &instruction->args.at[1]; - GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); - if (line == NULL) { - char buf[2048]; - snprintf(buf, 2047, "couldn't find label '%s' (instruction IF at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); - Ground.Log.Error(buf); - Ground.Flags.error = true; - return; - } - - arg->_offset = *line; - - } else if (instruction->type == GroundInstruction_CATCH) { - GroundArg* arg = &instruction->args.at[1]; - GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); - if (line == NULL) { - char buf[2048]; - snprintf(buf, 2047, "couldn't find label '%s' (instruction CATCH at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); - Ground.Log.Error(buf); - Ground.Flags.error = true; - return; - } - - arg->_offset = *line; - - } - } - -} - -/* - * Assigns an offset to each variable referenced. - */ -static inline GroundSize doOffsets(GroundProgram* program, GroundState* state) { - GroundSize size = 0; - for (GroundSize i = 0; i < program->len; i++) { - for (GroundSize j = 0; j < program->at[i].args.len; j++) { - GroundArg* arg = &program->at[i].args.at[j]; - - if ( - arg->type == GroundArg_Value || - arg->type == GroundArg_Label || - arg->type == GroundArg_LineRef - ) continue; - - GroundVariable* item = NULL; - HASH_FIND_STR(state->variables, arg->as.ref->string, item); - - if (item == NULL) { - item = malloc(sizeof(GroundVariable)); - if (item == NULL) { - Ground.Log.Error("malloc failed in Ground.Internal.run()"); - Ground.Flags.error = true; - return 0; - } - item->value = Ground.New.Value.Int(0); - strncpy(item->name, arg->as.ref->string, 2047); - item->_offset = size++; - HASH_ADD_STR(state->variables, name, item); - } - - arg->_offset = item->_offset; - size++; - } - } - return size; -} - void _GroundInternalRun(GroundProgram* program, GroundState* state) { - - // Precompute some really cool stuff - doLabels(program, state); - if (Ground.Flags.error) return; - - GroundSize size = doOffsets(program, state); - if (Ground.Flags.error) return; - - GroundValue* heap = malloc(sizeof(GroundValue) * size); - - for (GroundSize i = 0; i < program->len; i++) { - GroundInstruction instruction = Ground.Copy.Instruction(&program->at[i]); - int64_t status = Ground.Instruction.execute(&instruction, heap); - switch (status) { - case -2: - return; - case -1: - break; - default: - if (status < program->len) { - i = status - 1; - } else { - Ground.Log.Error("out of bounds jump in Ground.Internal.Run()"); - Ground.Flags.error = true; - return; - } - } - Ground.Free.Instruction(&instruction); + GroundBytecode bytecode = Ground.New.Bytecode(program, state); + if (Ground.Flags.error) { + return; } - + + Ground.Bytecode.Program.optimise(&bytecode.program); + if (Ground.Flags.error) { + return; + } + + Ground.Bytecode.Program.execute(&bytecode.program, &bytecode.heap); } diff --git a/src/New/Bytecode.c b/src/New/Bytecode.c new file mode 100644 index 0000000..78421ef --- /dev/null +++ b/src/New/Bytecode.c @@ -0,0 +1,210 @@ +#include "../../include/ground.h" + +static inline void doLabels(GroundProgram* program, GroundState* state) { + + for (GroundSize i = 0; i < program->len; i++) { + GroundInstruction* instruction = &program->at[i]; + if (instruction->type == GroundInstruction_CREATELABEL) { + if (instruction->args.len > 0) { + GroundArg* arg = &instruction->args.at[0]; + GroundLabel* label = NULL; + HASH_FIND_STR(state->labels, arg->as.ref->string, label); + + if (label == NULL) { + label = malloc(sizeof(GroundLabel)); + if (label == NULL) { + Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Flags.error = true; + return; + } + strncpy(label->name, arg->as.ref->string, 2047); + label->name[2047] = '\0'; + label->lineNum = i; + HASH_ADD_STR(state->labels, name, label); + } + } + } + } + + for (GroundSize i = 0; i < program->len; i++) { + GroundInstruction* instruction = &program->at[i]; + if (instruction->type == GroundInstruction_JUMP) { + GroundArg* arg = &instruction->args.at[0]; + GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); + if (line == NULL) { + char buf[2048]; + snprintf(buf, 2047, "couldn't find label '%s' (instruction JUMP at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); + Ground.Log.Error(buf); + Ground.Flags.error = true; + return; + } + + arg->_offset = *line; + + } else if (instruction->type == GroundInstruction_IF) { + GroundArg* arg = &instruction->args.at[1]; + GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); + if (line == NULL) { + char buf[2048]; + snprintf(buf, 2047, "couldn't find label '%s' (instruction IF at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); + Ground.Log.Error(buf); + Ground.Flags.error = true; + return; + } + + arg->_offset = *line; + + } else if (instruction->type == GroundInstruction_CATCH) { + GroundArg* arg = &instruction->args.at[1]; + GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); + if (line == NULL) { + char buf[2048]; + snprintf(buf, 2047, "couldn't find label '%s' (instruction CATCH at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); + Ground.Log.Error(buf); + Ground.Flags.error = true; + return; + } + + arg->_offset = *line; + + } + } + +} + +static inline void addToGroundBytecodeProgram(GroundBytecodeProgram* program, GroundBytecodeInstruction inst) { + if (program->len + 1 >= program->capacity) { + + } +} + +/* + * Assigns an offset to each variable referenced. + */ +static inline GroundSize doOffsets(GroundProgram* gp, GroundState* state, GroundBytecodeProgram* gbp) { + GroundSize size = 0; + + // Add size of state + GroundVariable *s, *tmp; + HASH_ITER(hh, state->variables, s, tmp) { + size++; + } + + for (GroundSize i = 0; i < gp->len; i++) { + for (GroundSize j = 0; j < gp->at[i].args.len; j++) { + GroundArg* arg = &gp->at[i].args.at[j]; + + if ( + arg->type == GroundArg_Label || + arg->type == GroundArg_LineRef + ) continue; + + if (arg->type == GroundArg_Value) { + GroundVariable* item = malloc(sizeof(GroundVariable)); + if (item == NULL) { + Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Flags.error = true; + return 0; + } + item->value = Ground.Copy.Value(&arg->as.value); + if (Ground.Flags.error) return 0; + item->_offset = size++; + snprintf(item->name, sizeof(item->name) - 1, "_._.ground_internal_constant_%zu", item->_offset); + HASH_ADD_STR(state->variables, name, item); + continue; + } + + GroundVariable* item = NULL; + HASH_FIND_STR(state->variables, arg->as.ref->string, item); + + if (item == NULL) { + item = malloc(sizeof(GroundVariable)); + if (item == NULL) { + Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Flags.error = true; + return 0; + } + item->value = Ground.New.Value.Int(0); + strncpy(item->name, arg->as.ref->string, 2047); + item->_offset = size++; + HASH_ADD_STR(state->variables, name, item); + } + + arg->_offset = item->_offset; + size++; + } + + // Convert to GroundBytecodeInstruction + GroundBytecodeInstruction inst = { + .type = gp->at[i].type, + .args.at = malloc(sizeof(GroundSize) * gp->at[i].args.len), + .args.len = gp->at[i].args.len, + .args.capacity = gp->at[i].args.len + }; + + if (inst.args.at == NULL) {} + + for (GroundSize j = 0; j < gp->at[i].args.len; j++) { + inst.args.at[j] = gp->at[i].args.at[j]._offset; + } + + gbp->at[i] = inst; + gbp->len++; + + } + return size; +} + + +GroundBytecode _GroundNewBytecode(GroundProgram* program, GroundState* state) { + + GroundBytecode bytecode = { + .program = { + .at = malloc(sizeof(GroundBytecodeInstruction) * program->len), + .capacity = program->len, + .len = 0, + }, + .heap = { + .heap = NULL, + .capacity = 0, + .len = 0 + } + }; + + if (bytecode.program.at == NULL) { + Ground.Log.Error("malloc failed in Ground.New.Bytecode"); + Ground.Flags.error = true; + return bytecode; + } + + // Precompute some really cool stuff + doLabels(program, state); + if (Ground.Flags.error) return bytecode; + + GroundSize size = doOffsets(program, state, &bytecode.program); + if (Ground.Flags.error) return bytecode; + + // Allocate heap + bytecode.heap.heap = malloc(sizeof(GroundValue) * size); + if (bytecode.heap.heap == NULL) { + Ground.Log.Error("malloc failed in Ground.New.Bytecode"); + Ground.Flags.error = true; + return bytecode; + } + bytecode.heap.capacity = size; + bytecode.heap.len = size; + + GroundVariable *s, *tmp; + + // Copy constants into heap + GroundSize i = 0; + HASH_ITER(hh, state->variables, s, tmp) { + bytecode.heap.heap[i] = Ground.Copy.Value(&s->value); + if (Ground.Flags.error) return bytecode; + i++; + } + + + return bytecode; + +} diff --git a/src/libmain.c b/src/libmain.c index 5a8c0b5..b372c80 100644 --- a/src/libmain.c +++ b/src/libmain.c @@ -32,6 +32,8 @@ GroundType _GroundNewType(enum GroundTypeType type, ...); GroundIdentifier* _GroundNewIdentifier(const char* id); +GroundBytecode _GroundNewBytecode (GroundProgram* program, GroundState* state); + void _GroundFreeValue(GroundValue* in); void _GroundFreeList(GroundList* in); void _GroundFreeString(GroundString* in); @@ -93,6 +95,13 @@ void _GroundLogWarning(const char* message); void _GroundLogPrintErrors(); +void _GroundBytecodeProgramExecute(GroundBytecodeProgram* program, GroundBytecodeHeap* heap); +void _GroundBytecodeProgramOptimise(GroundBytecodeProgram* program); + +int64_t _GroundBytecodeInstructionExecute(GroundBytecodeInstruction* instruction, GroundBytecodeHeap* heap); + +void _GroundBytecodeHeapSet(GroundBytecodeHeap* heap, GroundSize idx, GroundValue value); +GroundValue* _GroundBytecodeHeapGet(GroundBytecodeHeap* heap, GroundSize idx); struct _Ground Ground = { @@ -136,6 +145,8 @@ struct _Ground Ground = { .Type = _GroundNewType, .Identifier = _GroundNewIdentifier, + + .Bytecode = _GroundNewBytecode, }, .Free = { @@ -210,4 +221,18 @@ struct _Ground Ground = { .errors = NULL, .warnings = NULL, }, + + .Bytecode = { + .Program = { + .execute = _GroundBytecodeProgramExecute, + .optimise = _GroundBytecodeProgramOptimise, + }, + .Instruction = { + .execute = _GroundBytecodeInstructionExecute, + }, + .Heap = { + .set = _GroundBytecodeHeapSet, + .get = _GroundBytecodeHeapGet, + }, + }, };