Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Brainfuck Interpreter (Perl)
Index -> General Programming
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
Degensquared




PostPosted: 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
Sponsor
sponsor
wtd




PostPosted: 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




PostPosted: 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




PostPosted: 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




PostPosted: 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




PostPosted: 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.
Display posts from previous:   
   Index -> General Programming
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 6 Posts ]
Jump to:   


Style:  
Search: