Clem

From Esolang
Jump to navigation Jump to search

The Clem language

Clem (pronounced klem) is a stack based programming language with first-class functions created by User:Orby in 2014. The best way to learn Clem is to run the `clem` interpreter in interactive mode, allowing you to play with the available commands. A reference interpreter written in C is available here (from the Wayback Machine; retrieved on 21 March 2016). To run the example programs which come with the reference interpreter, type `clem example.clm` where example is the name of the program. This brief tutorial should be enough to get you started.

There are two main classes of functions. Atomic functions and compound functions. Compound functions are lists composed of other compound functions and atomic functions. Note that a compound function cannot contain itself.

Atomic Functions

The first type of atomic function is the constant. A constant is simply an integer value. For example, -10. When the interpreter encounters a constant, it pushes it to the stack. Run `clem` now. Type `-10` at the prompt. You should see

   > -10
   001: (-10)
   >

The value `001` describes the position of the function in the stack and `(-10)` is the constant you just entered. Now enter `+11` at the prompt. You should see

   > +11
   002: (-10)
   001: (11)
   >

Notice that `(-10)` has moved to the second position in the stack and `(11)` now occupies the first. This is the nature of a stack! All other atomic functions are commands. There are 14 in total:

   @  Rotate the top three functions on the stack
   #  Pop the function on top of the stack and push it twice
   $  Swap the top two functions on top of the stack
   %  Pop the function on top of the stack and throw it away
   /  Pop a compound function. Split off the first function, push what's left, 
      then push the first function.
   .  Pop two functions, concatenate them and push the result
   +  Pop a function. If its a constant then increment it. Push it
   -  Pop a function. If its a constant then decrement it. Push it
   <  Get a character from STDIN and push it to the stack. Pushes -1 on EOF.
   >  Pop a function and print its ASCII character if its a constant
   c  Pop a function and print its value if its a constant
   w  Pop a function from the stack. Peek at the top of the stack. While it is
      a non-zero constant, execute the function.
   q  Quit
   h  Print this list

Typing a command at the prompt will execute the command. Type `#` at the prompt (the duplicate command). You should see

   > #
   003: (-10)
   002: (11)
   001: (11)
   > 

Notice that the (11) has been duplicated. Now type `%` at the prompt (the drop command). You should see

   > %
   002: (-10)
   001: (11)
   > 

To push a command to the stack, simply enclose it in parenthesis. Type `(-)` at the prompt. This will push the decrement command to the stack. You should see

   > (-)
   003: (-10)
   002: (11)
   001: (-)
   > 

Compound functions

You may also enclose multiple atomic functions in parenthesis to form a compound function. When you enter a compound function at the prompt, it is pushed to the stack. Type `($+$)` at the prompt. You should see

   > ($+$)
   004: (-10)
   003: (11)
   002: (-)
   001: ($ + $)
   >

Technically, everything on the stack is a compound function. However, some of the compound functions on the stack consist of a single atomic function (in which case, we will consider them to be atomic functions for the sake of convenience). When manipulating compound functions on the stack, the `.` command (concatenation) is frequently useful. Type `.` now. You should see

   > . 
   003: (-10)
   002: (11)
   001: (- $ + $)
   > 

Notice that the first and second functions on the stack were concatenated, and that the second function on the stack comes first in the resulting list. To execute a function that is on the stack (whether it is atomic or compound), we must issue the `w` command (while). The `w` command will pop the first function on the stack and execute it repeatedly so long as the second function on the stack is a non-zero constant. Try to predict what will happen if we type `w`. Now, type `w`. you should see

   > w
   002: (1)
   001: (0)
   > 

Is that what you expected? The two numbers sitting on top of the stack were added and their sum remains. Let's try it again. First we'll drop the zero and push a 10 by typing `%10`. You should see

   > %10
   002: (1)
   001: (10)
   > 

Now we'll type the entire function in one shot, but we'll add an extra `%` at the end to get rid of the zero. Type `(-$+$)w%` at the prompt. You should see

   > (-$+$)w%
   001: (11)
   > 

(Note this algorithm only works if the first constant on the stack is positive).

Strings

Strings are also present. They are mostly syntactic sugar, but can be quite useful. When the interpreter encounters a string, it pushes each character from last to first onto the stack. Type `%` to drop the 11 from the previous example. Now, type `0 10 "Hi!"` on the prompt. The `0` will insert a NULL terminator and the `10` will insert a new-line character. You should see

   > 0 10 "Hi!"
   005: (0)
   004: (10)
   003: (33)
   002: (105)
   001: (72)
   > 

Type `(>)w` to print characters from the stack until we encounter the NULL terminator. You should see

   > (>)w
   Hi!
   001: (0)
   >

These can easily be concatenated to produce a quine

   > (")10$#34$(34 40 (>)w)....1$w")10$#34$(34 40 (>)w)....1$w
   (")10$#34$(34 40 (>)w)....1$w")10$#34$(34 40 (>)w)....1$w
   Empty stack
   >

Conclusions

Hopefully this should be enough to get you started with the interpreter. The language design should be relatively straightforward. E-mail orbitaldecay@gmail.com with any questions or comments.

External resources