   ] map peek ;
 
 DEFER: 'rhs'
+
+: syntax ( string -- parser )
+  #! Parses the string, ignoring white space, and
+  #! does not put the result in the AST.
+  token sp hide ;
 
 : 'identifier' ( -- parser )
   #! Return a parser that parses an identifer delimited by


: 'group' ( -- parser )
  [
    "(" token sp hide ,
    [ 'choice' sp ] delay ,
    ")" token sp hide  ,
  ] seq* [ first ] action ;

: 'repeat0' ( -- parser )
  [
    "{" token sp hide ,
    [ 'choice' sp ] delay ,
    "}" token sp hide  ,
  ] seq* [ first <ebnf-repeat0> ] action ;

: 'optional' ( -- parser )
  [
    "[" token sp hide ,
    [ 'choice' sp ] delay ,
    "]" token sp hide  ,
  ] seq* [ first <ebnf-optional> ] action ;

: 'sequence' ( -- parser )

: 'rule' ( -- parser )
  [
    'non-terminal' [ ebnf-non-terminal-symbol ] action  ,
    "=" syntax  ,
    'rhs'  ,
  ] seq* [ first2 <ebnf-rule> ] action ;

: 'ebnf' ( -- parser )
  'rule' sp "." syntax list-of [ <ebnf> ] action ;

: ebnf>quot ( string -- quot )
  'ebnf' parse [
