Initial commit of dem beast./plot.py
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
#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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
#ifndef RAVA_IR_H
|
||||
#define RAVA_IR_H
|
||||
|
||||
#include "../types/types.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
RAVA_OP_NOP,
|
||||
|
||||
RAVA_OP_LOAD_CONST,
|
||||
RAVA_OP_LOAD_LONG,
|
||||
RAVA_OP_LOAD_DOUBLE,
|
||||
RAVA_OP_LOAD_STRING,
|
||||
RAVA_OP_LOAD_LOCAL,
|
||||
RAVA_OP_LOAD_FIELD,
|
||||
RAVA_OP_LOAD_STATIC,
|
||||
RAVA_OP_LOAD_ARRAY,
|
||||
|
||||
RAVA_OP_STORE_LOCAL,
|
||||
RAVA_OP_STORE_FIELD,
|
||||
RAVA_OP_STORE_STATIC,
|
||||
RAVA_OP_STORE_ARRAY,
|
||||
|
||||
RAVA_OP_ADD,
|
||||
RAVA_OP_SUB,
|
||||
RAVA_OP_MUL,
|
||||
RAVA_OP_DIV,
|
||||
RAVA_OP_MOD,
|
||||
RAVA_OP_NEG,
|
||||
|
||||
RAVA_OP_AND,
|
||||
RAVA_OP_OR,
|
||||
RAVA_OP_XOR,
|
||||
RAVA_OP_NOT,
|
||||
RAVA_OP_SHL,
|
||||
RAVA_OP_SHR,
|
||||
RAVA_OP_USHR,
|
||||
|
||||
RAVA_OP_EQ,
|
||||
RAVA_OP_NE,
|
||||
RAVA_OP_LT,
|
||||
RAVA_OP_LE,
|
||||
RAVA_OP_GT,
|
||||
RAVA_OP_GE,
|
||||
|
||||
RAVA_OP_JUMP,
|
||||
RAVA_OP_JUMP_IF_TRUE,
|
||||
RAVA_OP_JUMP_IF_FALSE,
|
||||
RAVA_OP_LABEL,
|
||||
|
||||
RAVA_OP_CALL,
|
||||
RAVA_OP_CALL_STATIC,
|
||||
RAVA_OP_CALL_VIRTUAL,
|
||||
RAVA_OP_CALL_NATIVE,
|
||||
RAVA_OP_RETURN,
|
||||
RAVA_OP_RETURN_VOID,
|
||||
|
||||
RAVA_OP_NEW,
|
||||
RAVA_OP_NEW_ARRAY,
|
||||
RAVA_OP_ARRAY_LENGTH,
|
||||
RAVA_OP_GET_FIELD,
|
||||
RAVA_OP_PUT_FIELD,
|
||||
|
||||
RAVA_OP_CAST,
|
||||
RAVA_OP_INSTANCEOF,
|
||||
|
||||
RAVA_OP_THROW,
|
||||
RAVA_OP_POP,
|
||||
RAVA_OP_DUP,
|
||||
|
||||
RAVA_OP_PRINT,
|
||||
RAVA_OP_PRINTLN,
|
||||
|
||||
RAVA_OP_STRING_LENGTH,
|
||||
RAVA_OP_STRING_CHARAT,
|
||||
RAVA_OP_STRING_SUBSTRING,
|
||||
RAVA_OP_STRING_EQUALS,
|
||||
RAVA_OP_STRING_COMPARETO,
|
||||
|
||||
RAVA_OP_LOAD_THIS,
|
||||
|
||||
RAVA_OP_FILE_READ,
|
||||
RAVA_OP_FILE_WRITE,
|
||||
RAVA_OP_FILE_EXISTS,
|
||||
RAVA_OP_FILE_DELETE,
|
||||
|
||||
RAVA_OP_CURRENT_TIME_MILLIS,
|
||||
RAVA_OP_NANO_TIME,
|
||||
|
||||
RAVA_OP_INC_LOCAL,
|
||||
RAVA_OP_DEC_LOCAL,
|
||||
RAVA_OP_LOAD_LOCAL_CONST_ADD,
|
||||
RAVA_OP_LOAD_LOCAL_CONST_LT_JUMPFALSE,
|
||||
RAVA_OP_LOAD_LOCAL_CONST_LE_JUMPFALSE,
|
||||
RAVA_OP_LOAD_TWO_LOCALS,
|
||||
RAVA_OP_ADD_LOCAL_TO_LOCAL,
|
||||
RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE
|
||||
} RavaOpCode_e;
|
||||
|
||||
typedef union {
|
||||
int64_t int_value;
|
||||
double float_value;
|
||||
char *string_value;
|
||||
int label_id;
|
||||
struct {
|
||||
int index;
|
||||
RavaType_t *type;
|
||||
} var;
|
||||
struct {
|
||||
char *class_name;
|
||||
char *method_name;
|
||||
int arg_count;
|
||||
} call;
|
||||
struct {
|
||||
char *class_name;
|
||||
char *field_name;
|
||||
} field;
|
||||
struct {
|
||||
int local_index;
|
||||
int64_t const_value;
|
||||
int label_id;
|
||||
} super;
|
||||
struct {
|
||||
int index1;
|
||||
int index2;
|
||||
} two_locals;
|
||||
struct {
|
||||
int dest_index;
|
||||
int src_index;
|
||||
} add_locals;
|
||||
struct {
|
||||
int local1;
|
||||
int local2;
|
||||
int label_id;
|
||||
} cmp_locals;
|
||||
} RavaOperand_u;
|
||||
|
||||
typedef struct {
|
||||
RavaOpCode_e opcode;
|
||||
RavaOperand_u operand;
|
||||
int line;
|
||||
} RavaInstruction_t;
|
||||
|
||||
typedef struct {
|
||||
RavaInstruction_t *instructions;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
int next_label_id;
|
||||
} RavaInstructionList_t;
|
||||
|
||||
struct LabelTable_s;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
RavaType_t *return_type;
|
||||
RavaType_t **param_types;
|
||||
size_t param_count;
|
||||
int local_count;
|
||||
RavaInstructionList_t *instructions;
|
||||
struct LabelTable_s *label_table;
|
||||
} RavaMethod_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *superclass;
|
||||
RavaMethod_t **methods;
|
||||
size_t method_count;
|
||||
size_t method_capacity;
|
||||
} RavaClass_t;
|
||||
|
||||
typedef struct {
|
||||
RavaClass_t **classes;
|
||||
size_t class_count;
|
||||
size_t class_capacity;
|
||||
} RavaProgram_t;
|
||||
|
||||
RavaInstructionList_t* rava_instruction_list_create();
|
||||
void rava_instruction_list_destroy(RavaInstructionList_t *list);
|
||||
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr);
|
||||
int rava_instruction_list_new_label(RavaInstructionList_t *list);
|
||||
|
||||
RavaMethod_t* rava_method_create(const char *name, RavaType_t *return_type);
|
||||
void rava_method_destroy(RavaMethod_t *method);
|
||||
|
||||
RavaClass_t* rava_class_create(const char *name);
|
||||
void rava_class_destroy(RavaClass_t *class);
|
||||
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method);
|
||||
|
||||
RavaProgram_t* rava_program_create();
|
||||
void rava_program_destroy(RavaProgram_t *program);
|
||||
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class);
|
||||
|
||||
void rava_ir_print(RavaProgram_t *program);
|
||||
|
||||
#endif
|
||||
+669
@@ -0,0 +1,669 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "ir_gen.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr);
|
||||
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt);
|
||||
|
||||
static void _rava_ir_clear_locals(RavaIRGenerator_t *gen) {
|
||||
RavaLocalVar_t *current = gen->locals;
|
||||
while (current) {
|
||||
RavaLocalVar_t *next = current->next;
|
||||
free(current->name);
|
||||
free(current);
|
||||
current = next;
|
||||
}
|
||||
gen->locals = NULL;
|
||||
}
|
||||
|
||||
static void _rava_ir_add_local(RavaIRGenerator_t *gen, const char *name, size_t index) {
|
||||
RavaLocalVar_t *local = calloc(1, sizeof(RavaLocalVar_t));
|
||||
local->name = strdup(name);
|
||||
local->index = index;
|
||||
local->next = gen->locals;
|
||||
gen->locals = local;
|
||||
}
|
||||
|
||||
static int _rava_ir_find_local(RavaIRGenerator_t *gen, const char *name) {
|
||||
for (RavaLocalVar_t *local = gen->locals; local; local = local->next) {
|
||||
if (strcmp(local->name, name) == 0) {
|
||||
return (int)local->index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer) {
|
||||
RavaIRGenerator_t *gen = calloc(1, sizeof(RavaIRGenerator_t));
|
||||
gen->program = rava_program_create();
|
||||
gen->current_class = NULL;
|
||||
gen->current_method = NULL;
|
||||
gen->analyzer = analyzer;
|
||||
gen->next_local = 0;
|
||||
gen->locals = NULL;
|
||||
gen->loop_context = NULL;
|
||||
gen->error_message = NULL;
|
||||
gen->had_error = false;
|
||||
return gen;
|
||||
}
|
||||
|
||||
void rava_ir_generator_destroy(RavaIRGenerator_t *generator) {
|
||||
if (!generator) return;
|
||||
_rava_ir_clear_locals(generator);
|
||||
free(generator->error_message);
|
||||
free(generator);
|
||||
}
|
||||
|
||||
static void _rava_ir_emit(RavaIRGenerator_t *gen, RavaInstruction_t instr) {
|
||||
if (!gen->current_method) return;
|
||||
rava_instruction_list_add(gen->current_method->instructions, instr);
|
||||
}
|
||||
|
||||
static void _rava_ir_gen_binary_expr(RavaIRGenerator_t *gen, RavaASTNode_t *expr) {
|
||||
_rava_ir_gen_expression(gen, expr->data.binary.left);
|
||||
_rava_ir_gen_expression(gen, expr->data.binary.right);
|
||||
|
||||
RavaInstruction_t instr = {0};
|
||||
instr.line = expr->line;
|
||||
|
||||
switch (expr->data.binary.op) {
|
||||
case RAVA_BINOP_ADD: instr.opcode = RAVA_OP_ADD; break;
|
||||
case RAVA_BINOP_SUB: instr.opcode = RAVA_OP_SUB; break;
|
||||
case RAVA_BINOP_MUL: instr.opcode = RAVA_OP_MUL; break;
|
||||
case RAVA_BINOP_DIV: instr.opcode = RAVA_OP_DIV; break;
|
||||
case RAVA_BINOP_MOD: instr.opcode = RAVA_OP_MOD; break;
|
||||
case RAVA_BINOP_EQ: instr.opcode = RAVA_OP_EQ; break;
|
||||
case RAVA_BINOP_NE: instr.opcode = RAVA_OP_NE; break;
|
||||
case RAVA_BINOP_LT: instr.opcode = RAVA_OP_LT; break;
|
||||
case RAVA_BINOP_LE: instr.opcode = RAVA_OP_LE; break;
|
||||
case RAVA_BINOP_GT: instr.opcode = RAVA_OP_GT; break;
|
||||
case RAVA_BINOP_GE: instr.opcode = RAVA_OP_GE; break;
|
||||
case RAVA_BINOP_AND: instr.opcode = RAVA_OP_AND; break;
|
||||
case RAVA_BINOP_OR: instr.opcode = RAVA_OP_OR; break;
|
||||
default: instr.opcode = RAVA_OP_NOP; break;
|
||||
}
|
||||
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
|
||||
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) {
|
||||
if (!expr) return;
|
||||
|
||||
RavaInstruction_t instr = {0};
|
||||
instr.line = expr->line;
|
||||
|
||||
switch (expr->type) {
|
||||
case RAVA_AST_LITERAL_EXPR:
|
||||
if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
|
||||
instr.opcode = RAVA_OP_LOAD_STRING;
|
||||
instr.operand.string_value = strdup(expr->data.literal.value.string_value);
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_LONG) {
|
||||
instr.opcode = RAVA_OP_LOAD_LONG;
|
||||
instr.operand.int_value = expr->data.literal.value.int_value;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_DOUBLE) {
|
||||
instr.opcode = RAVA_OP_LOAD_DOUBLE;
|
||||
instr.operand.float_value = expr->data.literal.value.float_value;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else {
|
||||
instr.opcode = RAVA_OP_LOAD_CONST;
|
||||
instr.operand.int_value = expr->data.literal.value.int_value;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_IDENTIFIER_EXPR: {
|
||||
int local_index = _rava_ir_find_local(gen, expr->data.identifier.name);
|
||||
if (local_index >= 0) {
|
||||
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_AST_BINARY_EXPR:
|
||||
_rava_ir_gen_binary_expr(gen, expr);
|
||||
break;
|
||||
|
||||
case RAVA_AST_UNARY_EXPR:
|
||||
if (expr->data.unary.op == RAVA_UNOP_MINUS) {
|
||||
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
||||
instr.opcode = RAVA_OP_NEG;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.unary.op == RAVA_UNOP_NOT) {
|
||||
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
||||
instr.opcode = RAVA_OP_NOT;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.unary.op == RAVA_UNOP_PREINC || expr->data.unary.op == RAVA_UNOP_PREDEC) {
|
||||
if (expr->data.unary.operand->type == RAVA_AST_IDENTIFIER_EXPR) {
|
||||
int local_index = _rava_ir_find_local(gen, expr->data.unary.operand->data.identifier.name);
|
||||
if (local_index >= 0) {
|
||||
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_LOAD_CONST;
|
||||
instr.operand.int_value = 1;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = (expr->data.unary.op == RAVA_UNOP_PREINC) ? RAVA_OP_ADD : RAVA_OP_SUB;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_DUP;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_STORE_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
}
|
||||
} else if (expr->data.unary.op == RAVA_UNOP_POSTINC || expr->data.unary.op == RAVA_UNOP_POSTDEC) {
|
||||
if (expr->data.unary.operand->type == RAVA_AST_IDENTIFIER_EXPR) {
|
||||
int local_index = _rava_ir_find_local(gen, expr->data.unary.operand->data.identifier.name);
|
||||
if (local_index >= 0) {
|
||||
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_LOAD_CONST;
|
||||
instr.operand.int_value = 1;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = (expr->data.unary.op == RAVA_UNOP_POSTINC) ? RAVA_OP_ADD : RAVA_OP_SUB;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_STORE_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_ASSIGN_EXPR:
|
||||
if (expr->data.assign.target->type == RAVA_AST_ARRAY_ACCESS_EXPR) {
|
||||
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.array);
|
||||
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.index);
|
||||
_rava_ir_gen_expression(gen, expr->data.assign.value);
|
||||
instr.opcode = RAVA_OP_STORE_ARRAY;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
_rava_ir_gen_expression(gen, expr->data.assign.target->data.member_access.object);
|
||||
_rava_ir_gen_expression(gen, expr->data.assign.value);
|
||||
instr.opcode = RAVA_OP_PUT_FIELD;
|
||||
instr.operand.field.field_name = strdup(expr->data.assign.target->data.member_access.member);
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else {
|
||||
_rava_ir_gen_expression(gen, expr->data.assign.value);
|
||||
|
||||
if (expr->data.assign.target->type == RAVA_AST_IDENTIFIER_EXPR) {
|
||||
int local_index = _rava_ir_find_local(gen, expr->data.assign.target->data.identifier.name);
|
||||
if (local_index >= 0) {
|
||||
instr.opcode = RAVA_OP_STORE_LOCAL;
|
||||
instr.operand.var.index = (size_t)local_index;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_MEMBER_ACCESS_EXPR:
|
||||
_rava_ir_gen_expression(gen, expr->data.member_access.object);
|
||||
instr.opcode = RAVA_OP_GET_FIELD;
|
||||
instr.operand.field.field_name = strdup(expr->data.member_access.member);
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
|
||||
case RAVA_AST_ARRAY_ACCESS_EXPR:
|
||||
_rava_ir_gen_expression(gen, expr->data.array_access.array);
|
||||
_rava_ir_gen_expression(gen, expr->data.array_access.index);
|
||||
instr.opcode = RAVA_OP_LOAD_ARRAY;
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
|
||||
case RAVA_AST_NEW_EXPR:
|
||||
if (expr->data.new_expr.type && expr->data.new_expr.type->data.type.is_array) {
|
||||
if (expr->data.new_expr.arguments_count > 0) {
|
||||
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_NEW_ARRAY;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.new_expr.type) {
|
||||
instr.opcode = RAVA_OP_NEW;
|
||||
instr.operand.call.class_name = strdup(expr->data.new_expr.type->data.type.type_name);
|
||||
instr.operand.call.arg_count = expr->data.new_expr.arguments_count;
|
||||
_rava_ir_emit(gen, instr);
|
||||
instr.opcode = RAVA_OP_DUP;
|
||||
_rava_ir_emit(gen, instr);
|
||||
for (size_t i = 0; i < expr->data.new_expr.arguments_count; i++) {
|
||||
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[i]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_CALL_VIRTUAL;
|
||||
instr.operand.call.method_name = strdup("<init>");
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_CALL_EXPR: {
|
||||
bool is_println = false;
|
||||
bool is_print = false;
|
||||
bool is_string_length = false;
|
||||
bool is_string_charat = false;
|
||||
bool is_string_equals = false;
|
||||
bool is_file_read = false;
|
||||
bool is_file_write = false;
|
||||
bool is_file_exists = false;
|
||||
bool is_file_delete = false;
|
||||
bool is_current_time_millis = false;
|
||||
bool is_nano_time = false;
|
||||
RavaASTNode_t *string_object = NULL;
|
||||
|
||||
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
RavaASTNode_t *member = expr->data.call.callee;
|
||||
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
||||
strcmp(member->data.member_access.object->data.identifier.name, "System") == 0) {
|
||||
if (strcmp(member->data.member_access.member, "currentTimeMillis") == 0) {
|
||||
is_current_time_millis = true;
|
||||
} else if (strcmp(member->data.member_access.member, "nanoTime") == 0) {
|
||||
is_nano_time = true;
|
||||
}
|
||||
}
|
||||
if (member->data.member_access.object->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
RavaASTNode_t *system_out = member->data.member_access.object;
|
||||
if (system_out->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
||||
strcmp(system_out->data.member_access.object->data.identifier.name, "System") == 0 &&
|
||||
strcmp(system_out->data.member_access.member, "out") == 0) {
|
||||
if (strcmp(member->data.member_access.member, "println") == 0) {
|
||||
is_println = true;
|
||||
} else if (strcmp(member->data.member_access.member, "print") == 0) {
|
||||
is_print = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
||||
strcmp(member->data.member_access.object->data.identifier.name, "Files") == 0) {
|
||||
if (strcmp(member->data.member_access.member, "read") == 0 && expr->data.call.arguments_count == 1) {
|
||||
is_file_read = true;
|
||||
} else if (strcmp(member->data.member_access.member, "write") == 0 && expr->data.call.arguments_count == 2) {
|
||||
is_file_write = true;
|
||||
} else if (strcmp(member->data.member_access.member, "exists") == 0 && expr->data.call.arguments_count == 1) {
|
||||
is_file_exists = true;
|
||||
} else if (strcmp(member->data.member_access.member, "delete") == 0 && expr->data.call.arguments_count == 1) {
|
||||
is_file_delete = true;
|
||||
}
|
||||
}
|
||||
if (strcmp(member->data.member_access.member, "length") == 0 && expr->data.call.arguments_count == 0) {
|
||||
is_string_length = true;
|
||||
string_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "charAt") == 0 && expr->data.call.arguments_count == 1) {
|
||||
is_string_charat = true;
|
||||
string_object = member->data.member_access.object;
|
||||
} else if (strcmp(member->data.member_access.member, "equals") == 0 && expr->data.call.arguments_count == 1) {
|
||||
is_string_equals = true;
|
||||
string_object = member->data.member_access.object;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_current_time_millis) {
|
||||
instr.opcode = RAVA_OP_CURRENT_TIME_MILLIS;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_nano_time) {
|
||||
instr.opcode = RAVA_OP_NANO_TIME;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_file_read) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
instr.opcode = RAVA_OP_FILE_READ;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_file_write) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
|
||||
instr.opcode = RAVA_OP_FILE_WRITE;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_file_exists) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
instr.opcode = RAVA_OP_FILE_EXISTS;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_file_delete) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
instr.opcode = RAVA_OP_FILE_DELETE;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_string_length) {
|
||||
_rava_ir_gen_expression(gen, string_object);
|
||||
instr.opcode = RAVA_OP_STRING_LENGTH;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_string_charat) {
|
||||
_rava_ir_gen_expression(gen, string_object);
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
instr.opcode = RAVA_OP_STRING_CHARAT;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_string_equals) {
|
||||
_rava_ir_gen_expression(gen, string_object);
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||
instr.opcode = RAVA_OP_STRING_EQUALS;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (is_println || is_print) {
|
||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||
}
|
||||
if (is_println) {
|
||||
instr.opcode = RAVA_OP_PRINTLN;
|
||||
} else {
|
||||
instr.opcode = RAVA_OP_PRINT;
|
||||
}
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||
RavaASTNode_t *member = expr->data.call.callee;
|
||||
_rava_ir_gen_expression(gen, member->data.member_access.object);
|
||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_CALL_VIRTUAL;
|
||||
instr.operand.call.class_name = strdup(gen->current_class->name);
|
||||
instr.operand.call.method_name = strdup(member->data.member_access.member);
|
||||
instr.operand.call.arg_count = expr->data.call.arguments_count;
|
||||
_rava_ir_emit(gen, instr);
|
||||
} else {
|
||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||
}
|
||||
instr.opcode = RAVA_OP_CALL_STATIC;
|
||||
if (expr->data.call.callee->type == RAVA_AST_IDENTIFIER_EXPR) {
|
||||
instr.operand.call.class_name = strdup(gen->current_class->name);
|
||||
instr.operand.call.method_name = strdup(expr->data.call.callee->data.identifier.name);
|
||||
instr.operand.call.arg_count = expr->data.call.arguments_count;
|
||||
}
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_AST_THIS_EXPR:
|
||||
instr.opcode = RAVA_OP_LOAD_THIS;
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) {
|
||||
if (!stmt) return;
|
||||
|
||||
RavaInstruction_t instr = {0};
|
||||
instr.line = stmt->line;
|
||||
|
||||
switch (stmt->type) {
|
||||
case RAVA_AST_BLOCK_STMT:
|
||||
for (size_t i = 0; i < stmt->children_count; i++) {
|
||||
_rava_ir_gen_statement(gen, stmt->children[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_IF_STMT: {
|
||||
_rava_ir_gen_expression(gen, stmt->data.if_stmt.condition);
|
||||
|
||||
int else_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
|
||||
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
|
||||
instr.operand.label_id = else_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
_rava_ir_gen_statement(gen, stmt->data.if_stmt.then_stmt);
|
||||
|
||||
instr.opcode = RAVA_OP_JUMP;
|
||||
instr.operand.label_id = end_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = else_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
if (stmt->data.if_stmt.else_stmt) {
|
||||
_rava_ir_gen_statement(gen, stmt->data.if_stmt.else_stmt);
|
||||
}
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = end_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_AST_WHILE_STMT: {
|
||||
int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
|
||||
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = start_label, .parent = gen->loop_context };
|
||||
gen->loop_context = &loop_ctx;
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = start_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
_rava_ir_gen_expression(gen, stmt->data.while_stmt.condition);
|
||||
|
||||
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
|
||||
instr.operand.label_id = end_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
_rava_ir_gen_statement(gen, stmt->data.while_stmt.body);
|
||||
|
||||
instr.opcode = RAVA_OP_JUMP;
|
||||
instr.operand.label_id = start_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = end_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
gen->loop_context = loop_ctx.parent;
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_AST_FOR_STMT: {
|
||||
if (stmt->data.for_stmt.init) {
|
||||
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
|
||||
_rava_ir_gen_statement(gen, stmt->data.for_stmt.init);
|
||||
} else {
|
||||
_rava_ir_gen_expression(gen, stmt->data.for_stmt.init);
|
||||
instr.opcode = RAVA_OP_POP;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
}
|
||||
|
||||
int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
int continue_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
||||
|
||||
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = continue_label, .parent = gen->loop_context };
|
||||
gen->loop_context = &loop_ctx;
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = start_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
if (stmt->data.for_stmt.condition) {
|
||||
_rava_ir_gen_expression(gen, stmt->data.for_stmt.condition);
|
||||
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
|
||||
instr.operand.label_id = end_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
|
||||
_rava_ir_gen_statement(gen, stmt->data.for_stmt.body);
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = continue_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
if (stmt->data.for_stmt.update) {
|
||||
_rava_ir_gen_expression(gen, stmt->data.for_stmt.update);
|
||||
instr.opcode = RAVA_OP_POP;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
|
||||
instr.opcode = RAVA_OP_JUMP;
|
||||
instr.operand.label_id = start_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
instr.opcode = RAVA_OP_LABEL;
|
||||
instr.operand.label_id = end_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
|
||||
gen->loop_context = loop_ctx.parent;
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_AST_RETURN_STMT:
|
||||
if (stmt->data.return_stmt.value) {
|
||||
_rava_ir_gen_expression(gen, stmt->data.return_stmt.value);
|
||||
instr.opcode = RAVA_OP_RETURN;
|
||||
} else {
|
||||
instr.opcode = RAVA_OP_RETURN_VOID;
|
||||
}
|
||||
_rava_ir_emit(gen, instr);
|
||||
break;
|
||||
|
||||
case RAVA_AST_EXPR_STMT:
|
||||
if (stmt->children_count > 0) {
|
||||
_rava_ir_gen_expression(gen, stmt->children[0]);
|
||||
instr.opcode = RAVA_OP_POP;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_VAR_DECL: {
|
||||
_rava_ir_add_local(gen, stmt->data.var_decl.name, gen->next_local);
|
||||
gen->next_local++;
|
||||
if (stmt->data.var_decl.initializer) {
|
||||
_rava_ir_gen_expression(gen, stmt->data.var_decl.initializer);
|
||||
instr.opcode = RAVA_OP_STORE_LOCAL;
|
||||
instr.operand.var.index = gen->next_local - 1;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RAVA_AST_BREAK_STMT:
|
||||
if (gen->loop_context) {
|
||||
instr.opcode = RAVA_OP_JUMP;
|
||||
instr.operand.label_id = gen->loop_context->break_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
|
||||
case RAVA_AST_CONTINUE_STMT:
|
||||
if (gen->loop_context) {
|
||||
instr.opcode = RAVA_OP_JUMP;
|
||||
instr.operand.label_id = gen->loop_context->continue_label;
|
||||
_rava_ir_emit(gen, instr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _rava_ir_gen_method(RavaIRGenerator_t *gen, RavaASTNode_t *method_node) {
|
||||
if (method_node->type != RAVA_AST_METHOD_DECL) return;
|
||||
|
||||
RavaType_t *return_type = rava_type_from_name(
|
||||
method_node->data.method_decl.return_type->data.type.type_name);
|
||||
|
||||
RavaMethod_t *method = rava_method_create(method_node->data.method_decl.name, return_type);
|
||||
gen->current_method = method;
|
||||
gen->next_local = 0;
|
||||
_rava_ir_clear_locals(gen);
|
||||
|
||||
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, method_node->data.method_decl.name);
|
||||
|
||||
for (size_t i = 0; i < method_node->children_count; i++) {
|
||||
RavaASTNode_t *child = method_node->children[i];
|
||||
|
||||
if (child->type == RAVA_AST_PARAM_DECL) {
|
||||
_rava_ir_add_local(gen, child->data.var_decl.name, gen->next_local);
|
||||
gen->next_local++;
|
||||
} else if (child->type == RAVA_AST_BLOCK_STMT) {
|
||||
_rava_ir_gen_statement(gen, child);
|
||||
}
|
||||
}
|
||||
|
||||
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
|
||||
|
||||
method->local_count = gen->next_local;
|
||||
rava_class_add_method(gen->current_class, method);
|
||||
gen->current_method = NULL;
|
||||
}
|
||||
|
||||
static void _rava_ir_gen_constructor(RavaIRGenerator_t *gen, RavaASTNode_t *ctor_node) {
|
||||
if (ctor_node->type != RAVA_AST_CONSTRUCTOR_DECL) return;
|
||||
|
||||
RavaType_t *void_type = rava_type_from_name("void");
|
||||
RavaMethod_t *method = rava_method_create("<init>", void_type);
|
||||
gen->current_method = method;
|
||||
gen->next_local = 0;
|
||||
_rava_ir_clear_locals(gen);
|
||||
|
||||
for (size_t i = 0; i < ctor_node->children_count; i++) {
|
||||
RavaASTNode_t *child = ctor_node->children[i];
|
||||
if (child->type == RAVA_AST_PARAM_DECL) {
|
||||
_rava_ir_add_local(gen, child->data.var_decl.name, gen->next_local);
|
||||
gen->next_local++;
|
||||
} else if (child->type == RAVA_AST_BLOCK_STMT) {
|
||||
_rava_ir_gen_statement(gen, child);
|
||||
}
|
||||
}
|
||||
|
||||
RavaInstruction_t ret_instr = {0};
|
||||
ret_instr.opcode = RAVA_OP_RETURN_VOID;
|
||||
_rava_ir_emit(gen, ret_instr);
|
||||
|
||||
method->local_count = gen->next_local;
|
||||
rava_class_add_method(gen->current_class, method);
|
||||
gen->current_method = NULL;
|
||||
}
|
||||
|
||||
static void _rava_ir_gen_class(RavaIRGenerator_t *gen, RavaASTNode_t *class_node) {
|
||||
if (class_node->type != RAVA_AST_CLASS_DECL) return;
|
||||
|
||||
RavaClass_t *class = rava_class_create(class_node->data.class_decl.name);
|
||||
if (class_node->data.class_decl.superclass) {
|
||||
class->superclass = strdup(class_node->data.class_decl.superclass);
|
||||
}
|
||||
gen->current_class = class;
|
||||
|
||||
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, class_node->data.class_decl.name);
|
||||
|
||||
for (size_t i = 0; i < class_node->children_count; i++) {
|
||||
RavaASTNode_t *child = class_node->children[i];
|
||||
|
||||
if (child->type == RAVA_AST_METHOD_DECL) {
|
||||
_rava_ir_gen_method(gen, child);
|
||||
} else if (child->type == RAVA_AST_CONSTRUCTOR_DECL) {
|
||||
_rava_ir_gen_constructor(gen, child);
|
||||
}
|
||||
}
|
||||
|
||||
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
|
||||
|
||||
rava_program_add_class(gen->program, class);
|
||||
gen->current_class = NULL;
|
||||
}
|
||||
|
||||
RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *root) {
|
||||
if (!generator || !root) return NULL;
|
||||
|
||||
if (root->type == RAVA_AST_COMPILATION_UNIT) {
|
||||
for (size_t i = 0; i < root->children_count; i++) {
|
||||
RavaASTNode_t *child = root->children[i];
|
||||
if (child->type == RAVA_AST_CLASS_DECL) {
|
||||
_rava_ir_gen_class(generator, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return generator->program;
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef RAVA_IR_GEN_H
|
||||
#define RAVA_IR_GEN_H
|
||||
|
||||
#include "../parser/parser.h"
|
||||
#include "../semantic/semantic.h"
|
||||
#include "ir.h"
|
||||
|
||||
typedef struct RavaLocalVar_t {
|
||||
char *name;
|
||||
size_t index;
|
||||
struct RavaLocalVar_t *next;
|
||||
} RavaLocalVar_t;
|
||||
|
||||
typedef struct RavaLoopContext_t {
|
||||
int break_label;
|
||||
int continue_label;
|
||||
struct RavaLoopContext_t *parent;
|
||||
} RavaLoopContext_t;
|
||||
|
||||
typedef struct {
|
||||
RavaProgram_t *program;
|
||||
RavaClass_t *current_class;
|
||||
RavaMethod_t *current_method;
|
||||
RavaSemanticAnalyzer_t *analyzer;
|
||||
int next_local;
|
||||
RavaLocalVar_t *locals;
|
||||
RavaLoopContext_t *loop_context;
|
||||
char *error_message;
|
||||
bool had_error;
|
||||
} RavaIRGenerator_t;
|
||||
|
||||
RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer);
|
||||
void rava_ir_generator_destroy(RavaIRGenerator_t *generator);
|
||||
|
||||
RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *root);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user