Условное потребление символа в лексере, написанном на C ++ - PullRequest
0 голосов
/ 07 февраля 2020

Я пишу лексер для небольшой грамматики, и я нахожусь в точке, где мне нужно уменьшить количество дублируемого кода, который я пишу, поэтому внутри моего лексера я написал следующую функцию шаблона:

class Lexer
{
private:
  std::optional<char> consume_if(Error err)
  {
    err_ = err;
    return std::nullopt;
  }

  template <typename UnaryPredicate, typename ...Others>
  std::optional<char> consume_if(Error err, UnaryPredicate p, Others... others)
  {
    if (eof())
    {
      return std::nullopt;
    }

    return p(peek()) == 0 ? consume_if(err, others...) : consume();
  }

  std::optional<std::string> parse_foo();  // see below

  // I omitted functions I considered obvious. If needed, they can be added.
};

Теперь, текущее использование правила foo (где foo = ALPHA *(ALPHA / DIGIT / "+" / "-" / ".") должно быть (но, очевидно, проблематично c):

std::optional<std::string> Lexer::parse_foo()
{
  static auto is_valid_punct = [](char c) { return c == '+' || c == '-' || c == '.'; };

  std::string foo = consume_if(Err::INVALID_FOO, std::isalpha);  // takes unsigned char, so this will be a problem

  std::optional<char> c;
  do
  {
    c = consume_if(Err::INVALID_FOO, std::isalpha, std::isdigit, is_valid_punct);
    foo.push_back(*c);  // but what do I do if c is nullopt?
  } while (c);

  return foo;
}

Теперь я знаю, что могу сделать эту работу с правильным if с, но тогда это нарушит цель consume_if.

Могу ли я написать шаблонную функцию c consume_if? Нужны ли мне макросы вместо этого? Есть ли лучший подход ко всему этому, пожалуйста?

...