#include #include #include #include "lexer/lexer.h" #include "parser/parser.h" #include "semantic/semantic.h" #include "ir/ir.h" #include "ir/ir_gen.h" #include "runtime/runtime.h" #include "repl/repl.h" static char* read_file(const char *filename) { FILE *file = fopen(filename, "r"); if (!file) { fprintf(stderr, "Error: Cannot open file '%s'\n", filename); return NULL; } fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); char *content = malloc(size + 1); if (!content) { fclose(file); return NULL; } size_t read_bytes = fread(content, 1, size, file); content[read_bytes] = '\0'; fclose(file); return content; } static const char* find_main_class(const char *source) { static char class_name[256]; const char *p = strstr(source, "public static"); if (!p) p = strstr(source, "static public"); if (!p) return "Main"; while (p > source) { p--; if (strncmp(p, "class ", 6) == 0) { p += 6; while (*p == ' ') p++; int i = 0; while (*p && *p != ' ' && *p != '{' && *p != '\n' && i < 255) { class_name[i++] = *p++; } class_name[i] = '\0'; return class_name; } } return "Main"; } static void print_usage(const char *prog) { fprintf(stderr, "Usage: %s [options] [file.java] [class] [method]\n", prog); fprintf(stderr, "\nOptions:\n"); fprintf(stderr, " -i, --interactive Start interactive REPL\n"); fprintf(stderr, " -h, --help Show this help message\n"); fprintf(stderr, " -v, --version Show version\n"); fprintf(stderr, "\nExamples:\n"); fprintf(stderr, " %s Start REPL (interactive mode)\n", prog); fprintf(stderr, " %s file.java Run file.java\n", prog); fprintf(stderr, " %s file.java Main Run Main class from file.java\n", prog); fprintf(stderr, " %s -i Start REPL explicitly\n", prog); } static void print_version(void) { printf("Rava %s - Java Interpreter\n", RAVA_REPL_VERSION); printf("A stack-based VM for Java source code\n"); } static int run_file(const char *filename, const char *class_name_arg, const char *method_name_arg) { char *source = read_file(filename); if (!source) return 1; const char *class_name = class_name_arg ? class_name_arg : find_main_class(source); const char *method_name = method_name_arg ? method_name_arg : "main"; RavaLexer_t *lexer = rava_lexer_create(source); RavaParser_t *parser = rava_parser_create(lexer); RavaASTNode_t *ast = rava_parser_parse(parser); if (!ast || parser->had_error) { fprintf(stderr, "Parse error: %s\n", parser->error_message ? parser->error_message : "unknown"); free(source); return 1; } RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); if (!rava_semantic_analyze(analyzer, ast)) { fprintf(stderr, "Semantic error: %s\n", analyzer->error_message ? analyzer->error_message : "unknown"); free(source); return 1; } RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); RavaProgram_t *program = rava_ir_generate(ir_gen, ast); if (!program) { fprintf(stderr, "IR generation failed\n"); free(source); return 1; } RavaVM_t *vm = rava_vm_create(program); if (!rava_vm_execute(vm, class_name, method_name)) { fprintf(stderr, "Runtime error: %s\n", vm->error_message ? vm->error_message : "unknown"); free(source); return 1; } RavaValue_t result = rava_vm_get_result(vm); int ret = 0; if (result.type == RAVA_VAL_INT) { ret = (int)result.data.int_val; } rava_vm_destroy(vm); rava_program_destroy(program); rava_ir_generator_destroy(ir_gen); rava_semantic_analyzer_destroy(analyzer); rava_ast_node_destroy(ast); rava_parser_destroy(parser); rava_lexer_destroy(lexer); free(source); return ret; } int main(int argc, char **argv) { if (argc == 1) { return rava_repl_run(); } for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { print_usage(argv[0]); return 0; } if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { print_version(); return 0; } if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--interactive") == 0) { return rava_repl_run(); } } const char *filename = NULL; const char *class_name = NULL; const char *method_name = NULL; int pos_arg = 0; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') continue; switch (pos_arg) { case 0: filename = argv[i]; break; case 1: class_name = argv[i]; break; case 2: method_name = argv[i]; break; } pos_arg++; } if (!filename) { print_usage(argv[0]); return 1; } return run_file(filename, class_name, method_name); }