2013-11-27 42 views
2

我正在嘗試編寫一個簡單的Perl調試器,並且遇到以下問題。'Goto undefined subroutine&main :: 1'編寫一個簡單的Perl調試器

我運行下面的代碼作爲調試器:

{ 
    package DB; 

    sub DB { } 

    sub sub 
    { 
    &$sub; 

    # this is what produces the problem 
    $i = 1*1; 
    } 
} 

1; 

我加載這通過設置PERL5DB環境變量 - 例如:

export PERL5DB="BEGIN { require './debugger/tracer.pl'; }

鑑於這種簡單的小Perl腳本:

#!/usr/bin/env perl 

use Getopt::Long; 

print "hello world"; 

我運行腳本:

perl -d test.pl

運行時,它會生成以下錯誤:

$ perl -d test.pl 
Goto undefined subroutine &main::1 at /home/vagrant/perl5/perlbrew/perls/perl-5.16.0/lib/site_perl/5.16.0/Exporter.pm line 25. 
BEGIN failed--compilation aborted at test.pl line 6. 

我已經分離出在& $子後運行問題什麼;在調試器中調用sub。這個問題發生在基本Perl腳本包含的特定軟件包中 - 在這種情況下,Getopt :: Long,儘管我也發現了IO :: File的相同結果。

我的Perl很生疏,尤其是像調試器這樣的高級主題。

任何人都可以幫助我理解如何在& $ sub;在調試器中調用sub以很好地放置我正在導入的包?

謝謝!

回答

6

當您不使用明確的return語句而離開Perl子程序時,Perl將返回子程序中最後一條語句的值。

特別地,這意味着,如果你有一個子程序調用另一子程序作爲其最後一條語句,像這樣:

package DB { 
    sub sub { 
     warn "Hello from DB::sub, about to call $sub\n"; 
     &$sub; 
    } 
} 

然後通過&$sub叫其他子程序的返回值傳遞給原始的調用者,就像你已經做了明確的return &$sub

但是,如果&$sub呼叫的最後一件事你DB::sub子程序,那麼Perl將剛剛扔掉它的返回值,而是在這種情況下$i = 1*1,其評估來回報您實際最後一條語句—值數字1

現在,當你define a custom debugger這樣,Perl將包裹普通子程序調用與您DB::sub子程序調用。因此,您的代碼會導致每個子程序調用返回數字1!這並不令人意外,這會很大程度上破壞很多非常的

具體來說,根據您的錯誤信息,它看起來像Exporter模塊(這是被許多其他模塊的符號導出到呼叫者的命名空間)的東西是調用一個子程序應該參考返回另一子程序。但是由於你的調試器,它實際上返回1,下面的嘗試調用返回的子例程試圖調用一個名爲1(它被映射到main::包,因爲numeric symbol names are superglobal),然後失敗的子例程。


但是,如果你真的需要做一些呼籲&$subDB::sub?好了,解決方法是保存返回值,就像這樣:

package DB { 
    sub DB { } 
    sub sub { 
     warn "Hello from DB::sub, about to call $sub...\n"; 

     # call &sub, save the return value in @rv 
     my @rv = (wantarray ? &$sub : scalar &$sub); 

     warn "Hello again from DB::sub, just called $sub and got @rv!\n"; 

     # ...and return the saved return value 
     return (wantarray ? @rv : $rv[0]); 
    } 
} 

1; 

(代碼是輕微的事實,我們DB::sub可能在任一列表或標量上下文中調用複雜,我們需要通過適當的上&$sub上下文。該wantarray應該注意的是,雖然)。

+0

哇,非常感謝你!你完全正確 - 似乎已經解決了這個問題。非常感謝!!我們很難探索Perl調試器的世界 - 除了調試器文檔和讀取Perl5調試器代碼本身之外,我們還沒有發現太多依賴。我們應該檢查的任何其他資源?真的很感謝幫助! – shedd

2

添加到從ILMARI Karonen答案。

DB :: sub也可以在無值(void)上下文中調用,因此返回處理需要考慮到這一點。有關更多詳細信息,請參閱wantarray中的文檔。

以下代碼處理所有三種情況。

package DB { 
    sub DB { } 
    sub sub { 

     # call &sub, save the return value in @rv 
     my @rv;   
     if(defined(wantarray)) { 
      @rv = (wantarray ? &$sub : scalar &$sub); 
     } 
     else { 
      # wantarray is undef 
      &$sub; 
     } 

     # after invoking &$sub 

     # return @rv 
     if(defined(wantarray)) { 
      return (wantarray ? @rv : $rv[0]); 
     } 
     else { 
      return undef 
     } 
    } 
} 

1; 
+0

謝謝!這真的很有幫助! – shedd