#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: {} SETLISTAT: {} GETLISTAT: {} GETLISTSIZE: {} LISTAPPEND: {} GETSTRSIZE: {} GETSTRCHARAT: {} 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: {} 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: {} Ground.Log.Error("operation fell through in Ground.Instruction.execute()"); Ground.Flags.error = true; return -1; }