#!/usr/local/bin/perl -w
use strict ;
my (%state, %tape, $current_state, $the_line) ;
my ($tape_pointer, $pos, $program_file, $tape) = (0, 0, @ARGV, '') ;

$tape=~ s/^_+// ;                           ## Remove leading _ from tape
map($tape{$pos++}=$_ , split(//, $tape)) ;  ## Convert to hash for easy negative position handling

open(PROGRAM, $program_file) || die "ERROR : Unable to open $program_file : $!\n" ;
while (defined($the_line = <PROGRAM>)) {    ## Store states
   $the_line =~ s/\#.*$// ;                ## Remove comments
   $the_line =~ s/^\s+// ;                 ## Remove leading spaces
   next if $the_line =~ /^\s*$/ ;          ## Skip empty lines
   if ($the_line =~ /(\w+)\s+(\w)\s+(\w+)\s+(\w)\s+([RL])/i) {
       my ($this_state, $this_value, $next_state, $next_value, $dir) = ($1, $2, $3, $4, $5) ;
       $current_state = $this_state unless $current_state ;
       $state{$this_state}{$this_value}{next_state} = $next_state ;
       $state{$this_state}{$this_value}{next_value} = $next_value ;
       $state{$this_state}{$this_value}{dir}        = ($dir =~ /R/i) ? 1 : -1 ;
   } else {
       die "ERROR : Do not understand the following line : $the_line\n" ;
   }
}

while (defined($state{$current_state})) {    ## Run the program
   $tape{$tape_pointer} = '_' unless defined($tape{$tape_pointer}) ;
   my $current_value = $tape{$tape_pointer} ;
   my $next_value    = $tape{$tape_pointer} = $state{$current_state}{$current_value}{next_value} ;
   $tape_pointer    += $state{$current_state}{$current_value}{dir} ;
   $current_state    = $state{$current_state}{$current_value}{next_state} ;
}

## Print the result ##
undef $tape ;
foreach my $i (sort {$a <=> $b} (keys(%tape))) {
   $tape .= $tape{$i} ;
}
$tape =~ s/_+$// ;     ## Clean up leading and trailing _
$tape =~ s/^_+// ;
print "$tape\n" ;
