2.2 Parsing sequences
Using or/p, it is possible to choose between alternatives when parsing, but what if a particular grammar permits any number of elements in sequence? For that, you can use the many/p combinator. It accepts a parser and attempts to parse it over and over again until it fails. For example, here is a parser that parses any number of occurrences of the letter a:
> (parse-string (many/p (char/p #\a)) "") (success '())
> (parse-string (many/p (char/p #\a)) "a") (success '(#\a))
> (parse-string (many/p (char/p #\a)) "aaaa") (success '(#\a #\a #\a #\a))
This allows creating grammars that parse arbitrary numbers of values. The many/p combinator accepts an optional keyword argument #:min to specify a minimum number of values to parse. This can be used to parse two integers separated by some amount of whitespace, for example.
> (define two-integers/p (do [x <- integer/p] (many/p space/p #:min 1) [y <- integer/p] (pure (list x y)))) > (parse-string two-integers/p "13 102") (success '(13 102))
Perhaps even more frequently, though, you may want to parse some number of values separated by some delimiter. For example, perhaps you want to parse a whole list of integers separated by commas. That can be accomplished by passing a parser for the #:sep argument to many/p.
> (define many-integers/p (many/p integer/p #:sep (char/p #\,))) > (parse-string many-integers/p "1,2,3,5,8,13") (success '(1 2 3 5 8 13))
Often an unbounded number of values is undesirable: some limit is desired. The #:max argument to many/p allows specifying a max number of values to parse. For example, we may not wish to allow more than five comma-separated integers.
> (define at-most-five-integers/p (many/p integer/p #:sep (char/p #\,) #:max 5)) > (parse-string at-most-five-integers/p "1,2,3") (success '(1 2 3))
> (parse-string at-most-five-integers/p "1,2,3,5,8,13") (success '(1 2 3 5 8))