The grammar you defined contains only 2 different entities: Terminals (a character) or an Optional part of the grammar.
In the Haskell code below, this is reflected by the definition of the discriminated union Grammar.
The first task is to convert a given concrete syntax (e.g. "A[B]") into a list of Grammar parts (each terminal or optional). In the code below, the function fromString does just that.
The interesting part, though is how to generate all possible strings for a given syntax.
In the code below, the function generate does this, recursively.
For an empty grammar list (which is the end of the recursion), the output is a single empty string.
If a terminal symbol is found in the grammar list at a given position, the respective character is pasted in front of all variations, generated from the remainder of the grammar list.
If an optional part is found in the grammar list, the list of the remainder of the grammar list is yielded twice; once with the optional part prepended and once without.
For the non-functional people reading this, it should be pointed out that fmap is a function which maps a list to another list (element wise).
The other function I used in the code below, non-haskellers might stumble over is concat, which turns a list of lists into a list.
data Grammar = Terminal Char | Optional [Grammar] deriving (Show,Eq)
fromString :: String -> [Grammar] -> ([Grammar],String)
fromString [] acc = (acc,"")
fromString ('[':cs) acc =
let (o,rest) = fromString cs [] in
fromString rest (acc ++ [Optional o])
fromString (']':cs) acc = (acc,cs)
fromString (c:cs) acc = fromString cs (acc ++ [Terminal c])
generate :: [Grammar] -> [String]
generate [] = [""]
generate ((Terminal c) : parts) = fmap (\s -> c : s) $ generate parts
generate ((Optional gs) : parts) = tails ++ (concat . fmap prependOpts $ tails)
where
tails = generate parts
opts = generate gs
prependOpts :: String -> [String]
prependOpts tail = fmap (\o -> o ++ tail) $ opts
Putting it all together in the REPL (interactive shell), running
fromString "A[B][C]" [], for example yields:
([Terminal 'A',Optional [Terminal 'B'],Optional [Terminal 'C']],"")
And if we run generate on the grammar list above (the first part of the tuple), we get all our strings:
generate (fst $ fromString "A[B][C]" [])
["A","AC","AB","ABC"]