Initial commit of dem beast./plot.py

This commit is contained in:
2025-12-02 06:54:32 +01:00
commit c9cf356cbd
58 changed files with 9092 additions and 0 deletions
+200
View File
@@ -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");
}
}
}
+197
View File
@@ -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
View File
@@ -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
View File
@@ -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