# To build this: # perl -MParse::RecDescent - javap.grammar Java::Javap::Grammar { my %methods; my $constructors; } comp_unit : comp_stmt comp_unit_decl '{' body '}' { my $retval = $item{ comp_unit_decl }; $retval->{ compiled_from } = "$item{ comp_stmt }.java"; $retval->{ contents } = $item{ body }; $retval->{ methods } = \%methods; $retval->{ constructors } = $constructors; $retval; } | comp_stmt : 'Compiled from "' NAME '.java"' { $item{NAME} } comp_unit_decl : ACCESS class_qualifier(s?) CLASS_OR_INTERFACE qualified_name extends_clause(?) implements_clause(?) { my $perl_qualified_name = $item{ qualified_name }; $perl_qualified_name =~ s/\./::/g; { access => $item{ ACCESS }, qualifiers => $item{ 'class_qualifier(s?)' }, class_or_interface => $item{ CLASS_OR_INTERFACE }, implements => $item{ 'implements_clause(?)' }[0], parent => $item{ 'extends_clause(?)' }[0], java_qualified_name => $item{ qualified_name }, perl_qualified_name => $perl_qualified_name, } } class_qualifier : 'final' { 'final' } | 'abstract' { 'status' } extends_clause : 'extends' qualified_name { $item{ qualified_name } } implements_clause : 'implements' comma_list { $item{ comma_list } } body : body_element(s?) { $item[1] } body_element : constant { $item[1] } | 'static' '{' '}' ';' { { body_element => 'static_block' } } | method { $item[1] } | variable { $item[1] } constant : ACCESS 'static' constant_modifier(s?) arg NAME ';' { { body_element => 'constant', access => $item{ ACCESS }, modifiers => $item{ 'constant_modifier(s?)' }, type => $item{ arg }[0], name => $item{ NAME }, } } | 'static' 'transient' arg NAME ';' { { body_element => 'transient_constant', type => $item{ arg }[0], name => $item{ NAME }, } } constant_modifier : 'final' | 'transient' | 'volatile' method : ACCESS method_qualifier(s?) arg NAME '(' arg_list(?) ')' throws_clause(?) ';' { $methods{ $item[4] }++; my $args = $item{ 'arg_list(?)' }[0]; $args = [] unless defined $args; { body_element => 'method', access => $item[1], attrs => $item[2], returns => $item[3][0], name => $item[4], args => $args, throws => $item{ 'throws_clause(?)' }, } } | ACCESS /(native)?/ qualified_name '(' arg_list(?) ')' throws_clause(?) ';' { $constructors++; my $args = $item{ 'arg_list(?)' }[0]; $args = [] unless defined $args; { body_element => 'constructor', access => $item[1], native => ( $item[2] eq 'native' ) ? 'native' : '', args => $args, throws => $item{ 'throws_clause(?)' }, } } method_qualifier : 'abstract' { 'abstract' } | 'native' { 'native' } | 'static' { 'static' } | 'synchronized' { 'synchronized' } | 'final' { 'final' } throws_clause : 'throws' comma_list { $item{comma_list} } variable : ACCESS var_modifier(s?) arg NAME ';' { { body_element => 'variable', access => $item{ ACCESS }, name => $item{ NAME }, type => $item{ arg }[0], } } var_modifier : 'volatile' | 'final' | 'transient' qualified_name : NAME '.' qualified_name { "$item{NAME}.$item{qualified_name}" } | NAME '.' NAME { "$item[1].$item[3]" } | NAME { $item[1] } comma_list : qualified_name ',' comma_list { my @names = ( $item[1] ); if ( ref( $item[3] ) eq 'ARRAY' ) { push @names, @{ $item[3] }; } else { push @names, $item[3]; } \@names; } | qualified_name ',' qualified_name { [ $item[1], $item[3] ] } | qualified_name { $item[1] } arg_list : arg ',' arg_list { [ @{ $item[1] }, @{ $item[3] } ] } | arg ',' arg { [ @{ $item[1] }, @{ $item[3] } ] } | arg { $item[1] } arg : qualified_name array_depth { my $array_text = ''; foreach my $i ( 1 .. $item[2] ) { $array_text .= 'Array of '; } [ { name => $item[1], array_depth => $item[2], array_text => $array_text, } ] } array_depth : ARRAY_LEVEL(s?) { my $depth = scalar @{ $item[1] }; $depth; } ARRAY_LEVEL : '[]' { 1 } NAME : /^([\w\d\$]+)/ { $1 } ACCESS : 'public' { $item[1] } | 'protected' { $item[1] } | 'private' { $item[1] } | { '' } CLASS_OR_INTERFACE : 'class' { $item[1] } | 'interface' { $item[1] } comment : '/*' /[^*]*/ '*/' {} |