How to get results from pyparsing Forward object?
<p>Let us assume we have the following string</p>

<pre><code>string = """
object obj1{
    attr1 value1;


    object obj2 {
        attr2 value2;
    }
}

object obj3{
    attr3 value3;
    attr4 value4;
}

"""
</code></pre>

<p>There is a nested object, and we use Forward to parse this. </p>

<pre><code>from pyparsing import *
word = Word(alphanums)

attribute = word.setResultsName("name")
value = word.setResultsName("value")

object_grammar = Forward()

attributes = attribute + value + Suppress(";") + LineEnd().suppress()
object_type = Suppress("object ") + word.setResultsName("object_type") + Suppress('{') + LineEnd().suppress()

object_grammar &lt;&lt;= object_type+\
    OneOrMore(attributes|object_grammar) + Suppress("}") | Suppress("};")

for i, (obj, _, _) in enumerate(object_grammar.scanString(string)):
    print('\n')
    print('Enumerating over object {}'.format(i))
    print('\n')
    print('This is the object type {}'.format(obj.object_type))
    print(obj.asXML())
    print(obj.asDict())
    print(obj.asList())
    print(obj)
    print(obj.dump())
</code></pre>

<p>These are the results. The obj.asXML() function contains all the information, however since it has been flattened, the order of the information is essential to parsing the result. Is this the best way to do it? I must be missing something. I would like a solution that works for both nested and not nested objects, i.e. for obj1, obj2 and obj3.</p>

<p>Also, <code>setResultsName('object_type')</code> doesn't return the <code>object_type</code> for the parent object. The output of the program above is shown below. Any suggestions?</p>

<pre><code>Enumerating over object 0

This is the object type obj2

&lt;ITEM&gt;
  &lt;object_type&gt;obj1&lt;/object_type&gt;
  &lt;name&gt;attr1&lt;/name&gt;
  &lt;value&gt;value1&lt;/value&gt;
  &lt;object_type&gt;obj2&lt;/object_type&gt;
  &lt;name&gt;attr2&lt;/name&gt;
  &lt;value&gt;value2&lt;/value&gt;
&lt;/ITEM&gt;
{'object_type': 'obj2', 'name': 'attr2', 'value': 'value2'}
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
- name: attr2
- object_type: obj2
- value: value2


Enumerating over object 1


This is the object type obj3

&lt;ITEM&gt;
  &lt;object_type&gt;obj3&lt;/object_type&gt;
  &lt;name&gt;attr3&lt;/name&gt;
  &lt;value&gt;value3&lt;/value&gt;
  &lt;name&gt;attr4&lt;/name&gt;
  &lt;value&gt;value4&lt;/value&gt;
&lt;/ITEM&gt;
{'object_type': 'obj3', 'name': 'attr4', 'value': 'value4'}
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
- name: attr4
- object_type: obj3
- value: value4
</code></pre>

<p>While you have successfully processed your input string, let me suggest some refinements to your grammar.</p>

<p>When defining a recursive grammar, one usually wants to maintain some structure in the output results. In your case, the logical piece to structure is the content of each object, which is surrounded by opening and closing braces. Conceptually:</p>

<pre><code>object_content = '{' + ZeroOrMore(attribute_defn | object_defn) + '}'
</code></pre>

<p>Then the supporting expressions are just (still conceptually):</p>

<pre><code>attribute_defn = identifier + attribute_value + ';'
object_defn = 'object' + identifier + object_content
</code></pre>

<p>The actual Python/pyparsing for this looks like:</p>

<pre><code>LBRACE,RBRACE,SEMI = map(Suppress, "{};")

word = Word(alphas, alphanums)
attribute = word

# expand to include other values if desired, such as ints, reals, strings, etc.
attribute_value = word 
attributeDefn = Group(word("name") + value("value") + SEMI)

OBJECT = Keyword("object")
object_header = OBJECT + word("object_name")
object_grammar = Forward()
object_body = Group(LBRACE 
                    + ZeroOrMore(object_grammar | attributeDefn)
                    + RBRACE)
object_grammar &lt;&lt;= Group(object_header + object_body("object_content"))
</code></pre>

<p><code>Group</code> does two things for us: it structures the results into sub-objects; and it keeps the results names at one level from stepping on those at a different level (so no need for <code>listAllMatches</code>).</p>

<p>Now instead of <code>scanString</code>, you can just process your input using <code>OneOrMore</code>:</p>

<pre><code>print(OneOrMore(object_grammar).parseString(string).dump())
</code></pre>

<p>Giving:</p>

<pre><code>[['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]], ['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]]
[0]:
  ['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]]
  - object_content: [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]
    [0]:
      ['attr1', 'value1']
      - name: attr1
      - value: value1
    [1]:
      ['object', 'obj2', [['attr2', 'value2']]]
      - object_content: [['attr2', 'value2']]
        [0]:
          ['attr2', 'value2']
          - name: attr2
          - value: value2
      - object_name: obj2
  - object_name: obj1
[1]:
  ['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]
  - object_content: [['attr3', 'value3'], ['attr4', 'value4']]
    [0]:
      ['attr3', 'value3']
      - name: attr3
      - value: value3
    [1]:
      ['attr4', 'value4']
      - name: attr4
      - value: value4
  - object_name: obj3
</code></pre>

<p>I started to just make simple changes to your code, but there was a fatal flaw in your original. Your parser separated the left and right braces into two separate expressions - while this "works", it defeats the ability to define the group structure of the results. </p>

python pyparsing