31int main(
int argc,
const char *argv[]) {
32 bool print_tokens =
false;
33 bool print_ir =
false;
34 bool output_is_object =
false;
38 std::cerr <<
"\033[33mUsage: topazc \"path/to/src.tp\"\033[0m\n";
43 std::ifstream file(argv[1]);
44 if (!file.is_open()) {
45 std::cerr <<
"\033[31mCompilation error: Error openning file: does not exist!\033[0m\n";
49 std::filesystem::path libs_path =
"libs";
50 if (std::filesystem::exists(libs_path)) {
51 if (!std::filesystem::is_directory(libs_path)) {
52 std::cerr <<
"\033[31mCompilation error: Directory with libraries does not exists!\033[0m\n";
57 std::cerr <<
"\033[31mCompilation error: Directory with libraries does not exists!\033[0m\n";
61 std::filesystem::path file_path = std::filesystem::absolute(argv[1]);
62 std::string executable_path = file_path;
64 for (
int i = 1; i < argc; i++) {
65 if (strcmp(argv[i],
"--tokens") == 0) {
68 else if (strcmp(argv[i],
"--ir") == 0) {
71 else if (strcmp(argv[i],
"--obj") == 0) {
72 output_is_object =
true;
74 else if (strcmp(argv[i],
"--path") == 0) {
76 std::cerr <<
"\033[31mCompilation error: After \033[0m'--path'\033[31m option should be followed by the path to the output file!\033[0m\n";
79 executable_path = argv[++i];
81 else if (strcmp(argv[i],
"--debug") == 0) {
86 if (executable_path.find(
'.') != std::string::npos) {
87 for (
int i = executable_path.size() - 1; executable_path[i] !=
'.'; i--) {
88 executable_path.pop_back();
90 executable_path.pop_back();
94 const char *obj_ext =
".obj";
95 const char *exe_ext =
".exe";
97 const char *obj_ext =
".o";
98 const char *exe_ext =
"";
102 executable_path += exe_ext;
104 const std::string object_path = executable_path + obj_ext;
106 std::ostringstream content;
107 content << file.rdbuf();
109 Lexer lexer(content.str(), file_path.string(), debug);
110 std::vector<Token> tokens = lexer.
tokenize();
112 std::cout <<
"\033[1m\033[32mTokens:\033[0m\n";
113 for (
Token& token : tokens) {
114 std::cout << token.to_str() <<
'\n';
118 Parser parser(tokens, debug);
119 std::vector<AST::StmtPtr> stmts_for_semantic = parser.
parse();
121 SemanticAnalyzer semantic(stmts_for_semantic, std::filesystem::absolute(libs_path), file_path.string(), debug);
125 std::vector<AST::StmtPtr> stmts_for_codegen = parser.
parse();
127 CodeGenerator codegen(stmts_for_codegen, std::filesystem::absolute(libs_path), file_path.string(), debug);
133 std::cout <<
"\033[1m\033[32mLLVM IR:\033[0m\n";
137 std::unique_ptr<llvm::Module> module = codegen.
get_module();
139 llvm::InitializeNativeTarget();
140 llvm::InitializeNativeTargetAsmPrinter();
141 llvm::InitializeNativeTargetAsmParser();
143 if (module->getFunction(
"main") ==
nullptr) {
144 std::cerr <<
"\033[31mCompilation error: Program does not have entry point 'main'\033[0m" <<
'\n';
147 auto getTriple = []() -> std::string {
148 const char *env_triple = std::getenv(
"TOPAZ_TRIPLE");
149 if (env_triple && *env_triple) {
150 return std::string(env_triple);
153 std::array<char, 256> buffer{};
156 std::unique_ptr<FILE, int(*)(FILE*)> pipe(_popen(
"clang -dumpmachine",
"r"), _pclose);
158 std::unique_ptr<FILE, int(*)(FILE*)> pipe(popen(
"clang -dumpmachine",
"r"), pclose);
163 while (fgets(buffer.data(),
static_cast<int>(buffer.size()), pipe.get()) !=
nullptr) {
164 result += buffer.data();
166 while (!result.empty() && (result.back() ==
'\n' || result.back() ==
'\r')) {
171 auto defaultTripleForHost = []() -> std::string {
173 #if defined(__aarch64__) || defined(_M_ARM64)
174 return "aarch64-pc-windows-msvc";
176 return "x86_64-pc-windows-msvc";
178 #elif defined(__APPLE__)
179 #if defined(__aarch64__)
180 return "arm64-apple-darwin";
182 return "x86_64-apple-darwin";
185 #if defined(__aarch64__)
186 return "aarch64-unknown-linux-gnu";
188 return "x86_64-pc-linux-gnu";
192 std::string target_triple = getTriple();
193 if (target_triple.empty()) {
194 target_triple = defaultTripleForHost();
196 module->setTargetTriple(llvm::Triple(target_triple));
199 const llvm::Target *target = llvm::TargetRegistry::lookupTarget(target_triple, error);
201 std::cerr << error <<
'\n';
205 std::string CPU =
"generic";
206 std::string features =
"";
207 llvm::TargetOptions opt;
208 auto reloc_model = std::optional<llvm::Reloc::Model>();
209 std::unique_ptr<llvm::TargetMachine> target_machine(target->createTargetMachine(target_triple, CPU, features, opt, reloc_model));
210 if (!target_machine) {
211 std::cerr <<
"\033[31mCompilation error: Failed to create TargetMachine for triple '" << target_triple <<
"'\033[0m\n";
215 module->setDataLayout(target_machine->createDataLayout());
218 llvm::raw_fd_ostream dest(object_path, ec, llvm::sys::fs::OF_None);
220 std::cerr <<
"\033[31mCompilation error: Could not open file '" << object_path <<
"': " << ec.message() <<
"\033[0m\n";
224 llvm::legacy::PassManager pass;
226 auto fileType =
static_cast<llvm::CodeGenFileType
>(1);
227 if (target_machine->addPassesToEmitFile(pass, dest,
nullptr, fileType)) {
228 std::cerr <<
"\033[31mCompilation error: TargetMachine can't emit a file of this type\033[0m\n";
236 if (output_is_object) {
237 std::cout <<
"\033[36;1mCOMPILING SUCCESS. Built object:\033[0m " << object_path <<
'\n';
241 const char *env_linker = std::getenv(
"TOPAZC_LINKER");
242 std::string linker = env_linker ? std::string(env_linker) : std::string(
"clang");
244 std::string link_cmd = linker +
" \"" + object_path +
"\" -o \"" + executable_path +
"\" -fuse-ld=lld";
245 #elif defined(__APPLE__)
246 std::string link_cmd = linker +
" \"" + object_path +
"\" -o \"" + executable_path +
"\"";
248 std::string link_cmd = linker +
" \"" + object_path +
"\" -o \"" + executable_path +
"\" -no-pie";
250 auto runAndCapture = [](
const std::string& cmd) -> std::pair<int, std::string> {
253 std::unique_ptr<FILE, int(*)(FILE*)> pipe(_popen(cmd.c_str(),
"r"), _pclose);
255 std::unique_ptr<FILE, int(*)(FILE*)> pipe(popen(cmd.c_str(),
"r"), pclose);
258 return { -1, std::string(
"Failed to spawn: ") + cmd };
260 std::array<char, 512> buf{};
261 while (fgets(buf.data(),
static_cast<int>(buf.size()), pipe.get()) !=
nullptr) {
262 output += buf.data();
266 code = _pclose(pipe.release());
268 code = pclose(pipe.release());
270 return { code, output };
273 auto [linkRes, link_out] = runAndCapture(link_cmd);
275 std::cerr <<
"\033[31mCompilation error: Link command: " << link_cmd <<
'\n';
276 std::cerr << link_out <<
'\n';
277 std::cerr <<
"Linking failed with code " << linkRes <<
"\033[0m\n";
281 std::cout <<
"\033[36;1mCOMPILING SUCCESS. Built executable:\033[0m " << executable_path <<
'\n';
283 if (std::remove(object_path.c_str()) != 0) {
284 std::cerr <<
"\033[31mCompilation error: Warning: Failed to remove object file: " << object_path <<
"\033[0m\n";
int main(int argc, const char *argv[])