Brainfuck Interpreter (Perl) 
	 
	
		| Author | 
		Message | 
	 
		 
		Degensquared
 
 
 
    
		 | 
		
		
			
				  Posted: Thu Dec 18, 2008 10:33 pm    Post subject: Brainfuck Interpreter (Perl)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				An interpreter for Brainfuck that I wrote in perl as a challenge to myself. I had trouble implementing this while I was using turing, but I found that the dynamic arrays and regex really helped out. I'm looking for some critique here. What could I have done differently, what did I do well? I'm very new to perl, so if I went about certain problems in a way that could be solved much easier using some feature of perl of which I'm not aware, I'd appreciate the information.
 
 
Usage: perl bfi.pl input.txt
 
 
	  | code: | 	 		  #!/usr/bin/perl -w
 
use strict;
 
use 5.010;
 
 
# ------------------------------------------------
 
# BrainFuck Intepreter -- By: Cody Veal (12/15/08)
 
# ------------------------------------------------
 
 
# OPEN INPUT FILE
 
die "use the following usage: perl bfi.pl code.txt" if (scalar(@ARGV) != 1);
 
open my $stream, $ARGV[0] or die "error opening file: $!";
 
 
# INITIALIZE POINTER, ARRAY, COUNTER, LOOP STACK
 
my $top = 5000;
 
 
my @array = (1..$top);
 
my $ptr = 0;
 
my $i = 0;
 
my @loops;
 
 
for my $i (0..scalar(@array)-1) {
 
    $array[$i] = 0;
 
}
 
 
# SET UP INPUT
 
my $input = "";
 
 
# concatanates all data into a single line
 
while (<$stream>) {
 
    chomp;
 
    $input .= $_;
 
}
 
 
# substitutes any non-bf characters with nothing (removes all chars that are not bf commands)
 
$input =~ s/[^\+\-\.\[\],<>]//g;
 
 
# ERROR CHECK
 
my $rbracket = scalar(grep(/[\[]/, $input));
 
my $lbracket = scalar(grep(/[\]]/, $input));
 
 
die "bracket numbers don't match --  ([:$rbracket | ]:$lbracket)" if $rbracket != $lbracket;
 
 
# ENTER EXECUTION LOOP
 
while ($i < length($input)) {
 
    my $c = substr($input,$i,1);
 
    $i += 1;
 
    
 
    # move pointer to left (wrap to top if ptr is at 0)
 
    if ($c eq "<") {
 
        $ptr = $top + 1 if ($ptr == 0);
 
        $ptr -= 1;
 
    }
 
    
 
    # move pointer to right (wrap to 0 if ptr is at top)
 
    elsif ($c eq ">") {
 
        $ptr = -1 if ($ptr == $top);
 
        $ptr += 1;
 
    }
 
    
 
    # increment value at ptr by 1 (wrap to 0 if value is 255)
 
    elsif ($c eq "+"){
 
        $array[$ptr] = -1 if ($array[$ptr] == 255);
 
        $array[$ptr] += 1;
 
    }
 
    
 
    # decrement value at ptr by 1 (wrap to 255 if value is 0)
 
    elsif ($c eq "-") {
 
        $array[$ptr] = 256 if ($array[$ptr] == 0);
 
        $array[$ptr] -= 1;
 
    }
 
    
 
    # print ascii char of value at ptr
 
    elsif ($c eq ".") {
 
        print chr($array[$ptr]);
 
    }
 
    
 
    # get ascii value of char from input and store in value at ptr
 
    elsif ($c eq ",") {
 
        my $in = <STDIN>;
 
        $array[$ptr] = ord(substr($in,0,1));
 
    }
 
    
 
    # store the place after the [ symbol occurs on the top of stack
 
    elsif ($c eq "[") {
 
        push @loops, $i;
 
    }
 
    
 
    # if value at ptr is == 0, pop loop location from top of stack, else go to position after last [ was found.
 
    elsif ($c eq "]") {
 
        if ($array[$ptr] != 0) {
 
            $i = $loops[scalar(@loops)-1];
 
        }
 
        else {
 
            pop @loops;
 
        }
 
    }
 
}  | 	 
  | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
		 
		Sponsor Sponsor 
		 
  
		 | 
		
 | 
	 
	 
		  | 
	 
				 
		wtd
 
 
 
    
		 | 
		
		
			
				  Posted: Thu Dec 18, 2008 11:45 pm    Post subject: RE:Brainfuck Interpreter (Perl)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				You could store operations as anonymous subroutine references in a hash, where indexes for the hash are the character.
 
 
Something like:
 
 
	  | code: | 	 		  use 5.010;
 
use strict;
 
 
my %ops = {
 
    "+" => sub { say "+ op encountered" }
 
};
 
 
$a{"+"}->();  | 	 
  | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		Insectoid
 
  
 
    
		 | 
		
		
			
				  Posted: Fri Dec 19, 2008 9:00 am    Post subject: RE:Brainfuck Interpreter (Perl)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				| Wow, just had a look at the brainfuck wiki. Looks like it could be fun to learn! though it would be a pain in the arse to debug... | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		Degensquared
 
 
 
    
		 | 
		
		
			
				  Posted: Fri Dec 19, 2008 11:45 am    Post subject: Re: Brainfuck Interpreter (Perl)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				wtd: That sounds interesting, could you explain the syntax a little bit? Where did $a come from? Perhaps that was supposed to be $ops, which would make sense.  Why does it require the -> to the anonymous sub? I thought that changing the % to a $ made it a reference to the value of whatever is at that index? Or am I confused about what the meaning of that arrow is? I'd really appreciate the clarification.
 
 
insectoid: I'd suggest using the Brainfuck Machine (http://www.kacper.kwapisz.eu/index.php?i=19) if you want to do programming in Brainfuck. It has a step-through debugger and a table with the memory values. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		Insectoid
 
  
 
    
		 | 
		
		
			
				  Posted: Fri Dec 19, 2008 12:21 pm    Post subject: RE:Brainfuck Interpreter (Perl)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				| No, I don't want to learn it. I just said it could be fun. The language is too odd to learn now. I might get brainfucked. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		wtd
 
 
 
    
		 | 
		
		
			
				  Posted: Fri Dec 19, 2008 2:25 pm    Post subject: RE:Brainfuck Interpreter (Perl)  | 
	
				
				 | 
			 
			 
				
  | 
			 
			
				Oh, that was me mixing up decent naming with my experimentation.
 
 
	  | code: | 	 		  use 5.010;
 
use strict;
 
 
my %ops = {
 
    "+" => sub { say "+ op encountered" }
 
};
 
 
$ops{"+"}->();  | 	  
 
 
%ops is the name of the hash.  The % sigil becomes $ when it's accessed.  As for the -> well that dereferences the subroutine references and the () calls the subroutine. | 
			 
			
				 | 
			 
		  | 
	 
	 
		 | 
		
		 | 
	 
	  
		  | 
	 
				 
		 | 
	 
 
	
	
	 
	
	 |