Esoasm
One thing that there is is a distinct lack of is C compilers to esolangs. People have made like ten million C compilers to x86, but not to esolangs. So, I made an assembly language designed to serve as a programming language that can easily be interpreted by a esolang with addressable memory but without free jumps (because you can’t directly implement functions without jumps) so that you can compile C to this assembly language, assemble it, and translate the binary into something that you can easily run in said esolang
Spec
SET
ADD
SUB
MUL
GETMEM
SETMEM
BRANCH
INPUT
OUTPUT
LABEL
Total of 14 op-codes
SET $1 10: var1 = 10; op code 0
SET $1 $2: var1 = var2; op code 1
ADD $1 10: var1 += 10; op code 2
ADD $1 $2: var1 += var2; op code 3
SUB $1 10: var1 -= 10; op code 4
SUB $1 $2: var1 -= var2; op code 5
MUL $1 10: var1 *= 10; op code 6
MUL $1 $2: var1 *= var 2; op code 7
GETMEM $1 $2: var1 = *var2; op code 8
SETMEM $1 $2: *var1 = var2; op code 9
BRANCH $1 %START: if (var1 >= 0){goto START;}; op code 10
BRANCH $1 $2: if (var1 >= 0){goto *var2;}; op code 11
INPUT $1: var1 = getchar(); op code 12
OUTPUT $1: putchar(var1); op code 13
LABEL START: create a label named START pointing to the next line by replaces each instance of %START in the code with the line number of the next line; no op code, because it is purely for the assembler
Assembler
Returns a list, filled with lists of the bytecode of each line.
function assemble(asm_code) { let bin_code = []; let lineNum = 0; let OPS = ["SET", "ADD", "SUB", "MUL", "GETMEM", "SETMEM", "BRANCH", "INPUT", "OUTPUT"]; for (let line of asm_code.split("\n")) { let parts = line.split(" "); if (OPS.includes(parts[0])) { lineNum++; } else if (parts[0] == "LABEL") { asm_code = asm_code.split(`%${parts[1]}`).join(lineNum); } } for (let line of asm_code.split("\n")) { let nextLine = [-1, 0, 0]; let parts = line.split(" "); if (parts[0] == "SET") { nextLine[0] = 0; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2]; if (parts[2][0] == "$"){ nextLine[0]++; nextLine[2] = parts[2].slice(1); } } else if (parts[0] == "ADD") { nextLine[0] = 2; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2]; if (parts[2][0] == "$") { nextLine[0]++; nextLine[2] = parts[2].slice(1); } } else if (parts[0] == "SUB") { nextLine[0] = 4; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2]; if (parts[2][0] == "$") { nextLine[0]++; nextLine[2] = parts[2].slice(1); } } else if (parts[0] == "MUL") { nextLine[0] = 6; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2]; if (parts[2][0] == "$") { nextLine[0]++; nextLine[2] = parts[2].slice(1); } } else if (parts[0] == "GETMEM") { nextLine[0] = 8; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2].slice(1); } else if (parts[0] == "SETMEM") { nextLine[0] = 9; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2].slice(1); } else if (parts[0] == "BRANCH") { nextLine[0] = 10; nextLine[1] = parts[1].slice(1); nextLine[2] = parts[2]; if (parts[2][0] == "$") { nextLine[0]++; nextLine[2] = parts[2].slice(1); } } else if (parts[0] == "INPUT") { nextLine[0] = 12; nextLine[1] = parts[1].slice(1); } else if (parts[0] == "OUTPUT") { nextLine[0] = 13; nextLine[1] = parts[1].slice(1); } if (nextLine[0]>=0) bin_code.push(nextLine); } return bin_code; }