Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 跨嵌套子例程保留本地上下文 我们考虑下面的通缉代码。我对进程进行递归调用,对于每个递归,我使用本地%上下文。这样,当我从电话中返回时,我就可以恢复上下文 sub process { my %context; # Local context process() if rerun(); job1(); job2(); sub job1() {print $context{foo}} sub job2() {print $context{bar}} }_Perl - Fatal编程技术网

Perl 跨嵌套子例程保留本地上下文 我们考虑下面的通缉代码。我对进程进行递归调用,对于每个递归,我使用本地%上下文。这样,当我从电话中返回时,我就可以恢复上下文 sub process { my %context; # Local context process() if rerun(); job1(); job2(); sub job1() {print $context{foo}} sub job2() {print $context{bar}} }

Perl 跨嵌套子例程保留本地上下文 我们考虑下面的通缉代码。我对进程进行递归调用,对于每个递归,我使用本地%上下文。这样,当我从电话中返回时,我就可以恢复上下文 sub process { my %context; # Local context process() if rerun(); job1(); job2(); sub job1() {print $context{foo}} sub job2() {print $context{bar}} },perl,Perl,不幸的是,它没有像我预期的那样管理嵌套的子例程。通过将子例程从进程子例程移出,我将遇到问题,因为我将无法再访问%context。因此,我需要使其全局化,并使用如下堆栈: my %context; # Local context my @context_stack; sub process { push @context_stack, %context; %context = undef; process() if rerun(); job1()

不幸的是,它没有像我预期的那样管理嵌套的子例程。通过将子例程从进程子例程移出,我将遇到问题,因为我将无法再访问
%context
。因此,我需要使其全局化,并使用如下堆栈:

my %context;        # Local context
my @context_stack;

sub process {
    push @context_stack, %context;
    %context = undef;

    process() if rerun();

    job1();
    job2();

    %context = pop @context_stack;
}

sub job1() {print $context{foo}}
sub job2() {print $context{bar}}
第三种解决方案是将上下文传递给所有子例程,这对于非常小的子例程来说可能很烦人。此外,
%context
对我的所有程序来说都是全局的。所以我失去了这个变量的隐私

my %context;        # Local context
my @context_stack;

sub process {
    push @context_stack, %context;
    %context = undef;

    process() if rerun(\%context);

    job1(\%context);
    job2(\%context);

    %context = pop @context_stack;
}

sub job1() {$context = shift; print $context->{foo}}
sub job2() {$context = shift; print $context->{bar}}
最好的方法是什么

编辑

为了更好地了解我的具体情况,我提供了另一个示例:

process(@ARGV);
exit 0;

sub process {
    my $infile = shift;
    my $outfile = shift;

    open my $fp_in,  '<', $infile;
    open my $fp_out, '>', $outfile;

    LINE: while(<$fp_in>) { 
        remove_c_comment(); 

        say STDERR "File is $infile";

        process($1, "$1.processed") if /#include "(.*?)";
        warning("Huh raisin, no!") if /\braisin/;

        say STDERR "Fill is still $infile";

        print $fp_out $_;
    }

    sub remove_c_comment { s|//.*$|| }
    sub warning { say "[Warning] $infile:$. ".shift() }
}
进程(@ARGV);
出口0;
子过程{
我的$infle=shift;
我的$outfile=shift;
在、、$outfile中打开我的$fp_;
行:while(){
删除_c_comment();
说STDERR“文件是$infle”;
处理($1,“$1.已处理”)如果/#包括“(.*)”;
警告(“啊,葡萄干,不!”)如果/\brasin/;
说STDERR“Fill仍然是$infle”;
打印$fp\u out$;
}
子移除|c|u注释{s |/.$| |}
子警告{say“[warning]$infle:$.”.shift()}
}

你正在寻找的东西——但你可能不知道——被称为a。(另见:)

上下文在此块中保持私有,但所有子例程都可以访问

或者,您可以从子例程返回代码引用,如下所示:

use strict;
use warnings;

sub make_sub_with_context {
    my %context;
    $context{"bar"} = 1;
    return sub { print $context{"bar"}++ };
}

my $job1_with_context = make_sub_with_context();
my $another_job_with_context = make_sub_with_context();
$job1_with_context->();
$job1_with_context->();

$another_job_with_context->();
$another_job_with_context->();
$another_job_with_context->();
这可能是一个更好的例子

编辑:

根据更新后的示例,您的问题规范似乎是迭代一组文件,并(递归地)遍历引用的文件

有点像
find
,但遵循
include
指令。我想指出的是,通过这样做,你所做的可能会以一个循环结束,这是不理想的

我可以建议采取不同的方法吗?不要重复:

use strict;
use warnings;

my @files_to_process = @ARGV;
my %done;

while ( my $infile = pop @files_to_process ) {
    next if $done{$infile}++;
    open my $fp_in, '<', $infile or die $!;
    open my $fp_out, '>', $infile . ".processed" or die $!;
    while ( my $line = <$fp_in> ) {
        $line =~ s|\/\/.*$||;
        if ( my ($include) = ( $line =~ m/#include "(.*?)"/ ) ) {
            push @files_to_process, $include;
        }
        print {$fp_out} $line;
    }
    close($fp_out);
    close($fp_in);
}
使用严格;
使用警告;
我的@files\u to\u进程=@ARGV;
我的%完成了;
while(my$infle=pop@files\u to\u进程){
下一步如果$done{$infle}++;
在“,$infle.”中打开我的$fp_。已处理“或死亡$!;
while(我的$line=){
$line=~s |\/\/.$|;
如果(我的($include)=($line=~m/#include“(.*)/){
将@files\u推送到\u进程,$include;
}
打印{$fp_out}$行;
}
关闭(fp_out);
关闭(fp_in);
}
再多想一想,这个任务需要按照声明顺序进行扩展——我会提供——也许采用面向对象的方法会有所帮助。比如:

use strict;
use warnings;

package parser;

sub new {
    my ($class) = @_;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub process {
    my ( $self, $infile, $outfile ) = @_;
    open my $fp_in,  '<', $infile;
    open my $fp_out, '>', $outfile;

LINE: while ( my $line = <$fp_in> ) {
        $line =~ s|\/\/.*$||;

        say STDERR "File is $infile";

        if ( my ($includefile) = ( $line =~ m/#include "(.*?)"/ ) ) {
            my $processor = parser->new();
               $processor -> process( $includefile, "$includefile.processed" );
        }
        $self->warning("Huh raisin, no!") if /\braisin/;

        say STDERR "Fill is still $infile";

        print $fp_out $line;
    }
}

package main;

my $processor = parser->new()->process(@ARGV);
使用严格;
使用警告;
包解析器;
次新{
我的($class)=@;
我的$self={};
祝福$self,$class;
返回$self;
}
子过程{
我的($self,$infle,$outfile)=@;
在、、$outfile中打开我的$fp_;
行:while(我的$LINE=){
$line=~s |\/\/.$|;
说STDERR“文件是$infle”;
如果(my($includefile)=($line=~m/#include“(.*)/){
my$processor=parser->new();
$processor->process($includefile,$includefile.processed”);
}
$self->warning(“啊,葡萄干,不!”)如果/\brasin/;
说STDERR“Fill仍然是$infle”;
打印$fp_out$行;
}
}
主包装;
我的$processor=parser->new()->进程(@ARGV);

只需将这些变量括在另一对大括号中,
{my%context;sub process{..}sub job1{..}
或创建一个单独的类/包。听起来您所要的是全局变量+
局部变量。请参阅:IOW,使
%context
成为全局变量,并在
子流程中使用
local%context=which
。这并不能解决问题<代码>%context
如果要避免使用堆栈,则仍然需要是
进程的本地。但是,闭包可以很好地将与
进程
相关的所有函数与程序的其余部分隔离开来。我想我遗漏了一些东西-您能否在您的说明中包括您使用
%context
的目的是什么?因为我的下一个思路是创建一个生成匿名sub的
子例程工厂。(即使没有,由于所使用资源的性质,它实际上也没有那么高效)。答案更新。很好的方法,但我不能这样做。我必须按照文件中出现的内容来处理包含。例如,如果我在一个包含的文件中定义FOO 42,我必须在我的主文件中看到这个声明。我可能仍然建议使用相同的方法,但采用两次通过的方法,但请耐心等待,我会看看是否能想出更好的方法。我假设“按照第一次看到的顺序列出所有定义语句”是一个合理的目标,对吗?
use strict;
use warnings;

package parser;

sub new {
    my ($class) = @_;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub process {
    my ( $self, $infile, $outfile ) = @_;
    open my $fp_in,  '<', $infile;
    open my $fp_out, '>', $outfile;

LINE: while ( my $line = <$fp_in> ) {
        $line =~ s|\/\/.*$||;

        say STDERR "File is $infile";

        if ( my ($includefile) = ( $line =~ m/#include "(.*?)"/ ) ) {
            my $processor = parser->new();
               $processor -> process( $includefile, "$includefile.processed" );
        }
        $self->warning("Huh raisin, no!") if /\braisin/;

        say STDERR "Fill is still $infile";

        print $fp_out $line;
    }
}

package main;

my $processor = parser->new()->process(@ARGV);