Lasagna
Note
This article is copied from the GitHub repository.
Basics
A program file, with extension .bin.lsg
, is defined by a list of instructions (each being one byte), and corresponding arguments. If, at any point, the stack is popped without anything on it, the program will immediately halt with an error.
Text
A text representation of a program, with extension .txt.lsg
, is formatted with one instruction per line.
Comments
Comments in textual form are any text surrounded by square brackets, with nesting allowed.
[This is a [comment]]
Load
There is a special case for load - you can load many bytes at once, and it's compiled to separate load instructions. There are 4 different ways to format this data: raw bytes, a string, an integer, or a float.
Bytes
Raw bytes are formatted with a pound sign, arbitrarily many bytes, and another pound sign.
# 01 23 45 67 89 AB CD EF #
01 23 45 67 89 AB CD EF
Float
Floats are stored in IEEE 754 format, using 32 bytes to store the value. All floats MUST be formatted with a number before and after the decimal point, and optionally with an exponent. Hexadecimal-style floats are not supported.
0.0
, -6.2e1
00 00 00 00
, C2 78 00 00
Integer
Integers are stored big-endian, two's complement, with 6 distinct types, marked with a suffix. Any integers that won't fit into their type will fail to compile to a binary program.
0_u8
, -1_i8
, 2_u16
, -3_i16
, 4_u32
, -5_i32
00
, FF
, 00 02
, FF FD
, 00 00 00 04
, FF FF FF FB
String
Strings are stored as ASCII, backwards in the stack, with a null byte at the end. They are stored backwards for ease of printing.
'Hello, world!'
00 21 64 6C 72 6F 77 20 2C 6F 6C 6C 65 48
Instructions
Any invalid instruction will make the program fail before running. Each instruction is formatted as a kind, an index, and, 3 bits of a type (if applicable, else 000
). In textual representation, the type of the operation, if applicable, is put after the instruction.
Type | Name | Bits |
---|---|---|
Unsigned 8-bit integer | u8
|
000
|
Signed 8-bit integer | i8
|
001
|
Unsigned 16-bit integer | u16
|
010
|
Signed 16-bit integer | i16
|
011
|
Unsigned 32-bit integer | u32
|
100
|
Signed 32-bit integer | i32
|
101
|
Float | float
|
110
|
String | str
|
111
|
Instruction | Typed? | Textual Representation | Description |
---|---|---|---|
00 000
|
No | noop
|
Does nothing. |
00 001
|
Yes | load
|
Load the next value in the file to the stack. |
00 010
|
Yes | take
|
Take a value from stdin and put it on the stack plus a true boolean byte, or if reading fails, just puts a false boolean byte. |
00 011
|
Yes | put
|
Pop a value from the stack, and write to stdout. Failing to write still pops from the stack. |
00 100
|
Yes | discard
|
Pop a value from the stack and discard it. |
00 101
|
Yes | copy
|
Push the value on the stack to the stack again, copying it. |
00 110
|
Yes | random
|
Push one random value to the stack. Invalid for strings and floats. |
00 111
|
Yes | swap
|
Swap the last two values on the stack. |
01 000
|
No | label
|
Defines a label that can be jumped to later. Followed by four bytes, being the label's ID. In textual representation, this is an arbitrarily long string, and each string is assigned an ID at compile time. |
01 001
|
No | jump
|
Unconditionally jumps to the label in the next four bytes in the file. Like before, this is compiled from a string from textual representation, and it fails to compile if the label doesn't exist. If a label's byte ID does not exist, then this instruction is invalid. This pushes to a special jump stack. |
01 010
|
No | jumpzero
|
Pops a byte from the stack, and if it is zero, jumps to the label in the next four bytes in the file. This pushes to a special jump stack. |
01 011
|
No | jumpnonzero
|
Pops a byte from the stack, and if it is not zero, jumps to the label in the next four bytes. This pushes to a special jump stack. |
01 100
|
No | return
|
Pops a from the jump stack (mentioned above), and jumps one past that jump instruction. If there is nothing left on the jump stack, then this immediately ends the program without error. |
01 101
|
No | rotleft
|
Pops the last value from the stack and puts it at the start of the stack. This is equivalent to moving a "pop index offset" to the left, and this method of implementation may be faster. |
01 110
|
No | rotright
|
Pops the first value from the stack and puts it at the end of the stack. This is equivalent to moving a "pop index offset" to the right, and this method of implementation may be faster. |
01 111
|
No | fork
|
Spawns a new child of the process, and pushes a 00 if on the parent, and a 01 if on the child. The child process obtains a copy of the current stack and jump stack. |
10 000
|
Yes | add
|
Pops two values of the specified type from the stack, adds them, and pushes the resulting value, plus a boolean byte indicating if overflow occurred. Invalid for strings. If you need concatenation, just push both strings and remove the null terminator. |
10 001
|
Yes | subtract
|
Subtracts two values, and pushes the resulting value, plus a boolean byte indicating if overflow occurred. Invalid for strings. |
10 010
|
Yes | multiply
|
Multiplies two values, and pushes the resulting value, plus a boolean byte indicating if overflow occurred. Invalid for strings. |
10 011
|
Yes | divide
|
Divides two values, and pushes the resulting value, plus a boolean byte indicating if there was a divide by zero. Invalid for strings. |
10 100
|
Yes | remainder
|
Gets the remainder after dividing two values, and pushes the resulting value, plus a boolean byte indicating if there was a divide by zero. Invalid for strings. |
10 101
|
Yes | order
|
Pushes a 00 if the two given values are equal, a FF if the first is larger, a 01 if the second is larger, and a 7F if they cannot be compared. |
10 110
|
Yes | shiftleft
|
Bit-shifts a value leftwards by another value, and pushes the resulting value, filling empty space with zeros and discarding bits outside. Invalid for strings and floats. |
10 111
|
Yes | shiftright
|
Bit-shifts a value rightwards by another value, and pushes the resulting value, filling empty space with zeros and discarding bits outside. Invalid for strings and floats. |
11
|
Yes x2 | cast
|
Casts a value to another type, and if successful, pushes the result, then 01, to the stack. If the cast is invalid, pushes 00 to the stack. |
Care must be taken to not confuse types of stack values.