Stack Exchange
preserving text structure information - pyparsing
Using pyparsing, is there a way to extract the context you are in during recursive descent. Let me explain what I mean. I have the following code:
import pyparsing as pp

openBrace = pp.Suppress(pp.Literal("{"))
closeBrace = pp.Suppress(pp.Literal("}"))
ident = pp.Word(pp.alphanums + "_" + ".")
comment = pp.Literal("//") + pp.restOfLine
messageName = ident
messageKw = pp.Suppress(pp.Keyword("msg"))
text = pp.Word(pp.alphanums + "_" + "." + "-" + "+")
otherText = ~messageKw + pp.Suppress(text)
messageExpr = pp.Forward()
messageExpr << (messageKw + messageName + openBrace +
                pp.ZeroOrMore(otherText) + pp.ZeroOrMore(messageExpr) +
                pp.ZeroOrMore(otherText) + closeBrace).ignore(comment)
testStr = "msg msgName1 { some text msg msgName2 { some text } some text }"
print messageExpr.parseString(testStr)

which produces this output: ['msgName1', 'msgName2']
In the output, I would like to keep track of the structure of embedded matches. What I mean is that, for example, I would like the following output with the test string above: ['msgName1', 'msgName1.msgName2'] to keep track of the hierarchy in the text. However, I am new to pyparsing and have yet to find a way yet to extract the fact that "msgName2" is embedded in the structure of "msgName1."
Is there a way to use the setParseAction() method of ParserElement to do this, or maybe using naming of results?
Helpful advice would be appreciated. 

Attach a parse action to messageName to push the name onto an external stack, and attach a parse action to closeBrace to pop that last name off the stack. In the first parse action, after pushing the current name onto the stack, you can replace the name in the input tokens with tokens[0] = '.'.join(stack)

Thanks to Paul McGuire for his sagely advice. Here are the additions/changes I made, which solved the problem:
msgNameStack = []

def pushMsgName(str, loc, tokens):
    msgNameStack.append(tokens[0])
    tokens[0] = '.'.join(msgNameStack)

def popMsgName(str, loc, tokens):
    msgNameStack.pop()

closeBrace = pp.Suppress(pp.Literal("}")).setParseAction(popMsgName)
messageName = ident.setParseAction(pushMsgName)

And here is the complete code:
import pyparsing as pp

msgNameStack = []


def pushMsgName(str, loc, tokens):
    msgNameStack.append(tokens[0])
    tokens[0] = '.'.join(msgNameStack)


def popMsgName(str, loc, tokens):
    msgNameStack.pop()

openBrace = pp.Suppress(pp.Literal("{"))
closeBrace = pp.Suppress(pp.Literal("}")).setParseAction(popMsgName)
ident = pp.Word(pp.alphanums + "_" + ".")
comment = pp.Literal("//") + pp.restOfLine
messageName = ident.setParseAction(pushMsgName)
messageKw = pp.Suppress(pp.Keyword("msg"))
text = pp.Word(pp.alphanums + "_" + "." + "-" + "+")
otherText = ~messageKw + pp.Suppress(text)
messageExpr = pp.Forward()
messageExpr << (messageKw + messageName + openBrace +
                pp.ZeroOrMore(otherText) + pp.ZeroOrMore(messageExpr) +
                pp.ZeroOrMore(otherText) + closeBrace).ignore(comment)

testStr = "msg msgName1 { some text msg msgName2 { some text } some text }"
print messageExpr.parseString(testStr)

