Author Topic: Perl brainfuck Interpreter (sans input)  (Read 4622 times)

Spectere

  • \m/ (-_-) \m/
  • Administrator
  • Hero Member
  • *****
  • Posts: 5716
  • printf("%s\n", "Hi!");
    • View Profile
    • spectere.net
Perl brainfuck Interpreter (sans input)
« on: June 16, 2008, 02:34:55 AM »
This is my first-ever Perl program.  I even forewent the "HELLO WHIRLED" nonsense and skipped right onto the good stuff.

I wrote this while my laptop was churning through Lunicks updates:

Code: [Select]
#!/usr/bin/perl

# I'm loves my switch()
use Switch;

# variabledeclarationsectionstuff
my $prog; # program storage thingie
my $ip = -1; # instruction pointer
my $ramptr = 0; # memory pointer
my $ram; # the actual memory storage
my $maxram = 9999; # 10k oughta be enough for anyone...
my $maxint = (2**8)-1; # set the highest number per memory position (normally (2^8)-2 -- 8-bit precision)
my $loopip; # where do each of the loops start
my $loopptr = -1; # how deeply nested are we?
my $nestlvl = 0; # used to traverse loops for '['
my $proglen; # holds program length

# open file
open my $bffile, $ARGV[0] or die "Could not open $ARGV[0]: $!";

# read file to memory
$prog   .= <$bffile> until eof($bffile);
$proglen = length($prog);

# initialize the memory
$ram[$ramptr] = 0 until ($ramptr++ == $max_ram);

# close file
close $prog;

# start interpremacating
while($ip++ < $proglen) {
switch(substr($prog,$ip,1)) {
case '+' { if(++$ram[$ramptr] > $maxint) { $ram[$ramptr] = 0; } }
case '-' { if(--$ram[$ramptr] < 0) { $ram[$ramptr] = $maxint; } }
case '>' { if(++$ramptr > $maxram) { $ramptr = 0; } }
case '<' { if(--$ramptr < 0) { $ramptr = $maxram; } }
case '.' { if($ram[$ramptr] == 10) { print "\n" } else { print sprintf("%c",$ram[$ramptr]); } }  #make sure this gets printed as a character
case ',' { print "Input not yet implemented!\n"; }
case '[' { unless($ram[$ramptr] == 0) { $loopip[++$loopptr] = $ip; }
           else { $nestlvl++; until($nestlvl == 0) {
           switch(substr($prog,++$ip,1)) {
           case '[' { $nestlvl++; }
           case ']' { $nestlvl--; } } } } }
case ']' { unless($ram[$ramptr] == 0) { $ip = $loopip[$loopptr]; } else { $loopptr--; } }
}
}

# be nice and print a trailing newline
print "\n";

I looked around for approximately three minutes and didn't find any good way of pulling input from the console without requiring the user to hit enter, so I just left it out.  Most brainfuck programs are just people showing off anyway, so it probably doesn't matter all that much.

It's very quick and dirty.  Like I said, first Perl program and done while my system installed updates (WRITTEN COMPLETELY IN A CLI ENVIRONMENT USING nano GASP OH NO).  It's exceedingly slow -- the three quines that I threw at it took between five and ten seconds to run on my laptop (Pentium M 1.73GHz) while my C# interpreter dealt with them very quickly.  My best guess would be that my method for pulling characters out of strings is highly inefficient (probably not helped by the fact that you don't declare variable types in Perl), but I was on a time budget with this so I kept research to a minimum and just stuck with methods that I was familiar with.

I have to say, I LOVE the post-statement evaluations that Perl has, not to mention the fun "OR DIE" clause.

I also find it amusing that the meat of the interpreter is small enough to fit inside of the "new message" textbox.  Yay, brainfuck!
"This is a machine for making cows."

Bobbias

  • #1 Poster
  • Hero Member
  • *****
  • Posts: 7210
  • 404 Avatar not found.
    • View Profile
    • Magnetic Architect
Re: Perl brainfuck Interpreter (sans input)
« Reply #1 on: June 16, 2008, 08:03:30 AM »
I'm not fond of weird operators like .= and declaring every variable with $. I also prefer ^ to ** for powers.

I do like the "or die" and "until" stuff, and how nice "open my $bffile" looks (though I'm not fond that prefix $ again for the !).

My reason for not liking the $ is it's just slow for me to type it when I need it, and making every variable typeless and prefixed with $ just makes programs look uglier to me. I prefer having static types that can by explicitly and implicitly cast into other types (I prefer to be able to find at a glance what type the variable is originally supposed to be).
This is going in my sig. :)

BANNED FOR BAD PUNS X_x

Spectere

  • \m/ (-_-) \m/
  • Administrator
  • Hero Member
  • *****
  • Posts: 5716
  • printf("%s\n", "Hi!");
    • View Profile
    • spectere.net
Re: Perl brainfuck Interpreter (sans input)
« Reply #2 on: June 16, 2008, 08:14:22 AM »
I'm not fond of weird operators like .=

Purely optional, short for "$prog = $prog . <$bffile>" in this case.  A dot in Perl concatenates strings.

and declaring every variable with $.

It helps separate variables from functions and has the advantage of working in monochromic consoles.  I don't mind it.

I also prefer ^ to ** for powers.

Eh, it's a different way to do it (several other languages use **).  Either way, it beats relying on other includes to provide power methods, or doing something like pow(2,8).

My reason for not liking the $ is it's just slow for me to type it when I need it, and making every variable typeless and prefixed with $ just makes programs look uglier to me. I prefer having static types that can by explicitly and implicitly cast into other types (I prefer to be able to find at a glance what type the variable is originally supposed to be).

Dynamic types are far from a bad thing with languages like this.  For the type of applications that Perl (and other scripting languages, for that matter) is designed for, static typing tends to be more of a burden than anything else.  Thankfully, unlike PHP, it's really bleeding obvious what kind of results you're going to get when you perform cross-type operations.  With PHP you pretty much have to roll a 1d20 to save against random behavior with each implicit conversion.
"This is a machine for making cows."

Bobbias

  • #1 Poster
  • Hero Member
  • *****
  • Posts: 7210
  • 404 Avatar not found.
    • View Profile
    • Magnetic Architect
Re: Perl brainfuck Interpreter (sans input)
« Reply #3 on: June 16, 2008, 12:07:51 PM »
It helps separate variables from functions and has the advantage of working in monochromic consoles.  I don't mind it.

I can sorta understand that, but it still bothers me. Mostly because I'm not used to it though.

Eh, it's a different way to do it (several other languages use **).  Either way, it beats relying on other includes to provide power methods, or doing something like pow(2,8).
True, I've seen ** used in a number of places, but IMO it just kinda looks ugly. I guess It's sorta the same issue as the first one, I'm just too used to ^. ^ makes me think "raised" and therefore, "raised to the power".

Dynamic types are far from a bad thing with languages like this.  For the type of applications that Perl (and other scripting languages, for that matter) is designed for, static typing tends to be more of a burden than anything else.  Thankfully, unlike PHP, it's really bleeding obvious what kind of results you're going to get when you perform cross-type operations.  With PHP you pretty much have to roll a 1d20 to save against random behavior with each implicit conversion.
Good point. I think I'd end up using prefix names to tell me what they are (well, the clarify anyway).
This is going in my sig. :)

BANNED FOR BAD PUNS X_x

Spectere

  • \m/ (-_-) \m/
  • Administrator
  • Hero Member
  • *****
  • Posts: 5716
  • printf("%s\n", "Hi!");
    • View Profile
    • spectere.net
Re: Perl brainfuck Interpreter (sans input)
« Reply #4 on: June 16, 2008, 02:39:58 PM »
I can sorta understand that, but it still bothers me. Mostly because I'm not used to it though.

Considering I wrote this without syntax highlighting, trust me when I say that it helps immensely. :)

True, I've seen ** used in a number of places, but IMO it just kinda looks ugly. I guess It's sorta the same issue as the first one, I'm just too used to ^. ^ makes me think "raised" and therefore, "raised to the power".

Oh, don't get me wrong, I agree. :P  I'm used to calculators, where ^ is pretty much the de facto standard.

When compared to pow(2,8) and such things, though, it's definitely the lesser of two evils.

Good point. I think I'd end up using prefix names to tell me what they are (well, the clarify anyway).

The problem with that is that the data type can change depending on what you want to do.

Let's say you're parsing a file that has a list of numbers, incrementing each one by one, and printing them to the screen.  In Perl, all you'd have to do this is this per line:

Code: [Select]
$myVar = <$myFile>;
print ++$myVar;

(note: I'm not sure if you can do a postfix operator on file line reads...if so, I'd totally do it just to be a douche ;))

All file input is done with strings and, in this case, the string is seamlessly converted.  Perfect for if you want to make a quick script to process many "strings" of numbers.  ReMaic -- a Quake demo recamming tool -- is one tool that probably greatly benefits from this.

In something like, say, VB.NET (C# would be extremely similar), that code would look more like this:

Code: [Select]
inData = sReader.ReadLine
numData = Convert.ToInt32(inData)
numData += 1
Console.WriteLine(numData)

(note: I know that Val(inData) will work for VB.NET, but I didn't want to have to rely on the Microsoft.VisualBasic namespace.  And yes, I know that VB.NET allows implicit type conversions...stfuad)

In this example it's just one extra step, but what would happen if you were processing a lot of data?  Perhaps, a list of coordinates or something of that sort.  It would start to get a little tedious.

Implicit conversions aren't always a good idea, but in data processing they can save a lot of time and effort, not to mention allow for neater code in many cases.
"This is a machine for making cows."