Preprocessor.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. m_lines = m_program.split_view('\n', true);
  17. }
  18. const String& Preprocessor::process()
  19. {
  20. for (; m_line_index < m_lines.size(); ++m_line_index) {
  21. auto& line = m_lines[m_line_index];
  22. bool include_in_processed_text = false;
  23. if (line.starts_with("#")) {
  24. auto keyword = handle_preprocessor_line(line);
  25. if (m_options.keep_include_statements && keyword == "include")
  26. include_in_processed_text = true;
  27. } else if (m_state == State::Normal) {
  28. include_in_processed_text = true;
  29. }
  30. if (include_in_processed_text) {
  31. m_builder.append(line);
  32. }
  33. m_builder.append("\n");
  34. }
  35. m_processed_text = m_builder.to_string();
  36. return m_processed_text;
  37. }
  38. static void consume_whitespace(GenericLexer& lexer)
  39. {
  40. lexer.ignore_while([](char ch) { return isspace(ch); });
  41. if (lexer.peek() == '/' && lexer.peek(1) == '/')
  42. lexer.ignore_until([](char ch) { return ch == '\n'; });
  43. }
  44. Preprocessor::PreprocessorKeyword Preprocessor::handle_preprocessor_line(const StringView& line)
  45. {
  46. GenericLexer lexer(line);
  47. consume_whitespace(lexer);
  48. lexer.consume_specific('#');
  49. consume_whitespace(lexer);
  50. auto keyword = lexer.consume_until(' ');
  51. if (keyword.is_empty() || keyword.is_null() || keyword.is_whitespace())
  52. return {};
  53. handle_preprocessor_keyword(keyword, lexer);
  54. return keyword;
  55. }
  56. void Preprocessor::handle_preprocessor_keyword(const StringView& keyword, GenericLexer& line_lexer)
  57. {
  58. if (keyword == "include") {
  59. consume_whitespace(line_lexer);
  60. m_included_paths.append(line_lexer.consume_all());
  61. return;
  62. }
  63. if (keyword == "else") {
  64. VERIFY(m_current_depth > 0);
  65. if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1)) {
  66. m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; });
  67. m_state = State::Normal;
  68. }
  69. if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) {
  70. m_state = State::SkipElseBranch;
  71. }
  72. return;
  73. }
  74. if (keyword == "endif") {
  75. VERIFY(m_current_depth > 0);
  76. --m_current_depth;
  77. if (m_depths_of_not_taken_branches.contains_slow(m_current_depth)) {
  78. m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; });
  79. }
  80. if (m_depths_of_taken_branches.contains_slow(m_current_depth)) {
  81. m_depths_of_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth; });
  82. }
  83. m_state = State::Normal;
  84. return;
  85. }
  86. if (keyword == "define") {
  87. if (m_state == State::Normal) {
  88. auto key = line_lexer.consume_until(' ');
  89. consume_whitespace(line_lexer);
  90. DefinedValue value;
  91. value.filename = m_filename;
  92. value.line = m_line_index;
  93. auto string_value = line_lexer.consume_all();
  94. if (!string_value.is_empty())
  95. value.value = string_value;
  96. m_definitions.set(key, value);
  97. }
  98. return;
  99. }
  100. if (keyword == "undef") {
  101. if (m_state == State::Normal) {
  102. auto key = line_lexer.consume_until(' ');
  103. line_lexer.consume_all();
  104. m_definitions.remove(key);
  105. }
  106. return;
  107. }
  108. if (keyword == "ifdef") {
  109. ++m_current_depth;
  110. if (m_state == State::Normal) {
  111. auto key = line_lexer.consume_until(' ');
  112. if (m_definitions.contains(key)) {
  113. m_depths_of_taken_branches.append(m_current_depth - 1);
  114. return;
  115. } else {
  116. m_depths_of_not_taken_branches.append(m_current_depth - 1);
  117. m_state = State::SkipIfBranch;
  118. return;
  119. }
  120. }
  121. return;
  122. }
  123. if (keyword == "ifndef") {
  124. ++m_current_depth;
  125. if (m_state == State::Normal) {
  126. auto key = line_lexer.consume_until(' ');
  127. if (!m_definitions.contains(key)) {
  128. m_depths_of_taken_branches.append(m_current_depth - 1);
  129. return;
  130. } else {
  131. m_depths_of_not_taken_branches.append(m_current_depth - 1);
  132. m_state = State::SkipIfBranch;
  133. return;
  134. }
  135. }
  136. return;
  137. }
  138. if (keyword == "if") {
  139. ++m_current_depth;
  140. if (m_state == State::Normal) {
  141. // FIXME: Implement #if logic
  142. // We currently always take #if branches.
  143. m_depths_of_taken_branches.append(m_current_depth - 1);
  144. }
  145. return;
  146. }
  147. if (keyword == "elif") {
  148. VERIFY(m_current_depth > 0);
  149. // FIXME: Evaluate the elif expression
  150. // We currently always treat the expression in #elif as true.
  151. if (m_depths_of_not_taken_branches.contains_slow(m_current_depth - 1) /* && should_take*/) {
  152. m_depths_of_not_taken_branches.remove_all_matching([this](auto x) { return x == m_current_depth - 1; });
  153. m_state = State::Normal;
  154. }
  155. if (m_depths_of_taken_branches.contains_slow(m_current_depth - 1)) {
  156. m_state = State::SkipElseBranch;
  157. }
  158. return;
  159. }
  160. if (keyword == "pragma") {
  161. line_lexer.consume_all();
  162. return;
  163. }
  164. if (!m_options.ignore_unsupported_keywords) {
  165. dbgln("Unsupported preprocessor keyword: {}", keyword);
  166. VERIFY_NOT_REACHED();
  167. }
  168. }
  169. const String& Preprocessor::processed_text()
  170. {
  171. VERIFY(!m_processed_text.is_null());
  172. return m_processed_text;
  173. }
  174. };