# We define this subroutine anonymously and store it in a lexical # scalar to avoid it getting found by itself. my $find_globs; $find_globs = sub { my ($pkg) = @_; my @vars; no strict 'refs'; my @globs = values %$pkg; # The symbol table is made available through a hash. That hash is # the package's name plus two colons. The values in the symbol # table are typeglobs. Typeglobs are holders of the values used # when you access a global variable, like $foo. That accesses # the *foo typeglob's scalar value. Typeglobs are prefixed with # a "*", as you can see. foreach my $glob (values %$pkg) { my $name = *$glob{NAME}; # Each glob also saves its name, next to the variable-data. if ($name =~ /::\z/) { # As you might recall, a symbol table is made available # through a hash which ends in "::". This hash also lives in # a typeglob, and is thus stored in the symbol table. # (Actually, I'm kind of cheating here. There could be # other datatypes defined here than the hash, and perhaps # the hash isn't even defined. The program won't break # if there are; it just won't return non-hashes that end # with "::".) push @vars => $find_globs->("$pkg$name") unless $name eq 'main::'; # From the main package all packages can be reached, even # main itself. That means *main::main:: points to main. You # see where this is leading us: nowhere. So don't follow # any mains. } else { my @types = ( defined $$glob ? '$' : (), defined @$glob ? '@' : (), defined %$glob ? '%' : (), defined &$glob ? '&' : (), ); # Here we see which data types are defined. push @vars => map $_ . *$glob{PACKAGE} . "::$name", @types; # Not only does it save the name, it also saves the package # it lives in. } } return @vars; }; use Data::Dumper; # Just to get extra packages. :) # Here you might want to do() your program file. print "$_\n" for $find_globs->('main::');