Driver.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #include "Driver.h"
  2. #include "Ast.h"
  3. #include "Semantic.h"
  4. #include "Builtin.h"
  5. #include "CodeGeneration.h"
  6. #include "Linking.h"
  7. #include "Printer.h"
  8. #include "ErrorReporting.h"
  9. #include <cstdio>
  10. #include <set>
  11. #include <filesystem>
  12. #include <functional>
  13. #include <algorithm>
  14. extern std::unique_ptr<std::vector<std::unique_ptr<qlow::ast::AstObject>>> parsedClasses;
  15. extern FILE* qlow_parser_in;
  16. extern int qlow_parser_parse(void);
  17. extern const char* qlow_parser_filename;
  18. using namespace qlow;
  19. Options Options::parseOptions(int argc, char** argv)
  20. {
  21. static const std::map<std::string, bool Options::*> boolArgs =
  22. {
  23. {"-S", &Options::emitAssembly},
  24. {"--emit-assembly", &Options::emitAssembly},
  25. {"-L", &Options::emitLlvm},
  26. {"--emit-llvm", &Options::emitLlvm},
  27. };
  28. Options options{};
  29. for (int i = 1; i < argc; i++) {
  30. std::string arg = argv[i];
  31. if (boolArgs.find(arg) != boolArgs.end()) {
  32. bool Options::* attr = boolArgs.find(arg)->second;
  33. options.*attr = true;
  34. }
  35. else if (arg == "-o" || arg == "--out") {
  36. if (argc > i + 1) {
  37. options.outfile = argv[++i];
  38. }
  39. else {
  40. throw "Please specify a filename after '-o'";
  41. }
  42. }
  43. else if (arg.rfind("-O", 0) == 0) {
  44. if (arg.size() > 2) {
  45. options.optLevel = std::stoi(arg.substr(2));
  46. }
  47. else {
  48. options.optLevel = 2;
  49. }
  50. }
  51. else if (arg.rfind("-l", 0) == 0) {
  52. if (arg.size() > 2) {
  53. options.libs.push_back(arg.substr(2));
  54. }
  55. }
  56. else {
  57. if (options.outfile == "")
  58. options.outfile = arg + ".o";
  59. options.infiles.push_back(std::move(arg));
  60. }
  61. }
  62. if (options.outfile == "")
  63. options.outfile = "a.out";
  64. return options;
  65. }
  66. Driver::Driver(int argc, char** argv) :
  67. options{ Options::parseOptions(argc, argv) }
  68. {
  69. }
  70. int Driver::run(void) try
  71. {
  72. Printer& printer = Printer::getInstance();
  73. if (options.infiles.empty()) {
  74. qlow::printError(ErrorCode::NO_INFILES, printer);
  75. return 1;
  76. }
  77. #ifdef DEBUGGING
  78. printer << "starting parser" << std::endl;
  79. #endif
  80. //printer.logError("driver not yet implemented", {options.emitAssembly ? "asm" : "noasm", 10, 11, 12, 13});
  81. bool errorOccurred = parseStage();
  82. if (errorOccurred) {
  83. printer << "Aborting due to syntax errors." << std::endl;
  84. return 1;
  85. }
  86. errorOccurred = semanticStage();
  87. if (errorOccurred) {
  88. printer << "Aborting due to semantic errors." << std::endl;
  89. return 1;
  90. }
  91. for (auto& [a, b] : semClasses->classes) {
  92. #ifdef DEBUGGING
  93. printer << a << ": " << b->toString() << std::endl;
  94. #endif
  95. }
  96. /*auto main = semClasses->classes.find("Main");
  97. qlow::sem::Class* mainClass = nullptr;
  98. if (main == semClasses->classes.end()) {
  99. printer.logError("No Main class found");
  100. return 1;
  101. }
  102. else {
  103. mainClass = main->second.get();
  104. }*/
  105. auto* mainMethod = semClasses->getMethod("main");
  106. if (mainMethod == nullptr && false) {
  107. // TODO handle main ckeck well
  108. qlow::printError(printer, "no main method found");
  109. return 1;
  110. }
  111. #ifdef DEBUGGING
  112. printer << "starting code generation!" << std::endl;
  113. #endif
  114. std::unique_ptr<llvm::Module> mod = nullptr;
  115. try {
  116. mod = qlow::gen::generateModule(*semClasses);
  117. }
  118. catch (const char* err) {
  119. reportError(err);
  120. return 1;
  121. }
  122. catch (SemanticError& err) {
  123. err.print(printer);
  124. return 1;
  125. }
  126. catch (...) {
  127. reportError("unknown error during code generation");
  128. return 1;
  129. }
  130. // TODO create better tempfile
  131. tempObject = "/tmp/temp.o";
  132. try {
  133. qlow::gen::generateObjectFile(tempObject, std::move(mod), options.optLevel);
  134. }
  135. catch (const char* msg) {
  136. printError(printer, msg);
  137. return 1;
  138. }
  139. catch (...) {
  140. printError(printer, "unknown error during object file creation");
  141. reportError("unknown error during object file creation");
  142. return 1;
  143. }
  144. #ifdef DEBUGGING
  145. printer << "object exported!" << std::endl;
  146. #endif
  147. try {
  148. linkingStage();
  149. }
  150. catch (...) {
  151. reportError("unknown error during linking");
  152. return 1;
  153. }
  154. return 0;
  155. }
  156. catch (InternalError& e) {
  157. e.print(Printer::getInstance());
  158. return 1;
  159. }
  160. bool Driver::parseStage(void)
  161. {
  162. using namespace std::literals;
  163. Printer& printer = Printer::getInstance();
  164. this->ast = std::make_unique<ast::Ast>();
  165. bool errorOccurred = false;
  166. std::set<std::filesystem::path> alreadyParsed = {};
  167. std::set<std::filesystem::path> toParse = {};
  168. toParse.insert(options.infiles.begin(), options.infiles.end());
  169. while(!toParse.empty()) {
  170. auto filename = toParse.extract(toParse.begin()).value();
  171. auto dirPath = filename.parent_path();
  172. std::FILE* file = std::fopen(filename.c_str(), "r");
  173. if (!file) {
  174. reportError("could not open file "s + filename.string() + ".");
  175. errorOccurred = true;
  176. continue;
  177. }
  178. try {
  179. // parse file content and add parsed objects to global ast
  180. ast::Parser parser(file, filename);
  181. this->ast->merge(parser.parse());
  182. for (auto& import : parser.getImports()) {
  183. auto importPath = dirPath / import->getRelativePath();
  184. #ifdef DEBUGGING
  185. printer << "imported " << importPath << std::endl;
  186. #endif
  187. if (alreadyParsed.count(dirPath) == 0) {
  188. toParse.insert(importPath);
  189. }
  190. }
  191. }
  192. catch (const CompileError& ce) {
  193. ce.print(printer);
  194. errorOccurred = true;
  195. }
  196. catch (const char* errMsg) {
  197. reportError(errMsg);
  198. errorOccurred = true;
  199. }
  200. catch (...) {
  201. reportError("an unknown error occurred.");
  202. errorOccurred = true;
  203. throw;
  204. }
  205. if (file)
  206. std::fclose(file);
  207. }
  208. return errorOccurred;
  209. }
  210. bool Driver::semanticStage(void)
  211. {
  212. Printer& printer = Printer::getInstance();
  213. bool errorOccurred = false;
  214. try {
  215. std::tie(this->context, this->semClasses) = qlow::sem::createFromAst(*this->ast);
  216. }
  217. catch(SemanticError& se) {
  218. se.print(printer);
  219. errorOccurred = true;
  220. }
  221. catch(const char* err) {
  222. reportError(err);
  223. errorOccurred = true;
  224. }
  225. catch (...) {
  226. reportError("an unknown error occurred.");
  227. errorOccurred = true;
  228. }
  229. return errorOccurred;
  230. }
  231. bool Driver::linkingStage(void)
  232. {
  233. using namespace std::literals;
  234. bool errorOccurred = false;
  235. auto linkerPath = qlow::getLinkerExecutable();
  236. std::vector<std::string> ldArgs = {
  237. tempObject.string(), "-e", "_qlow_start", "-o", options.outfile,
  238. "-lc",
  239. #ifdef __linux__
  240. "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2"
  241. #endif
  242. };
  243. std::copy(options.libs.begin(), options.libs.end(), std::back_inserter(ldArgs));
  244. int linkerRun = qlow::invokeProgram(linkerPath, ldArgs);
  245. if (linkerRun != 0) {
  246. reportError("linker error");
  247. errorOccurred = true;
  248. }
  249. return errorOccurred;
  250. }