quiz about symbolic manipulation

Bengt Richter bokr at oz.net
Tue Dec 17 08:52:02 EST 2002


On Mon, 16 Dec 2002 14:24:59 GMT, Michael Hudson <mwh at python.net> wrote:

>bokr at oz.net (Bengt Richter) writes:
>
>> Well, for a toy problem, parsing according to python grammar is probably
>> overkill. I.e.,
>> 
>> 'square(square(x+y)+z)+square(x+w)'
>> 
>> becomes
>> 
>> ['eval_input',
>>  ['testlist',
>>   ['test',
>>    ['and_test',
>>     ['not_test',
>>      ['comparison',
>>       ['expr',
>>        ['xor_expr',
>[... and on and on and on ...]
>
>Bengt probably knows this, but you can use the compiler package to
>make this very much pleasanter...
>
Christmas is here early ;-)

>>>> compiler.transformer.parse('square(square(x+y)+z)+square(x+w)')
>Module(None, Stmt([Discard(Add((CallFunc(Name('square'),
>[Add((CallFunc(Name('square'), [Add((Name('x'), Name('y')))], None,
>None), Name('z')))], None, None), CallFunc(Name('square'),
>[Add((Name('x'), Name('w')))], None, None))))]))
>>>> _.node.nodes[0].expr
>Add((CallFunc(Name('square'), [Add((CallFunc(Name('square'),
>[Add((Name('x'), Name('y')))], None, None), Name('z')))], None, None),
>CallFunc(Name('square'), [Add((Name('x'), Name('w')))], None, None)))
>
>Hmm, well the fact that pprint.pprint doesn't know how to deal with
>these thigns doesn't help, but these really are nicer to work with :)
>
How about this as relatively simple prettyprinting for this kind of output?
[ 5:49] C:\pywk\clp>ppcomp.py -h

Usage:  python ppcomp.py [-i | -h | -f filename | expression ]
        (nothing specified reads stdin, -i prompts, -h prints this, else the obvious)


[ 5:49] C:\pywk\clp>ppcomp.py square(square(x+y)+z)+square(x+w)
Module(
  None,
  Stmt(
    [
      Discard(
        Add(
          (
            CallFunc(
            | Name(
            | | 'square'),
            | [
            | | Add(
            | |   (
            | |     CallFunc(
            | |     | Name(
            | |     | | 'square'),
            | |     | [
            | |     | | Add(
            | |     | |   (
            | |     | |     Name(
            | |     | |     | 'x'),
            | |     | |     Name(
            | |     | |       'y')))],
            | |     | None,
            | |     | None),
            | |     Name(
            | |       'z')))],
            | None,
            | None),
            CallFunc(
              Name(
              | 'square'),
              [
              | Add(
              |   (
              |     Name(
              |     | 'x'),
              |     Name(
              |       'w')))],
              None,
              None))))]))

[ 5:50] C:\pywk\clp>ppcomp.py -i
Enter expression (or just press Enter to quit):
Expr> a,b,c = 1,2,3
Module(
  None,
  Stmt(
    [
      Assign(
        [
        | AssTuple(
        |   [
        |     AssName(
        |     | 'a',
        |     | 'OP_ASSIGN'),
        |     AssName(
        |     | 'b',
        |     | 'OP_ASSIGN'),
        |     AssName(
        |       'c',
        |       'OP_ASSIGN')])],
        Tuple(
          [
            Const(
            | 1),
            Const(
            | 2),
            Const(
              3)]))]))


(not very tested, but not too bad?  ;-)
====< ppcomp.py >====================================================
# ppcomp.py
# pretty print some compiler output -- bokr at oz.net 2002-12-17
import compiler, re, sys
rxb = re.compile(r'([\[\](),])')
IND = '  '
def ppcomp(s):
    out = []; wrout = out.append # sys.stdout.write
    sp = [s.strip() for s in rxb.split(`compiler.transformer.parse(s)`)]
    nest = 0
    for t in sp:
        if not t: continue
        if t in ['(','[']:
            wrout(t)
            nest += 1
            wrout('\n'); wrout(IND*nest)
        elif t in [')',']']:
            wrout(t)
            nest -= 1
        else:
            wrout(t)
            if t == ',': wrout('\n'); wrout(IND*nest)
    # make vertical connecting lines
    out = ''.join(out).splitlines()
    nl = len(out)
    linewd=[]
    for y in range(nl):
        linewd.append(len(out[y])-len(out[y].lstrip()))
    lastwd = 0
    for y in range(nl):
        w = linewd[y];
        if w>=lastwd:
            lastwd=w; continue
        # draw line upwards if spaces above when indent decreases
        ydraw = y-1
        while ydraw>=0 and w<linewd[ydraw] and out[ydraw][w]==' ':
            s = out[ydraw]
            out[ydraw] = s[:w] + '|' + s[w+1:]
            ydraw -= 1
    return '\n'.join(out)

if __name__ == '__main__':
    import sys
    s=''
    if len(sys.argv)<2:
        print 'Enter Python source and end with ^Z'
        s = sys.stdin.read()
    elif sys.argv[1]=='-f' and len(sys.argv)>2:
        f = file(sys.argv[2])
        s = f.read()
        f.close()
    elif sys.argv[1]=='-i':
        s='anything'
        print 'Enter expression (or just press Enter to quit):'
        while s:
            s = raw_input('Expr> ').rstrip()
            if s: print ppcomp(s)
    elif sys.argv[1]=='-h':
        print """
Usage:  python ppcomp.py [-i | -h | -f filename | expression ]
        (nothing specified reads stdin, -i prompts, -h prints this, else the obvious)
"""
    else:
        s = sys.argv[1]
    if s: print ppcomp(s)
=====================================================================

Regards,
Bengt Richter



More information about the Python-list mailing list