Eniuq

From Esolang
Jump to navigation Jump to search

Eniuq is a stack- and queue-based esoteric programming language in which it is impossible to write nontrivial quines, but flow control is done by the methods normally used for quines. It was invented by Edward Cree.

This is because the "output" operators actually append to the program stream (the 'queue' in eniuq terminology); the only way to output something is to encounter an invalid operator.

All operators are single characters, but not all characters are operators; those that are not will be output and otherwise have no effect.

All values are 32-bit unsigned integers.

Eniuq has no built-in facilities for named variables, procedures, or functions.

Operators

The operators are:

+ - * / arithmetic; 31- becomes 2 (not 232-2).
& | ^ bitwise
0-9 integer literals
! NOT; maps 0 to 0xffffffff, anything else to 0
? read an integer from input
~ reverse the order of the entire stack
d duplicate bottom stack element
D duplicate N elements, eg. {2 1 4 5 ...} -> {1 4 1 4 5 ...}
f fetch an element out of the stack, eg. {2 1 4 ...} -> {4 1 4 ...} because the 2nd element was 4
k discard bottom stack element
K discard N elements, eg. {2 1 4 5 ...} -> {5 ...}
o output a number (as a char). It is not sent to stdout, but rather appended to the queue.
O output N elements (as chars), eg. {2 `A `B `C ...} -> {`C} and appends AB to the queue.

There is a preprocessor, epp, which encodes backtick (`) followed by any character to something that will store that character on the stack. So, for instance, `O becomes 89*7+. Also, any text enclosed in "double quotes" is converted into reversed backtick form; thus 4"32"1 is equivalent to 4`2`31.

Quines

Any program which does not contain any operators is trivially a quine; for instance, while we can't write a Hello World program (because o and d, being operators, can't be output), we can write the following:

'Sup, Earth

This is a quine, because none of its constituent characters is a valid operator, so each is written to stdout with no side-effects.

No program containing operators is a quine.

Flow Control

It's quite difficult to do flow control, because there aren't any conditional statements. What you typically have to do is have your actual program code on the stack, and then compute bits of your program, write them to the queue, and thus have them executed. So, a simple loop would be:

`O`5`D`5`A5D5O

This prints an infinite sequence of AAAAAAAAAAAAAAAAAAAAA...

A more sophisticated loop, with a termination condition, appears in "unary.en", which nukes the loop body code with a `K' when the termination condition is true (that is, when the loop counter reaches zero), and otherwise reiterates it with an `O'.

Computational class

By using an encoding in which strings are encoded in length-prefixed form, four of the instructions of Underload can be directly encoded into Eniuq:

  • :: 1D1+D (i.e. duplicate the length of the top string on the stack, add 1 to get the length of the string with included length, then duplicate that many elements)
  • !: K
  • (literal): code that pushes the character codes of each element of onto the stack in reverse order, then its length (this works recursively, although doing so will involve an additional layer of "translate a character code into an expression that produces it" each time)
  • ^: O

Although several of Underload's instructions are not so easy to implement in Eniuq (especially a), the instructions :!()^ turn out to form a Turing-complete subset (specifically, one that can encode arbitrary Minsky machines). See Underload § :!()^ Minsky machine for details.

Implementation

The interpreter can be found here (Version 0.3, source tarball).

The tarball also contains documentation and some sample programs (of sharply limited utility).

Implementation Limits

The stack is limited to 256 items, and the queue to 1024 instructions. Overflowing either of these limits produces a runtime error; for example, try running qoverrun.enp, which is designed to produce a queue overrun: each time it executes one 8D8O, it queues two more of them.

Interpreter Usage

To run an .enp file, use ./eniuq foo.enp [-d]. The switch -d enables debugging output; it's rather voluminously verbose.

To preprocess an .en file, use ./epp <foo.en >foo.enp.