#!/usr/bin/perl -w # parse Python files; print out class's and def's use strict; use Parse::RecDescent; #use GraphViz::Parse::RecDescent; $::RD_HINT = 1; #$::RD_TRACE = 1; sub slurp { local $/; return <>; } sub slurpFile { my $name = shift; local $/; open F, "<$name" or die "unable to open file $name"; $_ = ; close F; return $_; } my $parser = Parse::RecDescent->new(q{ pyfile: (import|class|def|comment|other)(s) | import: 'from' package 'import' imports { print "from $item[2] import " . (ref($item[4]) ? join(" ", @{$item[4]}) : $item[4]) . "\n"; } |'import' imports { print "import $item[2]\n"; } class: 'class' id '(' param(s? /,/) ')' ':' { print "class $item[2](" . join(", ", @{$item[4]}) . ")\n"; } |'class' id ':' { print "class $item[2]\n"; } def: /^/ /\s*/ 'def' id '(' param(s? /,/) ')' ':' { print "$item[3]def $item[6](" . join(", ", @{$item[8]}) . ")\n"; } comment: /^\s*#.*/ other: /.*/ package: dottedId {$item[1]} | id {$item[1]} imports: id 'as' id { "$item[1] as $item[3]" } |id(s /\s+/) { join(" ", @{$item[1]}) } |'*' param: '(' param(s /,/) ')' { "(" . join(", ", @{$item[2]}) . ")" } |defaultParam |dottedId |id defaultParam: id '=' dottedId { "$item[1]=$item[3]" } dottedId: /[A-Za-z0-9_.]+/ id: /[*]?[A-Za-z0-9_]+/ }); if ( $ARGV[0] ) { $parser->pyfile(slurpFile($ARGV[0])); } else { $parser->pyfile(slurp()); } #my $graph = GraphViz::Parse::RecDescent->new($parser, rankdir=>1); #print $graph->as_png;