A few days ago I wrote my first BNF grammar after already having a parser which implemented it. One section specifies how one can search between two values:
between_value ::= 'BETWEEN' '[' value ',' value ']' | 'BETWEEN' '[' value '=>' value ']' | '[' value ',' value ']' | '[' value '=>' value ']'
That's more or less equivalent to the following regex:
/(?:BETWEEN)?\s*\[\s*$value\s*(?:,|=>)\s*$value\s*\]/
The HOP parser, of course, can handle this, but it doesn't handle it as gracefully as I would like, so I extended it.
concatenate( absorb( optional( match( KEYWORD => 'BETWEEN' ) ) ), absorb($lbracket), $Value, absorb($either_comma), $Value, absorb($rbracket), ),
match() is the new name of the old &_ function. absorb() means "match this but throw away the value." optional() means "0 or 1 of the following value."
All things told, this makes things much easier to read and allows us to skip many of the annoying transformations that were required to get rid of of unwanted values.
Couldn't you make another description for the operator, e.g.
op
::= ','|'=>'
and rewrite that as
between_value
::= 'BETWEEN' '[' value op value ']'
| '[' value op value ']'
?
Or if you were using EBNF,
between_value
::= ['BETWEEN'] '[' value op value ']'