Counterfish

From Esolang
Jump to navigation Jump to search

Based on Minsky Swap. Neither Portable Minsky Machine Notation nor Szewczyk notation for Minsky machine are suited to directly implementing two register counter machines. PMMN requires significant restructuring of some algorithms to run with only two registers (PMMN is effectively a restricted subset of the hypothetical Minsky machine language),[citation needed] and SNMM is not TC with only two registers. This is an attempt at a somewhat usable two register counter machine. Accidentally became a Deadfish reference.


Token Description
i Increment current register
d If current register is not 0, decrement and skip the next token, otherwise NOP
s Swap registers
o Output current register (as an integer, or optionally as a list of integers or characters Gödel encoded using prime factorisation)
:{label} Program label - NOP
_{label} Jump to matching :{label}

:{label} tokens must be whitespace delimited. _{label} tokens must be whitespace terminated. idso tokens may be run together or separated by whitespace.


Multiple :{label}s are not an error. They could be useful for NOPs, comments, or other markers. However, the jump behaviour when multiple targets exist is undefined. Implementations may choose to pick first, closest, not yet visited, random, etc.

Use :{label}s (no whitespace) to document code.

I/O

An interpreter should provide a mechanism to set the first register to a user supplied value before starting the program. Ideally it should Gödel-encode user supplied lists or strings into a single register value.

An integer output mask should be optionally accepted to filter the results of the o command based on the prime factorisation of the mask to be applied to all instances of o encountered during a particular execution.

Examples

Truth Machine

d_zero i
:one o _one
:zero o

Copy (duplicate and add) a prime encoded 'virtual' register

:Duplicate_a_prime_encoded_v.reg
:adds_vreg.2_into_vreg.3_and_vreg.5
:requires_non_zero_prime_encoded_input_into_r0_vreg.2

:Display_before_state
  o

:dupe_add
  d_done i
  :add_one
    d_added
    d_earlyzero
    s
    iiiiiiiiiiiiiii
    s
  _add_one

:added s _dupe_add

:earlyzero
  is
:adjust
  dd dd dd dd dd dd dd dd dd dd dd dd dd dd d_done siis
_adjust

:done
:display_result
  so

This program illustrates the exponential slowdown that such restricted machines are subject to. Duplicating 5 takes ~6secs on my laptop. Duplicating 6 takes 1.5 minutes.

Example output:

  • Input: 2**3 = 8 (vreg.2 = 3)
 R0: 8
    [3]
 R1: 3375
    [0, 3, 3]
  • Input: 2**5 = 32 (vreg.2 = 5)
 R0: 32
    [5]
 R1: 759375
    [0, 5, 5]
  • Input 2**3 * 3**4 = 648 (add to existing value)
 R0: 648
    [3, 4]
 R1: 273375
    [0, 7, 3]
  • Input: 2**3 * 7**2 = 392 (Leaving adjacent vregs untouched)
 R0: 392
    [3, 0, 0, 2]
 R1: 165375
    [0, 3, 3, 2]

Hello, World!

This is a terrible way to encode data in this language, using virtual registers as 'cells' to encode an entire string at once. It is meant to be a challenge for an optimising interpreter, and performance profiler, as well as a demonstration of a macro compiler extension. Since incrementing by a constant is accomplished by run length encoding instructions like Deadfish iiiiiiiiii or bf +++++++++, and for virtual registers this means repeating runs of loops to achieve the same thing. The repeat(constant) { code block } macro handles this (with auto label suffix incrementing). This program takes a stupid amount of time to execute. I haven't profiled it yet, but 1000s of years to heat-death-of-the-universe is what the example is aiming for. I'm hoping an optimising interpreter can take mathematical shortcuts and make this run from just the macro-expanded code (829 lines), but it's a WIP.

:Hello_World_in_13_prime_encoded_virtual_registers
:with_counterfish_macro_expansion

ii
repeat(72)  { :H0 sd_H1 sii_H0 }
:H72
repeat(101) { :E0 sd_E1 siii_E0 }
:E101
repeat(108) { :L0 sd_L1 s repeat(1085) { i } _L0 }
:L108
repeat(111) { :O0 sd_O1 s repeat(253) { i } _O0 }
:O111
repeat(44)  { :COMMA0 sd_COMMA1 siiiiiiiiiiiii_COMMA0 }
:COMMA44
repeat(32)  { :SPACE0 sd_SPACE1 siiiiiiiiiiiiiiiii_SPACE0 }
:SPACE32
repeat(87)  { :W0 sd_W1 siiiiiiiiiiiiiiiiiii_W0 }
:W87
repeat(114) { :R0 sd_R1 repeat(29) { i } _R0 }
:R114
repeat(100) { :D0 sd_D1 repeat(37) { i } _D0 }
:D100
repeat(33)  { :EXCLAIM0 sd_EXCLAIM1 repeat(43) { i } _EXCLAIM0 }
:EXCLAIM33
:DONE o

External resources