Filth

From Esolang
Jump to navigation Jump to search

Filth (a recursive acronym meaning Filth is [a] Lame Turing Hack) is a lame Turing hack. It is a concept esoteric programming language created by Brandon Zimmerman (User:Dev squid) in 2010, and is inspired by Befunge and Forth. It is based around a hypothetical stack machine (called a 'Filth Machine'). An interpreter was created by User:Madk in July 2010. Another interpreter was created by User:Bananaapple in September 2020.

Style

Filth is a language with somewhat of a personality; that is, it hates you, your mother, your future and/or existing posterity, your cat, and your guts. It forces you, the Filth programmer, to construct arithmetic and bitwise logic statements with only NOR logic. A healthy Filth Machine uses a Harvard architecture; that is, code and data are contained in two separate memory spaces. There is an additional stack called the 'command stack' which can be used to store commands for later execution. What makes Filth unique is that both command and data spaces are stack-based, allowing command-space code to be operated upon exactly like normal stack data. The Filth stacks are LIFO stacks. A Filth Machine's native word size is 8-bits wide; however, to simplify its design, the command stack is based on units of commands, not any particular length of data, much in the same way the base unit in Redcode is a line, not a specific unit of data like a byte. It should also be noted here that the actual code space is not a stack, but is a linear array of read-only instructions.

Syntax

As the result of a syntactical indecision by the author, Filth can have one of two syntaxes: one with a mnemonic-and-operand syntax à la Assembly, and one with single-character operators à la Brainfuck. With the former, code structure is a bit more imposed, whereas with the latter, there are no syntactical rules and foreign characters are ignored, making it easier to write a parser for. For the sake of simplicity, only the latter syntax will be explained here.

Operators

First, to help defining the operators, the notation X has to be defined.

  • X will always denote one hexadecimal character* denoting its hexadecimal value (e.g. A will denote 10).
  • XX will always denote two hexadecimal characters* denoting their hexadecimal value (A0 will denote 160).
  • D denotes a non-zero decimal character denoting its decimal value (e.g. 5 denoting 5).
  • AAA denotes a string of up-to-three alphanumeric characters (a-z, A-Z and 0-9). Case insensitive.

* Both uppercase and lowercase hexadecimal characters can be used

When operators evaluate booleans, by definition any non-zero byte is considered true, and zero is considered false. When operators push booleans to stack, 01(hex) is used as the value for true.

_   - (nop) no operation.
XX  - (push) pushes the literal constant XX or onto the data stack. [push xx]
+   - (dup) duplicates the top byte on the data stack, pushing a copy of the top byte onto the data stack. [pop a, push a, push a]
:D  - (swap) swaps the top two units of size D bytes on the data stack; [pop a, pop b, push a, push b]
;D  - (conditional swap) pops a Boolean value, then swaps the top two units of size D bytes on the data stack if
      the Boolean value is true. [pop a, if a { pop b, pop c, push b, push c }]
$   - (del) discards the top byte from the data stack. [pop a]
@   - (rot) rotates the top three bytes on the data stack, shifting the third-to-last byte to the top of the stack and shifting the
      top two bytes on the data stack down. [pop a, pop b, pop c, push b, push a, push c]
~   - (nor) performs bitwise nor of the top two bytes on the data stack and pushes the result onto the data stack. [pop a, pop b,
      push (a nor b)]
!   - (absolute comp) compares the top two bytes on the data stack; if equal, push Boolean true onto the data stack, otherwise 
      false. [pop a, pop b, push (a == b)]
?   - (relative comp) compares the top two bytes on the data stack; if the second-to-last byte is less than the last byte, push
      Boolean true onto the data stack, otherwise false. [pop a, pop b, push (b < a)]
/C  - (cmd push) pushes the command 'C' onto the command stack.
\D  - (cmd pop) first pops the top D commands from the command stack and then executes them in order.
-C  - (cmd do) executes the command 'C', but operates on the command stack rather than the data stack; valid operands are 
      '_', '+', ':D', ';D', '$', and '@'; any control Booleans are still pushed to and popped from the data stack.
*AAA - (def label) defines the label AAA, holding the current place in the code stream. If label is already defined, 
      it overwrites the existing definition.
^AAA - (jump label) pops a Boolean value, then jumps to the defined label AAA if the Boolean
      value is true. Labels are defined runtime when passing *AAA. If the boolean value is false, 
      the program should not crash if the label does not exist yet.
.   - (output) pop an ASCII value from the data stack and prints it to standard output. [pop a, stdout a]
,   - (input) waits for an ASCII value from standard input and pushes on onto the stack. [stdin a, push a]
#   - (terminate) terminates the program. If it is popped from the command stack using \D, where D > 1 and it would be
      followed by any operations, do not execute the operations after. # must terminate the program immediately.
q   - (quine-ify) print 'q#'.

Furthermore, all listed implementations also support comments that are enclosed by two '|' (pipe) characters.

Computational Class

Currently, no tests have been conducted to test whether or not Filth is Turing-complete, and so will be considered non-computable until further research proves otherwise. Since stack machines and NOR logic can be proven to be Turing-complete, it can be hypothesized that Filth may be Turing-complete.

Examples

Cat:

*lp,.FF^lp#

Hello World:

0021646C726F77202C6F6C+6548*lp+.^lp#

Quine:

q#

Programming in Filth

The notation (x => y) when used in this section means that the code defined here takes x from the stack, and puts y on the stack. x and y may be replaced by a more descriptive label.

Swap organization

Reflect top n (abc...yz becomes zy...cba)

n Filth code
2 :1
3 :1@
4 :1:2:1
5 00:1@@:3:1:2:1$
6 :1@:3:1@
7 00@@:1:2:400:1@@:3:1:2:1$$

Swap top with n-th from top (e.g. if n=4 abcd becomes dbca)

n Filth code
2 :1
3 :1@
4 @:2:1
5 00:3@:3@@:1:2:3@@:3$
6 :3@:3@:2:1:3@@:3
7 00:4@:2:1:4@@00:3@:3@@:1:2:3@@:3$@:4@:2:1:4$

Boolean operations

For use in this section three different boolean notations will be distinguished:

  • Filth booleans (FB) (00 is false, all other is true; this is how Filth commands such as jump label accept boolean input)
  • Strict filth booleans (SFB) (00 is false, 01 is true, other bytes invalid; This is how Filth commands give output)
  • Last-bit booleans (LBB) (in each byte, if the last bit is 0 (the byte is even), it is false, if the last bit is 1 it is true; this is just defined for use in this section)

Please note that converting strict filth booleans to filth booleans is automatic, and converting strict filth booleans to last bit booleans is automatic too. Hence, if we can convert to strict filth booleans, those strict filth booleans can be used as input to any command/function needing any of the three as input.

Conversion from Last-bit booleans to strict filth ones

FE~FE~

Conversion from filth booleans to strict filth ones

00!FE~

Boolean NOT (LBB => LBB)

FE~

Boolean OR (LBB, LBB => LBB)

~FE~

Boolean AND (LBB, LBB => LBB)

FE~:1FE~~

Boolean NOR (LBB, LBB => LBB)

~

External resources

Interpreters:

Download interpreter Specifics:

  • Written in a variant of BlitzBasic
  • Source-available, binary available for Microsoft Windows
  • Supports comments


Newer interpreter Specifics:

  • Written in nim
  • FOSS (License: The Unlicense)
  • Comments and debugging
  • Error handling