Counterfish
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. It 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.
Duplicate :{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³ = 8 (vreg.2 = 3)
R0: 8 [3] R1: 3375 [0, 3, 3]
- Input: 2⁵ = 32 (vreg.2 = 5)
R0: 32 [5] R1: 759375 [0, 5, 5]
- Input 2³ * 3⁴ = 648 (add to existing value)
R0: 648 [3, 4] R1: 273375 [0, 7, 3]
- Input: 2³ * 7² = 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