51 std::cerr <<
"Error: ";
80 std::vector<std::string>
argv;
93 std::cout <<
"https://lostsidedead.biz\n";
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);
106 std::string p =
"linux";
119 }
else if (p ==
"linux") {
122 }
else if (p ==
"windows") {
127 std::vector<char *> v;
129 for (
int i = 0; i <
argc; ++i) {
130 if (std::string(
argv[i]) !=
"--args") {
131 v.push_back(
argv[i]);
137 std::vector<std::string> arg_v;
138 for (
int i = stop + 1; i <
argc; ++i) {
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)");
175 while ((value = argz.
proc(arg)) != -1) {
223 }
else if (arg.
arg_value ==
"interpret") {
253 std::cerr <<
Col(
"MXVM: ",
mx::Color::RED) <<
"Command Line Argument Parsing Sytnax Error: " << exec.
text() <<
"\n";
256 std::cerr <<
Col(
"MXVM: ",
mx::Color::RED) <<
" Exception: " << e.what() <<
"\n";
260 constexpr std::string_view ext =
".mxvm";
271 std::cerr <<
Col(
"MXVM: Errror: ",
mx::Color::RED) <<
"please set module path.\n";
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";
295 program->setMainBase(program.get());
302 std::vector<std::string> object_files;
304 const char *as_env = getenv(
"AS");
305 if (as_env !=
nullptr) {
309 const char *asf = getenv(
"ASFLAGS");
310 if (asf !=
nullptr) {
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");
322 std::ostringstream as_cmd;
323 as_cmd << assembler <<
" " << asflags <<
" " << f <<
" -o " << obj_file;
324 std::cout << as_cmd.str() <<
"\n";
326 int as_result = system(as_cmd.str().c_str());
327 if (as_result != 0) {
331 object_files.push_back(obj_file);
335 const char *cc_env = getenv(
"CC");
336 if (cc_env !=
nullptr) {
340 const char *ldf = getenv(
"LDFLAGS");
341 if (ldf !=
nullptr) {
346 std::ostringstream modules_archives;
347 std::set<std::string> arch;
349 if (m.module ==
true && m.mod !=
"main" && m.name !=
"strlen") {
354 for (
auto &m : arch) {
355 modules_archives << args->
module_path <<
"/modules/" << m <<
"/libmxvm_" << m <<
"_static.a ";
358 std::ostringstream cc_cmd;
359 cc_cmd << linker <<
" ";
361 for (
auto &obj : object_files) {
362 cc_cmd << obj <<
" ";
365 cc_cmd << modules_archives.str() <<
" "
369 std::cout << cc_cmd.str() <<
"\n";
370 int cc_result = system(cc_cmd.str().c_str());
371 if (cc_result != 0) {
376 std::vector<std::string> object_files;
378 const char *clang_env = getenv(
"CLANG");
379 if (clang_env !=
nullptr) {
383 const char *cflags_env = getenv(
"CFLAGS");
384 if (cflags_env !=
nullptr) {
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");
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) {
404 object_files.push_back(obj_file);
408 const char *ldf = getenv(
"LDFLAGS");
409 if (ldf !=
nullptr) {
415 std::ostringstream modules_archives;
416 std::set<std::string> arch;
418 if (m.module ==
true && m.mod !=
"main" && m.name !=
"strlen") {
422 for (
auto &m : arch) {
423 modules_archives << args->
module_path <<
"/modules/" << m <<
"/libmxvm_" << m <<
"_static.a ";
425 std::ostringstream clang_link_cmd;
426 clang_link_cmd << clang <<
" ";
427 for (
auto &obj : object_files) {
428 clang_link_cmd << obj <<
" ";
430 clang_link_cmd << modules_archives.str() <<
" "
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) {
467 std::string input_file(input);
469 file.open(input_file, std::ios::in);
470 if (!file.is_open()) {
471 throw mx::Exception(
"Error could not open file: " + input_file);
473 std::ostringstream stream;
474 stream << file.rdbuf();
480 program->filename = input_file;
486 std::string output_file(output);
487 std::string program_name = output_file.empty() ? program->name +
".s" : output_file;
489 if (program->root_name == program->name)
490 program->object =
false;
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);
501 std::ofstream htmlFile(program->name +
".html");
502 if (htmlFile.is_open()) {
514 std::cerr <<
Col(
"MXVM: Exception: ",
mx::Color::RED) <<
"Failed to generate intermedaite code" <<
"\n";
520 program->print(std::cerr);
521 program->memoryDump(std::cerr);
524 }
catch (
const std::runtime_error &e) {
527 program->print(std::cerr);
528 program->memoryDump(std::cerr);
531 }
catch (
const std::exception &e) {
534 program->print(std::cerr);
535 program->memoryDump(std::cerr);
541 program->print(std::cerr);
542 program->memoryDump(std::cerr);
553 if (signum == SIGINT) {
554 std::cout <<
"MXVM: Signal SIGINT Received Exiting...\n";
556 std::cout <<
"MXVM: Debug Mode Dumping Memory.\n";
564BOOL WINAPI CtrlHandler(DWORD ctrlType) {
567 std::cout <<
"MXVM: Signal SIGINT Received Exiting...\n";
569 std::cout <<
"MXVM: Debug Mode Dumping Memory.\n";
576 case CTRL_CLOSE_EVENT:
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) {
587 program->setArgs(
argv);
588 program->setMainBase(program.get());
589 std::fstream debug_output;
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";
600 sigemptyset(&sa.sa_mask);
602 sigaction(SIGINT, &sa,
nullptr);
604 SetConsoleCtrlHandler(CtrlHandler, TRUE);
608 std::string input_file(input);
610 file.open(input_file, std::ios::in);
611 if (!file.is_open()) {
612 throw mx::Exception(
"Error could not open file: " + input_file);
614 program->filename = input_file;
615 std::ostringstream stream;
616 stream << file.rdbuf();
620 bool uses_std_module =
false;
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());
635 void *set_args = (
void *)dlsym(handle,
"set_program_args");
636 using set_program_args_t = void (*)(int,
const char **);
638 auto func =
reinterpret_cast<set_program_args_t
>(set_args);
639 func(
static_cast<int>(c_argv.size()), c_argv.data());
645 void *free_args = (
void *)dlsym(handle_,
"free_program_args");
646 using set_program_args_t = void (*)();
648 auto func =
reinterpret_cast<set_program_args_t
>(free_args);
655 void *handle_ =
nullptr;
659 if (program->object) {
660 throw mx::Exception(
"Requires one program object to execute");
665 void *handle =
nullptr;
667 if (ext.second.mod_name ==
"std") {
668 uses_std_module =
true;
669 handle = ext.second.handle;
673 if (uses_std_module) {
674 args_raii.init(
argv, handle);
677 program->flatten(program.get());
678 if (only_test ==
false)
679 exitCode = program->exec();
682 if (debug_output.is_open()) {
683 program->print(debug_output);
684 program->post(debug_output);
685 program->memoryDump(debug_output);
691 std::ofstream fout(program->name +
".html");
696 std::cerr <<
Col(
"MXVM: Error: ",
mx::Color::RED) <<
"Failed to generate intermediate code.\n";
702 if (debug_output.is_open()) {
703 program->print(debug_output);
704 program->memoryDump(debug_output);
708 }
catch (
const std::runtime_error &e) {
711 if (debug_output.is_open()) {
712 program->print(debug_output);
713 program->memoryDump(debug_output);
717 }
catch (
const std::exception &e) {
720 if (debug_output.is_open()) {
721 program->print(debug_output);
722 program->memoryDump(debug_output);
729 if (debug_output.is_open()) {
730 program->print(debug_output);
731 program->memoryDump(debug_output);
738 if (debug_output.is_open()) {
739 debug_output.close();
744 std::cout <<
Col(
"MXVM: ",
mx::Color::RED) <<
"Program exited with: " << exitCode <<
"\n";
750 for (
const auto &obj : program->objects) {
751 for (
auto &lbl : obj->labels) {
752 if (lbl.second.second)
755 for (
auto &v : obj->vars) {
763 if(args ==
nullptr) {
764 std::cerr <<
"Error arguments null.\n";
768 std::ofstream file(
"Makefile");
769 if (!file.is_open()) {
773 char *ldflags = getenv(
"LDFLAGS");
774 std::string ld_flags;
775 if (ldflags !=
nullptr)
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);
790 std::ostringstream compile_cmd;
791 compile_cmd <<
"mxvmc \"" << args->
source_file <<
"\""
793 <<
" --object-path \"" << args->
object_path <<
"\""
794 <<
" --action compile"
795 <<
" --target " << args->
target;
797 compile_cmd <<
" --toolchain " << args->
toolchain;
799 compile_cmd <<
" --include \"" << args->
include_path <<
"\"";
801 file <<
"### Makefile generated by MXVM\n";
802 file <<
"### Source: " << args->
source_file <<
"\n";
803 file <<
"### Target: " << args->
target <<
"\n";
805 file <<
"### Toolchain: " << args->
toolchain <<
"\n";
807 file <<
"PROGRAM = " << prog_name <<
"\n";
808 file <<
"LDFLAGS = " << ld_flags <<
"\n";
810 file <<
".PHONY: all run clean\n\n";
812 file <<
"\tLDFLAGS=\"$(LDFLAGS)\" " << compile_cmd.str() <<
"\n\n";
816 <<
" --object-path \"" << args->
object_path <<
"\""
817 <<
" --target " << args->
target;
819 file <<
" --toolchain " << args->
toolchain;
822 file <<
"\trm -f $(PROGRAM) $(PROGRAM).exe *.o *.s\n";
Generic command-line argument parser with concept-constrained string types.
Exception type thrown for argument parsing errors.
String text() const
Get the error message.
Generic command-line argument parser supporting single/double-dash options.
Argz< String > & addOptionSingleValue(const int &c, const String &description)
Register a single-dash option that takes a value.
int proc(Argument< String > &a)
Process the next argument from the command line.
General-purpose exception with errno-aware factory method.
static Base * base
pointer to the main program base
Main MXVM parser — tokenizes source, builds AST, and generates intermediate code.
std::string object_path
search path for .mxvm object files
bool generateDebugHTML(std::ostream &out, std::unique_ptr< Program > &program)
Generate debug HTML output for the program.
uint64_t scan()
Tokenize the source and return the token count.
std::string include_path
system module include path
std::string module_path
search path for .mxvm module files
bool generateProgramCode(const Mode &m, std::unique_ptr< Program > &program)
Walk the AST and populate a Program with instructions and variables.
Complete MXVM program: instruction interpreter and native x64 code generator.
int64_t pos(const char *substr, const char *s)
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)
int64_t init(void)
Initialize SDL2 subsystems.
int argc(void)
Return the number of stored command-line arguments.
const char * argv(int idx)
Return the command-line argument at the given index.
Main MXVM header aggregating all subsystem includes.
const std::string BRIGHT_GREEN
const std::string BRIGHT_BLUE
const std::string BRIGHT_RED
const std::string BRIGHT_CYAN
bool instruct_mode
enable instruction trace mode
Platform
Target platform for native code generation.
bool debug_mode
enable verbose debug output during parsing
bool html_mode
enable HTML debug output
std::vector< std::string > argv
A parsed or registered command-line argument definition.
String arg_value
parsed value (for value-taking options)
#define VERSION_INFO
MXVM version string.
std::ostream & operator<<(std::ostream &out, const vm_action &ae)
void signal_action(int signum)
mxvm::Program * signal_program
int process_arguments(Args *args)
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)
int action_translate(const mxvm::Platform &platform, std::unique_ptr< mxvm::Program > &program, Args *args)
Args proc_args(int argc, char **argv)
void collectAndRegisterAllExterns(std::unique_ptr< mxvm::Program > &program)
int translate_x64(const mxvm::Platform &platform, std::unique_ptr< mxvm::Program > &program, Args *args)
void createMakefile(Args *args)