pith

From Esolang
Jump to navigation Jump to search
pith
Paradigm(s) Imperative
Designed by User:ZippyMagician
Appeared in 2021
Memory system Stack
Computational class Turing-complete
Reference implementation pith
File extension(s) .ph


pith is a 3-stack esolang themed around vectors, designed by User:ZippyMagician.

About

pith is a language based around vectors. It features 3 stacks; The left stack I, the right stack J, and the control stack N. Each command is one byte, with two data types also present in the source code. In general, a pith program will look like a sequence of ascii characters, with occasional newlines. All characters not used by pith are ignored, which makes comments using text possible without any delimiter.

Each program written in pith is split into a line-by-line structure, wherein the , operator can jump to various other lines. pith is not space sensitive, but is newline sensitive. If a program reaches the end of a line but hasn't halted, it will move onto the next line. If there is no next line, the program will terminate. Similarly, jumping to a line past the last one will terminate the program.

The two data types found in pith are vectors and floats. Floats are just a 64-bit floating point number as defined by the IEEE 754 standard. A vector is an array of two of these floating point numbers, stylized as [F, F].

Syntax

Since there are a sizable amount of operators, they are separated into different sections. X represents the argument. If an operation takes an argument, it comes after the operator.

Stack operations

Op Arg? Description Notes
= N Construct vector such that the top values of I and J are pushed to N as <I, J> N/A
* N Deconstruct vector such that vector <A, B> sees A being pushed to I and B to J N/A
/ N Pop a value from I and push to J N/A
\ N Pop a value from J and push to I N/A
& Y Duplicate the top vector of N X times. default value of X is 1
^ N Pop top value from I N/A
v N Pop top value from J N/A

Vector operations

Op Arg? Description Notes
: Y Construct vector <A, B> based on argument [A, B] and push to N, or construct vector [M, 0] based on argument M N/A
. N Calculate the dot product of the top two items in N and push to I and J N/A
+ N Add the top two items in N N/A
- N Subtract the top two items in N Given the top of N: [<A, B>, <C, D>], replace with: [<A-C, B-D>]

General math operations

Op Arg? Description Notes
@ N Calculate the sign of the magnitude of the top item in N and push to I and J N/A
% N Deconstruct the top item in N, take the absolute value of both sides, and push to I and J, respectively not affected by $
~ TBD TBD TBD

I/O

Op Arg? Description Notes
N Calculate the magnitude of the top item in N and push to stdout as char N/A
_ N Calculate the magnitude of the top item in N and push to stdout N/A
# Y Pop X vector magnitudes from stdin and reconstruct, pushing to N. default value of X is 1

Control flow

Op Arg? Description Notes
, Y Pop the top vector of N. If its magnitude is 0, jump to line X N/A
! N Halts the program N/A
< N NOP N/A
> N Jump to the matching < N/A

Other

Op Arg? Description Notes
$ N Any operation that pushes the same value to I and J will instead push to one of the following, which cycles on each instance of this op: [I, J, both] N/A

Programs

Cat program

<#&,1_>
!

Truth Machine

#&,1<&_>
_

Hello World

:72|:101|:108&2||:111&|:44|:32|:87||:114||:100|:33|

Division

Only works when the output is a whole number

#2:1*<&*-&,1==:1+*>
==_

Computational Class

pith can be proven to be Turing Complete by translation of the Szewczyk notation for a Minsky Machine. To achieve this, do as follows:

  1. Initialize the program with a line dedicated to :0*, which will push a 0 to both the I and J stacks. Repeat this for the number of registers the program will make use of. Follow it with a :0, and line# of first instruction to avoid running any dedicated lines for jumping.
  2. For each command X -1, add a line which will use = to navigate to desired value to modify, :1+ to increment, and then * to move all reconstructed vectors back into the stack
  3. For each command X Y, add a line which use = to navigate to desired register in stack, &2%=+, followed by DEDICATED LINE #, followed by :1- and then repeated * to move all vectors back to the stack, and then :0, followed by line# + 1

Dedicated lines exist so the stack can still be replaced when this jump occurs. To do this, simply make the line contain * repeated to remove all registers still on the stack, and then :0, followed by Y + 1 + OFFSET where OFFSET is the number of dedicated lines used by jumps. If compiled by hand, you could use the same dedicated line for multiple jumps if they go to the same place.

While bulky and impractical, this is a simple way of proving Turing-completeness, instead of just hand-waving it due to laziness.

Example

1 -1
1 1
1 1

becomes

:0*:0,2              Initialize registers (only one used)
*:0,3                Dedicated line, second and third instructions can share this
=:1+*                  First instruction
=&2%=+,1:1-*:0,4       Second instruction
=&2%=+,1:1-*:0,5       Third instruction

Links