This is a page devoted to short interpreters/compilers I've written for esolangs that already have an implementation, just for science I guess.
53-bit signed cells (64-bit floating point), infinite tape both left and right. Each character of input must be on its own line (, will take a whole line but ignore any characters after the first). Does not support outputting ASCII control characters, 8-bit ASCII characters, or Unicode characters, and will error out if the program tries to output a cell greater than 255 (0-32 and 127-255 will just print a space instead of their respective byte).
Please note I am not good at APL so this code is trash (the conditionals use the eval of a string indexed in a nested array. Every time.)
ascii←'!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~',⍨32⍴' '
ascii[11]←"\n"[1]
ascii←({⍵,' '}⍣129)ascii
set←{arr←⊃⍵[1] ⋄ ind←⊃⍵[2] ⋄ val←⊃⍵[3] ⋄ arr[ind]←val ⋄ arr}
tape←1⍴0 ⋄ ip←dp←1 ⋄ code←⍞ ⋄ data←(⊂tape),(⊂dp),(⊂code),(⊂ip)
left←{dp←1-⍨⊃⍵[2] ⋄ tape←⍎⊃((⊂'⊃⍵[1]'),⊂'(0,⊃⍵[1])⊣dp←1')[1+dp<1] ⋄ (⊂tape),(⊂dp),⍵[3],⍵[4]}
right←{dp←1+⊃⍵[2] ⋄ tape←⍎⊃((⊂'⊃⍵[1]'),⊂'((⊃⍵[1]),0)')[1+dp>⍴⊃⍵[1]] ⋄ (⊂tape),(⊂dp),⍵[3],⍵[4]}
change←{dp←⊃⍵[2] ⋄ tape←⊃⍵[1] ⋄ ind←dp ⋄ val←⍶ ind⌷tape ⋄ tape←set (⊂tape),(⊂ind),(⊂val) ⋄ (⊂tape),(⊂dp),⍵[3],⍵[4]}
plus←{⍵+1} change ⋄ minus←{⍵-1} change
out←{⍞←⍎⊃((⊂'ascii[(⊃⍵[1])[⊃⍵[2]]]'),⊂'''''')[1+0=(⊃⍵[2])⌷⊃⍵[1]] ⋄ ⍵}
in←{inpline←⍞ ⋄ inp←⍎⊃((⊂'0'),⊂'⍸ascii=1⌷inpline')[1+0<⍴inpline] ⋄ dp←⊃⍵[2] ⋄ tape←⊃⍵[1] ⋄ tape←set (⊂tape),(⊂dp),⊂1⌷inp ⋄ (⊂tape),(⊂dp),⍵[3],⍵[4]}
open_←'0⊣open←{ip←⊃⍵[4] ⋄ code←⊃⍵[3] ⋄ ip←(({code←⊃⍵[1] ⋄ ip←1+⊃⍵[2] ⋄ d←⊃⍵[3] ⋄ d←⍎⊃('
open_←open_,'(⊂''d''),⊂''d+1'')[1+''[''=ip⌷code] ⋄ d←⍎⊃((⊂''d''),⊂''d-1'')[1+'']''=ip⌷code] ⋄ (⊂'
open_←open_,'code),(⊂ip),(⊂d)}⍣{0=⊃⍵[3]})(⊂code),(⊂ip),(⊂1))[2] ⋄ (⍵[1]),(⍵[2]),(⊂code),⊂ip}'
⍎open_ ⋄ ⎕ERASE 'open_'
close_←'0⊣close←{ip←⊃⍵[4] ⋄ code←⊃⍵[3] ⋄ ip←(({code←⊃⍵[1] ⋄ ip←1-⍨⊃⍵[2] ⋄ d←⊃⍵[3] ⋄ d←⍎⊃('
close_←close_,'(⊂''d''),⊂''d+1'')[1+'']''=ip⌷code] ⋄ d←⍎⊃((⊂''d''),⊂''d-1'')[1+''[''=ip⌷code] ⋄ (⊂'
close_←close_,'code),(⊂ip),(⊂d)}⍣{0=⊃⍵[3]})(⊂code),(⊂ip),(⊂1))[2] ⋄ (⍵[1]),(⍵[2]),(⊂code),⊂ip}'
⍎close_ ⋄ ⎕ERASE 'close_'
opencond←{dp←⊃⍵[2] ⋄ tape←⊃⍵[1] ⋄ ⍎⊃((⊂'⍵'),⊂'open ⍵')[1+0=dp⌷tape]}
closecond←{dp←⊃⍵[2] ⋄ tape←⊃⍵[1] ⋄ ⍎⊃((⊂'⍵'),⊂'close ⍵')[1+1-0=dp⌷tape]}
exec←{⍎⊃({⍵,' ⍵'}¨('left' 'right' 'plus' 'minus' 'out' 'in' 'opencond' 'closecond'))[⍸'<>+-.,[]'=(⊃⍵[3])[⊃⍵[4]]]}
advance←{⍎⊃(((⊂'0'),⊂'{(⍵[1]),(⍵[2]),(⍵[3]),(⊂1+⊃⍵[4])}⍵')[1+(⊃⍵[4])<⍴⊃⍵[3]])}
({advance exec ⍵}⍣{⍵≡0})data
The following is an implementation of Deadfish~ in C-INTERCAL (however, it should work in most INTERCAL dialects, as it uses only INTERCAL-72 constructs). Input a line of Deadfish~ code to this program. (If it's over 1024 characters, change the top line of the interpreter to accommodate it.)
There is one limitation which is that the w command exhibits really weird behavior when mixed with c commands or additional w commands. w can only reliably be used in the program w.
I also believe this supports () and {} up to 65535 levels (same limit for the two types combined), but I can't say for sure; I started this program several years ago, finished it today, and along the way forgot what that giant unreadable blocks from 160-169 and 170-179 actually do (I know they count brackets but I don't know how), and of course INTERCAL is difficult to read. I did test each type of bracket nested in the other type, and they do work.
DO .30 <- #1024 DO NOTE: Global length constant.
DO ,2 <- .30 DO NOTE: Original Turing text array.
PLEASE ,1 <- .30 DO NOTE: Decoded array.
DO WRITE IN ,2
DO NOTE: Array decoding.
PLEASE .20 <- #0 DO NOTE: Current tape position.
DO .21 <- #1 DO NOTE: Counter.
(1) DO FORGET #1
DO (10) NEXT
DO ABSTAIN FROM NEXTING + CALCULATING + FORGETTING + RESUMING
(10) PLEASE (11) NEXT
DO .30 <- .21
DO FORGET #1
DO (4) NEXT
(11) PLEASE .1 <- '"?'",2SUB.21"$#256'"~"#0$#65535"'~#65535
DO .1 <- '.1~.1'~#1
DO .2 <- #1
DO (1000) NEXT
DO RESUME .3
DO REINSTATE NEXTING + CALCULATING + FORGETTING + RESUMING
PLEASE .1 <- .20
DO .2 <- ,2SUB.21
DO (1000) NEXT
DO .20 <- .3~#255
DO ,1SUB.21 <- .20
PLEASE (2) NEXT
DO (1) NEXT
(2) DO (3) NEXT
DO FORGET #1
DO (4) NEXT
(3) PLEASE .1 <- .21
DO .2 <- #1
DO (1000) NEXT
DO .21 <- .3
PLEASE .1 <- .3
DO .2 <- .30
DO (1010) NEXT
PLEASE .1 <- .3
DO .2 <- #1
DO (1010) NEXT
DO .3 <- '.3~.3'~#1
PLEASE .1 <- .3
DO .2 <- #1
DO (1009) NEXT
DO RESUME .3
(4) PLEASE .10 <- #0 DO NOTE: Register.
DO .22 <- #1 DO NOTE: Instruction pointer position.
PLEASE .11 <- #0 DO NOTE: Output tape position.
DO .12 <- #0 DO NOTE: Loop repeats left. (Uses stash stack for
nested loops.)
PLEASE .13 <- #0 DO NOTE: Bracket depth.
DO FORGET #1
DO NOTE:
//If the output character isn't the right one it may be because the compiler
//shares the position of the input and output tapes. If so put .20 instead of
//#0.
PLEASE (5) NEXT
DO NOTE: Interpretation.
(5) DO FORGET #1
DO (100) NEXT
PLEASE (110) NEXT
DO (120) NEXT
DO (130) NEXT
DO (140) NEXT
PLEASE (150) NEXT
DO (160) NEXT
DO (170) NEXT
DO (180) NEXT
PLEASE (190) NEXT
DO (6) NEXT
DO (5) NEXT
(6) DO (7) NEXT
DO GIVE UP
(7) PLEASE .1 <- .22
DO .2 <- #1
DO (1000) NEXT
DO .22 <- .3
PLEASE .1 <- .3
DO .2 <- .30
DO (1010) NEXT
DO .3 <- '.3~.3'~#1
PLEASE .1 <- .3
DO .2 <- #1
DO (1010) NEXT
DO .3 <- '.3~.3'~#1
DO .3 <- '?".3$#65535"'~#1
PLEASE .1 <- .3
DO .2 <- #1
DO (1000) NEXT
PLEASE RESUME .3
DO NOTE: Check 'i'.
(100) DO .1 <- ,1SUB.22
DO .2 <- #105
PLEASE (1010) NEXT
DO .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (101) NEXT
DO RESUME #1
(101) DO (102) NEXT
PLEASE .1 <- .10
DO .2 <- #1
DO (1009) NEXT
DO .10 <- .3
DO (103) NEXT
PLEASE RESUME #2
(102) DO RESUME .3
(103) DO .1 <- .10
DO .2 <- #256
PLEASE (1010) NEXT
DO .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1009) NEXT
DO (104) NEXT
DO RESUME #1
(104) DO (105) NEXT
PLEASE .10 <- #0
DO RESUME #2
(105) DO RESUME .3
DO NOTE: Check 'd'.
(110) PLEASE .1 <- ,1SUB.22
DO .2 <- #100
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (111) NEXT
DO RESUME #1
(111) DO (112) NEXT
PLEASE .1 <- .10
DO .2 <- #1
DO (1010) NEXT
DO .10 <- .3
DO (113) NEXT
PLEASE RESUME #2
(112) DO RESUME .3
(113) DO .1 <- .10
DO .2 <- #65535
PLEASE (1010) NEXT
DO .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1009) NEXT
DO (114) NEXT
DO RESUME #1
(114) DO (115) NEXT
PLEASE .10 <- #0
DO RESUME #2
(115) DO RESUME .3
DO NOTE: Check 's'.
(120) PLEASE .1 <- ,1SUB.22
DO .2 <- #115
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (121) NEXT
DO RESUME #1
(121) DO (122) NEXT
PLEASE .1 <- .10
DO .2 <- .10
DO (1030) NEXT
DO .10 <- .3
DO (123) NEXT
PLEASE RESUME #2
(122) DO RESUME .3
(123) DO .1 <- .10
DO .2 <- #256
PLEASE (1010) NEXT
DO .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1009) NEXT
DO (124) NEXT
DO RESUME #1
(124) DO (125) NEXT
PLEASE .10 <- #0
DO RESUME #2
(125) DO RESUME .3
DO NOTE: Check 'o'.
(130) PLEASE .1 <- ,1SUB.22
DO .2 <- #111
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (131) NEXT
DO RESUME #1
(131) DO (132) NEXT
DO READ OUT .10
PLEASE RESUME #2
(132) DO RESUME .3
DO NOTE: Check 'c'.
(140) PLEASE .1 <- ,1SUB.22
DO .2 <- #99
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (141) NEXT
DO RESUME #1
(141) DO (142) NEXT
PLEASE ,3 <- #1
DO .3 <- .10
DO NOTE:
The example program at
http://www.muppetlabs.com/~breadbox/intercal-man/s05.html#2
has been shamelessly copied here.
PLEASE .3 <- !3~#15'$!3~#240'
DO .3 <- !3~#15'$!3~#240'
DO .2 <- !3~#15'$!3~#240'
DO .1 <- .11
PLEASE (1010) NEXT
DO .11 <- .2
DO ,3SUB#1 <- .3
PLEASE READ OUT ,3
DO RESUME #2
(142) DO RESUME .3
DO NOTE: Check '{'.
(150) PLEASE .1 <- ,1SUB.22
DO .2 <- #123
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (151) NEXT
DO RESUME #1
(151) DO (152) NEXT
DO STASH .12
DO .12 <- #10
PLEASE RESUME #2
(152) DO RESUME .3
DO NOTE: Check '}'.
(160) PLEASE .1 <- ,1SUB.22
DO .2 <- #125
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
DO (1000) NEXT
DO (161) NEXT
DO RESUME #1
(161) DO (162) NEXT
PLEASE .1 <- .12
DO .2 <- #1
DO (1010) NEXT
DO .12 <- .3
PLEASE .1 <- '.3~.3'~#1
DO (1009) NEXT
DO (163) NEXT
DO .13 <- #1
DO (165) NEXT
DO ABSTAIN FROM (165)
PLEASE RESUME #2
(163) DO (164) NEXT
DO RETRIEVE .12
PLEASE RESUME #3
(164) DO RESUME .3
(162) DO RESUME .3
(165) PLEASE DON'T FORGET #1
DO REINSTATE (165)
DO .1 <- '.13~.13'~#1
DO .2 <- #1
PLEASE (1009) NEXT
DO (166) NEXT
DO .1 <- .22
DO (1010) NEXT
PLEASE .22 <- .3
DO .1 <- ,1SUB.22
DO .2 <- #125
PLEASE (1010) NEXT
DO .1 <- '.3~.3'~#1
DO .2 <- #1
DO (1009) NEXT
PLEASE (168) NEXT
DO .1 <- ,1SUB.22
DO .2 <- #123
PLEASE (1010) NEXT
DO .1 <- '.3~.3'~#1
DO .2 <- #1
DO (1009) NEXT
PLEASE (169) NEXT
DO (165) NEXT
(166) PLEASE (167) NEXT
DO RESUME #2
(167) DO RESUME .3
(168) DO (167) NEXT
PLEASE .1 <- .13
DO .2 <- #1
DO (1000) NEXT
DO .13 <- .3
PLEASE RESUME #1
(169) DO (167) NEXT
PLEASE .1 <- .13
DO .2 <- #1
DO (1010) NEXT
DO .13 <- .3
PLEASE RESUME #1
DO NOTE: Check '('.
(170) DO .1 <- ,1SUB.22
DO .2 <- #40
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
DO (1000) NEXT
DO (171) NEXT
DO RESUME #1
(171) DO (172) NEXT
PLEASE .1 <- '.10~.10'~#1
DO .2 <- #1
DO (1009) NEXT
DO (173) NEXT
DO RESUME #2
(172) DO RESUME .3
(173) DO (172) NEXT
PLEASE .13 <- #1
DO (175) NEXT
DO ABSTAIN FROM (175)
DO RESUME #3
(175) PLEASE DON'T FORGET #1
DO REINSTATE (175)
DO .1 <- '.13~.13'~#1
DO .2 <- #1
PLEASE (1009) NEXT
DO (176) NEXT
DO .1 <- .22
DO (1000) NEXT
PLEASE .22 <- .3
DO .1 <- ,1SUB.22
DO .2 <- #40
PLEASE (1010) NEXT
DO .1 <- '.3~.3'~#1
DO .2 <- #1
DO (1009) NEXT
PLEASE (178) NEXT
DO .1 <- ,1SUB.22
DO .2 <- #41
PLEASE (1010) NEXT
DO .1 <- '.3~.3'~#1
DO .2 <- #1
DO (1009) NEXT
PLEASE (179) NEXT
DO (175) NEXT
(176) PLEASE (177) NEXT
DO RESUME #2
(177) DO RESUME .3
(178) DO (177) NEXT
PLEASE .1 <- .13
DO .2 <- #1
DO (1000) NEXT
DO .13 <- .3
PLEASE RESUME #1
(179) DO (177) NEXT
PLEASE .1 <- .13
DO .2 <- #1
DO (1010) NEXT
DO .13 <- .3
PLEASE RESUME #1
DO NOTE: Check 'h'.
(180) PLEASE .1 <- ,1SUB.22
DO .2 <- #104
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
PLEASE (1000) NEXT
DO (181) NEXT
DO RESUME #1
(181) DO (182) NEXT
PLEASE GIVE UP
(182) DO RESUME .3
DO NOTE: Check 'w'.
(190) PLEASE .1 <- ,1SUB.22
DO .2 <- #119
DO (1010) NEXT
PLEASE .3 <- '.3~.3'~#1
DO .1 <- .3
DO .2 <- #1
DO (1000) NEXT
PLEASE (191) NEXT
DO RESUME #1
(191) DO (192) NEXT
DO ,1 <- #13
PLEASE DO ,1 SUB #1 <- #238
DO ,1 SUB #2 <- #108
DO ,1 SUB #3 <- #112
PLEASE ,1 SUB #4 <- #0
DO ,1 SUB #5 <- #64
DO ,1 SUB #6 <- #194
PLEASE DO ,1 SUB #7 <- #48
DO ,1 SUB #8 <- #26
DO ,1 SUB #9 <- #244
PLEASE DO ,1 SUB #10 <- #168
DO ,1 SUB #11 <- #24
DO ,1 SUB #12 <- #16
DO ,1 SUB #13 <- #162
PLEASE READ OUT ,1
(192) DO RESUME .3
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.HashMap;
public class KangarooInterpreter {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<String> code = new ArrayList<>();
HashMap<String, BigInteger> skips = new HashMap<>();
System.out.print("""
Enter your code line by line.
To end code input, type "$END".
""");
while (true) {
String line = scan.nextLine();
if (line.equals("$END")) {
break;
}
code.add(line);
}
int counter = 0;
for (int i = 0; i < code.size(); i++)
skips.put(code.get(i).substring(0, code.get(i).indexOf(":")), BigInteger.ZERO);
while (true) {
String label = code.get(counter).substring(0, code.get(counter).indexOf(":"));
if (skips.get(label).equals(BigInteger.ZERO)) {
if (code.get(counter).matches("[a-z]+: skip ([a-z]+, )+[a-z]+")) {
String[] arguments = code.get(counter).substring(code.get(counter).indexOf(":") + 7).split(", ");
for (int i = 0; i < arguments.length; i++) {
skips.put(arguments[i], skips.get(arguments[i]).add(new BigInteger("1")));
}
}
else if (code.get(counter).matches("[a-z]+: print [a-z]+"))
System.out.println(skips.get(code.get(counter).substring(code.get(counter).indexOf(":") + 8)));
else if (code.get(counter).matches("[a-z]+: input [a-z]+"))
skips.put(code.get(counter).substring(code.get(counter).indexOf(":") + 8), new BigInteger(scan.nextLine()));
else if (code.get(counter).matches("[a-z]+: halt"))
break;
}
else
skips.put(label, skips.get(label).add(new BigInteger("-1")));
counter++;
if (counter >= code.size()) {
counter = 0;
}
}
}
}
I added extra commands to the above implementation, these being: