TCPU/src/main.c
2025-01-20 22:52:23 +05:00

151 lines
4.2 KiB
C

#include "VM/VM.h"
#include "instructions/instructions.h"
#include "collections/List.h"
#include "compiler/compiler.h"
#define arg_is(STR) (strcmp(argv[argi], STR) == 0)
i32 compileSources(cstr source_file, cstr out_file);
i32 bootFromImage(cstr image_file);
i32 main(const i32 argc, cstr* argv){
if(argc < 2){
printfe("ERROR: no arguments provided. Use --help to know more.\n");
return 1;
}
bool boot = false;
cstr NULLABLE(image_file) = NULL;
bool compile = false;
cstr NULLABLE(out_file) = NULL;
cstr NULLABLE(source_file) = NULL;
for(i32 argi = 1; argi < argc; argi++){
if(arg_is("-h") || arg_is("--help")){
printf(
"-h, --help Show this message.\n"
"-op, --opcodes Show list of all instructions.\n"
"-i, --image [FILE] Boot VM using image file.\n"
"-c, --compile [SOURCE_FILE] [OUT_FILE] Compile assembly source files to machine code.\n"
);
return 0;
}
else if(arg_is("-op") || arg_is("--opcodes")){
for(u8 opcode = 0; opcode < 255; opcode++){
const Instruction* instr = Instruction_getByOpcode(opcode);
if(instr != NULL){
printf("%02X %s\n", opcode, instr->name);
}
}
return 0;
}
else if(arg_is("-i") || arg_is("--image")){
if(boot){
printfe("--image flag is set already\n");
return 1;
}
boot = true;
if(++argi >= argc){
printfe("ERROR: no image file specified\n");
return 1;
}
image_file = argv[argi];
}
else if(arg_is("-c") || arg_is("--compile")){
if(compile){
printfe("--compile flag is set already\n");
return 1;
}
compile = true;
if(++argi >= argc){
printfe("ERROR: no source file file specified\n");
return 1;
}
source_file = argv[argi];
if(++argi >= argc){
printfe("ERROR: no output file file specified\n");
return 1;
}
out_file = argv[argi];
}
else {
printfe("ERROR: unknown argument '%s'\n", argv[argi]);
return 1;
}
}
i32 exit_code = 0;
if(compile){
exit_code = compileSources(source_file, out_file);
}
if(exit_code == 0 && boot){
exit_code = bootFromImage(image_file);
}
return exit_code;
}
i32 bootFromImage(cstr image_file){
FILE* file = fopen(image_file, "rb");
if(file == NULL){
printfe("ERROR: can't open file '%s'\n", image_file);
return 1;
}
const size_t buffer_size = 1024*1024;
u8* vm_memory = malloc(buffer_size);
memset(vm_memory, 0, buffer_size);
size_t bytes_read = fread(vm_memory, 1, buffer_size, file);
fclose(file);
if(bytes_read == (size_t)EOF){
printfe("ERROR: can't read file '%s'\n", image_file);
free(vm_memory);
return 1;
}
VM vm;
VM_init(&vm);
i32 exit_code = 1;
if(VM_setMemory(&vm, vm_memory, bytes_read)){
exit_code = VM_boot(&vm);
}
if(vm.state == VMState_InternalError){
if(vm.error_message){
printfe("VM ERROR: %s\n", vm.error_message);
free(vm.error_message);
}
else printfe("VM ERROR: unknown (error_message is null)\n");
}
if(exit_code != 0){
printfe("program exited with code %i\n", exit_code);
}
free(vm_memory);
return exit_code;
}
i32 compileSources(cstr source_file, cstr out_file){
Compiler cmp;
Compiler_init(&cmp);
bool success = Compiler_compile(&cmp, source_file, out_file, true);
if(!success){
if(cmp.error_message){
printfe("COMPILER ERROR: %s\n", cmp.error_message);
free(cmp.error_message);
}
else printfe("COMPILER ERROR: unknown (error_message is null)\n");
Compiler_free(&cmp);
return 111;
}
Compiler_free(&cmp);
return 0;
}