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.

239 lines
6.9 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 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. #include <algorithm>
  2. #include <cassert>
  3. #include <iostream>
  4. #include "molasses/parser_primitives.h"
  5. #include "molasses/generator_primitives.h"
  6. namespace molasses {
  7. std::vector<std::string> operator>>(std::vector<std::string> current_stack, const operation& next_op) {
  8. {
  9. auto args = next_op.argument_types();
  10. while(not (args.empty() or current_stack.empty())) {
  11. if(current_stack.back() != args.back()) {
  12. throw type_input_error();
  13. } else {
  14. args.pop_back();
  15. current_stack.pop_back();
  16. }
  17. }
  18. if(not args.empty()) {
  19. throw value_missing_error();
  20. }
  21. }
  22. {
  23. auto return_types = next_op.return_types();
  24. std::move(return_types.begin(), return_types.end(), std::back_inserter(current_stack));
  25. }
  26. return current_stack;
  27. }
  28. std::optional<int32_t> try_parse_int32(const std::string& str) {
  29. int32_t value;
  30. auto begin = str.data();
  31. auto end = str.data()+str.size();
  32. auto result = std::from_chars(begin, end, value, 10);
  33. // TODO: Add other bases
  34. if(result.ptr == end) {
  35. return value;
  36. }
  37. return std::nullopt;
  38. }
  39. auto find_ptr_by_name_in_container(auto container, const auto& name) -> typeof(*std::begin(container)) {
  40. auto it = std::find_if(std::begin(container), std::end(container), [&](auto elem){
  41. return elem->name() == name;
  42. });
  43. if(it != std::end(container)) {
  44. return *it;
  45. }
  46. return {};
  47. }
  48. std::shared_ptr<type> parser_context::lookup_type(const std::string & name) const {
  49. return find_ptr_by_name_in_container(types, name);
  50. }
  51. std::shared_ptr<operation> parser_context::lookup_operation(const std::string & name) const {
  52. return find_ptr_by_name_in_container(operations, name);
  53. }
  54. bool type_check(
  55. const parser_context& parser_state,
  56. const lexed_output& lexer_state,
  57. const std::vector<symbol>& consumed_stream,
  58. std::vector<std::string> execution_input,
  59. const std::vector<std::string>& execution_output
  60. ) {
  61. auto& type_stack = execution_input;
  62. for(const auto& symbol : consumed_stream) {
  63. const auto& symbol_text = lexer_state.dictionary.at(symbol);
  64. if(auto is_int = try_parse_int32(symbol_text); is_int) {
  65. type_stack.emplace_back("i32");
  66. } else if(auto is_op = parser_state.lookup_operation(symbol_text); is_op) {
  67. type_stack = type_stack >> *is_op;
  68. }
  69. }
  70. return type_stack == execution_output;
  71. }
  72. generate_context parse(parser_context ctx, const lexed_output& lexer_data) {
  73. enum op : int {
  74. DO_KW = 1,
  75. SEPARATOR_KW,
  76. PROC_KW,
  77. END_KW
  78. };
  79. lexed_output fake;
  80. fake.dictionary[PROC_KW] = "__PROC__";
  81. fake.dictionary[SEPARATOR_KW] = "__--__";
  82. fake.dictionary[DO_KW] = "__DO__";
  83. fake.dictionary[END_KW] = "__END__";
  84. auto tokens = concatenate(fake, lexer_data);
  85. std::vector<std::shared_ptr<procedure_operation>> parsed_procedures;
  86. auto register_pointer_type = [&](std::string full_ptr_type_name) -> void {
  87. if(auto type = ctx.lookup_type(full_ptr_type_name); !type) {
  88. ctx.types.push_back(std::make_shared<primitive_type>(std::move(full_ptr_type_name), architecture_ptr_size));
  89. }
  90. };
  91. auto compact_type_modifiers = [&](const std::vector<std::string>& type_info) -> std::vector<std::string> {
  92. std::vector<std::string> ret_val;
  93. for(auto elem : type_info) {
  94. if(elem == "ptr") {
  95. if(ret_val.empty()) throw type_expected_with_modifier_error();
  96. ret_val.back() += " ptr";
  97. register_pointer_type(ret_val.back());
  98. } else {
  99. ret_val.push_back(elem);
  100. }
  101. }
  102. return ret_val;
  103. };
  104. auto parse_proc = [&](auto it) -> std::pair<typeof(it), std::shared_ptr<procedure_operation>> {
  105. #define CHECK_FOR_UNEXPECTED_STREAM_END \
  106. if(it == tokens.symbols.end()) { \
  107. throw expecting_token_error(); \
  108. }
  109. if(*it != PROC_KW) {
  110. throw unexpected_token_error();
  111. }
  112. ++it;
  113. CHECK_FOR_UNEXPECTED_STREAM_END;
  114. std::string name = tokens.dictionary.at(*it);
  115. ++it;
  116. CHECK_FOR_UNEXPECTED_STREAM_END;
  117. // Process arguments list
  118. std::vector<std::string> argument_types;
  119. while(*it != SEPARATOR_KW) {
  120. argument_types.emplace_back(tokens.dictionary.at(*it));
  121. ++it;
  122. CHECK_FOR_UNEXPECTED_STREAM_END;
  123. }
  124. ++it;
  125. CHECK_FOR_UNEXPECTED_STREAM_END;
  126. argument_types = compact_type_modifiers(argument_types);
  127. // Process return types list
  128. std::vector<std::string> return_types;
  129. while(*it != DO_KW) {
  130. return_types.emplace_back(tokens.dictionary.at(*it));
  131. ++it;
  132. CHECK_FOR_UNEXPECTED_STREAM_END;
  133. }
  134. ++it;
  135. CHECK_FOR_UNEXPECTED_STREAM_END;
  136. return_types = compact_type_modifiers(return_types);
  137. // Process return types list
  138. std::vector<symbol> body;
  139. while(*it != END_KW) {
  140. body.emplace_back(*it);
  141. ++it;
  142. CHECK_FOR_UNEXPECTED_STREAM_END;
  143. }
  144. ++it;
  145. return std::make_pair(it, std::make_shared<procedure_operation>(name, argument_types, return_types, body));
  146. #undef CHECK_FOR_UNEXPECTED_STREAM_END
  147. };
  148. auto progress = tokens.symbols.begin();
  149. do {
  150. auto [iterator, procedure] = parse_proc(progress);
  151. ctx.operations.push_back(procedure);
  152. parsed_procedures.emplace_back(std::move(procedure));
  153. progress = iterator;
  154. } while (progress != tokens.symbols.end());
  155. for(auto& proc : parsed_procedures) {
  156. if(not type_check(ctx, tokens, proc->_body, proc->_args, proc->_rets)) {
  157. throw procedure_stack_error();
  158. }
  159. }
  160. return {
  161. tokens,
  162. ctx,
  163. parsed_procedures
  164. };
  165. }
  166. std::vector<std::string> procedure_operation::generate(const parser_context& ctx, const lexed_output& lexer_data) const {
  167. std::vector<std::string> ops = generate_label(name());
  168. for(auto&& instruction : generate_enter()) {
  169. ops.push_back(instruction);
  170. }
  171. for(auto elem : _body) {
  172. auto token = lexer_data.dictionary.at(elem);
  173. if(auto result = try_parse_int32(token); result) {
  174. for(auto&& instruction : generate_push_int32(result.value())) {
  175. ops.push_back(instruction);
  176. }
  177. } else if(auto op = ctx.lookup_operation(token); op) {
  178. for(auto&& instruction : op->emit(ctx)) {
  179. ops.push_back(instruction);
  180. }
  181. } else {
  182. throw unknown_token_error();
  183. }
  184. }
  185. for(auto&& instruction : generate_return()) {
  186. ops.push_back(instruction);
  187. }
  188. return ops;
  189. }
  190. std::vector<std::string> procedure_operation::emit(const parser_context& ctx) const {
  191. return generate_call(name());
  192. }
  193. std::vector<std::string> generate(generate_context ctx) {
  194. std::vector<std::string> generated;
  195. for(auto instr : initialize_stack()) {
  196. generated.push_back(instr);
  197. }
  198. for(auto proc : ctx.procedures) {
  199. for(auto instr : proc->generate(ctx.parser, ctx.lexer)) {
  200. generated.push_back(instr);
  201. }
  202. }
  203. return generated;
  204. }
  205. }