I would like to parse a file with the following syntax (but with an indefinite number of nesting) with Python:
<XProtocol>
{
    <str1."fds"> "str2"
    <str3> 123.0
    <str4> { 1 2 3 4 5 6 6 "str" "str" 43 "str" 4543 }
    <weird1."str5">
    {
        <weird2."str6"> { "str" }
        <also."weird3"> 1
        <againweird> { 1 "fds" }
        { }
        <even> <more."weird4"> { } { } { } { "a" }
    }
}
The desidered output would be something like:
'XProtocol':
{
    'str1."fds"': 'str2',
    'str3': 123.0,
    'str4': (1, 2, 3, 4, 5, 6, 6, 'str', 'str', 43, 'str', 4543),
    'weird1."str5"':
    {
        'weird2."str6"': ( 'str' ),
        'also."weird3"': 1,
        'againweird': ((1, 'fds'), None),
        'even': { 'more."weird4"': (None, None, None, 'a') },
    }
}  
I have unsuccessfully tried using the following code:
import pyparsing as pp
def parse_x_prot(text):        
    lbra = pp.Literal('{').suppress()
    rbra = pp.Literal('}').suppress()
    lang = pp.Literal('<').suppress()
    rang = pp.Literal('>').suppress()
    dot = pp.Literal('.').suppress()
    cstr = pp.quotedString.addParseAction(pp.removeQuotes)
    tag = pp.Group(
        lang +
        pp.Word(pp.alphanums) +
        pp.Optional(pp.Group(dot + cstr)) +
        rang)
    val = pp.OneOrMore(
        cstr | pp.Word(pp.nums + '.')
    )
    exp = pp.Forward()
    exp << pp.OneOrMore(
        pp.Group(
            tag + pp.OneOrMore(
                (lbra + (val | exp) + rbra) |
                (val + exp)
            )
        )
    )
    return exp.parseString(text)
I must be doing something wrong, but haven't yet figured out exactly what... just to be more precise: the following code tells me it expects a '}' instead of a new 'tag'.
A couple of things:
In your definition of tag, you wrap it in a Group, but I think you really want to use Combine.
The second thing, your nesting in exp mixes up the repetition with the recursion.
This works for me (also, take of the .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))
Giving:
['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']
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With