     [ <ebnf-ignore> ] "~" syntax grouped ;
 
 : ignore-repeat0-parser ( -- parser )
-    [ <ebnf-ignore-repeat0> ] "*~" syntax grouped ;
+    [ <ebnf-repeat0> <ebnf-ignore> ] "*~" syntax grouped ;
 
 : ignore-repeat1-parser ( -- parser )
-    [ <ebnf-ignore-repeat1> ] "+~" syntax grouped ;
+    [ <ebnf-repeat1> <ebnf-ignore> ] "+~" syntax grouped ;
 
 : optional-parser ( -- parser )
     [ <ebnf-optional> ] "?" syntax grouped ;

                any-character-parser ,
            ] choice*
            [ dup , "~" token hide , ] seq* [ first <ebnf-ignore> ] action ,
            [ dup , "*~" token hide , ] seq* [ first <ebnf-ignore-repeat0> ] action ,
            [ dup , "+~" token hide , ] seq* [ first <ebnf-ignore-repeat1> ] action ,
            [ dup , "*" token hide , ] seq* [ first <ebnf-repeat0> ] action ,
            [ dup , "+" token hide , ] seq* [ first <ebnf-repeat1> ] action ,
            [ dup , "?[" token ensure-not , "?" token hide , ] seq* [ first <ebnf-optional> ] action ,

C: <ebnf-semantic> ebnf-semantic
C: <ebnf> ebnf

: filter-hidden ( seq -- seq )
    ! Remove elements that produce no AST from sequence
    [ ebnf-ensure-not? ] reject [ ebnf-ensure? ] reject
    [ ebnf-ignore? ] reject ;

: syntax ( string -- parser )
    ! Parses the string, ignoring white space, and
