The language you describe is neither regular nor contextual. Therefore, you need to resort to the Prolog extensions offered by DCG. There are some idioms you can get used to:
% any sequence seq([]) --> []. seq([E|Es]) --> [E], seq(Es).
Using this nonterminal, we can describe a sequence that is repeated and shared by a single character:
rep(Seq, Sep) --> seq(Seq), [Sep], seq(Seq).
This is clearly too general. You only need ab and c . Now you can add additional requirements:
rep(Seq, Sep) --> seq(Seq), {phrase(abs,Seq)}, [Sep], seq(Seq). abs --> [] | ("a"|"b"), abs.
So now:
s --> rep(_,c).
An alternative is the "hard code" of the grammar, as @CapelliC showed. Using seq//1 makes the approach more flexible.
Itโs convenient enough to use double quotes for a list of characters. See this answer on how to enable the use of double quotes to represent a list of characters.
false source share