Preprocessor.cpp 5.4 KB

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