Preprocessor.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Preprocessor.h"
  7. #include <AK/Assertions.h>
  8. #include <AK/GenericLexer.h>
  9. #include <AK/StringBuilder.h>
  10. #include <ctype.h>
  11. namespace Cpp {
  12. Preprocessor::Preprocessor(const String& filename, const StringView& program)
  13. : m_filename(filename)
  14. , m_program(program)
  15. {
  16. GenericLexer program_lexer { m_program };
  17. for (;;) {
  18. if (program_lexer.is_eof())
  19. break;
  20. auto line = program_lexer.consume_until('\n');
  21. bool has_multiline = false;
  22. while (line.ends_with('\\') && !program_lexer.is_eof()) {
  23. auto continuation = program_lexer.consume_until('\n');
  24. line = StringView { line.characters_without_null_termination(), line.length() + continuation.length() + 1 };
  25. // Append an empty line to keep the line count correct.
  26. m_lines.append({});
  27. has_multiline = true;
  28. }
  29. if (has_multiline)
  30. m_lines.last() = line;
  31. else
  32. m_lines.append(line);
  33. }
  34. }
  35. const String& Preprocessor::process()
  36. {
  37. for (; m_line_index < m_lines.size(); ++m_line_index) {
  38. auto& line = m_lines[m_line_index];
  39. bool include_in_processed_text = false;
  40. if (line.starts_with("#")) {
  41. auto keyword = handle_preprocessor_line(line);
  42. if (m_options.keep_include_statements && keyword == "include")
  43. include_in_processed_text = true;
  44. } else if (m_state == State::Normal) {
  45. include_in_processed_text = true;
  46. }
  47. if (include_in_processed_text) {
  48. m_builder.append(line);
  49. }
  50. m_builder.append("\n");
  51. }
  52. m_processed_text = m_builder.to_string();
  53. return m_processed_text;
  54. }
  55. static void consume_whitespace(GenericLexer& lexer)
  56. {
  57. auto ignore_line = [&] {
  58. for (;;) {
  59. if (lexer.consume_specific("\\\n"sv)) {
  60. lexer.ignore(2);
  61. } else {
  62. lexer.ignore_until('\n');
  63. break;
  64. }
  65. }
  66. };
  67. for (;;) {
  68. if (lexer.consume_specific("//"sv))
  69. ignore_line();
  70. else if (lexer.consume_specific("/*"sv))
  71. lexer.ignore_until("*/");
  72. else if (lexer.next_is("\\\n"sv))
  73. lexer.ignore(2);
  74. else if (lexer.is_eof() || !lexer.next_is(isspace))
  75. break;
  76. else
  77. lexer.ignore();
  78. }
  79. }
  80. Preprocessor::PreprocessorKeyword Preprocessor::handle_preprocessor_line(const StringView& line)
  81. {
  82. GenericLexer lexer(line);
  83. consume_whitespace(lexer);
  84. lexer.consume_specific('#');
  85. consume_whitespace(lexer);
  86. auto keyword = lexer.consume_until(' ');
  87. if (keyword.is_empty() || keyword.is_null() || keyword.is_whitespace())
  88. return {};
  89. handle_preprocessor_keyword(keyword, lexer);
  90. return keyword;
  91. }
  92. void Preprocessor::handle_preprocessor_keyword(const StringView& keyword, GenericLexer& line_lexer)
  93. {
  94. if (keyword == "include") {
  95. consume_whitespace(line_lexer);
  96. m_included_paths.append(line_lexer.consume_all());
  97. return;
  98. }
  99. if (keyword == "else") {
  100. VERIFY(m_current_depth > 0);
  101. if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1)) {
  102. m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; });
  103. m_state = State::Normal;
  104. }
  105. if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) {
  106. m_state = State::SkipElseBranch;
  107. }
  108. return;
  109. }
  110. if (keyword == "endif") {
  111. VERIFY(m_current_depth > 0);
  112. --m_current_depth;
  113. if (m_depths_of_not_taken_branches.contains_slow(m_current_depth)) {
  114. m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; });
  115. }
  116. if (m_depths_of_taken_branches.contains_slow(m_current_depth)) {
  117. m_depths_of_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; });
  118. }
  119. m_state = State::Normal;
  120. return;
  121. }
  122. if (keyword == "define") {
  123. if (m_state == State::Normal) {
  124. auto key = line_lexer.consume_until(' ');
  125. consume_whitespace(line_lexer);
  126. DefinedValue value;
  127. value.filename = m_filename;
  128. value.line = m_line_index;
  129. auto string_value = line_lexer.consume_all();
  130. if (!string_value.is_empty())
  131. value.value = string_value;
  132. m_definitions.set(key, value);
  133. }
  134. return;
  135. }
  136. if (keyword == "undef") {
  137. if (m_state == State::Normal) {
  138. auto key = line_lexer.consume_until(' ');
  139. line_lexer.consume_all();
  140. m_definitions.remove(key);
  141. }
  142. return;
  143. }
  144. if (keyword == "ifdef") {
  145. ++m_current_depth;
  146. if (m_state == State::Normal) {
  147. auto key = line_lexer.consume_until(' ');
  148. if (m_definitions.contains(key)) {
  149. m_depths_of_taken_branches.append(m_current_depth - 1);
  150. return;
  151. } else {
  152. m_depths_of_not_taken_branches.append(m_current_depth - 1);
  153. m_state = State::SkipIfBranch;
  154. return;
  155. }
  156. }
  157. return;
  158. }
  159. if (keyword == "ifndef") {
  160. ++m_current_depth;
  161. if (m_state == State::Normal) {
  162. auto key = line_lexer.consume_until(' ');
  163. if (!m_definitions.contains(key)) {
  164. m_depths_of_taken_branches.append(m_current_depth - 1);
  165. return;
  166. } else {
  167. m_depths_of_not_taken_branches.append(m_current_depth - 1);
  168. m_state = State::SkipIfBranch;
  169. return;
  170. }
  171. }
  172. return;
  173. }
  174. if (keyword == "if") {
  175. ++m_current_depth;
  176. if (m_state == State::Normal) {
  177. // FIXME: Implement #if logic
  178. // We currently always take #if branches.
  179. m_depths_of_taken_branches.append(m_current_depth - 1);
  180. }
  181. return;
  182. }
  183. if (keyword == "elif") {
  184. VERIFY(m_current_depth > 0);
  185. // FIXME: Evaluate the elif expression
  186. // We currently always treat the expression in #elif as true.
  187. if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1) /* && should_take*/) {
  188. m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; });
  189. m_state = State::Normal;
  190. }
  191. if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) {
  192. m_state = State::SkipElseBranch;
  193. }
  194. return;
  195. }
  196. if (keyword == "pragma") {
  197. line_lexer.consume_all();
  198. return;
  199. }
  200. if (!m_options.ignore_unsupported_keywords) {
  201. dbgln("Unsupported preprocessor keyword: {}", keyword);
  202. VERIFY_NOT_REACHED();
  203. }
  204. }
  205. const String& Preprocessor::processed_text()
  206. {
  207. VERIFY(!m_processed_text.is_null());
  208. return m_processed_text;
  209. }
  210. };