#include "../../include/ground.h" #include #include #include /* * Return values guide: * -2: Exit program * -1: Nothing * 0-infinity: Jump to instruction number */ 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 (size_t i = 0; i < instruction->args.len; i++) { if (instruction->args.at[i].type == GroundArg_ValueRef) { size_t 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 (size_t 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 (size_t 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: { size_t 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; }