Overview

Underload is a Turing-complete stack based programming language. Elements on the stack are of variable length and manipulated by a set of eight instructions.

Instruction set

InstructionDescription
~exchange the top two elements
:duplicate the top element
!discard the top element
*concatenate the top element to the end of the second element
aenclose the top element in parentheses
Soutput the top element then discard it
^remove the top element then execute it
( )add a new element containing everything between the parentheses

Example Programs

Hello, World!

A simple program to demonstrate output in Underload:

(Hello, World!)S

First (Hello, World!) adds a new element containing “Hello, World!” to the stack. Next, S displays and discards the element.

Quine

A quine is a program which outputs its own source code:

(:aSS):aSS

First (:aSS) adds a new element containing “:aSS” to the stack:

:aSS

Then : duplicates the top element. The new top element is to the right:

:aSS:aSS

Next a encloses the top element in parentheses:

:aSS(:aSS)

Finally SS will display and discard the top two elements.

Implemention in Redcode

        org    underl

        stack  equ (ip-1)

ip      dat    prog,      prog

exec    mov    >ip,       <stack    ; ^
        jmn    exec,      @stack
        add    #1,        stack
efind   jmn    efind,     >stack
        mov.ba stack,     stack
        sub.a  #1,        stack
        mov    #prog-ip,  ip
        mov.a  #prog-ip,  ip
ecopy   mov    {stack,    }ip
        jmn    ecopy,     *stack
        jmp    underl

enclose sub    #2,        stack     ; a
        mov.ba stack,     stack
        mov    #41,       *stack
eloop   add.a  #2,        stack
        mov    *stack,    {stack
        jmn    eloop,     *stack
        mov    #40,       *stack
        jmp    underl

swap    jmn    swap,      }stack    ; ~
sfinda  jmn    sfinda,    }stack
        mov    {stack,    <stack
scopy   mov    {stack,    <stack
        jmn    scopy,     @stack
        mov.ab stack,     stack
        add    #1,        stack
sfindb  jmn    sfindb,    >stack
        sub    #1,        stack
scopyb  mov    {stack,    <stack
        jmn    scopyb,    @stack
        jmp    dcopy

push    nop    <stack,    >pcount   ; ()
pcopy   mov    >ip,       <stack
        sne    #41,       @stack
        sub    #1,        pcount
        sne    #40,       @stack
        jmp    pcopy,     >pcount
pcount  jmn    pcopy,     #0
        jmp    underl,    >stack

concat  jmn    concat,    >stack    ; *
cloop   sub    #2,        stack
        mov    >stack,    @stack
        jmn    cloop,     @stack
        jmp    underl,    >stack

output  sne    #0,        >stack    ; S
        jmp    underl
ofind   jmn    ofind,     >stack
        mov.ba stack,     stack
        sub.a  #2,        stack
oloop   sts    *stack,    0
        jmn    oloop,     {stack
        jmp    underl

duplic  jmn    duplic,    }stack    ; :
        mov    {stack,    <stack
dcopy   mov    {stack,    <stack
        jmn    dcopy,     @stack

drop    jmn    drop,      >stack    ; !

underl  sne    #33,       @ip
        jmp    drop,      >ip
        sne    #94,       @ip
        jmp    exec,      >ip
        seq    #97,       @ip
        sne    #65,       @ip
        jmp    enclose,   >ip

        mov.ba stack,     stack

        sne    #58,       @ip
        jmp    duplic,    >ip
        sne    #126,      @ip
        jmp    swap,      >ip

        mov    #0,        <stack
        add    #1,        stack

        sne    #40,       @ip
        jmp    push,      >ip
        sne    #42,       @ip
        jmp    concat,    >ip
        seq    #115,      @ip
        sne    #83,       @ip
        jmp    output,    >ip

prog