# this function is not recursive; it is called once # and returns with the subroutine calls it /would have/ # made had it be implicitly recursive sub get_sub (param1,...,paramN) # shift params, which are are assumed to data stucts refs initialize @retsubs = () if terminating condition FALSE # create/modify params used in recursive call initialize new _param1 to some value; ... initialize _paramN to some value; loop to get set of next subs for next level of recursion push "sub {return get_sub(_param1,...,paramN);})" onto @retsubs; end loop endif return {substack=>@retsubs,retval1=>'somevalue'}; end get_sub # initialize call stack with first set of subs to call my @callstack = array of subs returned by get_sub(param1,...,paramN); # now execute the call stack until it's been exhausted while(@callstack) { pop next $sub off of @callstack; execute sub ref, $x = $sub->(); push subs returned by get_sub(param1,...,paramN) onto @callstack; end while #### ... return sub { my $arg1 = shift; my $arg2 = shift; ... ;}; ... #### my @subrefs = (); # loop, push sub refs onto @subrefs push (@subrefs,sub { ... }); # end loop ... return { subref => @subrefs, val1 => 1, val2 => 'abc' }; ... #### # make call my $caller = get_sub(...); # extract subrefs from the returned hash ref my @subrefs = @{$caller->{subrefs}}; # push returned subs onto call stack push(@callstack,@subrefs); #### #!/usr/bin/env perl use strict; use warnings; use FLAT::DFA; use FLAT::NFA; use FLAT::PFA; use FLAT::Regex::WithExtraOps; my $PRE = "abc&(def)*"; my $dfa = FLAT::Regex::WithExtraOps->new($PRE)->as_pfa->as_nfa->as_dfa->as_min_dfa->trim_sinks; my $next = $dfa->new_acyclic_string_generator; print "PRE: $PRE\n"; print "Acyclic:\n"; while (my $string = $next->()) { print " $string\n"; } $next = $dfa->new_deepdft_string_generator(); print "Deep DFT (default):\n"; for (1..10) { while (my $string = $next->()) { print " $string\n"; last; } } $next = $dfa->new_deepdft_string_generator(5); print "Deep DFT (5):\n"; for (1..10) { while (my $string = $next->()) { print " $string\n"; last; } } #### PRE: abc&(def)* Acyclic: deabfc deabcf dabcef dabefc dabecf daebfc daebcf abc adbcef adbefc adbecf adebfc adebcf Deep DFT (default): deabfdcef deabfc deabcf deafbdcef deafbdecf deafbc deafdbcef deafdbefc deafdbecf dabcef Deep DFT (5): defdefdefdefdeabfdcef defdefdefdefdeabfdcefdef defdefdefdefdeabfdcefdefdef defdefdefdefdeabfdcefdefdefdef defdefdefdefdeabfdcefdefdefdefdef defdefdefdefdeabfdefdcef defdefdefdefdeabfdefdcefdef defdefdefdefdeabfdefdcefdefdef defdefdefdefdeabfdefdcefdefdefdef defdefdefdefdeabfdefdcefdefdefdefdef #### sub get_acyclic_sub { my $self = shift; my ($start,$nodelist_ref,$dflabel_ref,$string_ref,$accepting_ref,$lastDFLabel) = @_; my @ret = (); foreach my $adjacent (keys(%{$nodelist_ref->{$start}})) { $lastDFLabel++; if (!exists($dflabel_ref->{$adjacent})) { $dflabel_ref->{$adjacent} = $lastDFLabel; foreach my $symbol (@{$nodelist_ref->{$start}{$adjacent}}) { push(@{$string_ref},$symbol); my $string_clone = dclone($string_ref); my $dflabel_clone = dclone($dflabel_ref); push(@ret,sub { return $self->get_acyclic_sub($adjacent,$nodelist_ref,$dflabel_clone,$string_clone,$accepting_ref,$lastDFLabel); }); pop @{$string_ref}; } } } return {substack=>[@ret], lastDFLabel=>$lastDFLabel, string => ($self->array_is_subset([$start],[@{$accepting_ref}]) ? join('',@{$string_ref}) : undef)}; } sub init_acyclic_iterator { my $self = shift; my %dflabel = (); my @string = (); my $lastDFLabel = 0; my %nodelist = $self->as_node_list(); my @accepting = $self->get_accepting(); # initialize my @substack = (); my $r = $self->get_acyclic_sub($self->get_starting(),\%nodelist,\%dflabel,\@string,\@accepting,$lastDFLabel); push(@substack,@{$r->{substack}}); return sub { while (1) { if (!@substack) { return undef; } my $s = pop @substack; my $r = $s->(); push(@substack,@{$r->{substack}}); if ($r->{string}) { return $r->{string}; } } } } sub new_acyclic_string_generator { my $self = shift; return $self->init_acyclic_iterator(); }