Home

Awesome

Stack Cats

Stack Cats (abbreviated as SKS) is a stack-based, reversible (esoteric) programming language. It was originally conceived of for a language-design challenge on Code Golf Stack Exchange, but later designed and developed independently of that.

Basics

Every program in Stack Cats is written on a single line, where each character is a command. Being a reversible programming language means that for every command there is a way to undo it. The language is designed such that any snippet of commands can be undone by mirroring it. This means that the string of commands is reversed and all characters that come in symmetric pairs are swapped ((), {}, [], <>, \/). For instance, the snippet >[[(!-)/ undoes the snippet \(-!)]]<. Therefore, Stack Cats programs are made up exclusively of characters which are either self-symmetric (in most fonts) like -_|!:I or which come in pairs, i.e. (){}[]<>\/. Note that from a theoretical standpoint, self-symmetric characters compute involutions, while symmetric pairs compute bijections (and their inverses).

Syntax

As stated above, Stack Cats programs are written on a single line. However, source files may contain additional lines for comments or command-line instructions. Everything starting at the first newline is ignored by the interpreter.

Beyond that there are only two syntactic rules for Stack Cats:

  1. Every valid program must have mirror symmetry. That is, if the entire program is mirrored (see above), it must remain unchanged. This has a few implications. a) Every Stack Cats program computes an involution on the global memory state (since every program is its own inverse). b) Every even-length program computes the identity (i.e. a cat program) provided that it terminates, since the second half undoes the first. c) Every non-trivial program has odd length. If we call the command in the centre of the program A, then every such program has the structure pAq, where p is an arbitrary program and q computes its inverse. Note that A needs to be one of the self-symmetric characters, so it is itself an involution. Hence, programming in Stack Cats is about finding a function p which transforms a very simple involution A into the desired program.
  2. Parentheses, (), and braces, {}, need to be balanced correctly, as they form loops. They can be nested arbitrarily but not interleaved like ({)}. ([] and <> can appear individually and don't need be matched.)

Note that using unknown characters (i.e. any which don't correspond to a command) will result in an error at the start of the program.

Memory model

Stack Cats operates on an infinite tape of stacks. The tape has a tape head which can be moved and points at the "current" stack. Commands tend to operate locally on or near the tape head. The stacks store arbitrary-precision (signed) integers and contain an implicit, infinite amount of zeros at the bottom. Initially, all stacks but the one where the tape head starts are empty (apart from those zeros).

Note that any zeros on top of this implicit pool of zeros are not distinguishable from it by any means. Therefore, in the remainder of this document "the bottom of the stack" always refers to the last non-zero value on the stack.

I/O

To ensure full reversibility, Stack Cats has no I/O commands, as these side-effects cannot be reversed cleanly. Instead, when the program starts, all input (which has to be finite) is read from the standard input stream. A -1 is pushed on the initial stack, and then all the bytes from the input are pushed, with the first input byte on top and the last input byte at the bottom (just above the -1).

At the end of the program (provided it terminates), the contents of the current stack (pointed at by the tape head) are taken modulo 256 and printed as bytes to the standard output stream. Again, the value on top is used for the first byte and the value at the bottom is used for the last byte. If the value at the very bottom is -1, it is ignored. In order to print trailing null bytes you can either put a -1 below them, or you can use any non-zero multiple of 256 which are also printed as null-bytes.

Execution Options

Every specification-compliant interpreter should provide the following options for executing Stack Cats programs:

Commands

In the following section, "the stack" refers to the stack currently pointed at by the tape head, and "the top" refers to the top value on that stack.

Control Flow

Remember that () and {} always have to be balanced correctly.

In summary, () is a loop which is entered and left only when the top is positive, whereas {} is a loop which always iterates at least once and stops when the value from the beginning is seen again at the end of an iteration.

Arithmetic

Stack manipulation

Movement and tape manipulation

Interpreters

This repository contains two reference implementations, one in Python and one in Ruby.

Ruby

The Ruby interpreter can be run as follows:

ruby ./interpreter.rb [options] ./program.sks

It supports the following options:

Options can be combined like -imd.

Python 3

The Python 3 interpreter can be run like the Ruby interpreter:

python3 ./interpreter.py [options] ./program.sks

It has all the options of the Ruby interpreter, plus two extras: