The language you are describing is neither regular nor context free. So you need to resort to the Prolog extensions that are offered in DCGs. There are some idioms you might get used to:
% any sequence
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
With this non-terminal, we might describe a sequence that is repeated and separated by one character:
rep(Seq, Sep) -->
seq(Seq),
[Sep],
seq(Seq).
That is clearly too general. You only wanted ab
and c
. You may now add further requirements:
rep(Seq, Sep) -->
seq(Seq),
{phrase(abs,Seq)},
[Sep],
seq(Seq).
abs --> [] | ("a"|"b"), abs.
So now:
s -->
rep(_,c).
The alternative is to "hard code" the grammar, as @CapelliC has shown. Using seq//1
makes the approach a bit more flexible.
It is quite convenient to use double quotes for list of characters.
See this answer how to permit to use double-quotes to represent a list of chars.