MXVM 1.8.1
Virtual Machine, Compiler, and Pascal Frontend
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1
6#include "version_info.hpp"
7#include "argz.hpp"
8#include <csignal>
9#include <dlfcn.h>
10#include <filesystem>
11#include <fstream>
12#include <iostream>
13#include <memory>
14#include <mxvm/mxvm.hpp>
15#include <set>
16#include <sstream>
17#include <string>
18#include <string_view>
19#include <vector>
20#ifdef _WIN32
21#include <windows.h>
22#endif
23
35
36std::ostream &operator<<(std::ostream &out, const vm_action &ae) {
37 switch (ae) {
39 out << "null action";
40 break;
42 out << "translate";
43 break;
45 out << "interpret";
46 break;
48 out << "compille";
49 break;
50 default:
51 std::cerr << "Error: ";
52 break;
53 }
54 return out;
55}
56
57std::ostream &operator<<(std::ostream &out, const vm_target &t) {
58 switch (t) {
60 out << "linux";
61 break;
63 out << "macos";
64 break;
66 out << "windows";
67 break;
68 }
69 return out;
70}
71
72struct Args {
73 std::string source_file;
74 std::string output_file;
75 std::string module_path = "/usr/local/lib";
76 std::string object_path = ".";
77 std::string include_path = "/usr/local/include/mxvm/modules";
80 std::vector<std::string> argv;
83 char **platform_argv = nullptr;
84 bool Makefile = false;
85 bool only_test = false;
86 std::string toolchain;
87};
88
89template <typename T>
90void print_help(T &type) {
91 std::cout << Col("MXVM: Compiler/Interpreter ", mx::Color::BRIGHT_CYAN) << "v" << VERSION_INFO << "\n";
92 std::cout << "(C) 2026 " << Col("LostSideDead Software", mx::Color::BRIGHT_BLUE) << "\n";
93 std::cout << "https://lostsidedead.biz\n";
94 type.help(std::cout);
95}
96
97int process_arguments(Args *args);
98int action_translate(const mxvm::Platform &platform, std::unique_ptr<mxvm::Program> &program, Args *args);
99int action_interpret(bool only_test, std::string_view include_path, std::string_view object_path, const std::vector<std::string> &argv, std::string_view input, std::string_view mod_path);
100int translate_x64(const mxvm::Platform &platform, std::unique_ptr<mxvm::Program> &program, Args *args);
101void collectAndRegisterAllExterns(std::unique_ptr<mxvm::Program> &program);
102void createMakefile(Args *args);
103
104Args proc_args(int argc, char **argv) {
105 Args args;
106 std::string p = "linux";
107#ifdef _WIN32
108 p = "windows";
109#endif
110#ifdef __APPLE__
111 p = "macos";
112#endif
113#ifdef __linux__
114 p = "linux";
115#endif
116 if (p == "macos") {
119 } else if (p == "linux") {
122 } else if (p == "windows") {
125 }
126
127 std::vector<char *> v;
128 int stop = 0;
129 for (int i = 0; i < argc; ++i) {
130 if (std::string(argv[i]) != "--args") {
131 v.push_back(argv[i]);
132 } else {
133 stop = i;
134 break;
135 }
136 }
137 std::vector<std::string> arg_v;
138 for (int i = stop + 1; i < argc; ++i) {
139 args.argv.push_back(argv[i]);
140 }
141 mx::Argz<std::string> argz(static_cast<int>(v.size()), v.data());
142 args.platform_argc = argc;
143 args.platform_argv = argv;
144 argz.addOptionSingleValue('o', "output file")
145 .addOptionSingleValue('a', "action")
146 .addOptionDoubleValue(128, "action", "action to take [translate, interpret]")
147 .addOptionSingleValue('t', "target")
148 .addOptionDoubleValue(129, "target", "output target: [linux, macos]")
149 .addOptionSingle('d', "debug mode")
150 .addOptionDouble(130, "debug", "debug mode")
151 .addOptionSingle('i', "instruction trace mode")
152 .addOptionDouble(131, "instruction", "instruction trace on")
153 .addOptionSingle('h', "Help")
154 .addOptionDouble(132, "help", "Help output")
155 .addOptionDouble(133, "html", "debug html")
156 .addOptionSingle('D', "print html")
157 .addOptionSingleValue('x', "object path")
158 .addOptionDoubleValue(136, "object-path", "Object path")
159 .addOptionSingleValue('p', "path")
160 .addOptionDoubleValue(134, "path", "module path")
161 .addOptionSingleValue('I', "include path")
162 .addOptionDoubleValue(137, "include", "include path")
163 .addOptionSingle('m', "gemerate Makefile")
164 .addOptionDouble(140, "makefile", "generate Makefile")
165 .addOptionDouble(141, "dry-run", "check for correctness do not execute")
166 .addOptionSingleValue('T', "toolchain prefix")
167 .addOptionDoubleValue(142, "toolchain", "cross-compilation toolchain prefix (e.g. x86_64-w64-mingw32)");
168
169 if (argc == 1) {
170 print_help(argz);
171 }
173 int value = 0;
174 try {
175 while ((value = argz.proc(arg)) != -1) {
176 switch (value) {
177 case 141:
178 args.only_test = true;
179 break;
180 case 'T':
181 case 142:
182 args.toolchain = arg.arg_value;
183 break;
184 case 'm':
185 case 140:
186 args.Makefile = true;
187 break;
188 case 'I':
189 case 137:
190 args.include_path = arg.arg_value;
191 break;
192 case 'x':
193 case 136:
194 args.object_path = arg.arg_value;
195 break;
196 case 134:
197 case 'p':
198 args.module_path = arg.arg_value;
199 break;
200 case 133:
201 case 'D':
202 mxvm::html_mode = true;
203 break;
204 case 'h':
205 case 132:
206 print_help(argz);
207 break;
208 case 'i':
209 case 131:
210 mxvm::instruct_mode = true;
211 break;
212 case 'd':
213 case 130:
214 mxvm::debug_mode = true;
215 break;
216 case 'o':
217 args.output_file = arg.arg_value;
218 break;
219 case 'a':
220 case 128:
221 if (arg.arg_value == "translate") {
223 } else if (arg.arg_value == "interpret") {
225 } else if (arg.arg_value == "compile") {
227 } else {
228 throw mx::ArgException<std::string>("Error invalid action value");
229 }
230 break;
231 case 't':
232 case 129:
233 if (arg.arg_value == "macos") {
236 } else if (arg.arg_value == "linux") {
239 } else if (arg.arg_value == "windows") {
242 } else {
243 throw mx::Exception("Error platform unsupported.\n");
244 }
245 break;
246 default:
247 case '-':
248 args.source_file = arg.arg_value;
249 break;
250 }
251 }
252 } catch (mx::ArgException<std::string> &exec) {
253 std::cerr << Col("MXVM: ", mx::Color::RED) << "Command Line Argument Parsing Sytnax Error: " << exec.text() << "\n";
254 exit(EXIT_FAILURE);
255 } catch (const mx::Exception &e) {
256 std::cerr << Col("MXVM: ", mx::Color::RED) << " Exception: " << e.what() << "\n";
257 }
258
259 if (!args.source_file.empty()) {
260 constexpr std::string_view ext = ".mxvm";
261 if (args.source_file.size() < ext.size() ||
262 std::string_view(args.source_file).substr(args.source_file.size() - ext.size()) != ext) {
263 args.source_file += ext;
264 }
265 }
266 if (args.source_file.empty()) {
267 std::cerr << Col("MXVM: Error ", mx::Color::RED) << "source file required..\n";
268 exit(EXIT_FAILURE);
269 }
270 if (args.module_path.empty()) {
271 std::cerr << Col("MXVM: Errror: ", mx::Color::RED) << "please set module path.\n";
272 exit(EXIT_FAILURE);
273 }
274
275 return args;
276}
277
278int main(int argc, char **argv) {
279 Args args = proc_args(argc, argv);
280 return process_arguments(&args);
281}
282
284 if (args->Makefile) {
285 createMakefile(args);
286 return EXIT_SUCCESS;
287 }
288 int exitCode = 0;
289 if (!std::filesystem::is_regular_file(args->source_file) || !std::filesystem::exists(args->source_file)) {
290 std::cerr << Col("MXVM: Error: ", mx::Color::RED) << "input file: " << args->source_file << " does not exist or is not regular file.\n";
291 return EXIT_FAILURE;
292 }
293
294 std::unique_ptr<mxvm::Program> program(new mxvm::Program());
295 program->setMainBase(program.get());
296 program->platform = args->platform;
297 if (args->action == vm_action::compile) {
298 exitCode = action_translate(args->platform, program, args);
299 if (exitCode == 0) {
300 if (mxvm::Program::base != nullptr && !mxvm::Program::base->root_name.empty()) {
302 std::vector<std::string> object_files;
303 std::string assembler = args->toolchain.empty() ? "as" : args->toolchain + "-as";
304 const char *as_env = getenv("AS");
305 if (as_env != nullptr) {
306 assembler = as_env;
307 }
308 std::string asflags;
309 const char *asf = getenv("ASFLAGS");
310 if (asf != nullptr) {
311 asflags = asf;
312 }
313
314 for (auto &f : mxvm::Program::base->filenames) {
315 std::string obj_file = f;
316 size_t pos = obj_file.rfind(".s");
317 if (pos != std::string::npos) {
318 obj_file.replace(pos, 2, ".o");
319 } else {
320 obj_file += ".o";
321 }
322 std::ostringstream as_cmd;
323 as_cmd << assembler << " " << asflags << " " << f << " -o " << obj_file;
324 std::cout << as_cmd.str() << "\n";
325
326 int as_result = system(as_cmd.str().c_str());
327 if (as_result != 0) {
328 std::cerr << Col("MXVM: ", mx::Color::RED) << "Assembly failed\n";
329 return EXIT_FAILURE;
330 }
331 object_files.push_back(obj_file);
332 }
333
334 std::string linker = args->toolchain.empty() ? "cc" : args->toolchain + "-gcc";
335 const char *cc_env = getenv("CC");
336 if (cc_env != nullptr) {
337 linker = cc_env;
338 }
339 std::string ldflags;
340 const char *ldf = getenv("LDFLAGS");
341 if (ldf != nullptr) {
342 ldflags = ldf;
343 }
344 ldflags += " -lm ";
345
346 std::ostringstream modules_archives;
347 std::set<std::string> arch;
348 for (auto &m : mxvm::Program::base->external) {
349 if (m.module == true && m.mod != "main" && m.name != "strlen") {
350 arch.insert(m.mod);
351 }
352 }
353
354 for (auto &m : arch) {
355 modules_archives << args->module_path << "/modules/" << m << "/libmxvm_" << m << "_static.a ";
356 }
357
358 std::ostringstream cc_cmd;
359 cc_cmd << linker << " ";
360
361 for (auto &obj : object_files) {
362 cc_cmd << obj << " ";
363 }
364
365 cc_cmd << modules_archives.str() << " "
366 << ldflags << " "
367 << "-o " << mxvm::Program::base->root_name;
368
369 std::cout << cc_cmd.str() << "\n";
370 int cc_result = system(cc_cmd.str().c_str());
371 if (cc_result != 0) {
372 std::cerr << Col("MXVM: ", mx::Color::RED) << "Linking failed\n";
373 return EXIT_FAILURE;
374 }
375 } else if (args->platform == mxvm::Platform::DARWIN) {
376 std::vector<std::string> object_files;
377 std::string clang = args->toolchain.empty() ? "clang" : args->toolchain + "-clang";
378 const char *clang_env = getenv("CLANG");
379 if (clang_env != nullptr) {
380 clang = clang_env;
381 }
382 std::string cflags;
383 const char *cflags_env = getenv("CFLAGS");
384 if (cflags_env != nullptr) {
385 cflags = cflags_env;
386 }
387
388 for (auto &f : mxvm::Program::base->filenames) {
389 std::string obj_file = f;
390 size_t pos = obj_file.rfind(".s");
391 if (pos != std::string::npos) {
392 obj_file.replace(pos, 2, ".o");
393 } else {
394 obj_file += ".o";
395 }
396 std::ostringstream clang_cmd;
397 clang_cmd << clang << " -c " << cflags << " " << f << " -o " << obj_file;
398 std::cout << clang_cmd.str() << "\n";
399 int clang_result = system(clang_cmd.str().c_str());
400 if (clang_result != 0) {
401 std::cerr << Col("MXVM: ", mx::Color::RED) << "Assembly failed\n";
402 return EXIT_FAILURE;
403 }
404 object_files.push_back(obj_file);
405 }
406
407 std::string ldflags;
408 const char *ldf = getenv("LDFLAGS");
409 if (ldf != nullptr) {
410 ldflags = ldf;
411 }
412
413 ldflags += " -lm ";
414
415 std::ostringstream modules_archives;
416 std::set<std::string> arch;
417 for (auto &m : mxvm::Program::base->external) {
418 if (m.module == true && m.mod != "main" && m.name != "strlen") {
419 arch.insert(m.mod);
420 }
421 }
422 for (auto &m : arch) {
423 modules_archives << args->module_path << "/modules/" << m << "/libmxvm_" << m << "_static.a ";
424 }
425 std::ostringstream clang_link_cmd;
426 clang_link_cmd << clang << " ";
427 for (auto &obj : object_files) {
428 clang_link_cmd << obj << " ";
429 }
430 clang_link_cmd << modules_archives.str() << " "
431 << ldflags << " "
432 << "-o " << mxvm::Program::base->root_name;
433 std::cout << clang_link_cmd.str() << "\n";
434 int clang_link_result = system(clang_link_cmd.str().c_str());
435 if (clang_link_result != 0) {
436 std::cerr << Col("MXVM: ", mx::Color::RED) << "Linking failed\n";
437 return EXIT_FAILURE;
438 }
439 }
440 }
441 }
442 } else if (args->action == vm_action::translate) {
443 exitCode = action_translate(args->platform, program, args);
444 } else if (args->action == vm_action::interpret && !args->source_file.empty()) {
445 exitCode = action_interpret(args->only_test, args->include_path, args->object_path, args->argv, args->source_file, args->module_path);
446 } else if (args->action == vm_action::null_action && !args->source_file.empty()) {
447 exitCode = action_interpret(args->only_test, args->include_path, args->object_path, args->argv, args->source_file, args->module_path);
448 } else {
449 std::cerr << Col("MXVM: Error ", mx::Color::RED) << "invalid action/command\n";
450 return EXIT_FAILURE;
451 }
452 return exitCode;
453}
454
455int action_translate(const mxvm::Platform &platform, std::unique_ptr<mxvm::Program> &program, Args *args) {
456 return translate_x64(platform, program, args);
457}
458
459int translate_x64(const mxvm::Platform &platform, std::unique_ptr<mxvm::Program> &program, Args *args) {
460 std::string_view include_path = args->include_path;
461 std::string_view object_path = args->object_path;
462 std::string_view input = args->source_file;
463 std::string_view mod_path = args->module_path;
464 std::string_view output = args->output_file;
465 try {
466
467 std::string input_file(input);
468 std::fstream file;
469 file.open(input_file, std::ios::in);
470 if (!file.is_open()) {
471 throw mx::Exception("Error could not open file: " + input_file);
472 }
473 std::ostringstream stream;
474 stream << file.rdbuf();
475 file.close();
476 mxvm::Parser parser(stream.str());
477 parser.platform = platform;
478 parser.scan();
479
480 program->filename = input_file;
481 parser.module_path = std::string(mod_path);
482 parser.object_path = std::string(object_path);
483 parser.include_path = include_path;
484 if (parser.generateProgramCode(mxvm::Mode::MODE_COMPILE, program)) {
486 std::string output_file(output);
487 std::string program_name = output_file.empty() ? program->name + ".s" : output_file;
488 std::fstream file;
489 if (program->root_name == program->name)
490 program->object = false;
491 else
492 program->object = true;
493 file.open(program_name, std::ios::out);
494 if (file.is_open()) {
495 std::ostringstream code_v;
496 program->generateCode(platform, program->object, code_v);
497 program->assembly_code = code_v.str();
498 std::string opt_code = program->gen_optimize(program->assembly_code, platform);
499 file << opt_code;
500 if (mxvm::html_mode) {
501 std::ofstream htmlFile(program->name + ".html");
502 if (htmlFile.is_open()) {
503 parser.generateDebugHTML(htmlFile, program);
504 std::cout << Col("MXVM: Generated Debug HTML for: ", mx::Color::BRIGHT_GREEN) << program->name << "\n";
505 }
506 htmlFile.close();
507 }
508 file.close();
509 if (mxvm::Program::base != nullptr) {
510 mxvm::Program::base->add_filename(program->name + ".s");
511 }
512 }
513 } else {
514 std::cerr << Col("MXVM: Exception: ", mx::Color::RED) << "Failed to generate intermedaite code" << "\n";
515 exit(EXIT_FAILURE);
516 }
517 } catch (const mx::Exception &e) {
518 std::cerr << Col("MXVM: Exception: ", mx::Color::RED) << e.what() << "\n";
519 if (mxvm::debug_mode) {
520 program->print(std::cerr);
521 program->memoryDump(std::cerr);
522 }
523 return EXIT_FAILURE;
524 } catch (const std::runtime_error &e) {
525 std::cerr << Col("MXVM: Runtime Error: ", mx::Color::RED) << e.what() << "\n";
526 if (mxvm::debug_mode) {
527 program->print(std::cerr);
528 program->memoryDump(std::cerr);
529 }
530 return EXIT_FAILURE;
531 } catch (const std::exception &e) {
532 std::cerr << Col("MXVM: Exception: ", mx::Color::RED) << e.what() << "\n";
533 if (mxvm::debug_mode) {
534 program->print(std::cerr);
535 program->memoryDump(std::cerr);
536 }
537 return EXIT_FAILURE;
538 } catch (...) {
539 std::cerr << Col("MXVM: ", mx::Color::RED) << "Unknown Exception.\n";
540 if (mxvm::debug_mode) {
541 program->print(std::cerr);
542 program->memoryDump(std::cerr);
543 }
544 return EXIT_FAILURE;
545 }
546 return EXIT_SUCCESS;
547}
548
550
551#ifndef _WIN32
552void signal_action(int signum) {
553 if (signum == SIGINT) {
554 std::cout << "MXVM: Signal SIGINT Received Exiting...\n";
555 if (mxvm::debug_mode) {
556 std::cout << "MXVM: Debug Mode Dumping Memory.\n";
557 if (signal_program != nullptr)
558 signal_program->memoryDump(std::cout);
559 }
560 exit(EXIT_FAILURE);
561 }
562}
563#else
564BOOL WINAPI CtrlHandler(DWORD ctrlType) {
565 switch (ctrlType) {
566 case CTRL_C_EVENT: {
567 std::cout << "MXVM: Signal SIGINT Received Exiting...\n";
568 if (mxvm::debug_mode) {
569 std::cout << "MXVM: Debug Mode Dumping Memory.\n";
570 if (signal_program != nullptr)
571 signal_program->memoryDump(std::cout);
572 }
573 exit(EXIT_FAILURE);
574 }
575 return TRUE;
576 case CTRL_CLOSE_EVENT:
577 return TRUE;
578 default:
579 return FALSE;
580 }
581}
582#endif
583
584int action_interpret(bool only_test, std::string_view include_path, std::string_view object_path, const std::vector<std::string> &argv, std::string_view input, std::string_view mod_path) {
585 int exitCode = 0;
586 std::unique_ptr<mxvm::Program> program(new mxvm::Program());
587 program->setArgs(argv);
588 program->setMainBase(program.get());
589 std::fstream debug_output;
590 if (mxvm::debug_mode) {
591 debug_output.open("debug_info.txt", std::ios::out);
592 if (!debug_output.is_open()) {
593 std::cerr << Col("MXVM: Error ", mx::Color::RED) << "could not open debug_info.txt\n";
594 }
595 }
596 signal_program = program.get();
597#ifndef _WIN32
598 struct sigaction sa;
599 sa.sa_handler = signal_action;
600 sigemptyset(&sa.sa_mask);
601 sa.sa_flags = 0;
602 sigaction(SIGINT, &sa, nullptr);
603#else
604 SetConsoleCtrlHandler(CtrlHandler, TRUE);
605#endif
606
607 try {
608 std::string input_file(input);
609 std::fstream file;
610 file.open(input_file, std::ios::in);
611 if (!file.is_open()) {
612 throw mx::Exception("Error could not open file: " + input_file);
613 }
614 program->filename = input_file;
615 std::ostringstream stream;
616 stream << file.rdbuf();
617 file.close();
618 mxvm::Parser parser(stream.str());
619 parser.scan();
620 bool uses_std_module = false;
621 parser.module_path = std::string(mod_path);
622 parser.object_path = std::string(object_path);
623 parser.include_path = std::string(include_path);
624
625 class ArgsRaii {
626 public:
627 ArgsRaii() = default;
628 void init(const std::vector<std::string> &argv, void *handle) {
629 std::vector<const char *> c_argv;
630 c_argv.push_back("mxvmc");
631 for (const auto &arg : argv) {
632 c_argv.push_back(arg.c_str());
633 }
634
635 void *set_args = (void *)dlsym(handle, "set_program_args");
636 using set_program_args_t = void (*)(int, const char **);
637 if (set_args) {
638 auto func = reinterpret_cast<set_program_args_t>(set_args);
639 func(static_cast<int>(c_argv.size()), c_argv.data());
640 set = true;
641 handle_ = handle;
642 }
643 }
644 ~ArgsRaii() {
645 void *free_args = (void *)dlsym(handle_, "free_program_args");
646 using set_program_args_t = void (*)();
647 if (free_args) {
648 auto func = reinterpret_cast<set_program_args_t>(free_args);
649 func();
650 set = false;
651 }
652 }
653
654 bool set = false;
655 void *handle_ = nullptr;
656 };
657
658 if (parser.generateProgramCode(mxvm::Mode::MODE_INTERPRET, program)) {
659 if (program->object) {
660 throw mx::Exception("Requires one program object to execute");
661 }
662 ArgsRaii args_raii;
663
664 if (mxvm::Program::base != nullptr) {
665 void *handle = nullptr;
666 for (const auto &ext : mxvm::Program::base->external_functions) {
667 if (ext.second.mod_name == "std") {
668 uses_std_module = true;
669 handle = ext.second.handle;
670 break;
671 }
672 }
673 if (uses_std_module) {
674 args_raii.init(argv, handle);
675 }
676 }
677 program->flatten(program.get());
678 if (only_test == false)
679 exitCode = program->exec();
680
681 if (mxvm::debug_mode) {
682 if (debug_output.is_open()) {
683 program->print(debug_output);
684 program->post(debug_output);
685 program->memoryDump(debug_output);
686 }
687 }
688
689 if (mxvm::html_mode) {
690 std::cout << Col("MXVM: Generated ", mx::Color::BRIGHT_GREEN) << program->name << ".html\n";
691 std::ofstream fout(program->name + ".html");
692 parser.generateDebugHTML(fout, program);
693 fout.close();
694 }
695 } else {
696 std::cerr << Col("MXVM: Error: ", mx::Color::RED) << "Failed to generate intermediate code.\n";
697 return EXIT_FAILURE;
698 }
699 } catch (const mx::Exception &e) {
700 std::cerr << Col("MXVM: Exception: ", mx::Color::RED) << e.what() << "\n";
701 if (mxvm::debug_mode) {
702 if (debug_output.is_open()) {
703 program->print(debug_output);
704 program->memoryDump(debug_output);
705 }
706 }
707 return EXIT_FAILURE;
708 } catch (const std::runtime_error &e) {
709 std::cerr << Col("MXVM: Runtime Error: ", mx::Color::RED) << e.what() << "\n";
710 if (mxvm::debug_mode) {
711 if (debug_output.is_open()) {
712 program->print(debug_output);
713 program->memoryDump(debug_output);
714 }
715 }
716 return EXIT_FAILURE;
717 } catch (const std::exception &e) {
718 std::cerr << Col("MXVM: Exception: ", mx::Color::RED) << e.what() << "\n";
719 if (mxvm::debug_mode) {
720 if (debug_output.is_open()) {
721 program->print(debug_output);
722 program->memoryDump(debug_output);
723 }
724 }
725 return EXIT_FAILURE;
726 } catch (...) {
727 std::cerr << Col("MXVM: ", mx::Color::RED) << "Unknown Exception.\n";
728 if (mxvm::debug_mode) {
729 if (debug_output.is_open()) {
730 program->print(debug_output);
731 program->memoryDump(debug_output);
732 }
733 }
734 return EXIT_FAILURE;
735 }
736
737 if (mxvm::debug_mode) {
738 if (debug_output.is_open()) {
739 debug_output.close();
740 std::cout << Col("MXVM: Generated: ", mx::Color::BRIGHT_GREEN) << "debug information: debug_info.txt\n";
741 }
742 }
743 if (mxvm::debug_mode) {
744 std::cout << Col("MXVM: ", mx::Color::RED) << "Program exited with: " << exitCode << "\n";
745 }
746 return exitCode;
747}
748
749void collectAndRegisterAllExterns(std::unique_ptr<mxvm::Program> &program) {
750 for (const auto &obj : program->objects) {
751 for (auto &lbl : obj->labels) {
752 if (lbl.second.second)
753 mxvm::Program::base->add_extern(obj->name, lbl.first, false);
754 }
755 for (auto &v : obj->vars) {
756 mxvm::Program::base->add_extern(obj->name, v.first, false);
757 }
758 }
759}
760
761void createMakefile(Args *args) {
762
763 if(args == nullptr) {
764 std::cerr << "Error arguments null.\n";
765 return;
766 }
767
768 std::ofstream file("Makefile");
769 if (!file.is_open()) {
770 std::cerr << Col("MXVM Error: ", mx::Color::BRIGHT_RED) << " could not open file\n";
771 exit(EXIT_FAILURE);
772 }
773 char *ldflags = getenv("LDFLAGS");
774 std::string ld_flags;
775 if (ldflags != nullptr)
776 ld_flags = ldflags;
777
778 // Derive program name from source file (strip path and .mxvm extension)
779 std::string prog_name = args->source_file;
780 {
781 size_t slash = prog_name.rfind('/');
782 if (slash != std::string::npos)
783 prog_name = prog_name.substr(slash + 1);
784 size_t dot = prog_name.rfind(".mxvm");
785 if (dot != std::string::npos)
786 prog_name = prog_name.substr(0, dot);
787 }
788
789 // Build the mxvmc compile command with all relevant flags
790 std::ostringstream compile_cmd;
791 compile_cmd << "mxvmc \"" << args->source_file << "\""
792 << " --path \"" << args->module_path << "\""
793 << " --object-path \"" << args->object_path << "\""
794 << " --action compile"
795 << " --target " << args->target;
796 if (!args->toolchain.empty())
797 compile_cmd << " --toolchain " << args->toolchain;
798 if (!args->include_path.empty())
799 compile_cmd << " --include \"" << args->include_path << "\"";
800
801 file << "### Makefile generated by MXVM\n";
802 file << "### Source: " << args->source_file << "\n";
803 file << "### Target: " << args->target << "\n";
804 if (!args->toolchain.empty())
805 file << "### Toolchain: " << args->toolchain << "\n";
806 file << "\n";
807 file << "PROGRAM = " << prog_name << "\n";
808 file << "LDFLAGS = " << ld_flags << "\n";
809 file << "\n";
810 file << ".PHONY: all run clean\n\n";
811 file << "all:\n";
812 file << "\tLDFLAGS=\"$(LDFLAGS)\" " << compile_cmd.str() << "\n\n";
813 file << "run:\n";
814 file << "\tmxvmc \"" << args->source_file << "\""
815 << " --path \"" << args->module_path << "\""
816 << " --object-path \"" << args->object_path << "\""
817 << " --target " << args->target;
818 if (!args->toolchain.empty())
819 file << " --toolchain " << args->toolchain;
820 file << "\n\n";
821 file << "clean:\n";
822 file << "\trm -f $(PROGRAM) $(PROGRAM).exe *.o *.s\n";
823 file.close();
824 std::cout << Col("MXVM: ", mx::Color::BRIGHT_GREEN) << "Created Makefile for " << prog_name << "\n";
825}
Generic command-line argument parser with concept-constrained string types.
Exception type thrown for argument parsing errors.
Definition argz.hpp:102
String text() const
Get the error message.
Definition argz.hpp:110
Generic command-line argument parser supporting single/double-dash options.
Definition argz.hpp:126
Argz< String > & addOptionSingleValue(const int &c, const String &description)
Register a single-dash option that takes a value.
Definition argz.hpp:217
int proc(Argument< String > &a)
Process the next argument from the command line.
Definition argz.hpp:276
General-purpose exception with errno-aware factory method.
Definition exception.hpp:38
static Base * base
pointer to the main program base
Definition icode.hpp:197
Main MXVM parser — tokenizes source, builds AST, and generates intermediate code.
Definition parser.hpp:57
std::string object_path
search path for .mxvm object files
Definition parser.hpp:133
bool generateDebugHTML(std::ostream &out, std::unique_ptr< Program > &program)
Generate debug HTML output for the program.
Definition parser.cpp:987
uint64_t scan()
Tokenize the source and return the token count.
Definition parser.cpp:184
std::string include_path
system module include path
Definition parser.hpp:134
Platform platform
Definition parser.hpp:137
std::string module_path
search path for .mxvm module files
Definition parser.hpp:132
bool generateProgramCode(const Mode &m, std::unique_ptr< Program > &program)
Walk the AST and populate a Program with instructions and variables.
Definition parser.cpp:737
Complete MXVM program: instruction interpreter and native x64 code generator.
Definition icode.hpp:212
int64_t pos(const char *substr, const char *s)
Definition cstring.c:51
std::string Col(const std::string &col, std::string color)
Wrap a string with ANSI color codes if terminal supports color.
int main(int argc, char **argv)
Definition main.cpp:274
int64_t init(void)
Initialize SDL2 subsystems.
Definition sdl.c:26
int argc(void)
Return the number of stored command-line arguments.
Definition std.c:72
const char * argv(int idx)
Return the command-line argument at the given index.
Definition std.c:76
Main MXVM header aggregating all subsystem includes.
const std::string RED
Definition exception.hpp:70
const std::string BRIGHT_GREEN
Definition exception.hpp:78
const std::string BRIGHT_BLUE
Definition exception.hpp:80
const std::string BRIGHT_RED
Definition exception.hpp:77
const std::string BRIGHT_CYAN
Definition exception.hpp:82
bool instruct_mode
enable instruction trace mode
Definition parser.cpp:97
Platform
Target platform for native code generation.
Definition parser.hpp:42
bool debug_mode
enable verbose debug output during parsing
Definition parser.cpp:96
bool html_mode
enable HTML debug output
Definition parser.cpp:98
@ MODE_INTERPRET
Definition parser.hpp:37
@ MODE_COMPILE
Definition parser.hpp:38
@ BOOL
boolean
Definition icode.hpp:79
Definition main.cpp:72
std::vector< std::string > argv
Definition main.cpp:80
vm_target target
Definition main.cpp:79
char ** platform_argv
Definition main.cpp:83
int platform_argc
Definition main.cpp:82
vm_action action
Definition main.cpp:78
std::string output_file
Definition main.cpp:74
std::string module_path
Definition main.cpp:75
std::string source_file
Definition main.cpp:73
bool only_test
Definition main.cpp:85
std::string include_path
Definition main.cpp:77
bool Makefile
Definition main.cpp:84
std::string toolchain
Definition main.cpp:86
std::string object_path
Definition main.cpp:76
mxvm::Platform platform
Definition main.cpp:81
A parsed or registered command-line argument definition.
Definition argz.hpp:52
String arg_value
parsed value (for value-taking options)
Definition argz.hpp:55
#define VERSION_INFO
MXVM version string.
std::ostream & operator<<(std::ostream &out, const vm_action &ae)
Definition main.cpp:36
void signal_action(int signum)
Definition main.cpp:552
mxvm::Program * signal_program
Definition main.cpp:549
int process_arguments(Args *args)
Definition main.cpp:283
int action_interpret(bool only_test, std::string_view include_path, std::string_view object_path, const std::vector< std::string > &argv, std::string_view input, std::string_view mod_path)
Definition main.cpp:584
int action_translate(const mxvm::Platform &platform, std::unique_ptr< mxvm::Program > &program, Args *args)
Definition main.cpp:455
Args proc_args(int argc, char **argv)
Definition main.cpp:104
void collectAndRegisterAllExterns(std::unique_ptr< mxvm::Program > &program)
Definition main.cpp:749
vm_action
Definition main.cpp:24
@ compile
Definition main.cpp:28
@ null_action
Definition main.cpp:25
@ interpret
Definition main.cpp:27
@ translate
Definition main.cpp:26
vm_target
Definition main.cpp:30
@ x86_64_macos
Definition main.cpp:32
@ x86_64_linux
Definition main.cpp:31
@ x86_64_windows
Definition main.cpp:33
void print_help(T &type)
Definition main.cpp:90
int translate_x64(const mxvm::Platform &platform, std::unique_ptr< mxvm::Program > &program, Args *args)
Definition main.cpp:459
void createMakefile(Args *args)
Definition main.cpp:761