A few things:
In your tag definition, you wrap it in Group , but I think you really want to use Combine .
Secondly, your investment in exp mixes repetition with recursion.
This works for me (also, take .suppress() on dot ):
tag = pp.Combine( lang + pp.Word(pp.alphas, pp.alphanums) + pp.Optional(dot + cstr) + rang).setName("tag") exp = pp.Forward() key_value = pp.Group(tag + exp) number = pp.Regex(r'[+-]?\d+(\.\d*)?').setName("number") exp <<= (number | cstr | key_value | pp.Group(lbra + pp.ZeroOrMore(exp) + rbra))
Donation:
['XProtocol', [['str1.fds', 'str2'], ['str3', '123.0'], ... [0]: XProtocol [1]: [['str1.fds', 'str2'], ['str3', '123.0'], ['str4', ['1', '2', '3',... [0]: ['str1.fds', 'str2'] [1]: ['str3', '123.0'] [2]: ['str4', ['1', '2', '3', '4', '5', '6', '6', 'str', 'str', '43', ... [0]: str4 [1]: ['1', '2', '3', '4', '5', '6', '6', 'str', 'str', '43', ... [3]: ['weird1.str5', [['weird2.str6', ['str']], ['also.weird3', ... [0]: weird1.str5 [1]: [['weird2.str6', ['str']], ['also.weird3', '1'], ['againweird', ... [0]: ['weird2.str6', ['str']] [0]: weird2.str6 [1]: ['str'] [1]: ['also.weird3', '1'] [2]: ['againweird', ['1', 'fds']] [0]: againweird [1]: ['1', 'fds'] [3]: [] [4]: ['even', ['more.weird4', []]] [0]: even [1]: ['more.weird4', []] [0]: more.weird4 [1]: [] [5]: [] [6]: [] [7]: ['a']