Parser.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #include "Parser.h"
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. void Parser::commit_token()
  5. {
  6. if (m_token.is_empty())
  7. return;
  8. if (m_state == InRedirectionPath) {
  9. m_redirections.last().path = String::copy(m_token);
  10. m_token.clear_with_capacity();
  11. return;
  12. }
  13. m_tokens.append(String::copy(m_token));
  14. m_token.clear_with_capacity();
  15. };
  16. void Parser::commit_subcommand()
  17. {
  18. if (m_tokens.is_empty())
  19. return;
  20. m_subcommands.append({ move(m_tokens), move(m_redirections) });
  21. }
  22. void Parser::do_pipe()
  23. {
  24. m_redirections.append({ Redirection::Pipe, STDOUT_FILENO });
  25. commit_subcommand();
  26. }
  27. void Parser::begin_redirect_read(int fd)
  28. {
  29. m_redirections.append({ Redirection::FileRead, fd });
  30. }
  31. void Parser::begin_redirect_write(int fd)
  32. {
  33. m_redirections.append({ Redirection::FileWrite, fd });
  34. }
  35. Vector<Subcommand> Parser::parse()
  36. {
  37. for (int i = 0; i < m_input.length(); ++i) {
  38. char ch = m_input.characters()[i];
  39. switch (m_state) {
  40. case State::Free:
  41. if (ch == ' ') {
  42. commit_token();
  43. break;
  44. }
  45. if (ch == '|') {
  46. commit_token();
  47. if (m_tokens.is_empty()) {
  48. fprintf(stderr, "Syntax error: Nothing before pipe (|)\n");
  49. return { };
  50. }
  51. do_pipe();
  52. break;
  53. }
  54. if (ch == '>') {
  55. commit_token();
  56. begin_redirect_write(STDOUT_FILENO);
  57. // Search for another > for append.
  58. m_state = State::InWriteAppendOrRedirectionPath;
  59. break;
  60. }
  61. if (ch == '<') {
  62. commit_token();
  63. begin_redirect_read(STDIN_FILENO);
  64. m_state = State::InRedirectionPath;
  65. break;
  66. }
  67. if (ch == '\'') {
  68. m_state = State::InSingleQuotes;
  69. break;
  70. }
  71. if (ch == '\"') {
  72. m_state = State::InDoubleQuotes;
  73. break;
  74. }
  75. m_token.append(ch);
  76. break;
  77. case State::InWriteAppendOrRedirectionPath:
  78. if (ch == '>') {
  79. commit_token();
  80. m_state = State::InRedirectionPath;
  81. ASSERT(m_redirections.size());
  82. m_redirections[m_redirections.size() - 1].type = Redirection::FileWriteAppend;
  83. break;
  84. }
  85. // Not another > means that it's probably a path.
  86. m_state = InRedirectionPath;
  87. [[fallthrough]];
  88. case State::InRedirectionPath:
  89. if (ch == '<') {
  90. commit_token();
  91. begin_redirect_read(STDIN_FILENO);
  92. m_state = State::InRedirectionPath;
  93. break;
  94. }
  95. if (ch == '>') {
  96. commit_token();
  97. begin_redirect_read(STDOUT_FILENO);
  98. m_state = State::InRedirectionPath;
  99. break;
  100. }
  101. if (ch == '|') {
  102. commit_token();
  103. if (m_tokens.is_empty()) {
  104. fprintf(stderr, "Syntax error: Nothing before pipe (|)\n");
  105. return { };
  106. }
  107. do_pipe();
  108. m_state = State::Free;
  109. break;
  110. }
  111. if (ch == ' ')
  112. break;
  113. m_token.append(ch);
  114. break;
  115. case State::InSingleQuotes:
  116. if (ch == '\'') {
  117. commit_token();
  118. m_state = State::Free;
  119. break;
  120. }
  121. m_token.append(ch);
  122. break;
  123. case State::InDoubleQuotes:
  124. if (ch == '\"') {
  125. commit_token();
  126. m_state = State::Free;
  127. break;
  128. }
  129. m_token.append(ch);
  130. break;
  131. };
  132. }
  133. commit_token();
  134. commit_subcommand();
  135. if (!m_subcommands.is_empty()) {
  136. for (auto& redirection : m_subcommands.last().redirections) {
  137. if (redirection.type == Redirection::Pipe) {
  138. fprintf(stderr, "Syntax error: Nothing after last pipe (|)\n");
  139. return { };
  140. }
  141. }
  142. }
  143. return move(m_subcommands);
  144. }