use strict; sub state { my $c=shift; my $next=shift; my $alt=shift; my $visited=0; return {c => $c, next => $next, alt => $alt, visited => $visited}; } sub NFA { my $in=shift; my $out=shift; return {in => $in, out => $out}; } sub sym { my $c=shift; my $s=state($c, 0, 0); return NFA($s, $s); } sub dot { my $nfa1=shift; my $nfa2=shift; $nfa1->{out}{next}=$nfa2->{in}; return NFA($nfa1->{in}, $nfa2->{out}); } sub bar { my $nfa1=shift; my $nfa2=shift; my $s=state(256, $nfa1->{in}, $nfa2->{in}); my $t=state(256, 0, 0); $nfa1->{out}{next}=$nfa2->{out}{next}=$t; return NFA($s, $t); } sub que { my $nfa=shift; my $t=state(256, 0, 0); my $s=state(256, $nfa->{in}, $t); $nfa->{out}{next}=$t; return NFA($s, $t); } sub star { my $nfa=shift; my $s=state(256, 0, $nfa->{in}); $nfa->{out}{next}=$s; return NFA($s, $s); } sub plus { my $nfa=shift; my $s=state(256, 0, $nfa->{in}); $nfa->{out}{next}=$s; return NFA($nfa->{in}, $s); } sub accepted { my $nfa=shift; my $s=state(257, 0, 0); $nfa->{out}{next}=$s; return NFA($nfa->{in}, $s); } sub __reachable { my $s=shift; #state my $list=shift; #array of states, passed by reference if (!$s || $s->{visited}) { return; } push(@{$list},$s); $s->{visisted}=1; if ($s->{c} eq 256) { __reachable($s->{next}, $list); __reachable($s->{alt}, $list); } } sub reachable { my $list=shift; #array of states, passed by reference my $v=[]; #reference to another list foreach my $s(@{$list}) { if ($s) { __reachable($s, $v); } } foreach my $s(@{$v}) { $s->{visisted}=0; } return $v; } sub runNFA { my $nfa=shift; #NFA my $text=shift; #string my @a=split(//, $text); #string to array my $list1=[]; my $list2=[]; #array references push(@{$list1}, $nfa->{in}); $list1=reachable($list1); foreach my $c(@a) { foreach my $s(@{$list1}) { if ($s->{c} eq $c || $s->{c} eq '!') { push(@{$list2}, $s->{next}); if ($s->{alt}) { push(@{$list2}, $s->{alt}); } } } $list1=reachable($list2); #new list $list2=[]; #empty } foreach my $s(@{$list1}) { if ($s->{c} eq 257) { return 1; } } return 0; } my $nfa=accepted( dot( sym('a'), dot( star( dot( sym('b'), sym('b') ) ), sym('a') ) ) ); print runNFA($nfa, "aa");