Parser.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. m_state = State::InRedirectionPath;
  58. break;
  59. }
  60. if (ch == '<') {
  61. commit_token();
  62. begin_redirect_read(STDIN_FILENO);
  63. m_state = State::InRedirectionPath;
  64. break;
  65. }
  66. if (ch == '\'') {
  67. m_state = State::InSingleQuotes;
  68. break;
  69. }
  70. if (ch == '\"') {
  71. m_state = State::InDoubleQuotes;
  72. break;
  73. }
  74. m_token.append(ch);
  75. break;
  76. case State::InRedirectionPath:
  77. if (ch == '<') {
  78. commit_token();
  79. begin_redirect_read(STDIN_FILENO);
  80. m_state = State::InRedirectionPath;
  81. break;
  82. }
  83. if (ch == '>') {
  84. commit_token();
  85. begin_redirect_read(STDOUT_FILENO);
  86. m_state = State::InRedirectionPath;
  87. break;
  88. }
  89. if (ch == '|') {
  90. commit_token();
  91. if (m_tokens.is_empty()) {
  92. fprintf(stderr, "Syntax error: Nothing before pipe (|)\n");
  93. return { };
  94. }
  95. do_pipe();
  96. m_state = State::Free;
  97. break;
  98. }
  99. if (ch == ' ')
  100. break;
  101. m_token.append(ch);
  102. break;
  103. case State::InSingleQuotes:
  104. if (ch == '\'') {
  105. commit_token();
  106. m_state = State::Free;
  107. break;
  108. }
  109. m_token.append(ch);
  110. break;
  111. case State::InDoubleQuotes:
  112. if (ch == '\"') {
  113. commit_token();
  114. m_state = State::Free;
  115. break;
  116. }
  117. m_token.append(ch);
  118. break;
  119. };
  120. }
  121. commit_token();
  122. commit_subcommand();
  123. if (!m_subcommands.is_empty()) {
  124. for (auto& redirection : m_subcommands.last().redirections) {
  125. if (redirection.type == Redirection::Pipe) {
  126. fprintf(stderr, "Syntax error: Nothing after last pipe (|)\n");
  127. return { };
  128. }
  129. }
  130. }
  131. return move(m_subcommands);
  132. }