def indentedBlock(blockStatementExpr, indentStack, indent=True):
def checkPeerIndent(s,l,t):<EOL><INDENT>if l >= len(s): return<EOL>curCol = col(l,s)<EOL>if curCol != indentStack[-<NUM_LIT:1>]:<EOL><INDENT>if curCol > indentStack[-<NUM_LIT:1>]:<EOL><INDENT>raise ParseFatalException(s,l,"<STR_LIT>")<EOL><DEDENT>raise ParseException(s,l,"<STR_LIT>")<EOL><DEDENT><DEDENT>def checkSubIndent(s,l,t):<EOL><INDENT>curCol = col(l,s)<EOL>if curCol > indentStack[-<NUM_LIT:1>]:<EOL><INDENT>indentStack.append( curCol )<EOL><DEDENT>else:<EOL><INDENT>raise ParseException(s,l,"<STR_LIT>")<EOL><DEDENT><DEDENT>def checkUnindent(s,l,t):<EOL><INDENT>if l >= len(s): return<EOL>curCol = col(l,s)<EOL>if not(indentStack and curCol < indentStack[-<NUM_LIT:1>] and curCol <= indentStack[-<NUM_LIT:2>]):<EOL><INDENT>raise ParseException(s,l,"<STR_LIT>")<EOL><DEDENT>indentStack.pop()<EOL><DEDENT>NL = OneOrMore(LineEnd().setWhitespaceChars("<STR_LIT>").suppress())<EOL>INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('<STR_LIT>')<EOL>PEER   = Empty().setParseAction(checkPeerIndent).setName('<STR_LIT>')<EOL>UNDENT = Empty().setParseAction(checkUnindent).setName('<STR_LIT>')<EOL>if indent:<EOL><INDENT>smExpr = Group( Optional(NL) +<EOL>INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)<EOL><DEDENT>else:<EOL><INDENT>smExpr = Group( Optional(NL) +<EOL>(OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )<EOL><DEDENT>blockStatementExpr.ignore(_bslash + LineEnd())<EOL>return smExpr.setName('<STR_LIT>')<EOL>
Helper method for defining space-delimited indentation blocks,
    such as those used to define block statements in Python source code.

    Parameters:

     - blockStatementExpr - expression defining syntax of statement that
       is repeated within the indented block
     - indentStack - list created by caller to manage indentation stack
       (multiple statementWithIndentedBlock expressions within a single
       grammar should share a common indentStack)
     - indent - boolean indicating whether block must be indented beyond
       the the current level; set to False for block of left-most
       statements (default= ``True``)

    A valid block must contain at least one ``blockStatement``.

    Example::

        data = '''
        def A(z):
          A1
          B = 100
          G = A2
          A2
          A3
        B
        def BB(a,b,c):
          BB1
          def BBA():
            bba1
            bba2
            bba3
        C
        D
        def spam(x,y):
             def eggs(z):
                 pass
        '''


        indentStack = [1]
        stmt = Forward()

        identifier = Word(alphas, alphanums)
        funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":")
        func_body = indentedBlock(stmt, indentStack)
        funcDef = Group( funcDecl + func_body )

        rvalue = Forward()
        funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")")
        rvalue << (funcCall | identifier | Word(nums))
        assignment = Group(identifier + "=" + rvalue)
        stmt << ( funcDef | assignment | identifier )

        module_body = OneOrMore(stmt)

        parseTree = module_body.parseString(data)
        parseTree.pprint()

    prints::

        [['def',
          'A',
          ['(', 'z', ')'],
          ':',
          [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]],
         'B',
         ['def',
          'BB',
          ['(', 'a', 'b', 'c', ')'],
          ':',
          [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]],
         'C',
         'D',
         ['def',
          'spam',
          ['(', 'x', 'y', ')'],
          ':',
          [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]]