The basic problem is that the first alternative does match -- it just doesn't match what you want it to. As written, your parser matches a sequence of 3 thing, with the middle one being a repeated pattern having an alternative in it.
'[' // single char match
>> *(~ascii::char_("-]^") | (ascii::char_ >> '-' >>ascii::char_)) // complex pattern
>> ']' // single char match
So lets look at what happens when you try to match [a-c]
. First, you match the pattern '['
, which succeeds and leaves a-c]
. So then it looks at the complex pattern, which it tries to match 0 or more times. With in that *
repeat, it first tries ~ascii::char_("-]^")
, which matches a
, so success leaving -c]
. It then repeats, trying to match that pattern again, which fails (-
doesn't match), so it tries the second alternative where ascii::char
matches -
, but '-'
does not match c
, so it fails. So the end of the *
match it has matched the single character a
. Finally, it tries to match ']'
which fails against the -
, so the overall match fails.
Reading the above (if you can make sense of it) should make it clear what you need to do -- you need it to try the range match BEFORE it tries the single char match within the *
loop:
'[' >> *((ascii::char_ >> '-' >>ascii::char_) | ~ascii::char_("-]^")) >> ']'
Now it should match both [abc]
and [a-c]
, as well as things like [a-cmx-z]
.