[Tutor] perl to python?
Michael Powe
michael@trollope.org
Tue Dec 3 01:34:01 2002
well, the single thing that made perl most understandable to me was
reading larry wall's account that he designed perl to be like a
natural language. (he was a linguist before becoming a programmer.)
when you think of perl as a language like english or latin, some of
its peculiarities make a lot more sense (to me, anyway). that would
seem to me to introduce serious complexities in converting it to a
language like python, which is on the other side of the fence
altogether.
http://www.wall.org/~larry/natural.html
having completed my first successful, useful program in python, i must
say i think differently and approach problems differently in perl than
i do in python. some things can only be properly expressed in french,
trying to say them in english is useless. ;-)
"Deux Fous gagnent, mais jamais trois" -- A. Alekhine
mp
On Mon, Dec 02, 2002 at 07:23:24PM -0800, Danny Yoo wrote:
>
>
> [Note: the post I'm writing below is more about Perl than Python, and more
> about understanding Perl's parse trees than about writing a Python
> converter, so it's a bit off-topic.]
>
>
>
> On Mon, 2 Dec 2002, Lance wrote:
>
> > Is there a Perl to Python conversion program?
>
>
> Unfortunately, no, not yet.
>
>
> It should be technially possible to write a program to do this, but the
> code might end up looking even more miserable than the original Perl code.
>
>
> Still, I wonder how hard it would be to cook a toy example up.
>
>
>
> What makes such an automatic converter hard is that Perl's grammar doesn't
> appear to be really documented anywhere except in the Perl source code.
> We'd need a tool that generates a "parse tree" of Perl code; once we had a
> parse tree, we might have a good chance of writing a PerlToPython
> converter.
>
>
> In fact, it has been said that "Only Perl can parse Perl":
>
> http://www.everything2.com/index.pl?node=only%20Perl%20can%20parse%20Perl
>
>
> So such a converter would probably have to use Perl itself to generate the
> parse tree. Perl does provide a 'backend' module called B for this.
>
> http://www.perlpod.com/stable/perlcompile.html
>
>
>
> What does a "parse tree" look like? It's a low-level representation of
> the language. Here's an example of a such a "parse" of a simple
> 'hello.pl' program:
>
> ######
> [dyoo@tesuque dyoo]$ cat hello.pl
>
> print "Hello world\n";
>
> ###
>
>
>
> It's a simple little program. Here's its "parse tree":
>
> ###
> [dyoo@tesuque dyoo]$ perl -MO=Terse hello.pl
> LISTOP (0x81668b0) leave [1]
> OP (0x81668d8) enter
> COP (0x80fe8d8) nextstate
> LISTOP (0x8166868) print
> OP (0x8166890) pushmark
> SVOP (0x817bec8) const PV (0x80f6d88) "Hello world\n"
> test.pl syntax OK
> ######
>
>
> The capitalized letters on the left hand side are "opcodes" --- operation
> codes. If we visit this "tree" in a preorder traversal, we'll see that:
>
> 1. Perl calls "enter", whatever that means. I think it means that it
> will enter the program start.
>
> 2. It generates a nextstate, whatever that means.
>
> 3. It does a "pushmark" operation, whatever that is.
>
> 4. It puts the argument "hello world" on its stack. The 'SV' in SVOP
> stands for "scalar variable".
>
> 5. It calls the 'print' list operator.
>
> 6. Finally, it exits, with a return value of 1, I think.
>
>
>
> Here's a small Python program that's specifically designed to visit this
> particular tree. I know that it's incorrect and incomplete (I don't even
> understand the opcodes yet! *grin*), but it should give the flavor of
> what effort a PerlToPython converter might involve:
>
>
> ###
> """A small program to demonstrate what might be involved in parsing
> Perl into Python.
>
> Danny Yoo (dyoo@hkn.eecs.berkeley.edu)
> """
>
> parse_tree = ("LISTOP", "leave", 1,
> [("OP", "enter",
> [("COP", "nextstate",
> [("LISTOP", "print",
> [("OP", "pushmark", []),
> ("SVOP", "const PV", "Hello world\n", [])])])])])
>
> ## Some utility functions that we might need...
> def opcode(instruction):
> return instruction[0]
>
> def children(instruction):
> return instruction[-1]
>
> def operands(instruction):
> return instruction[1:-1]
>
>
> class PerlToPython:
> def __init__(self):
> self.stack = []
> self.lines = []
>
> def visit(self, instruction):
> op = opcode(instruction)
> dispatch_function = getattr(self, "visit_" + op)
> dispatch_function(instruction)
>
>
> def visit_LISTOP(self, instruction):
> for child in children(instruction):
> self.visit(child)
> args = operands(instruction)
> if args[0] == 'print':
> self.lines.append("print " + ','.join(self.stack))
> elif args[0] == 'leave':
> self.lines.append("raise SystemExit")
>
>
> def visit_OP(self, instruction):
> for child in children(instruction):
> self.visit(child)
> return ## fixme!
>
>
> def visit_COP(self, instruction):
> for child in children(instruction):
> self.visit(child)
> return ## fixme!
>
> def visit_SVOP(self, instruction):
> type, value = operands(instruction)
> if type == "const PV":
> self.stack.append("%s" % repr(value))
>
>
> if __name__ == '__main__':
> converter = PerlToPython()
> converter.visit(parse_tree)
> print '\n'.join(converter.lines)
> ###
>
>
>
> Here's an example of this in action:
>
> ###
> [dyoo@tesuque dyoo]$ python perl_into_python.py
> print 'Hello world\n'
> raise SystemExit
> ###
>
>
>
>
>
> Let's look at another Perl parse tree of a slightly more complicated
> program:
>
> ###
> [dyoo@tesuque dyoo]$ cat loops.pl
>
> for ($i = 0; $i < 10; $i++) {
> print "$i\n";
> }
>
>
> [dyoo@tesuque dyoo]$ perl -MO=Terse loops.pl
> LISTOP (0x80fa8c8) leave [1]
> OP (0x80fa928) enter
> COP (0x80fa8f0) nextstate
> BINOP (0x8166900) sassign
> SVOP (0x81668e0) const IV (0x80f6d88) 0
> UNOP (0x81668c0) null [15]
> SVOP (0x817bec8) gvsv GV (0x81025f0) *i
> BINOP (0x80fa8a0) leaveloop
> LOOP (0x80fa870) enterloop
> UNOP (0x8104820) null
> LOGOP (0x81047f8) and
> BINOP (0x8166988) lt
> UNOP (0x8166948) null [15]
> SVOP (0x8166928) gvsv GV (0x81025f0) *i
> SVOP (0x8166968) const IV (0x8102590) 10
> LISTOP (0x8104798) lineseq
> LISTOP (0x8104750) scope
> OP (0x8104718) null [174]
> LISTOP (0x8103fb8) print
> OP (0x8103fe0) pushmark
> UNOP (0x8103f90) null [67]
> OP (0x8184868) null [3]
> BINOP (0x8184840) concat [2]
> UNOP (0x8184720) null [15]
> SVOP (0x8184700) gvsv GV
> (0x81025f0) *i
> SVOP (0x8184740) const PV (0x8102614)
> "\n"
> UNOP (0x8184820) preinc [1]
> UNOP (0x8104928) null [15]
> SVOP (0x8104908) gvsv GV (0x81025f0) *i
> OP (0x8104778) unstack
> COP (0x81047c0) nextstate
> loops.pl syntax OK
> ###
>
>
> The complexity of this is a little bit deeper, but the idea is the same:
> we have to handle some of these new opcodes, like LOOP, and transform them
> into their Python equivalents. We may need to keep additional track of
> things like scope and nesting. Not a particularly "hard" task, but it
> might be a little complicated.
>
>
>
> Alternatively, it might also be possible to translate a Perl parse tree
> into a Python parse tree with the help of the 'compiler' module:
>
> http://www.python.org/doc/lib/compiler.html
>
> and then use a program called 'decompyle' to take that Python parse tree
> and reproduce human-readable text:
>
> http://www.crazy-compilers.com/decompyle/
>
>
> But somehow, I think this might take longer to write than I anticipated.
> Still, it is very possible to write this program. It might make a nice
> winter project. *grin*
>
>
>
> Good luck to you!
>
>
> _______________________________________________
> Tutor maillist - Tutor@python.org
> http://mail.python.org/mailman/listinfo/tutor