Mildfuck
Jump to navigation
Jump to search
Mildfuck is a brainfuck and infinite abacus inspired esolang created by Yb1 with only 6 commands. The name is derived from the first 4 commands, reading mild.
Storing data is a carbon copy of brainfuck, a tape with cells containing values from 0 to 255.
| Designed by | User:Yb1 |
|---|---|
| Appeared in | 2024 |
| Dimensions | one-dimensional |
| Computational class | ? |
| Reference implementation | See Mildfuck#Implementation |
| File extension(s) | .mild |
Commands
| Command | Description |
|---|---|
m |
Move pointer in pointer direction (right on start). |
i |
Increase current cell if less than 255. |
l |
No op, used as a skipping point for d.
|
d |
Invert pointer direction and if current cell is 0, skip to last l or else decrease the current cell.
|
g |
Get 1 ascii character input, and store it into the cell. |
o |
Output current cells value as an ascii character. |
Computational class
I have reasonable suspicion that this is Turing-complete, because this is very similar to an infinite abacus, which is Turing-complete.
Examples
Truth Machine
Not yet programmed, sorry. Replace this with a truth machine.
Cat program
The following furnishes a perpetually repeating cat program:
lmidgomd
Hello, World!
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiioomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiomiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiio
Implementation
The following implementation in Common Lisp assumes that the d instruction jumps back to the nearest preceding l token:
(deftype octet ()
"Defines an unsigned byte value in the range [0, 255]."
'(unsigned-byte 8))
(deftype hash-table-of (&optional (key-type T) (value-type T))
"Defines a hash table whose keys conform to the KEY-TYPE and whose
values adhere to the VALUE-TYPE."
(let ((predicate (gensym)))
(declare (type symbol predicate))
(setf (symbol-function predicate)
#'(lambda (candidate)
(declare (type T candidate) (ignorable candidate))
(and (hash-table-p candidate)
(loop for key of-type T being the hash-keys in candidate
using (hash-value value)
always (and (typep key key-type)
(typep value value-type))))))
`(satisfies ,predicate)))
(deftype list-of (&optional (element-type T))
"Defines a list whose elements comply with the ELEMENT-TYPE."
(let ((predicate (gensym)))
(declare (type symbol predicate))
(setf (symbol-function predicate)
#'(lambda (candidate)
(declare (type T candidate) (ignorable candidate))
(and (listp candidate)
(loop for element of-type T in candidate
always (typep element element-type)))))
`(satisfies ,predicate)))
(defun build-skip-table (code)
"Creates and returns a skip table for the piece of Mildfuck CODE."
(declare (type string code))
(let ((skip-table (make-hash-table :test #'eql))
(skip-targets NIL))
(declare (type (hash-table-of fixnum fixnum) skip-table))
(declare (type (list-of fixnum) skip-targets))
(loop for token of-type character across code
and position of-type fixnum from 0 by 1
if (char= token #\l) do
(push position skip-targets)
else if (char= token #\d) do
(if skip-targets
(setf (gethash position skip-table) (first skip-targets))
(error "No skip target exists for the \"d\" instruction ~
at position ~d." position))
end)
(the (hash-table-of fixnum fixnum) skip-table)))
(defun interpret-Mildfuck (code)
"Interprets the piece of Mildfuck CODE and returns no value."
(declare (type string code))
(let ((ip 0)
(skip-table (build-skip-table code))
(memory (make-hash-table :test #'eql))
(cell-pointer 0)
(pointer-direction :right))
(declare (type fixnum ip)
(type (hash-table-of fixnum fixnum) skip-table)
(type (hash-table-of integer octet) memory)
(type integer cell-pointer)
(type (member :left :right) pointer-direction))
(flet ((current-cell ()
"Returns the current cell value."
(the octet (gethash cell-pointer memory 0)))
((setf current-cell) (new-value)
"Stores the NEW-VALUE in the current cell, wrapping on
necessity in the valid byte range, and returns no value."
(declare (type integer new-value))
(setf (gethash cell-pointer memory 0) (mod new-value 256))
(values)))
(loop while (< ip (length code)) do
(case (char code ip)
(#\m (case pointer-direction
(:right (incf cell-pointer))
(:left (decf cell-pointer))
(otherwise (error "Invalid pointer direction: ~s."
pointer-direction))))
(#\i (when (< (current-cell) 255)
(incf (current-cell))))
(#\l NIL)
(#\d (setf pointer-direction
(case pointer-direction
(:right :left)
(:left :right)
(otherwise (error "Invalid pointer direction: ~s."
pointer-direction))))
(if (zerop (current-cell))
(setf ip (gethash ip skip-table))
(decf (current-cell))))
(#\g (format T "~&>> ")
(finish-output)
(setf (current-cell) (char-code (read-char)))
(clear-input))
(#\o (write-char (code-char (current-cell))))
(otherwise NIL))
(incf ip))))
(values))