You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
7.1 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. #include "molasses/lexer.h"
  2. #include "molasses/parser_primitives.h"
  3. #include <cstring>
  4. #include <filesystem>
  5. #include <fstream>
  6. #include <iostream>
  7. #include <sstream>
  8. #include <stack>
  9. #include <string>
  10. #include <variant>
  11. using compile_element = std::variant<molasses::lexed_output, molasses::generate_context, std::string>;
  12. int main(int argc, char** argv) {
  13. std::vector<std::string> arguments;
  14. while(argc > 1) {
  15. argv++;
  16. arguments.emplace_back(*argv, strlen(*argv));
  17. argc--;
  18. }
  19. std::stack<compile_element> compile_stack;
  20. for(auto elem : arguments) {
  21. if(elem == "generate") {
  22. if(std::holds_alternative<std::string>(compile_stack.top())) {
  23. auto filename = std::get<std::string>(compile_stack.top());
  24. compile_stack.pop();
  25. if(std::holds_alternative<molasses::generate_context>(compile_stack.top())) {
  26. auto generator = std::get<molasses::generate_context>(compile_stack.top());
  27. compile_stack.pop();
  28. auto assembler = molasses::generate(generator);
  29. std::ofstream output(filename+".s");
  30. for(const auto& line : assembler) {
  31. output << line;
  32. }
  33. compile_stack.emplace(filename);
  34. } else throw std::runtime_error("generate expects a parsed output");
  35. } else throw std::runtime_error("generate expects a filename");
  36. } else if(elem == "parse") {
  37. molasses::parser_context ctx;
  38. ctx = molasses::register_integers(ctx);
  39. ctx = molasses::register_i32_operations(ctx);
  40. if(std::holds_alternative<molasses::lexed_output>(compile_stack.top())) {
  41. auto lexer = std::get<molasses::lexed_output>(compile_stack.top());
  42. compile_stack.pop();
  43. auto generator = molasses::parse(ctx, lexer);
  44. compile_stack.emplace(generator);
  45. } else throw std::runtime_error("parse expects a lexed output");
  46. } else if(elem == "lex") {
  47. if(std::holds_alternative<std::string>(compile_stack.top())) {
  48. auto filename = std::get<std::string>(compile_stack.top());
  49. compile_stack.pop();
  50. if(not std::filesystem::exists(filename)) throw std::runtime_error("file "+filename+" does not exist");
  51. std::ifstream t(filename);
  52. std::stringstream buffer;
  53. buffer << t.rdbuf();
  54. auto lexed = molasses::lex(buffer.str());
  55. compile_stack.emplace(lexed);
  56. } else throw std::runtime_error("lex expects a filename");
  57. } else if(elem == "merge") {
  58. if(std::holds_alternative<molasses::lexed_output>(compile_stack.top())) {
  59. auto lexer_1 = std::get<molasses::lexed_output>(compile_stack.top());
  60. compile_stack.pop();
  61. if(std::holds_alternative<molasses::lexed_output>(compile_stack.top())) {
  62. auto lexer_2 = std::get<molasses::lexed_output>(compile_stack.top());
  63. compile_stack.pop();
  64. compile_stack.emplace(molasses::concatenate(lexer_1, lexer_2));
  65. } else throw std::runtime_error("merge expects 2 lexed outputs");
  66. } else throw std::runtime_error("merge expects 2 lexed outputs");
  67. } else if(elem == "assemble") {
  68. if(std::holds_alternative<std::string>(compile_stack.top())) {
  69. auto filename = std::get<std::string>(compile_stack.top());
  70. compile_stack.pop();
  71. std::stringstream compile; compile << "clang -c " << filename << ".s -o " << filename << ".o";
  72. std::stringstream link; link << "ld -e _start " << filename << ".o -o " << filename;
  73. std::cout << compile.str() << std::endl;
  74. system(compile.str().c_str());
  75. std::cout << link.str() << std::endl;
  76. system(link.str().c_str());
  77. } else throw std::runtime_error("assemble expects an assembly file");
  78. } else if(elem == "help" or elem == "--help") {
  79. std::cout << "# Sugar\n\n";
  80. std::cout << "## Commands\n\n";
  81. std::cout << "lex : string ➔ lexed_output\n";
  82. std::cout << "> takes a filename to a file that must be compiled\n\n";
  83. std::cout << "merge : lexed_output lexed_output ➔ lexed_output\n";
  84. std::cout << "> merges two lexed modules together\n\n";
  85. std::cout << "parse : lexed_output ➔ parsed_output\n";
  86. std::cout << "> prepares code for generation\n\n";
  87. std::cout << "generate : parsed_output string ➔ string\n";
  88. std::cout << "> takes a root filename, it will be appended with \".s\" and that will be the generated assembly file,\n";
  89. std::cout << "> the filename will not be consumed\n\n";
  90. std::cout << "assemble : string ➔ _ \n";
  91. std::cout << "> takes a root filename, it will be appended with \".s\" and that file will be compiled,\n";
  92. std::cout << "> the compiled output will be the given filename\n\n";
  93. std::cout << "help : _ ➔ _ \n";
  94. std::cout << "> prints this help\n\n";
  95. std::cout << "## Examples\n\n";
  96. std::cout << "- compile the file \"example.mol\" into the \"potato.s\" assembly file\n";
  97. std::cout << "> `$ sugar example.mol lex parse potato generate`\n";
  98. std::cout << "\n";
  99. std::cout << "- compile the file \"example.mol\" into the \"potato\" executable\n";
  100. std::cout << "> `$ sugar example.mol lex parse potato generate assemble`\n";
  101. std::cout << "\n";
  102. std::cout << "- compile the file \"example.mol\" and \"2.mol\" into the \"potato\" executable\n";
  103. std::cout << "> `$ sugar example.mol lex 2.mol lex merge parse potato generate assemble`\n";
  104. } else compile_stack.emplace(elem);
  105. }
  106. if(compile_stack.size() > 1) throw std::runtime_error("build left unfinished operations");
  107. if(not compile_stack.empty()) {
  108. if(std::holds_alternative<molasses::lexed_output>(compile_stack.top())) {
  109. auto lexer = std::get<molasses::lexed_output>(compile_stack.top());
  110. for(auto elem : lexer.symbols) {
  111. std::cout << elem << " ";
  112. }
  113. std::cout << "\n\n";
  114. for(auto [id, name] : lexer.dictionary) {
  115. std::cout << id << ": " << name << "\n";
  116. }
  117. } else if(std::holds_alternative<molasses::generate_context>(compile_stack.top())) {
  118. auto generator = std::get<molasses::generate_context>(compile_stack.top());
  119. for(const auto& elem : generator.procedures) {
  120. std::cout << elem->_name << " : ";
  121. for(const auto& args : elem->_args) {
  122. std::cout << args << " ";
  123. }
  124. std::cout << "->";
  125. for(const auto& rets : elem->_rets) {
  126. std::cout << " " << rets;
  127. }
  128. std::cout << "\n";
  129. }
  130. }
  131. }
  132. }