Mildfuck

From Esolang
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.

Mildfuck
Designed by User:Yb1
Appeared in 2024
Dimensions one-dimensional
Computational class ?
Reference implementation See Mildfuck#Implementation
File extension(s) .mild

Commands

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

by User:Yayimhere

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))