Esolang spec
Esolang spec is an esolang invented by User:None1. Programs in this esolang are like specifications of esolangs.
Program structure
A program must be like this:
(header) ==Memory== (variable definition) ==Commands== (command 1) (command 2) ...
This esolang is case-insensitive. All whitespaces are mandatory.
Section 1: header
It must be like this:
esolang name is an esolang invented by name.
For example:
ABCD is an esolang invented by EFG.
This section has no effect, but it is mandatory.
Section 2: memory
This section defines variables, which are unbounded signed integers. Only these variables can be defined: stack, queue, accumulator and tape.
This section must be like this:
This esolang has a/an variable 1, a/an variable 2,... and a/an variable n.
and is not needed when there's only one variable. You must define at least one variable.
For example:
This esolang has a stack.
Or:
This esolang has a stack, a queue, an accumulator and a tape.
There's also a temporary variable t, but you can't access it directly.
Section 3: commands
This is the main part of the program. Each line is an instruction, which must be like this:
* command name: behavior.
The command name has no effect except for being a label. It's case-insensitive and must be at least 1 character. The behavior decides what this command does. The period at the end is not mandatory.
The following table shows all valid behaviors.
| Meaning\Operating variable | Stack/Queue top | Accumulator | Tape |
|---|---|---|---|
| t=n (n∈Z) | Take n | Take n | Take n |
| t=ov | Pop stack/queue | Get value of accumulator | Get value of current cell |
| ov=t | Push (it) into stack/queue | Store (it) in the accumulator | Store (it) in current cell |
| Read integer input and store in t | Read an integer | Read an integer | Read an integer |
| Print the value of t as integer | Print (it) as an integer | Print (it) as an integer | Print (it) as an integer |
| Read ASCII character input and store in t | Read a character | Read a character | Read a character |
| Print the value of t as an ASCII character | Print (it) as an ASCII character | Print (it) as an ASCII character | Print (it) as an ASCII character |
| ov+=t | Add stack top/queue front by it | Add accumulator by it | Add current cell by it |
| ov*=t | Multiply stack top/queue front by it | Multiply accumulator by it | Multiply current cell by it |
| Print "string" | Print "string" | Print "string" | Print "string" |
| If ov is nonzero | If stack/queue is nonempty, | If accumulator is nonzero, | If current cell is nonzero, |
| If ov is zero | If stack/queue is empty, | If accumulator is zero, | If current cell is zero, |
| Jump to label | Jump to matching label | Jump to matching label | Jump to matching label |
| &ov++ (& is the address operator) | Duplicate top of stack/push a copy of queue front at queue back | (TBD) | Move the tape pointer 1 cell right |
| &ov-- | Discard top of stack/queue | (TBD) | Move the tape pointer 1 cell left |
(Any it's in brackets can be omitted; Any it's can be substituted with a literal integer n, which sets t to n before operation.)
You can use , or and to concatenate multiple behaviors, e.g.:
* a: Read an integer, store in the accumulator.
Or:
* a: Read an integer and store in the accumulator.
Both will read an integer and then store it in the variable "accumulator".
Examples
Hello, world!
h is an esolang invented by w. ==Memory== This esolang has a stack. ==Commands== * h: Print "Hello, world!"
Truth machine
t is an esolang invented by m. ==Memory== This esolang has an accumulator. ==Commands== * a: Read an integer and store in the accumulator. * b: Get value of accumulator, print it as an integer. * c: If accumulator is nonzero, jump to matching b.
Compiler to C++
Fuck, that was hard to make. ~ User:Cleverxia
This interpreter features unofficial behaviors like the inline "while" loop, multiple data structures, randomness, etc.
code=`Input code here`
c=`#include<bits/stdc++.h>
using namespace std;
#define int int64_t
struct tape{int64_t c[1000005],p=500000;void r(){p++;}void l(){p--;}int g(){return c[p];}void s(int a){c[p]=a;}};
`;let [s1,s2,s3,s4]=code.replaceAll(/[[Category:.+]]/g,'').split(/==[CMademnorsy]+==/)
if(s4)throw "compilation error: unexpected section"
if(!s2||!s1)throw "compilation error: section missing"
if(!/^.+ is an esolang invented by .+\.?\n$/.exec(s1))throw `compilation error: section 1 does not comply to specification`
if(!(Q=[...s2.matchAll(/(an?|\d+) (stack|queue|accumulator|tape)/g)]).length)throw `compilation error: section 2 does not comply to specification`
T=[0,0,0,0]
for(i of Q[0])T[{stack:0,queue:1,accumulator:2,tape:3}[i.split` `[1]]]+=+i.split` `[0]||1;
c+=`#define STACK_MAX ${T[0]}
#define QUEUE_MAX ${T[1]}
#define ACCU_MAX ${T[2]}
#define TAPE_MAX ${T[3]}
tape t[${T[3]||1}];int r[${T[2]||1}],T,_,ct,cr,cq,cs;
mt19937 rnd(std::chrono::steady_clock::now().time_since_epoch().count())RAND;
queue<int>q[${T[1]||1}];stack<int>s[${T[0]||1}];int main(){`;function $(t){return'L'+[...t].map(x=>x.charCodeAt()+9).join`_`};for(i of s3.split`
`)if(i){
if(!(Q=/\*\s+(\S+)\s*:\s*(.+?)\s*.?$/.exec(i)))throw `compilation error: section 3 does not comply to specification at line ${JSON.stringify(i)}`;let[JUNK,L,Z]=Q;L=$(L);Z=Z.split(/\s*(?:,|\sand\s)\s*/).map(e=>e.toLowerCase())
let ic='',tic='';
for(j of Z)if(j=j.trim())
if(j===('read an integer'))ic+=`cin>>T;`;else
if(j===('read a character'))ic+=`T=getchar();`;else
if(j.startsWith('take '))ic+=`T=${j.substr(5)};`;else
if(j===('add accumulator by it'))ic+=`r[cr]+=T;`;else
if(j===('get value of accumulator'))ic+=`T=r[cr];`;else
if(j===('discard top of stack'))ic+=`s[cs].pop();`;else
if(j===('pop stack'))ic+=`T=s[cs].top();s[cq].pop();`;else
if(j===('pop queue'))ic+=`T=q[cq].top();q[cq].pop();`;else
if(j===('multiply accumulator by it'))ic+=`r[cr]*=T;`;else
if(j==='switch to next tape')ic+='ct++;ct%=TAPE_MAX;';else
if(j===('get value of current cell'))ic+=`T=t[ct].g();`;else
if(j==='switch to next stack')ic+='cs++;cs%=STACK_MAX;';else
if(j==='switch to next queue')ic+='cq++;cq%=QUEUE_MAX;';else
if(j===('discard top of queue front'))ic+=`q[cq].pop();`;else
if(j==='switch to next accumulator')ic+='cr++;cr%=ACCU_MAX;';else
if(j===('add current cell by it'))ic+=`t[ct].s(t[ct].g()+T);`;else
if(j===('move the tape pointer 1 cell left'))ic+=`t[ct].l();`;else
if(j===('move the tape pointer 1 cell left'))ic+=`t[ct].r();`;else
if(j===('if accumulator is zero'))ic+=`if(!r[cr])goto ${L}end;`;else
if(j===('if stack is empty'))ic+=`if(s[cs].size())goto ${L}end;`;else
if(j===('if queue is empty'))ic+=`if(q[cq].size())goto ${L}end;`;else
if(j===('duplicate top of stack'))ic+=`s[cs].push(s[cs].top());`;else
if(j===('if accumulator is nonzero'))ic+=`if(r[cr])goto ${L}end;`;else
if(j==='push a random integer to stack')ic+=`s[cs].push(RAND());`;else
if(j==='push a random integer to queue')ic+=`q[cq].push(RAND());`;else
if(j==='assign a random integer to register')ic+=`r[cr]=(RAND());`;else
if(j===('multiply current cell by it'))ic+=`t[ct].s(t[ct].g()*T);`;else
if(j==='switch to previous tape')ic+='ct+=TAPE_MAX-1;ct%=TAPE_MAX;';else
if(j.startsWith('jump to matching '))ic+=`goto ${$(j.substr(17))};`;else
if(j===('if stack is nonempty'))ic+=`if(s[cs].empty())goto ${L}end;`;else
if(j===('if queue is nonempty'))ic+=`if(q[cq].empty())goto ${L}end;`;else
if(j===('if current cell is zero'))ic+=`if(!t[ct].g())goto ${L}end;`;else
if(Q=/push (-?\d+) into stack/.exec(j))ic+=`s[cs].push(${Q[1]||0});`;else
if(Q=/push (-?\d+) into queue/.exec(j))ic+=`q[cq].push(${Q[1]||0});`;else
if(Q=/print (-?\d+) as an integer/.exec(j))ic+=`cout<<(${Q[1]||0});`;else
if(j.startsWith('print')&&~j.indexOf('"'))ic+=`cout<<${j.substr(5)};`;else
if(j===('if current cell is nonzero'))ic+=`if(t[ct].g())goto ${L}end;`;else
if(Q=/add accumulator by (-?\d+)/.exec(j))ic+=`r[cr] +=( ${Q[1]||0});`;else
if(j==='switch to previous stack')ic+='cs+=STACK_MAX-1;cs%=STACK_MAX;';else
if(j==='switch to previous queue')ic+='cq+=QUEUE_MAX-1;cq%=QUEUE_MAX;';else
if(j==='assign a random integer to current cell')ic+=`t[ct].s(RAND());`;else
if(j===('push it into stack')||j==='push to stack')ic+=`s[cs].push(T);`;else
if(Q=/store (-?\d+) in current cell/.exec(j))ic+=`t[ct].s(${Q[1]||0});`;else
if(j===('push it into queue')||j==='push to queue')ic+=`q[cq].push(T);;`;else
if(Q=/store (-?\d+) in the accumulator/.exec(j))ic+=`r[cr]=(${Q[1]||0});`;else
if(j==='switch to previous accumulator')ic+='cr+=ACCU_MAX-1;cr%=ACCU_MAX;';else
if(Q=/multiply accumulator by (-?\d+)/.exec(j))ic+=`r[cr] *=( ${Q[1]||0});`;else
if(j===('print as an integer')||j==='print it as an integer')ic+=`cout<<(T);`;else
if(Q=/print (-?\d+) as an ascii character/.exec(j))ic+=`putchar(${Q[1]||0});`;else
if(j===('add stack top by it'))ic+=`_=T+s[cs].top();s[cs].pop();s[cs].push(_);`;else
if(Q=/add current cell by (-?\d+)/.exec(j))ic+=`t[ct].s(t[ct].g()+ ${Q[1]||0});`;else
if(j===('add queue front by it'))ic+=`_=T+q[cq].front();q[cq].pop();q[cq].push(_);`;else
if(j===('multiply stack top by it'))ic+=`_=T*s[cs].top();s[cs].pop();s[cs].push(_);`;else
if(j===('store it in current cell')||j==='store in current cell')ic+=`t[ct].s(T);;;`;else
if(j===('push a copy of queue front at queue back'))ic+=`q[cq].push(q[cq].front());`;else
if(Q=/multiply current cell by (-?\d+)/.exec(j))ic+=`t[ct].s(t[ct].g()* ${Q[1]||0});`;else
if(j===('multiply queue front by it'))ic+=`_=T*q[cq].front();q[cq].pop();q[cq].push(_);`;else
if(j===('store in the accumulator')||j==='store it in the accumulator')ic+=`r[cr]=(T);;`;else
if(j===('while accumulator is zero'))ic+=`if(!r[cr])goto ${L}end;`,tic=`if(r[cr])goto ${L};`;else
if(j===('print as an ascii character')||j==='print it as an ascii character')ic+=`putchar(T);`;else
if(j===('while accumulator is nonzero'))ic+=`if(r[cr])goto ${L}end;`,tic=`if(!r[cr])goto ${L};`;else
if(Q=/add stack top by (-?\d+)/.exec(j))ic+=`_=s[cs].top();s[cs].pop();s[cs].push(_+ ${Q[1]||0});`;else
if(j===('while stack is empty'))ic+=`if(s[cs].size())goto ${L}end;`,tic=`if(s[cs].empty())goto ${L};`;else
if(j===('while queue is empty'))ic+=`if(q[cq].size())goto ${L}end;`,tic=`if(q[cq].empty())goto ${L};`;else
if(j===('while current cell is zero'))ic+=`if(!t[ct].g())goto ${L}end;`,tic=`if(t[ct].g())goto ${L};`;else
if(Q=/add queue front by (-?\d+)/.exec(j))ic+=`_=q[cq].front();q[cq].pop();q[cq].push(_+ ${Q[1]||0});`;else
if(Q=/multiply stack top by (-?\d+)/.exec(j))ic+=`_=s[cs].top();s[cs].pop();s[cs].push(_* ${Q[1]||0});`;else
if(j===('while stack is nonempty'))ic+=`if(s[cs].empty())goto ${L}end;`,tic=`if(s[cs].size())goto ${L};`;else
if(j===('while queue is nonempty'))ic+=`if(q[cq].empty())goto ${L}end;`,tic=`if(q[cq].size())goto ${L};`;else
if(j===('while current cell is nonzero'))ic+=`if(t[ct].g())goto ${L}end;`,tic=`if(!t[ct].g())goto ${L};`;else
if(Q=/multiply queue front by (-?\d+)/.exec(j))ic+=`_=q[cq].front();q[cq].pop();q[cq].push(_* ${Q[1]||0});`;else tic+=`/*Comment: ${j}*/
`
c+=`${L}:${ic}
;${L}end:${tic};`
//console.log(Z,L,c);
}
console.log(c,'return 0',';}')