201 lines
7.0 KiB
C
201 lines
7.0 KiB
C
|
|
#define _POSIX_C_SOURCE 200809L
|
||
|
|
#include "ir.h"
|
||
|
|
#include "../runtime/labeltable.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
RavaInstructionList_t* rava_instruction_list_create() {
|
||
|
|
RavaInstructionList_t *list = calloc(1, sizeof(RavaInstructionList_t));
|
||
|
|
list->capacity = 16;
|
||
|
|
list->instructions = malloc(sizeof(RavaInstruction_t) * list->capacity);
|
||
|
|
list->count = 0;
|
||
|
|
list->next_label_id = 1;
|
||
|
|
return list;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_instruction_list_destroy(RavaInstructionList_t *list) {
|
||
|
|
if (!list) return;
|
||
|
|
free(list->instructions);
|
||
|
|
free(list);
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr) {
|
||
|
|
if (list->count >= list->capacity) {
|
||
|
|
list->capacity *= 2;
|
||
|
|
list->instructions = realloc(list->instructions,
|
||
|
|
sizeof(RavaInstruction_t) * list->capacity);
|
||
|
|
}
|
||
|
|
list->instructions[list->count++] = instr;
|
||
|
|
}
|
||
|
|
|
||
|
|
int rava_instruction_list_new_label(RavaInstructionList_t *list) {
|
||
|
|
return list->next_label_id++;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaMethod_t* rava_method_create(const char *name, RavaType_t *return_type) {
|
||
|
|
RavaMethod_t *method = calloc(1, sizeof(RavaMethod_t));
|
||
|
|
method->name = strdup(name);
|
||
|
|
method->return_type = return_type;
|
||
|
|
method->param_types = NULL;
|
||
|
|
method->param_count = 0;
|
||
|
|
method->local_count = 0;
|
||
|
|
method->instructions = rava_instruction_list_create();
|
||
|
|
method->label_table = NULL;
|
||
|
|
return method;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_method_destroy(RavaMethod_t *method) {
|
||
|
|
if (!method) return;
|
||
|
|
free(method->name);
|
||
|
|
free(method->param_types);
|
||
|
|
rava_instruction_list_destroy(method->instructions);
|
||
|
|
if (method->label_table) {
|
||
|
|
rava_labeltable_destroy(method->label_table);
|
||
|
|
}
|
||
|
|
free(method);
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaClass_t* rava_class_create(const char *name) {
|
||
|
|
RavaClass_t *class = calloc(1, sizeof(RavaClass_t));
|
||
|
|
class->name = strdup(name);
|
||
|
|
class->superclass = NULL;
|
||
|
|
class->methods = NULL;
|
||
|
|
class->method_count = 0;
|
||
|
|
class->method_capacity = 0;
|
||
|
|
return class;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_class_destroy(RavaClass_t *class) {
|
||
|
|
if (!class) return;
|
||
|
|
free(class->name);
|
||
|
|
free(class->superclass);
|
||
|
|
for (size_t i = 0; i < class->method_count; i++) {
|
||
|
|
rava_method_destroy(class->methods[i]);
|
||
|
|
}
|
||
|
|
free(class->methods);
|
||
|
|
free(class);
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method) {
|
||
|
|
if (class->method_count >= class->method_capacity) {
|
||
|
|
size_t new_capacity = class->method_capacity == 0 ? 4 : class->method_capacity * 2;
|
||
|
|
class->methods = realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity);
|
||
|
|
class->method_capacity = new_capacity;
|
||
|
|
}
|
||
|
|
class->methods[class->method_count++] = method;
|
||
|
|
}
|
||
|
|
|
||
|
|
RavaProgram_t* rava_program_create() {
|
||
|
|
RavaProgram_t *program = calloc(1, sizeof(RavaProgram_t));
|
||
|
|
program->classes = NULL;
|
||
|
|
program->class_count = 0;
|
||
|
|
program->class_capacity = 0;
|
||
|
|
return program;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_program_destroy(RavaProgram_t *program) {
|
||
|
|
if (!program) return;
|
||
|
|
for (size_t i = 0; i < program->class_count; i++) {
|
||
|
|
rava_class_destroy(program->classes[i]);
|
||
|
|
}
|
||
|
|
free(program->classes);
|
||
|
|
free(program);
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class) {
|
||
|
|
if (program->class_count >= program->class_capacity) {
|
||
|
|
size_t new_capacity = program->class_capacity == 0 ? 4 : program->class_capacity * 2;
|
||
|
|
program->classes = realloc(program->classes, sizeof(RavaClass_t*) * new_capacity);
|
||
|
|
program->class_capacity = new_capacity;
|
||
|
|
}
|
||
|
|
program->classes[program->class_count++] = class;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const char* _rava_opcode_name(RavaOpCode_e opcode) {
|
||
|
|
switch (opcode) {
|
||
|
|
case RAVA_OP_NOP: return "NOP";
|
||
|
|
case RAVA_OP_LOAD_CONST: return "LOAD_CONST";
|
||
|
|
case RAVA_OP_LOAD_LOCAL: return "LOAD_LOCAL";
|
||
|
|
case RAVA_OP_STORE_LOCAL: return "STORE_LOCAL";
|
||
|
|
case RAVA_OP_ADD: return "ADD";
|
||
|
|
case RAVA_OP_SUB: return "SUB";
|
||
|
|
case RAVA_OP_MUL: return "MUL";
|
||
|
|
case RAVA_OP_DIV: return "DIV";
|
||
|
|
case RAVA_OP_MOD: return "MOD";
|
||
|
|
case RAVA_OP_NEG: return "NEG";
|
||
|
|
case RAVA_OP_EQ: return "EQ";
|
||
|
|
case RAVA_OP_NE: return "NE";
|
||
|
|
case RAVA_OP_LT: return "LT";
|
||
|
|
case RAVA_OP_LE: return "LE";
|
||
|
|
case RAVA_OP_GT: return "GT";
|
||
|
|
case RAVA_OP_GE: return "GE";
|
||
|
|
case RAVA_OP_JUMP: return "JUMP";
|
||
|
|
case RAVA_OP_JUMP_IF_TRUE: return "JUMP_IF_TRUE";
|
||
|
|
case RAVA_OP_JUMP_IF_FALSE: return "JUMP_IF_FALSE";
|
||
|
|
case RAVA_OP_LABEL: return "LABEL";
|
||
|
|
case RAVA_OP_CALL: return "CALL";
|
||
|
|
case RAVA_OP_CALL_STATIC: return "CALL_STATIC";
|
||
|
|
case RAVA_OP_RETURN: return "RETURN";
|
||
|
|
case RAVA_OP_RETURN_VOID: return "RETURN_VOID";
|
||
|
|
case RAVA_OP_NEW: return "NEW";
|
||
|
|
case RAVA_OP_NEW_ARRAY: return "NEW_ARRAY";
|
||
|
|
case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH";
|
||
|
|
case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY";
|
||
|
|
case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY";
|
||
|
|
case RAVA_OP_POP: return "POP";
|
||
|
|
case RAVA_OP_DUP: return "DUP";
|
||
|
|
case RAVA_OP_PRINT: return "PRINT";
|
||
|
|
case RAVA_OP_PRINTLN: return "PRINTLN";
|
||
|
|
default: return "UNKNOWN";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void rava_ir_print(RavaProgram_t *program) {
|
||
|
|
if (!program) return;
|
||
|
|
|
||
|
|
printf("IR Program (%zu classes)\n", program->class_count);
|
||
|
|
printf("================================================================================\n\n");
|
||
|
|
|
||
|
|
for (size_t i = 0; i < program->class_count; i++) {
|
||
|
|
RavaClass_t *class = program->classes[i];
|
||
|
|
printf("Class: %s\n", class->name);
|
||
|
|
|
||
|
|
for (size_t j = 0; j < class->method_count; j++) {
|
||
|
|
RavaMethod_t *method = class->methods[j];
|
||
|
|
printf(" Method: %s (locals: %d)\n", method->name, method->local_count);
|
||
|
|
|
||
|
|
for (size_t k = 0; k < method->instructions->count; k++) {
|
||
|
|
RavaInstruction_t *instr = &method->instructions->instructions[k];
|
||
|
|
printf(" %04zu %-15s", k, _rava_opcode_name(instr->opcode));
|
||
|
|
|
||
|
|
switch (instr->opcode) {
|
||
|
|
case RAVA_OP_LOAD_CONST:
|
||
|
|
printf(" %lld", (long long)instr->operand.int_value);
|
||
|
|
break;
|
||
|
|
case RAVA_OP_LOAD_LOCAL:
|
||
|
|
case RAVA_OP_STORE_LOCAL:
|
||
|
|
printf(" [%d]", instr->operand.var.index);
|
||
|
|
break;
|
||
|
|
case RAVA_OP_LABEL:
|
||
|
|
case RAVA_OP_JUMP:
|
||
|
|
case RAVA_OP_JUMP_IF_TRUE:
|
||
|
|
case RAVA_OP_JUMP_IF_FALSE:
|
||
|
|
printf(" L%d", instr->operand.label_id);
|
||
|
|
break;
|
||
|
|
case RAVA_OP_CALL_STATIC:
|
||
|
|
printf(" %s.%s",
|
||
|
|
instr->operand.call.class_name,
|
||
|
|
instr->operand.call.method_name);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
printf("\n");
|
||
|
|
}
|
||
|
|
printf("\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|