Befunge

From Esolang
Jump to: navigation, search

Befunge is a two-dimensional esoteric programming language invented in 1993 by Chris Pressey with the goal of being as difficult to compile as possible.

History[edit]

Befunge is believed to be the first two-dimensional, ASCII-based, general-purpose (in the sense of "you could plausibly write Hunt the Wumpus in it" [1]) programming language. Its form was influenced in part by the multimedia scripting application AmigaVision, and in part by Forth.

The practice of multiprogramming was probably first developed in Befunge. The wire-crossing problem was also possibly first considered in the context of Befunge.

The original Befunge (known as "Befunge-93" to distinguish it from others) has spawned many descendants and remote cousins. The closest relative, and most direct extension, of Befunge-93 is Befunge-98 of the Funge-98 family of languages. Each Funge extends the central concepts of Befunge to a given number of dimensions (for example, Unefunge is one-dimensional, Trefunge is three-dimensional, Nefunge is n-dimensional, etc.).

Etymology[edit]

The word "Befunge" started life as a typographical error for the word "before", typed by Curtis Coleman at 4AM on a BBS chat system.

It was then reverse-endowed with a fictional morphology where it took on the meaning Be- (a corruption of the prefix bi-, for "two") + funge (fictional root of the word fungible, i.e. "interchangeable"). That is, to interchange (program codes with data) in two (dimensions).

The name is pronounced /bee-FUNJ/.

Language overview[edit]

A Befunge program consists of a two-dimensional playfield of fixed size. The playfield is initially loaded with the instructions of the program. It also doubles as an updateable storage unit.

Execution proceeds by the means of a program counter (-93) or instruction pointer (-98). The instruction pointer begins at a set location (the upper-left corner of the playfield) and is initially travelling in a set direction (right). As it encounters instructions, they are executed. The instructions may have an effect on the instruction pointer's direction and position (-98 only). The following, for example, is literally an infinite loop:

>v
^<

Instructions may also affect the contents of a stack in the manner of Forth.

Instructions[edit]

Befunge-93 has the following commands:

Cmd Description
+ Addition: Pop a and b, then push a+b
- Subtraction: Pop a and b, then push b-a
* Multiplication: Pop a and b, then push a*b
/ Integer division: Pop a and b, then push b/a, rounded down. According to the specifications, if a is zero, ask the user what result they want.
% Modulo: Pop a and b, then push the remainder of the integer division of b/a. According to the specifications, if a is zero, ask the user what result they want.
! Logical NOT: Pop a value. If the value is zero, push 1; otherwise, push zero.
` Greater than: Pop a and b, then push 1 if b>a, otherwise zero.
> PC direction right
< PC direction left
^ PC direction up
v PC direction down
? Random PC direction
_ Horizontal IF: pop a value; move right if value=0, left otherwise
| Vertical IF: pop a value; move down if value=0, up otherwise
" Toggle stringmode (push each character's ASCII value all the way up to the next ")
: Duplicate top stack value
\ Swap top stack values
$ Pop (remove) top stack value and discard
. Output top of stack as integer
, Output top of stack as ASCII character
# Bridge: jump over next command
g A "get" call (a way to retrieve data in storage). Pop y and x, then push ASCII value of the character at that position in the program
p A "put" call (a way to store a value for later use). Pop y, x and v, then change the character at the position (x,y) in the program to the character with ASCII value v
& Get integer from user and push it
~ Get character from user and push it
@ End program
09 Push corresponding number onto the stack

Computational class[edit]

Because Befunge-93 programs are given an explicit limit of 80x25 cells on the size of their playfield, but are also given a working stack, any Befunge-93 program should be simulatable by a push-down automaton.

However, the converse is not true; there surely exist some push-down automata which cannot be simulated by any Befunge-93 program (because they contain more states than can be encoded in the 80x25 playfield).

Befunge-98 removes the fixed-size restriction on the playfield, and thus should be Turing-complete.

Compilation[edit]

As stated, the design goal for Befunge was to create a language which was difficult to compile. This was realized by two main features:

  • self-modifying – the p instruction can write new instructions into the playfield; and
  • multi-dimensional – the same instruction can be executed in four different contexts (in a left-to-right series of instructions, or right-to-left, or upward or downward.)

Nevertheless, these obstacles have been overcome to some degree, and Befunge compilers have been written, using appropriate techniques.

The bf2c compiler included with the standard Befunge-93 distribution uses threaded code: each instruction is compiled to a snippet of C code, and control flows through the snippets just as it does in a Befunge interpreter (that is, conditionally on the value of some 'direction' register.) This does not result in a significant advantage over a good interpreter. Note that the bf2c compiler is not correct since it does not handle p correctly, but it would not be impossible to make it do so (although the C language might not be well-suited for this.)

The Betty compiler, for example, treats every possible straight line of instructions as a subprogram, and if a p instruction alters that subprogram, that subprogram is recompiled. This is an interesting variation on just-in-time compilation, and it results in a much better advantage over an interpreter, since many instructions can be executed in native code without making intervening decisions on the 'direction' register.

There are also programs which combine a Befunge interpreter and a copy of a given Befunge program into a single executable which runs the Befunge program when started. For Befunge-93 this can easily be done by having a preallocated 80×25 cell storage space in the interpreter, and filling it in with the chosen Befunge program. This might be considered a sort of pathological version of threaded code, and while it produces a similar effect to a compiler, that is, it generates a "native executable", it is not really considered the same thing. Sometimes such a tool is called a pseudo-compiler or linker. TBC (Tim's Befunge Compiler), and BFC (BeFunge Compiler) written by Uranium-239, are examples of such tools.

Examples[edit]

Hello, world![edit]

0"!dlroW ,olleH">:#,_@

Cat program[edit]

~:1+!#@_,

Factorial[edit]

0&>:1-:v v *_$.@ 
  ^    _$>\:^

Sieve of Eratosthenes[edit]

2>:3g" "-!v\  g30          <
 |!`"O":+1_:.:03p>03g+:"O"`|
 @               ^  p3\" ":<
2 234567890123456789012345678901234567890123456789012345678901234567890123456789

Quine[edit]

01->1# +# :# 0# g# ,# :# 5# 8# *# 4# +# -# _@

Another one:

0v
"<@_ #! #: #,<*2-1*92,*25,+*92*4*55.0

Simple game ("Less or More")[edit]

vv  <      <                                                                   
    2                                                                          
    ^  v<                                                                      
 v1<?>3v4                                                                      
    ^   ^                                                                      
>  >?>  ?>5^                                                                   
    v   v                                                                      
 v9<?>7v6                                                                      
    v  v<                                                                      
    8                                                                          
    >  >   ^                                                                   
 vv  <      <                                                                  
     2                                                                         
     ^  v<                                                                     
  v1<?>3v4                                                                     
     ^   ^                                                                     
 >  >?>  ?>5^                                                                  
     v   v      v          ,*25         <<                                     
  v9<?>7v6                              ,,                                     
     v  v<                              ""                                     
     8                                  ><                                     
     >  >   ^                           ""v                                    
  >*:.>0"!rebmun tupnI">:#,_$25*,:&:99p`|^<       _0"!niw uoY">:#,_$25*,@      
      ^         <                       >:99g01-*+^

Interpreters[edit]

Vb.Net[edit]

It will fail if you use the 'g' or 'p' function outside the 80x20 playfield. However, you can use them outside this range if the size of your code is greater.

Module Module1

    Sub Main()
        Console.WriteLine("Befunge Inteper By BlackCap")
        Console.Write("filepath> ")
        Dim code = FixLines(IO.File.ReadAllText(Console.ReadLine, Text.Encoding.Default))

        Dim Stack As New Stack(Of Integer)
        Dim StringMode, SkipNext As Boolean
        Dim xCur, yCur, dir As Integer

        Dim g = Function(i%) If(Stack.Count <= i, 0, Stack(i))
        Dim pop = Function() If(Stack.Count > 0, Stack.Pop, 0)

        Do
            If xCur < 0 OrElse yCur < 0 OrElse xCur >= code(0).Length OrElse yCur >= code.Length Then
                Select Case dir
                    Case Is = 0 : xCur = 0
                    Case Is = 1 : yCur = 0
                    Case Is = 2 : xCur = code(0).Length - 1
                    Case Is = 3 : yCur = code.Length - 1
                End Select
            End If

            Dim c As Char = code(yCur)(xCur)

            If SkipNext Then
                SkipNext = False
            Else
                If StringMode Then
                    If c = Chr(34) Then StringMode = False Else Stack.Push(AscW(c))
                Else
                    Select Case c
                        Case Is = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" : Stack.Push(Val(c)) ' Diggits
                        Case Is = "@" : Exit Do ' Terminate
                        Case Is = "$" : pop() ' Pop
                        Case Is = ":":Stack.Push(g(0)) ' Dupe
                        Case Is = "\" ' Swap
                            Dim a = pop(), b = pop()
                            Stack.Push(a) : Stack.Push(b)
                        Case Is = "+", "-", "*", "/", "%" ' Math
                            Dim a = pop(), b = pop()
                            Stack.Push(If(c = "+", b + a, If(c = "-", b - a, If(c = "*", b * a, If(c = "/", b / a, b Mod a)))))
                        Case Is = Chr(34) : StringMode = True ' StringMode
                        Case Is = "!" : Stack.Push(If(pop() = 0, 1, 0)) ' Not
                        Case Is = "`" ' Greater
                            Dim a = pop(), b = pop()
                            Stack.Push(If(b > a, 1, 0))
                        Case Is = "." : Console.Write(pop()) ' Output int
                        Case Is = "," : Console.Write(ChrW(pop())) ' Output ASCII
                        Case Is = "~" ' Read single char
                            Console.Write(vbCrLf & vbCrLf & "> ")
                            Stack.Push(AscW(Console.ReadKey.KeyChar))
                        Case Is = "&" ' Read a line
                            Console.Write(vbCrLf & vbCrLf & "=> ")
                            Array.ForEach(Console.ReadLine.ToArray, Sub(x As Char) Stack.Push(AscW(x)))
                        Case Is = "#" : SkipNext = True ' Skip
                        Case Is = ">", "v", "<", "^" : dir = ">v<^".IndexOf(c) ' Change direction
                        Case Is = "_" : dir = (pop() <> 0) * -2 ' Hor if
                        Case Is = "|" : dir = 1 + (pop() <> 0) * -2 ' Ver if
                        Case Is = "?" ' Random direction
                            Static R As New Random
                            dir = R.Next(0, 4)
                        Case Is = "g" ' Get
                            Dim y = pop(), x = pop()
                            Stack.Push(AscW(code(y)(x)))
                        Case Is = "p" ' Put
                            Dim y = pop(), x = pop(), val = pop()
                            code(y) = code(y).Remove(x) & ChrW(val) & code(y).Substring(x + 1)
                    End Select
                End If
            End If

            Select Case dir
                Case Is = 0 : xCur += 1 ' Right
                Case Is = 1 : yCur += 1 ' Down
                Case Is = 2 : xCur -= 1 ' Left
                Case Is = 3 : yCur -= 1 ' Up
            End Select
        Loop

        Console.WriteLine(vbCrLf & vbCrLf & "The program was terminated" & vbCrLf & "Press any key to exit")
        Console.ReadKey()
    End Sub

    Function FixLines(str As String) As String()
        Dim lines = Split(str, vbCrLf).ToList
        Dim l% = Math.Max((From a In lines Order By a.Length).Last.Length, 80)

        For i = lines.Count To 20
            lines.Add("")
        Next

        For i = 0 To lines.Count - 1
            For i2 = lines(i).Length + 1 To l
                lines(i) &= " "
            Next
        Next

        Return lines.ToArray
    End Function

End Module

Related languages[edit]

Befunge was preceded in 1991 by a similar but less featureful language Biota, which was designed for experiments in self-reproduction. It was followed soon after, in 1994, by another similar language, Orthagonal, the design of which was spurred by a discussion on alt.folklore.computers. Each of these three languages originated (as far as anyone can tell) completely independently of the other two.

Befunge has also provided inspiration to the design of subsequent languages, the most similar of these are known as fungeoids. Most of the languages are not similar enough to be called direct descendants, but often the author mentions the influence of Befunge in the accompanying commentary. Such languages include Wierd, a two-dimensional Turing tarpit; Befreak, a reversible language; and PATH, which combines in elements of Brainfuck.

External resources[edit]

Befunge-93

Befunge-98 and beyond

  • Funge-98 specification.
  • vsync's Funge stuff.
  • Fungus (from the Wayback Machine; retrieved on 22 March 2007) - a nice Befunge-98 IDE for Win32. Warning: its interperter is not fully standards compliant.
  • mooz' Befunge page (from the Wayback Machine; retrieved on 25 September 2006) - contains a Javascript interpreter and several interesting Befunge programs.
  • BeQunge A cross-platform Funge-98 interpreter, code editor, and debugger. Works in any number of dimensions.
  • J^4: Befunge Jeffrey Lee's Befunge site, features plenty of interesting programs.
  • Mycology and CCBI A complete Befunge-98 test suite based on the specification, and an interpreter which passes all the tests.
  • cfunge - Small fast Befunge-98 interpreter in C, standard compliant.
  • Sponge - a compiler (in Common Lisp) from a tiny subset of Scheme to Befunge 98.
  • PyFunge - A Befunge-93/Funge-98 interpreter in Python. Its goal is a fully functional, compliant and optimizing implementation of Funge-98.
  • Fungi - A standards compliant Funge-98 interpreter and debugger written in Haskell.
  • Closidrium - Author retrospective of creating a Befunge-98 Interpreter in Clojure.
  • Multilang - A shell supporting multiple languages, including Befunge-98.