pegtl - как пропустить пробелы для всей грамматики - PullRequest
0 голосов
/ 22 ноября 2018

Я пытаюсь разобрать очень простой язык с PEGTL.Я думаю, что нашел проблему, но не понимаю почему;пробелы не игнорируются.Я понимаю, что должна быть возможность не игнорировать пробелы, чтобы можно было анализировать языки, поддерживающие отступы.Но я не смог найти механизм для «поедания» пробелов по умолчаниюДано:

struct kw_enum : tao::pegtl::string<'e', 'n', 'u', 'm'> { };
struct enum_decl : tao::pegtl::seq<kw_enum, tao::pegtl::identifier, tao::pegtl::one<';'>> { };

следующее не может быть проанализировано:

enum thing;

Если я добавлю pegtl::space между каждым токеном явно, то это работает.Но было бы тяжело делать это во всей грамматике.

Как можно игнорировать / съедать / пропускать пробелы, как в C, без указания их явно?

1 Ответ

0 голосов
/ 22 ноября 2018

Я не думаю, что есть ярлык, вы должны указать грамматику таким образом, чтобы было однозначно, где и сколько пробелов вы допускаете.

Лучший способ сделать это, я думаю, этодобавьте удобный шаблон правил, который позволяет сопоставлять список (tao::pegtl::seq) правил, разделенных любым разрешенным разделителем (обычно пробел плюс комментарии).

struct comment : tao::pegtl::disable< /* whatever your comment syntax is */ > {};
struct separator : tao::pegtl::sor< tao::pegtl::ascii::space, comment > {}; // either/or
struct seps : tao::pegtl::star< separator > {}; // Any separators, whitespace or comments

// Template to generate rule
// tao::pegtl::seq<Rule0, Separator, Rule1, Separator, Rule2, ... , Separator, RuleN>
template <typename Separator, typename... Rules>
struct interleaved;

template <typename Separator, typename Rule0, typename... RulesRest>
struct interleaved<Separator, Rule0, RulesRest...>
  : tao::pegtl::seq<Rule0, Separator, interleaved<Separator, RulesRest...>> {};

template <typename Separator, typename Rule0>
struct interleaved<Separator, Rule0>
  : Rule0 {};

// Note: interleaved<Separator /*, no Rule! */> intentionally not defined.

struct enum_decl : interleaved<seps, kw_enum, tao::pegtl::identifier, tao::pegtl::one<';'> {};
// Expands to:
seq<kw_enum, seps, interleaved<seps, identifier, one<';'>>> ==
seq<kw_enum, seps, seq<identifier, seps, interleaved<seps, one<';'>>>> ==
seq<kw_enum, seps, seq<identifier, seps, one<';'>> ==
seq<kw_enum, seps, identifier, seps, one<';'>>

По существу, выполняется что-то вродевыше, вам нужно всего лишь заменить tao::pegtl::seq<R...> на interleaved<seps, R...>, но вы можете даже создать отдельный псевдоним для этого:

template<typename... Rules>
using sseq = interleaved<seps, Rules...>;

// Now you only have to replace tao::pegtl::seq with sseq
struct enum_decl : sseq<kw_enum, tao::pegtl::identifier, tao::pegtl::one<';'>> {};

Эта стратегия в основном нужна не из-за значимых пробелов языков, а потому, что вынет более раннего шага токенизатора при разборе, который бы отделял enum от thing.Другая стратегия заключалась бы в том, чтобы реализовать это вначале и выполнить последующий анализ на основе потока токенов вместо потока символов, но это большая перезапись и имеет свои недостатки.

Примечание: я не скомпилировал код, но суть здесь должна быть в стратегии.Пожалуйста, оставьте комментарий, если есть ошибка компиляции (я надеюсь, что я не испортил вариационные шаблоны) или если что-то неясно.

Примечание 2. Также вы, вероятно, не хотите заменять каждый seq с sseq.Например, если у вас есть логические и (&&), определенные как seq<one<'&'>, one<'&'>>, это то, что вы, вероятно, не хотите менять.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...