Surtic

From Esolang
Jump to navigation Jump to search

Surtic ("Sir Chick") is an esoteric programming language created by User:Digital Hunter with help from User:Galaxtone. "Surtic" is "citrus" spelled backwards, with some artistic liberty taken in its pronunciation.

Feel free to provide feedback or suggestions on the talk page.

Language basics

There are three variable groups for holding information (Group C, S or B)

Whitespace is ignored for instructions, but must be preserved within strings.

Surtic supports basic logic flow structures and traditional operations, but creative solutions must be used for basic maths operations (examples demonstrating this at the bottom of the page).

If an invalid instruction sequence is encountered, then consequences are left to whoever wrote the compiler.

There's no official way to write in comments, but {}{ example text here } may be used. Essentially, the first else block ensures that no other logic blocks will be run until a new if block, so the text within the second pair of brackets will be ignored. Being careful, all comments that come afterward can be written within an independent block. Do note, writing comments in this way does not come consequence-free, as the else blocks count as instructions.

Instruction syntax

All letters are case-insensitive (you can use capital and lowercase interchangeably).

# refers to any whole number.

{...} refers to one or more of something.

<cell> refers to C# for referencing a number variable, # must be greater than or equal to zero.

<bool> is the same as <cell> except for boolean variables (1s and 0s).

<str> is the same as <cell> except for string variables ('word's and 'bird's).

<equality> refers to == for equal to or != for not equal to.

<comparison> refers to < for less than, > for greater than, <= for less than or equal to, >= for greater than or equal to, or <equality>.

<bool comparison> refers to & for AND (If both booleans are true), | for OR (If either boolean is true), ^ for XOR (true iff they have opposite values).

'...' refers to an ASCII string value, containing any characters, using \ to escape characters, you cannot have have a string across multiple lines, newlines must be escaped using \n. Surtic does not use double quotes.

Escape Sequences

Sequence Value
\' '
\\ \
\n The ASCII character for newline. (10)

Variable groups

C

Cell variable group, Each variable contains an unbounded integer, with the default value of zero.

Instruction Description
<cell>{+} Increment the referenced cell variable by the number of plus symbols.
<cell>{-} Decrement the referenced cell variable by the number of hyphen symbols.
I<cell> Take a UTF-8 character from input and store in the referenced cell variable as a number. (Only the character shall be written to standard output followed by newline.)
O<cell> Take the number in the referenced cell variable (Mod 65536) and output it as a character. (Only the character shall be written to standard output.)
NI<cell> Take a number from input and store in the referenced cell variable. (Input shall be written to standard output as numbers are typed and deleted, followed by a newline.)
NO<cell> Take the number in the referenced cell variable and output it. (Only the number shall be written to standard output.)
R<cell>(<cell>:<cell>) Generate a random integer between the lesser of the values of the two cells in parentheses with the greater of the two values (inclusive) and store this integer in the first cell.
J<cell> Take the number in the referenced cell variable and jump execution ahead (or behind) by that number of instruction statements (program will halt if you jump outside of the program). More specific information on how this works exactly, later.

B

Boolean variable group, Each variable contains a boolean value (either true or false), with the default value of false.

Instruction Description
!<bool> Invert the referenced boolean variable.
?<bool>(<cell><comparison><cell>) Compare the 1st referenced cell variable and 2nd referenced cell variable and store the result in the referenced boolean variable.
?<bool>(<str><equality><str>) Compare the 1st referenced string variable and 2nd referenced string variable and store the result in the referenced boolean variable.
?<bool>(<bool><bool comparison><bool>) Compare the 2nd referenced boolean variable and 3rd referenced boolean variable and store the result in the 1st referenced boolean variable.

S

String variable group, Each variable contains a UTF-8 string value, with the default value of an empty string.

Instruction Description
K<str>:<str> Concatenate the 2nd referenced string variable to the end of the 1st referenced string variable and store it in the 1st referenced string variable.
<str>'...' Stores the string value within the referenced string variable.
I<str> Take in a string value from input and store it in the referenced string variable. (Input shall be written to standard output followed the rules for displaying unicode characters as shown in '...' as characters are typed and deleted, followed by a newline afterwards.)
O<str> Take the string value in the referenced string variable and output it. (Only the characters of the string are written to standard output.)
L<cell>:<str> Set the referenced cell variable to the length of the referenced string variable.
G<cell>:<str>(<cell>) "Get" the value of the character in the string with index specified by the cell in parentheses and put this value into the first cell. (If the index is not within the range from 0 to the length of referenced string variable then -1 is used instead.)
P<cell>:<str>(<cell>) "Put" the value of the first cell as a character into the string at the index specified by the cell in parentheses. (If the index is less than zero, do nothing. If the index is greater than the length of the string append the character to the end.)

Logic flow

Loop statements

Instruction Description
F<cell>[ Take the number in the referenced cell variable and execute the code within the block that many times. (Does not do anything if the number is less than or equal to zero)
W<cell>[ Take the number in the referenced cell variable and execute the code within the block until the number is less than or equal to zero.
W<bool>[ Execute the code within the block until the referenced boolean variable is false.

] ends a loop.

Conditional statements

Note: Nothing requires that an if code block must be written together (there can be else-ifs and elses dispersed throughout a program after their parent if block)

Instruction Description
I<bool>{ If the referenced boolean variable is true then execute the code within the block.
<bool>{ If previous if statements have failed and the referenced boolean variable is true then execute the code within the block.
{ If previous if statements have failed then execute the code within the block.

} ends a conditional block.

Program halt

Program execution finishes when a ~ is encountered, or when there is no more code to be read (EOF).

Advanced techniques

If you intend to use Surtic to solve more tricky problems or to do specific tasks, it is important to fully understand the nuances and capabilities of Surtic's available commands.

Using the jump instruction

Earlier, it was promised that this specific item would be explained in further detail. This is because there can be ambiguity in the meaning of an "instruction", and in where counting starts. An instruction in Surtic is defined, simply enough, as any one of the instructions listed above. Thus, there is an important difference between writing c0++ and c0+c0+, as long as you are working with the jump command in your code. The jump command only sees other instructions that are on the same nesting level as it, i.e., a jump instruction in the main body of your code will ignore instructions inside of conditional statements and loops, and a jump instruction inside of one of those blocks can only see the instructions inside there with it.

When the jump instruction is called to navigate the program, each instruction that the jump command can "see" is labelled with an integer index, where positive numbers come later in the code, negative numbers come prior, and the jump instruction itself is indexed zero. The value of the cell called is then used as the index that is "jumped" to. Be careful, because a cell with a value of zero is an inescapable infinite loop, as are negatively-valued cells if there is nothing within that span of code that can lead to an exit condition.

Defining and using functions

Using the jump instruction and careful planning, functions/macros can be described in your Surtic programs. The most effective use of functions is if you, in a very complicated program, have a significant amount of repeated code for performing the same operation on various variables (just like using functions in any other language).

One first step would be to have a dedicated c-variable for all your jump instructions to handle. The actual functions themselves should be written after the bulk of your code, separated with a ~. Set aside a few fodder variables of each type that should be sufficient for each function you plan to implement, and each function should start with a few instructions to set their values to those you wish to manipulate. The function will then do its thing, and be finished with instructions to return the values to the original variables. Whichever c-variable was set aside for jump instructions should then have its value increased by the number of instructions in the function (plus at least one more, to account for this step, then minus another one to make sure you don't land back on the original jump), and instruction flow should be sent back to where it was before the jump, with the appropriately altered variable states.

This is a garbage explanation, so an example program demonstrating what all this means will come in time.

Computational class

It has long been a dream of mine to demonstrate Surtic's Turing-completeness. One method of proof is to realise that programs written in brainfuck can be translated somewhat effectively to Surtic, with some limitations that will be explained.

BF instruction Demonstratably equivalent Surtic code
> c0+
< c0-
+ gc1:s0(c0)c1+pc1:s0(c0)
- gc1:s0(c0)c1-pc1:s0(c0)
. gc1:s0(c0)fc2[c1-]oc1
, ic1fc2[c1+]pc1:s0(c0)
[ gc1:s0(c0)?b0(c1==c2)wb0[
] gc1:s0(c0)?b0(c1==c2)]

So, what is all this? I use s0 to represent the tape, c0 is the pointer position, c1 is whatever value is being manipulated at any point, b0 is just a helpful boolean, and c2 represents everything that's been holding me back from doing this for so long.

The biggest problem with using a string to hold numerical data is that many characters are nonprinting, or could behave in interesting ways that would make this annoying. Thus, c2 represents an offset, a new "zero", that gets around this. Initialising c2 with the numerical value 32 for example means that a space character in s0 is treated as equivalent to a 0 stored in the tape. Since storing numbers in this way is limited by the ASCII character set and by this self-imposed limitation, only numbers from 0 to 95 can effectively be used with this translation. Unfortunately, this does mean that lowercase letters are out of the question, along with a few others, but this is irrelevant to the initial goal.

Strings in Surtic can be made arbitrarily long. This means that, if s0 is initialised full of spaces and made as long as necessary for the needs of the BF program to be translated, the BF code theoretically has access to an unbounded tape. BF is Turing-complete if the tape is unbounded even if the cell values are severely limited, and Surtic, by equivalence to this instance of BF, is therefore also Turing-complete.

Example programs

Programs solving popular problems and/or demonstrating ways to do some common tasks.

Note: all Surtic programs are expected to halt execution once the end of a program is reached.

Hello, world!

S1'Hello, world!\n'OS1

Or, without the use of strings,

c0++++++++fc0[c1++++fc1[c1-c2++c3+++c4+++c5+]c0-c2+c3+c4-c6+]oc2c3---oc3c3+++++++oc3oc3c3+++oc3oc5c4-oc4oc3c3+++oc3c3------oc3fc6[c3-]oc3c5+oc5c6++oc6

Infinite Cat

S1'\n'!B1WB1[IS2OS2OS1]

Fibonacci sequence

C1+C2+!B1WB1[NOC1FC2[C3+]FC1[C1-C2+]FC3[C3-C1+]]

Factorial

S1'Factorial: 'S2'Factorial of 'S3' is 'S4'.\n'OS1NIC1C1-C2+FC1[C3+FC2[FC3[C2+]]]OS2C1+NOC1OS3NOC2OS4

99 bottles of beer

S1' bottle'S2's'S3' of beer'S4' on the wall'S5','S6'\n'S7'.'S8'Take one down, pass it around'S9'No'S10'Go to the store, buy some more'C1+++++FC1[C1++++]FC1[C1+++]C1-FC1[C2+]C3++!B1WB1[NOC1OS1OS2OS3OS4OS5OS6NOC1OS1OS2OS3OS7OS6OS8OS5OS6C1-NOC1OS1OS2OS3OS4OS7OS6OS6?B1(C1>C3)]NOC1OS1OS2OS3OS4OS5OS6NOC1OS1OS2OS3OS7OS6OS8OS5OS6C1-NOC1OS1OS3OS4OS7OS6OS6NOC1OS1OS3OS4OS5OS6NOC1OS1OS3OS7OS6OS8OS5OS6OS9OS1OS2OS3OS4OS7OS6OS6OS9OS1OS2OS3OS4OS5OS6OS9OS1OS2OS3OS7OS6OS10OS5OS6NOC2OS1OS2OS3OS4OS7OS6

Truth-machine

S1'\n'C1++++++++FC1[C1+++++]FC1[C2+]C2+!B1WB1[IC3?B2(C3==C1)?B3(C3==C2)IB2{OC3OS1!B1}B3{WB1[OC3OS1]}]

Quines

s0'c1+++fc1[fc1[c1+]c1++]fc1[c2+++]c1+c2+oc2noc0oc1os0oc1os0'c1+++fc1[fc1[c1+]c1++]fc1[c2+++]c1+c2+oc2noc0oc1os0oc1os0
s1'This is a quine program!'s0'c1++fc1[fc1[c1++]]fc1[c1+]c1+++fc1[c2+++]c2--oc2c0+noc0oc1os1oc1oc2c0-noc0oc1os0oc1os0'c1++fc1[fc1[c1++]]fc1[c1+]c1+++fc1[c2+++]c2--oc2c0+noc0oc1os1oc1oc2c0-noc0oc1os0oc1os0

Deadfish Interpreter

s0'diissisdo'c9-c10++++fc10[fc10[c10++]]c8++++++++++fc8[fc8[c3+c4+c5+c6+]c10+++c5+c6+]fc8[c8-]c3+++++fc4[c10-]c10++c6+c5+++++lc7:s0?b1(c1<c7)wb1[gc0:s0(c1)?b3(c0==c3)?b4(c0==c4)?b5(c0==c5)?b6(c0==c6)ib3{c2+}ib4{c2-}ib5{fc2[fc2[c8+]]fc2[c2-]fc8[c2+c8-]}ib6{noc2}?b7(c2==c9)?b8(c2==c10)ib7{c2+}ib8{fc2[c2-]}c1+?b1(c1<c7)]

Add two numbers

S1'Number #'S2': 'S3' + 'S4' = 'S5'\n'C1+OS1NOC1OS2NIC2C1+OS1NOC1OS2NIC3FC2[C4+]FC3[C4+]NOC2OS3NOC3OS4NOC4OS5

Subtract two numbers

S1'Number #'S2': 'S3' - 'S4' = 'S5'\n'C1+OS1NOC1OS2NIC2C1+OS1NOC1OS2NIC3FC2[C4+]FC3[C4-]NOC2OS3NOC3OS4NOC4OS5

Multiply two numbers

S1'Number #'S2': 'S3' * 'S4' = 'S5'-'S6'\n'C1+OS1NOC1OS2NIC2C1+OS1NOC1OS2NIC3C1--?B1(C2<C1)IB1{!B2WB2[C2+C4+?B2(C2<C1)]FC4[C2+C4-]}?B2(C3<C1)IB2{!B3WB3[C3+C4+?B3(C3<C1)]FC4[C3+C4-]}?B1(B1^B2)?B2(C2=C1)?B3(C3=C1)?B2(B2|B3)!B2?B1(B1&B2)IB2{C3-FC2[C4+]FC4[FC3[C4+]]C3+}NOC2OS3NOC3OS4IB1{OS5}NOC4OS6

Divide two numbers

S1'Number #'S2': 'S3' / 'S4' = 'S5'-'S6'NaN'S7'\n'C1+OS1NOC1OS2NIC2C1+OS1NOC1OS2NIC3C1--?B1(C2<C1)IB1{!B2WB2[C2+C4+?B2(C2<C1)]FC4[C2+C4-]}?B2(C3<C1)IB2{!B3WB3[C3+C4+?B3(C3<C1)]FC4[C3+C4-]}?B1(B1^B2)?B2(C2=C1)?B3(C3=C1)?B2(B2|B3)!B2?B1(B1&B2)IB2{FC2[C5+]WC5[FC3[C5-]C4+]?B3(C5<C1)WB3[C5+?B3(C5<C1)]C4-}NOC2OS3NOC3OS4IB1{OS5}IB3{OS6}{NOC4}OS7

Store a number as a string

The program takes the value in c0 and converts it to the string in s1. The meat of the program doesn't need the nic0 at the start or the os1 at the end to function properly, but are there simply for demonstrative purposes so the user sees what's happening through i/o.

s0'0'gc6:s0(c5)c1++++++++++nic0!b1wb1[?b1(c0>=c1)fc2[c2-]fc3[c3-]fc4[c4-]fc0[c4+]?b0(c4>=c1)wb0[c3+fc4[c4-]fc0[c4+]fc1[c2+]fc2[c4-]?b0(c4>=c1)]fc0[c0-]fc3[c0+]fc6[c4+]s0''pc4:s0(c5)ks0:s1s1''ks1:s0]os1