Olus2000

From Esolang
Jump to navigation Jump to search
Not to be confused with User:Olus2000.
Olus2000
Paradigm(s) Concatenative
Designed by User:DolphyWind
Appeared in 2024
Memory system Stack-based
Computational class Turing complete
Major implementations Torth
Influenced by Forth
File extension(s) .olus2000

Olus2000 is a Forth-like esoteric programming language created for Code Guessing 64 as an in-joke. The author created Torth to write Olus2000 programs faster. Olus2000 uses a single stack memory system that operates with ternary integers. All binary operations, including addition, multiplication, and comparison, follow the Forth-style approach.

Grammar

<Program>    ::= <Block>
<Block>      ::= <Stmt> <WS> <Block> | ε
<Stmt>       ::= <Word> | <PosNumber> | <NegNumber> | <String> | <IfStmt> | <WhileStmt> | <Colon> | <Comment>
<Word>       ::= <Letter> { <Letter> | <Base10Digit> | "-" }
<PosNumber>  ::= "0lus2000!" <WS> { <OlusNumber> <WS> } "olus2000!"
<NegNumber>  ::= "0lus2ooo!" <WS> { <OlusNumber> <WS> } "olus2000!"
<OlusNumber> ::= "olus2" ("0" | "O" | "o") ("0" | "O" | "o") ("0" | "O" | "o")
<String>     ::= "\"" { <CHARACTER> } "\""
<IfStmt>     ::= "olus2o0O" <WS> <Block> [ "olus2o0o" <WS> <Block> ] "olus2oO0"
<WhileStmt>  ::= "olus2oOO" <Block> "olus2oO0"
<Colon>      ::= "olus2oOo"  <WS> <Word> <WS> <Block> "olus2oo0"
<Comment>    ::= "Olus2000!" <WS> { <CHARACTER> } <WS> "olus2000!"

<Letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N"
           | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b"
           | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p"
           | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "_" ;
<Base10Digit>      ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<SpecialCharacter> ::= "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "-"
                     | "=" | "+" | "[" | "]" | "{" | "}" | ";" | ":" | "'" | "," | "."
                     | "/" | "?" | "<" | ">" | "|" | "\\" | "~" | "`" | " "
<EscapeSequence>   ::= "\\" ( "\"" | "\\" | "n" | "t" | "r" | "\'" )
<WhiteSpace>       ::= " " | "\t" | "\n"
<WS>               ::= <WhiteSpace> { <WhiteSpace> }
<CHARACTER>        ::= <Letter> | <Base10Digit> | <SpecialCharacter> | <EscapeSequence>

Numbers

When encountered, numbers of Olus2000 are directly pushed onto the stack, just like how it is done in Forth. In Olus2000 a number is represented in an unconventional manner, as triplets of ternary digits encoded as olus2xxx statements where x can be either 0, O or o. When a PosNumber or a NegNumber statement is encountered, the olus2xxx statements are transformed into triplets of ternary digits by mapping 0 to 0, O to 1 and o to 2. The resulting digits are then concatenated to form a single ternary number. Additionally, if the statement is a NegNumber statement, the number is negated. Let's look at an example:

The Statement is "0lus2000! olus20O0 olus2o0O olus2000!"

> olus20O0 represents the triplet "010"
> olus2o0O represents the triplet "201"
> The results are concatenated to obtain the number 010201
> Since this is a PosNumber statement the number above is not negated

Strings

When a string statement is executed, the content of the string is immediately printed to the console. The program below prints "Hello World!" and inserts a new line

"Hello World!\n"

Words

By following Forth, Olus2000 allows creation of custom words. Below, you can find a list of built-in words.

Olus2000 Words
Word Action
olus2000 Pops the top value and prints it to stdout as a ternary integer
olus200O Reads a ternary integer from the stdin and pushes it onto the stack
olus200o Pops two ternary integers and pushes their sum
olus20O0 Pops two ternary integers and pushes their difference
olus20OO Pops two ternary integers and pushes their product
olus20Oo Pops two ternary integers, applies integer division and pushes the result
olus20o0 Pops two ternary integers, applies modulo operation and pushes the result
olus20oO Pops two ternary integers and pushes 1 if the second one is less than the first one. Otherwise pushes zero
olus20oo Pops two ternary integers and pushes 1 if the second one is less than or equal to the first one. Otherwise pushes zero
olus2O00 Pops two ternary integers and pushes 1 if the second one is equal to the first one. Otherwise pushes zero
olus2O0O Pops two ternary integers and pushes 1 if the second one is not equal to the first one. Otherwise pushes zero
olus2O0o Pops two ternary integers and pushes 1 if the second one is greater than or equal to the first one. Otherwise pushes zero
olus2OO0 Pops two ternary integers and pushes 1 if the second one is greater than the first one. Otherwise pushes zero
olus2OOO Reverses the entire stack
olus2OOo Pops the top value and pushes it back twice
olus2Oo0 Reverses the order of the top two elements on the stack
olus2OoO Pops the top value
olus2Ooo Rotates the top three values
olus2o00 Pushes the current length of the stack to the stack itself
olus2o0O If statement, must be terminated with olus2oO0. Checks, without popping, the top value of the stack. If it is a nonzero executes its body
olus2o0o Else keyword, must be used between olus2o0O and olus2oO0. Executes its body if the previous if block didn't execute
olus2oO0 Marks the end of olus2o0O or olus2oOO words
olus2oOO While loop, must be terminated with olus2oO0. Executes its body as long as the top value of the stack is non-zero without removing the value it checks
olus2oOo Used to create new words, must be terminated with olus2oo0
olus2oo0 Marks the end of olus2oOo
olus2ooO Pops an index and moves the item at the given index to the top of the stack
olus2ooo Pops a ternary integer and a stack index. Moves the integer to the specified index

Olus2000 -> Torth Transpiler

Here's a nice and simple transpiler that converts any Olus2000 code to equivalent Torth code.

import sys

olus2000_dict = {
    'olus2000': '.',
    'olus200O': ',',
    'olus200o': '+',
    'olus20O0': '-',
    'olus20OO': '*',
    'olus20Oo': '/',
    'olus20o0': '%',
    'olus20oO': '<',
    'olus20oo': '<=',
    'olus2O00': '==',
    'olus2O0O': '!=',
    'olus2O0o': '>=',
    'olus2OO0': '>',
    'olus2OOO': 'REVERSE',
    'olus2OOo': 'DUP',
    'olus2Oo0': 'SWAP',
    'olus2OoO': 'DROP',
    'olus2Ooo': 'ROT',
    'olus2o00': 'DEPTH',
    'olus2o0O': 'IF',
    'olus2o0o': 'ELSE',
    'olus2oO0': 'THEN',
    'olus2oOO': 'WHILE',
    'olus2oOo': ':',
    'olus2oo0': ';',
    'olus2ooO': 'GET',
    'olus2ooo': 'SET',
}

def olus_to_ternary(olus):
    last_three = olus[-3:]
    d = {
        '0': 0,
        'O': 1,
        'o': 2
    }
    return str(d[last_three[0]]) + str(d[last_three[1]]) + str(d[last_three[2]])

def main():
    code = ""
    if len(sys.argv) == 1:
        code = input()
    else:
        file = sys.argv[1]
        with open(file, 'r') as f:
            code = f.read()
    code_as_list = []
    last = 0
    in_string = False

    s = []
    for i, c in enumerate(code):
        if c == '\"':
            code_as_list.append(code[last:i + int(in_string)])
            last = i + int(in_string)

            in_string = not in_string
            s = []
            continue
        s.append(c)

    if last == 0:
        code_as_list.append(code[last:])
    else:
        code_as_list.append(code[last+1:])

    fin = []
    for c in code_as_list:
        if c.startswith('\"'):
            fin.append(c)
        else:
            fin.extend(c.split())
    code = fin

    NUMBER_MODE = 0
    COMMENT_MODE = 1
    NORMAL_MODE = 2

    mode = NORMAL_MODE
    negative_number = False

    result = []
    num = ''
    for op in code:
        prev_mode = mode
        if op == '0lus2000!':
            mode = NUMBER_MODE
            negative_number = False
        elif op == '0lus2ooo!':
            mode = NUMBER_MODE
            negative_number = True
        elif op == 'Olus2000!':
            mode = COMMENT_MODE
        elif op == 'olus2000!':
            mode = NORMAL_MODE

        if mode != NUMBER_MODE and prev_mode == NUMBER_MODE:
            if negative_number:
                num = '-' + num
            result.append(num)
            num = ''

        if mode != prev_mode:
            continue

        if mode == NUMBER_MODE:
            num += olus_to_ternary(op)
        elif mode == NORMAL_MODE:
            try:
                result.append(olus2000_dict[op])
            except KeyError:
                result.append(op)

    if mode == NUMBER_MODE and num != '':
        result.append(num)
    print(' '.join(result))

if __name__ == "__main__":
    main()

Examples

Some example programs written in Olus2000

99 Bottles of Beer on The Wall

olus2oOo WRITE_9 olus2o0O olus2OoO "ERROR" olus2o0o olus2OoO "9" olus2oO0 olus2oo0 olus2oOo WRITE_8 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_9 olus2o0o olus2OoO "8"
olus2oO0 olus2oo0 olus2oOo WRITE_7 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_8 olus2o0o olus2OoO "7" olus2oO0 olus2oo0 olus2oOo WRITE_6 olus2o0O 0lus2000! olus200O
olus2000! olus20O0 WRITE_7 olus2o0o olus2OoO "6" olus2oO0 olus2oo0 olus2oOo WRITE_5 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_6 olus2o0o olus2OoO "5" olus2oO0
olus2oo0 olus2oOo WRITE_4 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_5 olus2o0o olus2OoO "4" olus2oO0 olus2oo0 olus2oOo WRITE_3 olus2o0O 0lus2000! olus200O olus2000!
olus20O0 WRITE_4 olus2o0o olus2OoO "3" olus2oO0 olus2oo0 olus2oOo WRITE_2 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_3 olus2o0o olus2OoO "2" olus2oO0 olus2oo0 olus2oOo
WRITE_1 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_2 olus2o0o olus2OoO "1" olus2oO0 olus2oo0 olus2oOo WRITE_0 olus2o0O 0lus2000! olus200O olus2000! olus20O0 WRITE_1
olus2o0o olus2OoO "0" olus2oO0 olus2oo0 olus2oOo WRITE_HELPER olus2o00 olus2o0O olus2OoO 0lus2000! olus200O olus2000! olus200o olus2o0O 0lus2000! olus200O olus2000! olus20O0
olus2o0o olus2OoO WRITE_0 WRITE_HELPER olus2oO0 olus2o0o olus2OoO olus2oO0 olus2oo0 olus2oOo WRITE_NUM olus2o0O olus2OOo 0lus2000! olus2O0O olus2000! olus20o0 olus2Oo0 0lus2ooo!
olus200O olus2000! olus2Oo0 0lus2000! olus2O0O olus2000! olus20Oo WRITE_NUM olus2o0o olus2OoO WRITE_HELPER olus2oO0 olus2oo0 olus2oOo BOTTLES olus2OOo 0lus2000! olus200O
olus2000! olus20O0 olus2o0O olus2OoO "bottles" olus2o0o olus2OoO "bottle" olus2oO0 olus2oo0 olus2oOo LAST_LINE olus2OOo olus2o0O WRITE_NUM olus2o0o olus2OoO "No more" olus2oO0
" " BOTTLES " of beer on the wall.\n\n" olus2oo0 olus2oOo BEER_REGULAR olus2OOo WRITE_NUM " " BOTTLES " of beer on the wall,\n" olus2OOo WRITE_NUM " " BOTTLES
" of beer.\nTake one down, pass it around\n" 0lus2000! olus200O olus2000! olus20O0 LAST_LINE olus2oo0 olus2oOo BEER olus2OOo olus2o0O BEER_REGULAR BEER olus2oO0 olus2oo0
0lus2000! olus20O0 olus2o00 olus2000! BEER 

Look And Say Sequence

olus2oOo OLUS2OOO olus2o0O olus2OoO "ERROR" olus2o0o olus2OoO "3" olus2oO0 olus2oo0 olus2oOo OLUS2ooo olus2o0O 0lus2000! olus200O olus2000! olus20O0 OLUS2OOO olus2o0o olus2OoO
"2" olus2oO0 olus2oo0 olus2oOo OLUS2000 olus2o0O 0lus2000! olus200O olus2000! olus20O0 OLUS2ooo olus2o0o olus2OoO "1" olus2oO0 olus2oo0 olus2oOo OLUS200O 0lus2000! olus200O
olus2000! olus20O0 OLUS2000 olus2oo0 olus2oOo OLUS20O0 olus2OOo olus2Ooo olus2Oo0 olus2OOo olus2Ooo olus2O00 olus2o0O olus2OoO 0lus2000! olus2000 olus2000! olus2ooO 0lus2000!
olus200O olus2000! olus200o 0lus2000! olus2000 olus2000! olus2Oo0 olus2ooo olus2OoO olus2o0o olus2OoO olus2OOo 0lus2000! olus2000 olus2000! olus2Oo0 olus2ooo 0lus2000! olus2000
olus2000! 0lus2000! olus200O olus2000! olus2ooo olus2Oo0 olus2OoO olus2oO0 olus2oo0 olus2oOo OLUS20OO olus2Oo0 olus2OOo 0lus2ooo! olus200O olus2000! olus2O0O olus2oOO olus2OoO
olus2Oo0 OLUS20O0 olus2Oo0 olus2OOo 0lus2ooo! olus200O olus2000! olus2O0O olus2oO0 olus2OoO olus2Oo0 olus2OoO olus2OoO olus2oo0 olus2oOo OLUS20Oo OLUS20OO olus2OOO olus2o00
olus2oOO olus2Oo0 olus2OOo OLUS200O 0lus2000! olus2000 olus2000! olus2Oo0 olus2ooo 0lus2000! olus200O olus2000! olus20O0 olus2oO0 "\n" olus2OoO 0lus2ooo! olus200O olus2000!
olus2OOO 0lus2000! olus2000 olus2000! olus2oo0 0lus2ooo! olus200O olus2000! 0lus2000! olus200O olus2000! 0lus2000! olus2000 olus2000! 0lus2000! olus200O olus2000! OLUS200O "\n"
0lus2000! olus200O olus2000! olus2oOO olus2OoO OLUS20Oo 0lus2000! olus200O olus2000! olus2oO0