-
Notifications
You must be signed in to change notification settings - Fork 5
/
main.cpp
139 lines (113 loc) · 3.88 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include "vm/vm.h"
#include "vm/vm_defs.h"
#include "lexer/lexer.h"
#include "gen/gen.h"
#include "launch_options.hpp"
int main(int argc, char* argv[])
{
// Setup all launch options.
options::launch_options options{};
for (int i = 0; i < argc; i++)
{
const char* current_arg = argv[i];
// TODO: Add a check for the file input here...
if (options.next_arg_is_output_path)
{
options::output_path = current_arg;
options.next_arg_is_output_path = false;
}
else if (std::strcmp(current_arg, "-help") == 0)
{
std::printf("[usage]\n");
std::printf(" virtual-machine.exe <code/binary file name> <flags>\n");
std::printf("[flags]\n");
std::printf("-b Build flag, compiles the content in your inputted file and saves it to a file.\n");
std::printf("-d Debug flag, skips code compilation and instead just converts it to bytecode then runs it through the VM.\n");
std::printf("-o Out flag, lets you specify the binary's file name after the flag is passed.");
return EXIT_SUCCESS;
}
else if (std::strcmp(current_arg, "-b") == 0)
options.build_mode = true;
else if (std::strcmp(current_arg, "-d") == 0)
options.debug_mode = true;
else if (std::strcmp(current_arg, "-o") == 0)
options.next_arg_is_output_path = true;
}
// Force debug flag if in debug mode.
#ifdef _DEBUG
options.debug_mode = true;
#endif
// Open file.
#ifdef _DEBUG
const char* file_name = "D:\\virtual-machine\\output\\code.txt";
#else
const char* file_name = argv[1];
#endif
std::ifstream file_stream(file_name);
// Ensure file exists.
if (!file_stream)
{
std::printf("[error] No file by the name of \"%s\" exists.\n", file_name);
std::printf("[info] Usage:\n virtual-machine.exe <script_name.txt> <flags>\n");
std::printf("[info] Use '-help' for more information.");
return EXIT_FAILURE;
}
// Convert file stream to string.
std::stringstream file_stream_str;
file_stream_str << file_stream.rdbuf();
std::string code = file_stream_str.str();
// Close the passed file.
file_stream.close();
// If build mode is on without debug mode, then we just need to compile and save the binary, no need to run anything.
if (options.build_mode && !options.debug_mode)
{
// Lex the file code.
lexer lex(code);
// Get the lexer tokens.
const auto& lexer_tokens = lex.get_tokens();
// Turn the tokens into the vm's bytecode.
const auto& byte_code = gen::generate_code(lexer_tokens);
// Create binary output file.
std::ofstream output_file(!options::output_path.empty()
? options::output_path
: std::string(file_name) + ".bin");
// Write all byte code into the binary file.
for (const byte current_byte : byte_code)
output_file << current_byte;
std::printf("[info] Build successful!\n");
// Close the output file and exit.
output_file.close();
return EXIT_SUCCESS;
}
// If debug mode is on, then we straight up run the bytecode, no need to build and save it.
else if (options.debug_mode)
{
// Lex the file code.
lexer lex(code);
// Get the lexer tokens.
const auto& lexer_tokens = lex.get_tokens();
// Turn the tokens into the vm's bytecode.
const auto& byte_code = gen::generate_code(lexer_tokens);
if (lex.get_tokens().empty())
{
std::printf("[error] Nothing ran! No valid code passed!\n");
return EXIT_FAILURE;
}
// Run the virtual machine with the binary's byte code.
vm virtual_machine(byte_code);
return EXIT_SUCCESS;
}
// Read the binary file into a byte array, and run it's byte code.
std::ifstream bin_file(file_name, std::ios_base::binary | std::ios_base::ate);
const std::size_t bin_size = bin_file.tellg();
bin_file.seekg(0);
const std::vector<byte> bin_byte_code(bin_size);
bin_file.read((char*)bin_byte_code.data(), bin_size);
// Run the virtual machine with the binary's byte code.
vm virtual_machine(bin_byte_code);
return EXIT_SUCCESS;
}