Pancakes

From Esolang
Jump to navigation Jump to search

Pancakes is a stack-based programming language designed by User:CatCatDeluxe to have a simple parser with as little edge cases as possible, yet still be fun to program in. It has a stack consisting of 64-bit floating point numbers.

Programs in Pancakes are a bunch of tokens separated by whitespace, like most programming languages. There is no real concept of lines in Pancakes, newlines are just treated as any other whitespace character. This section will go over the various instruction types and a few syntax rules.

Syntax and Stuff

Comments

Comments are useful, but not needed. That doesn't mean I didn't implement them. Any text between a ~ and a newline is ignored.

Literals

A literal in Pancakes is just a number surrounded by whitespace. More specifically, they are any string matching the regex /^[+-]?\d+(\.\d+)?$/. They are written in decimal, and can be any valid 64-bit floating point number. Scientific notation is not supported though. Just write a bunch of zeros it's not that hard.

Some examples of literals:

100
234895798345.347658345
-12996.74566

Strings

Strings in Pancakes are really just a lot of numbers on the stack terminated by a zero. The standard library still has some string functions, and there is special syntax for it so you're not just writing numbers all day. Strings are written as any text surrounded by double quotes, or a single word preceded by a '. (shorthand strings)

Examples of strings:

"this is a string"
'this-is-also-a-string
'these_strings_can't_have_whitespace
"these can though wow cool"

Strings can also have escaped characters, with the use of a \. A full list of supported escape characters:

  • \n - Newline
  • \t - Tab
  • \e - Equivalent to \x1b
  • \x(2 hex digits) - ASCII code in hex for any character.

A backslash can also be put in front of any other character, and the string will just add it in and then ignore it. For example, \" will add a double quote to the string it's in. There is no escape code for a space character. If you need spaces, don't use a shorthand string.

Here are some examples:

"Pancakes is a very \"cool\" language".
'these_work\nhere_too
"\x1b[31mThis text would be red in a (good) terminal\x1b[0m"
"The escape character is '\\'."

Both literals and strings are pushed directly to the stack when they are encountered.

Function Calls

One of the main parts of Pancakes is a function call. You know how to add values to the stack, but they're only useful with functions. Function calls are any text that doesn't fit into the other parsing categories. The Pancakes standard library implements a lot of useful functions. Anything you do in Pancakes is with functions. There are no functions built in to the language, even the control flow function break (This will be covered later). Functions are only added with libraries made either with external languages or Pancakes itself. Functions take no arguments and do not return anything, They simply read and write to the stack or variables. Functions are called by simply writing the name of it in your code.

Examples

Here, the putnum, putchar, and putstring functions print numbers, numbers as characters, and sequences of numbers as strings respectively.

Prints the value '1':

1
putnum

Since whitespace is only used for separating tokens, you could also write it like this but please don't):

1

          putnum

or this (this one makes sense):

1 putnum

Prints a newline:

10 putchar

Prints a string:

"Hello World!\n" putstring

There are also stack manipulation functions, such as pop, dup, and swap. A good run-down of functions is coming later.

Control Flow

Any programming language needs control flow. And Pancakes is a programming language. Control flow is made of blocks, which contain more code, preceded by the block type (if or loop). In Pancakes, control flow is simple. You can have a conditional block or a looping block. Blocks are really just a bunch of instructions surrounded in the characters [ and ].

Block Types

There are two block types: if and loop. An if block will pop the pop value of the stack, and execute its contained code if the value is anything other than 0. A loop block will loop forever.

Examples

Prints "hi!":

1
if [
    "hi!\n" putstring
]

Prints "hi!" forever:

loop [
    "hi!\n" putstring
]

Exiting a block

You may have noticed that there is no way to exit a loop block. Well now there is, thanks to break and breaks.

The break function will exit the current block. This is not very useful, however, since you most likely will be using an if statement to control whether to break, but that would only break out of the if statement. So, there is also a breaks function. This pops the top value of the stack, and breaks out of that many blocks.

Example

Count to 100 (with the >= function, which pushes 1 if the second-to-top value of the stack is more than the top value of the stack, otherwise 0, also it pops those two values):

0
loop [
    ~ Add 1 to the top of the stack
    1 +
    ~ Print it
    dup putnum
    ~ Only do this if the top of the stack >= 100
    dup 100 >= if [
        ~ Break out of the if and loop
        2 breaks
    ]
]

Function Declaration

A function is declared by writing a block, preceded by the function name with a @ for the first character. Functions do not have a separate stack, so there is no need to pass arguments. Some functions do expect values to be on top of the stack though.

Function names

A function can have any name that does not contain the characters '[', ']', and '~', does not contain any whitespace, and does not match the number-detecting regex (see literals). The preferred naming style is hyphen-case.

Examples

This creates a function to duplicate the top stack value 10 times.

@dup10 [
    10
    loop [
        ~ Get the number under the counter and duplicate it
        swap dup
        ~ Get the counter from under both the numbers
        2 swapwith
        ~ Decrement the counter
        1 -
        ~ Exit if 0
        dup 0 <= if [
            ~ Remove the counter
            pop
            2 breaks
        ]
]

This function pushes the number 100 n times. It expects a number, the amount of times to push 100.

@n-push-100 [
    loop [
        100
        ~ Get the counter
        swap
        1 -
        dup 0 <= if [
            pop
            2 breaks
        ]
    ]
]

Function Overwriting

If a function is declared with the name of an already existing function, Pancakes will throw an error. This is to prevent accidental overwriting. There (should) be two ways to get past this. The first way is to prefix the function declaration with another @. This tells Pancakes that it's ok to overwrite functions.

An evil example:

@@pop [dup]

This makes any calls to pop turn into calls to this function, which is really just a call to dup.

Overwriting standard library functions is heavily discouraged. If you overwrite a function, it will overwrite that function in the function table. This means that any functions declared before the overriding will still be using the new, overwritten function.

The other way (should) be to pass a flag to the interpreter/compiler to allow overriding functions without the use of two @ symbols. This is so if Pancakes gets library support and there is a library conflict, you can prioritize one over the other and have it still work.

Standard Library Functions

Function Name Description Example
pop Discard the top stack value
10 pop
~ It's gone
dup Duplicate the top stack value
10 dup
~ There's 2 of them now
swap Swaps the top two values
1 2
swap
putnum
~ Prints "1"
swapwith Pops the top value as n. Swaps the new top value with the nth-from-top value.
1 2 3
2 swapwith
putnum
~ Prints "1"
size Pushes the size of the stack.
0 0
size
putnum
~ Prints "2"
putnum Pops the top stack value and prints it. Note that any output function does not print a trailing newline.
69420 putnum
~ Prints "69420"
~ Nice
putchar Pops the top stack value and prints it as a character
10 putchar
~ Outputs a newline
putstring Calls putchar until the top of the stack is 0. Discards the 0.
"CatCatDeluxe is cool.\n" putstring
~ Prints what's in the string.
getnum Gets a number from stdin. Pushes it to the stack. Invalid numbers are pushed as NaN.
getnum putnum
~ A cat program for numbers
break Breaks out of the top block.
1 if [
    break
    "I will never be printed :(" putstring
]
breaks Pops the stack, and breaks out of that many blocks.
1 if [
    1 if [
         2 breaks
    ]
    "I will never be printed :(" putstring
]

The standard library also includes all your normal arithmetic and comparison functions: +, -, /, *, % (modulus), ^ (power), =, >, <, >=, <=, and boolean logic: and, not, and or. For these functions, the second operand is popped first, then the first operand, so 10 1 - would be 9.

Examples

Truth Machine

getnum
loop [
    dup putnum
    dup 0 = if [
        2 breaks
    ]
]

Implementations

An interpreter in C++ is currently being developed.