diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-11 15:11:00 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-11 15:11:00 +0000 |
| commit | 55247a3f12a9eee7ba3fd7ca6d8fcea7a82c20f3 (patch) | |
| tree | a2a71e2eb8ca0b2c483518c1902d89d18709c9ab /src/main.c | |
| parent | 2e7abed7cfe84a2c0df371cde35f8f68cfdca16c (diff) | |
Added src/ folder. Now I will add the rest.
Diffstat (limited to 'src/main.c')
| -rw-r--r-- | src/main.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a455943 --- /dev/null +++ b/src/main.c @@ -0,0 +1,301 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "zprep.h" +#include "parser/parser.h" +#include "codegen/codegen.h" +#include "repl/repl.h" +#include "plugins/plugin_manager.h" + +// Forward decl for LSP +int lsp_main(int argc, char **argv); + +void print_search_paths() +{ + printf("Search paths:\n"); + printf(" ./\n"); + printf(" ./std/\n"); + printf(" /usr/local/lib/zen/\n"); +} + +void print_usage() +{ + printf("Usage: zc [command] [options] <file.zc>\n"); + printf("Commands:\n"); + printf(" run Compile and run the program\n"); + printf(" build Compile to executable\n"); + printf(" check Check for errors only\n"); + printf(" repl Start Interactive REPL\n"); + printf(" lsp Start Language Server\n"); + printf("Options:\n"); + printf(" -o <file> Output executable name\n"); + printf(" --emit-c Keep generated C file (out.c)\n"); + printf(" --freestanding Freestanding mode (no stdlib)\n"); + printf(" --cc <compiler> C compiler to use (gcc, clang, tcc)\n"); + printf(" -O<level> Optimization level\n"); + printf(" -g Debug info\n"); + printf(" -v, --verbose Verbose output\n"); + printf(" -q, --quiet Quiet output\n"); + printf(" -c Compile only (produce .o)\n"); +} + +int main(int argc, char **argv) +{ + // Defaults + memset(&g_config, 0, sizeof(g_config)); + strcpy(g_config.cc, "gcc"); + + if (argc < 2) + { + print_usage(); + return 1; + } + + // Parse command + char *command = argv[1]; + int arg_start = 2; + + if (strcmp(command, "lsp") == 0) + { + return lsp_main(argc, argv); + } + else if (strcmp(command, "repl") == 0) + { + run_repl(argv[0]); // Pass self path for recursive calls + return 0; + } + else if (strcmp(command, "run") == 0) + { + g_config.mode_run = 1; + } + else if (strcmp(command, "check") == 0) + { + g_config.mode_check = 1; + } + else if (strcmp(command, "build") == 0) + { + // default mode + } + else if (command[0] == '-') + { + // implicit build or run? assume build if starts with flag, but usually command first + // If file provided directly: "zc file.zc" -> build + if (strchr(command, '.')) + { + // treat as filename + g_config.input_file = command; + arg_start = 2; // already consumed + } + else + { + // Flags + arg_start = 1; + } + } + else + { + // Check if file + if (strchr(command, '.')) + { + g_config.input_file = command; + arg_start = 2; + } + } + + // Parse args + for (int i = arg_start; i < argc; i++) + { + char *arg = argv[i]; + if (strcmp(arg, "--emit-c") == 0) + { + g_config.emit_c = 1; + } + else if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0) + { + g_config.verbose = 1; + } + else if (strcmp(arg, "--quiet") == 0 || strcmp(arg, "-q") == 0) + { + g_config.quiet = 1; + } + else if (strcmp(arg, "--freestanding") == 0) + { + g_config.is_freestanding = 1; + } + else if (strcmp(arg, "--check") == 0) + { + g_config.mode_check = 1; + } + else if (strcmp(arg, "--cc") == 0) + { + if (i + 1 < argc) + { + strcpy(g_config.cc, argv[++i]); + } + } + else if (strcmp(arg, "-o") == 0) + { + if (i + 1 < argc) + { + g_config.output_file = argv[++i]; + } + } + else if (strncmp(arg, "-O", 2) == 0) + { + // Add to CFLAGS + strcat(g_config.gcc_flags, " "); + strcat(g_config.gcc_flags, arg); + } + else if (strcmp(arg, "-g") == 0) + { + strcat(g_config.gcc_flags, " -g"); + } + else if (arg[0] == '-') + { + // Unknown flag or C flag + strcat(g_config.gcc_flags, " "); + strcat(g_config.gcc_flags, arg); + } + else + { + if (!g_config.input_file) + { + g_config.input_file = arg; + } + else + { + printf("Multiple input files not supported yet.\n"); + return 1; + } + } + } + + if (!g_config.input_file) + { + printf("Error: No input file specified.\n"); + return 1; + } + + g_current_filename = g_config.input_file; + + // Load file + char *src = load_file(g_config.input_file); + if (!src) + { + printf("Error: Could not read file %s\n", g_config.input_file); + return 1; + } + + init_builtins(); + + // Initialize Plugin Manager + zptr_plugin_mgr_init(); + + // Register built-in plugins + extern ZPlugin brainfuck_plugin; + extern ZPlugin befunge_plugin; + extern ZPlugin lisp_plugin; + extern ZPlugin forth_plugin; + extern ZPlugin regex_plugin; + extern ZPlugin sql_plugin; + + zptr_register_plugin(&brainfuck_plugin); + zptr_register_plugin(&befunge_plugin); + zptr_register_plugin(&lisp_plugin); + zptr_register_plugin(&forth_plugin); + zptr_register_plugin(®ex_plugin); + zptr_register_plugin(&sql_plugin); + + Lexer l; + lexer_init(&l, src); + + // Parse + ParserContext ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.hoist_out = tmpfile(); // Temp file for plugin hoisting + if (!ctx.hoist_out) + { + perror("tmpfile for hoisting"); + return 1; + } + g_parser_ctx = &ctx; + + if (!g_config.quiet) + { + printf("[zc] Compiling %s...\n", g_config.input_file); + } + + ASTNode *root = parse_program(&ctx, &l); + if (!root) + { + // Parse failed + return 1; + } + + // Checking mode? + // analyze(root); // Implicit in parsing or separate step? Assuming separate if check_mode + + if (g_config.mode_check) + { + // Just verify + printf("Check passed.\n"); + return 0; + } + + // Codegen to C + FILE *out = fopen("out.c", "w"); + if (!out) + { + perror("fopen out.c"); + return 1; + } + + codegen_node(&ctx, root, out); + fclose(out); + + // Compile C + char cmd[8192]; + char *outfile = g_config.output_file ? g_config.output_file : "a.out"; + + // TCC-specific adjustments? + // Already handled by user passing --cc tcc + + snprintf(cmd, sizeof(cmd), "%s %s %s -o %s out.c -lm -lpthread -I./src", g_config.cc, + g_config.gcc_flags, g_config.is_freestanding ? "-ffreestanding" : "", outfile); + + if (g_config.verbose) + { + printf("[CMD] %s\n", cmd); + } + + int ret = system(cmd); + if (ret != 0) + { + printf("C compilation failed.\n"); + if (!g_config.emit_c) + { + remove("out.c"); + } + return 1; + } + + if (!g_config.emit_c) + { + // remove("out.c"); // Keep it for debugging for now or follow flag + remove("out.c"); + } + + if (g_config.mode_run) + { + char run_cmd[2048]; + sprintf(run_cmd, "./%s", outfile); + ret = system(run_cmd); + // Clean up executable if temp run? + // ZPrep behavior: keeps it. + return ret; + } + + zptr_plugin_mgr_cleanup(); + return 0; +} |
