中缀 to 后缀 递归下降 Parser

写了一个 infix to postfix 的递归下降 parser,但感觉写得好长,也不知道怎么回事。

#include <algorithm>
#include <string_view>
#include <stdexcept>

class InfixToPostfixParser {
public:
  auto infix_to_postfix(std::string_view infix) -> std::string {
    m_lookahead = infix;
    parse_expr();
    return std::move(m_postfix);
  }

private:

  void parse_expr() {
    if (no_more_tokens()) { return; }
    parse_term();
    parse_expr_rest();
  }

  void parse_expr_rest() {
    char const token = current_token();
    if (successfully_consume_one_of("+-")) {
      parse_term();
      m_postfix.push_back(token);
      parse_expr_rest();
    }
  }

  void parse_term() {
    parse_factor();
    parse_term_rest();
  }

  void parse_term_rest() {
    char const token = current_token();
    if (successfully_consume_one_of("*/")) {
      parse_factor();
      m_postfix.push_back(token);
      parse_term_rest();
    }
  }

  void parse_factor() {
    parse_unit();
    if (successfully_consume('^')) {
      parse_factor();
      m_postfix.push_back('^');
    }
  }

  void parse_unit() {
    if (successfully_consume('(')) {
      parse_expr();
      consume(')');
    } else {
      char const token = current_token();
      consume_one_of("0123456789");
      m_postfix.push_back(token);
    }
  }

  bool successfully_consume(char const token) {
    if (token != current_token()) { return false; }
    to_next_token();
    return true;
  }

  bool successfully_consume_one_of(std::string_view tokens) {
    if (tokens.find(current_token()) == std::string_view::npos) { return false; }
    to_next_token();
    return true;
  }

  void consume(char const token) {
    if (token != current_token()) {
      throw std::invalid_argument("Syntax Error");
    }
    to_next_token();
  }

  void consume_one_of(std::string_view tokens) {
    if (tokens.find(current_token()) == std::string_view::npos) {
      throw std::invalid_argument("Syntax Error");
    }
    to_next_token();
  }

  void to_next_token() {
    m_lookahead.remove_prefix(1);
  }

  [[nodiscard]] char current_token() const {
    if (no_more_tokens()) { return '\0'; }
    return m_lookahead.front();
  }

  [[nodiscard]] bool no_more_tokens() const {
    return m_lookahead.empty();
  }

  std::string m_postfix;
  std::string_view m_lookahead;
};
posted @ 2020-09-01 18:09  seideun  阅读(187)  评论(0)    收藏  举报