pegtl - how to skip spaces for the entire grammar












2















I am trying to parse a very simple language with PEGTL. I think I have found the problem, but don't understand why; white spaces are not ignored. I understand it must be possible to not ignore white space so that indentation-aware languages can also be parsed. But I couldn't find a mechanism to "eat" white spaces by default. Given:



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


the following cannot be parsed:



enum thing;


If I add pegtl::space between each token explicitly, then it works. But it would be major burden to do it in the entire grammar.



How can white spaces be ignored/eaten/skipped, like in C, without specifying those explicitly?










share|improve this question



























    2















    I am trying to parse a very simple language with PEGTL. I think I have found the problem, but don't understand why; white spaces are not ignored. I understand it must be possible to not ignore white space so that indentation-aware languages can also be parsed. But I couldn't find a mechanism to "eat" white spaces by default. Given:



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


    the following cannot be parsed:



    enum thing;


    If I add pegtl::space between each token explicitly, then it works. But it would be major burden to do it in the entire grammar.



    How can white spaces be ignored/eaten/skipped, like in C, without specifying those explicitly?










    share|improve this question

























      2












      2








      2








      I am trying to parse a very simple language with PEGTL. I think I have found the problem, but don't understand why; white spaces are not ignored. I understand it must be possible to not ignore white space so that indentation-aware languages can also be parsed. But I couldn't find a mechanism to "eat" white spaces by default. Given:



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


      the following cannot be parsed:



      enum thing;


      If I add pegtl::space between each token explicitly, then it works. But it would be major burden to do it in the entire grammar.



      How can white spaces be ignored/eaten/skipped, like in C, without specifying those explicitly?










      share|improve this question














      I am trying to parse a very simple language with PEGTL. I think I have found the problem, but don't understand why; white spaces are not ignored. I understand it must be possible to not ignore white space so that indentation-aware languages can also be parsed. But I couldn't find a mechanism to "eat" white spaces by default. Given:



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


      the following cannot be parsed:



      enum thing;


      If I add pegtl::space between each token explicitly, then it works. But it would be major burden to do it in the entire grammar.



      How can white spaces be ignored/eaten/skipped, like in C, without specifying those explicitly?







      c++ parsing






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 22 '18 at 9:22









      user1150609user1150609

      457




      457
























          1 Answer
          1






          active

          oldest

          votes


















          3














          I don't think there is a shortcut, you have to specify the grammar in a way that makes it unambiguous where and how many whitespaces you allow.



          The best way to do it I think is to add a convenience rule template that allows matching a list (tao::pegtl::seq) of rules separated by any allowed separater (generally whitespace plus comments).



          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<';'>>


          Basically, doing something like the above, you only need to replace tao::pegtl::seq<R...> with interleaved<seps, R...>, but you could even make a separate alias for that:



          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<';'>> {};


          This strategy is mostly needed not because of whitespace-significant languages but because you don't have an earlier tokenizer step in the parsing that would separate the enum from the thing. Another strategy would be to implement that first, and do the later-stage parsing based on a stream of tokens instead of a stream of characters, but that is a larger rewrite and has its own drawbacks.




          Note: I haven't compiled the code, but the point here should be the strategy. Please leave a comment if there is a compile error (I hope I haven't messed up the variadic templates) or if something is unclear.



          Note 2: Also you probably don't want to replace every seq with sseq. For example, if you have the logical and (&&) defined as seq<one<'&'>, one<'&'>>, that's something you probably don't want to change.







          share|improve this answer
























          • I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

            – user1150609
            Nov 22 '18 at 13:37











          • That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

            – palotasb
            Nov 22 '18 at 13:50











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427551%2fpegtl-how-to-skip-spaces-for-the-entire-grammar%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          3














          I don't think there is a shortcut, you have to specify the grammar in a way that makes it unambiguous where and how many whitespaces you allow.



          The best way to do it I think is to add a convenience rule template that allows matching a list (tao::pegtl::seq) of rules separated by any allowed separater (generally whitespace plus comments).



          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<';'>>


          Basically, doing something like the above, you only need to replace tao::pegtl::seq<R...> with interleaved<seps, R...>, but you could even make a separate alias for that:



          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<';'>> {};


          This strategy is mostly needed not because of whitespace-significant languages but because you don't have an earlier tokenizer step in the parsing that would separate the enum from the thing. Another strategy would be to implement that first, and do the later-stage parsing based on a stream of tokens instead of a stream of characters, but that is a larger rewrite and has its own drawbacks.




          Note: I haven't compiled the code, but the point here should be the strategy. Please leave a comment if there is a compile error (I hope I haven't messed up the variadic templates) or if something is unclear.



          Note 2: Also you probably don't want to replace every seq with sseq. For example, if you have the logical and (&&) defined as seq<one<'&'>, one<'&'>>, that's something you probably don't want to change.







          share|improve this answer
























          • I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

            – user1150609
            Nov 22 '18 at 13:37











          • That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

            – palotasb
            Nov 22 '18 at 13:50
















          3














          I don't think there is a shortcut, you have to specify the grammar in a way that makes it unambiguous where and how many whitespaces you allow.



          The best way to do it I think is to add a convenience rule template that allows matching a list (tao::pegtl::seq) of rules separated by any allowed separater (generally whitespace plus comments).



          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<';'>>


          Basically, doing something like the above, you only need to replace tao::pegtl::seq<R...> with interleaved<seps, R...>, but you could even make a separate alias for that:



          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<';'>> {};


          This strategy is mostly needed not because of whitespace-significant languages but because you don't have an earlier tokenizer step in the parsing that would separate the enum from the thing. Another strategy would be to implement that first, and do the later-stage parsing based on a stream of tokens instead of a stream of characters, but that is a larger rewrite and has its own drawbacks.




          Note: I haven't compiled the code, but the point here should be the strategy. Please leave a comment if there is a compile error (I hope I haven't messed up the variadic templates) or if something is unclear.



          Note 2: Also you probably don't want to replace every seq with sseq. For example, if you have the logical and (&&) defined as seq<one<'&'>, one<'&'>>, that's something you probably don't want to change.







          share|improve this answer
























          • I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

            – user1150609
            Nov 22 '18 at 13:37











          • That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

            – palotasb
            Nov 22 '18 at 13:50














          3












          3








          3







          I don't think there is a shortcut, you have to specify the grammar in a way that makes it unambiguous where and how many whitespaces you allow.



          The best way to do it I think is to add a convenience rule template that allows matching a list (tao::pegtl::seq) of rules separated by any allowed separater (generally whitespace plus comments).



          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<';'>>


          Basically, doing something like the above, you only need to replace tao::pegtl::seq<R...> with interleaved<seps, R...>, but you could even make a separate alias for that:



          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<';'>> {};


          This strategy is mostly needed not because of whitespace-significant languages but because you don't have an earlier tokenizer step in the parsing that would separate the enum from the thing. Another strategy would be to implement that first, and do the later-stage parsing based on a stream of tokens instead of a stream of characters, but that is a larger rewrite and has its own drawbacks.




          Note: I haven't compiled the code, but the point here should be the strategy. Please leave a comment if there is a compile error (I hope I haven't messed up the variadic templates) or if something is unclear.



          Note 2: Also you probably don't want to replace every seq with sseq. For example, if you have the logical and (&&) defined as seq<one<'&'>, one<'&'>>, that's something you probably don't want to change.







          share|improve this answer













          I don't think there is a shortcut, you have to specify the grammar in a way that makes it unambiguous where and how many whitespaces you allow.



          The best way to do it I think is to add a convenience rule template that allows matching a list (tao::pegtl::seq) of rules separated by any allowed separater (generally whitespace plus comments).



          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<';'>>


          Basically, doing something like the above, you only need to replace tao::pegtl::seq<R...> with interleaved<seps, R...>, but you could even make a separate alias for that:



          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<';'>> {};


          This strategy is mostly needed not because of whitespace-significant languages but because you don't have an earlier tokenizer step in the parsing that would separate the enum from the thing. Another strategy would be to implement that first, and do the later-stage parsing based on a stream of tokens instead of a stream of characters, but that is a larger rewrite and has its own drawbacks.




          Note: I haven't compiled the code, but the point here should be the strategy. Please leave a comment if there is a compile error (I hope I haven't messed up the variadic templates) or if something is unclear.



          Note 2: Also you probably don't want to replace every seq with sseq. For example, if you have the logical and (&&) defined as seq<one<'&'>, one<'&'>>, that's something you probably don't want to change.








          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 22 '18 at 12:04









          palotasbpalotasb

          2,37111420




          2,37111420













          • I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

            – user1150609
            Nov 22 '18 at 13:37











          • That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

            – palotasb
            Nov 22 '18 at 13:50



















          • I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

            – user1150609
            Nov 22 '18 at 13:37











          • That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

            – palotasb
            Nov 22 '18 at 13:50

















          I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

          – user1150609
          Nov 22 '18 at 13:37





          I thought about an approach, though couldn't express it correctly or my idea wouldn't work to begin with; make a class template that surrounds given rule (as template argument) with star<space>. I'll try your idea, and see how it works. Thanks!

          – user1150609
          Nov 22 '18 at 13:37













          That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

          – palotasb
          Nov 22 '18 at 13:50





          That's pegtl::pad<Rule, SepL, SepR> but you probably don't want that because you have to replace each element of every seq instead of just the seqs.

          – palotasb
          Nov 22 '18 at 13:50


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53427551%2fpegtl-how-to-skip-spaces-for-the-entire-grammar%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          Refactoring coordinates for Minecraft Pi buildings written in Python