Re: [stack] befreaked

Brent Kerby — 2003-06-28 06:36:51

> as a first program, i thought i'd attempt an implementation of
> conway's game of life.

That would be excellent :-)

One issue to deal with, though, is that Conway's game of life is
irreversible. You could implement it in Befreak, but not easily, without
rapidly running out of memory (since you cannot simply discard past game
states). You would need to use some method to compress the game history
(this has certainly been done before with Life, but never in Befreak :-)).

Of course, there are reversible cellular automata (albeit they probably
don't look as cool as Life); perhaps it would be easier to implement one of
those.

> the way i want to think of this is that
> there's a rectangular area, infinite in the east and south
> directions, and instructions for reading and writing cells
> in the area.

Befreak has no such instructions, although they could be added without much
trouble (it would have to XOR, of course, rather than overwrite). I think
I'd probably use "g" and "p" (get and put) as in Befunge, since "r" and "w"
are already used for I/O.

You mentioned the area should be infinite; I think that is a good idea. It
would fit the system (since the stack is infinite, the data area ought to be
also). The big question is now, should we just use the code area for the
data area (as in Befunge), or should it be separate? An advantage of having
a separate data area would be that the language could then still be
efficiently compiled, whereas self-modifying code pretty much thwarts any
such attempts. Of course, there's arguably not much interest in watching a
compiled Befreak program anyway, but who knows. Supposing the code area is
used for data, should the code area be extended to be infinite (instead of
wrapping around)?

This ties in with another issue that's been on my mind for a while ... I was
thinking of making a modified version of Befreak in which errors were
eliminated; i.e., there would be no way to write an invalid Befreak program.
This requires several changes to the language:

The biggest issue is that almost all instructions have the potential to
cause an "empty stack" error; to eliminate this, I was thinking of making
the stack a fixed size (modifyable of course, by the user, just as the size
of the code area can be modified). And then, instead of the stack growing
and shrinking, a stack pointer would simply move up and down through it,
wrapping around when it reaches one end. Then, empty stack errors are
impossible, provided the stack has at least size 3 (the maximum number of
items needed by any instruction).

Then, the "(" and ")" instructions would move the stack pointer up and down.
The stack would be initialized as all 0's, and so "(" would still act like
it was pushing a 0. It would be a typical policy still to ensure that the
top item is 0 before using ")" even though this would no longer be an error
if it wasn't (it would just mean the next time we do "(", we'd get something
other than a 0 as the top item). Programming in this version of Befreak
would probably be more bug-prone :-)

The goal is that the new "lenient Befreak" would be backwards-compatible
with normal Befreak. That is, normal Befreak programs should execute the
same using lenient Befreak, provided the stack size is set large enough.

Anyway, several other changes would need to be made: The return stack would
need to become fixed size and cyclic also. Undefined instructions would
simply pass as no-ops. The multiply and divide instructions present some
difficulty: when an error is generated, we could just sweep it under the rug
and treat the instruction as a no-op, but there's probably a more elegant
way ...

So, if that can all be worked out, then the fun thing to do would be to
generate random programs and watch what they do. In an irreversible
programming language, a random program would probably just hit a dead-end
pretty quickly. But with Befreak, I suspect the behavior could be much more
interesting (for one thing, given the complete finiteness of the system, and
reversibility, we know that any program will eventually end up exactly where
it started, although this may takes eons)

> > The interpreter needs documentation ... Use CTRL-L to load from a file,
> > CTRL-W to write, CTRL-R to rename... see the source for the rest :-)

I'm reminded again that I need to write documentation ... But until then, a
few other important things:

ALT-RIGHT (or CTRL-F): Step program forwards one step
ALT-LEFT (or CTRL-B): Step program backwards one step
ENTER : Pause/unpause
ALT-UP (or CTRL-P): Increase speed
ALT-DOWN (or CTRL-N): Decrease speed
CTRL-X: Cut/Paste
CTRL-V: Paste (while keeping on the clipboard)
CTRL-A/CTRL-D: Reflect contents of clipboard
CTRL-Q/CTRL-E: Rotate contents of clipboard

I hope your terminal has arrow keys, because you need them to move the
cursor around. Ahh, and this reminds me, it's set up to compile for DOS (a
few little quirks of PDCurses, etc.); for UNIX (Ncurses), remove the USEDOS
define at the top of bfi.h.

- Brent