Home

Awesome

The Calc4 Programming Language

Calc4 is a programming language where everything in its code is an operator.

Try It Out

To try Calc4 via your web browser, please visit Try Calc4. This website allows you to run the Calc4 source code you type on the fly.

Overview

The design of Calc4 is inspired by calculators. Calc4 allows you to program as if you were pressing the calculator's buttons. First of all, look at the next examples of Calc4 programs.

The first one is very simple and is exactly the same as using a calculator. The second one is worth noting. As you can imagine from the name, the {fib} computes the 38th Fibonacci sequence. This is similar to the Fibonacci button on a calculator. In other words, the code above can be thought of as the following actions on a calculator:

  1. Create a new Fibonacci button on a calculator
  2. Press the "3" button
  3. Press the "8" button
  4. Press the Fibonacci button

To achieve this style of programming, Calc4 introduces the concept that "everything is an operator". For example, the Fibonacci button is represented as a unary operator. Here, please be noted that this operator (or button) is not provided by default, but is defined manually by the programmer. In fact, "3" and "8" are also operators. The detail will be presented in the next section.

Despite such simple grammar, Calc4 is capable of performing various complex computations such as the Mandelbrot set shown below. The Mandelbrot set program is available here.

Mandelbrot Set Drawn by Calc4

Mandelbrot set drawn by Calc4

Key Features of Calc4

Everything is an Operator

The biggest feature of Calc4 is that the program consists only of operators in infix notation. Let me explain this by using the next sample code of Calc4.

The + in the above is of course an operator, but 4, 6, and 2 are also operators. The operator 6 takes one operand and returns (operand * 10) + 6. Its operand is the result of the operator 4.

That is to say, code 1 is equivalent to the following C code.

int operator2(int operand) {
    return (operand * 10) + 2;
}

int operator4(int operand) {
    return (operand * 10) + 4;
}

int operator6(int operand) {
    return (operand * 10) + 6;
}

int zeroOperator() {
    return 0;
}

return operator6(operator4(zeroOperator())) + operator2(zeroOperator());

Since the main goal of Calc4 is to program in the style of calculators, "46" is not a single token but is divided into two operators. In this manner, all code elements are expressed as operators in Calc4.

Highly Expressiveness Powered by Recursive Operators

Everything in Calc4 is an operator, but this does not mean Calc4 cannot represent complex programs. Calc4 offers a way to define custom operators. For example, you can define your original addition operator as follows. Here, D is an operator to define a new operator.

D[myadd|x, y|x + y] 12{myadd}23

Popular programming languages such as C provide loops to express complicated algorithms. Calc4 does not have such syntax. Instead, custom operators calling themselves, i.e. recursive operators, are available. The next code is the definition of the Fibonacci operator we saw earlier. You can find a typical recursive call.

D[fib|n|n <= 1? n ? (n-1){fib} + (n-2){fib}] 38{fib}

A more complex example is the image at the beginning of this README, the Mandelbrot set drawn by Calc4. The program is available here. It utilizes tail recursions instead of loops.

Another sample code is also available.

Getting Started

If you wish to simply try Calc4, the Try Calc4 website is the best choice. Below are the steps to build a native Calc4 environment.

Requirements

Building Calc4

  1. Install CMake
    • dnf
      sudo dnf install cmake -y
      
    • apt
      sudo apt update
      sudo apt install cmake -y
      
    • Binary
  2. Build and run
    • Unix-like systems
      git clone https://github.com/proprowataya/calc4.git
      mkdir calc4-build
      cd calc4-build
      cmake ../calc4
      cmake --build .
      ./calc4 ../calc4/sample/MandelbrotSet.txt
      
    • Windows
      git clone https://github.com/proprowataya/calc4.git
      mkdir calc4-build
      cd calc4-build
      cmake ..\calc4
      cmake --build . --config Release
      .\Release\calc4.exe ..\calc4\sample\MandelbrotSet.txt
      

If nothing is specified as a command-line argument, Calc4 works as REPL. Please input what you want to evaluate.

$ ./calc4
Calc4 REPL
    Integer size: 64
    Executor: StackMachine
    Optimize: on

> 72P101P108P108P111P32P119P111P114P108P100P33P10P
Hello world!
0
Elapsed: 0.1183 ms

> D[fib|n|n <= 1? n ? (n-1){fib} + (n-2){fib}] 38{fib}
39088169
Elapsed: 1457.58 ms

>

JIT Compilation (Optional)

You can use the JIT compiler supported by LLVM. The steps to enable JIT compilation are as follows.

  1. Install LLVM
    • apt
      sudo apt update
      sudo apt install llvm-dev -y
      
    • dnf
      sudo dnf install llvm-devel -y
      
    • Windows
      • You need to build the LLVM from the source code. Please follow the official instructions.
      • Make sure that llvm-config.exe is added to the PATH.
  2. Build again with an option
    • Unix-like systems
      cmake ../calc4 -DENABLE_JIT=ON
      cmake --build .
      ./calc4
      
    • Windows
      cmake ..\calc4 -DENABLE_JIT=ON
      cmake --build . --config Release
      .\Release\calc4.exe
      

Sample Codes

Hello world

Addition

Addition and Multiplication

Defining Custom Operators

Conditional Operators

Operators with Many Operands

Fibonacci Sequence (naïve version)

Fibonacci Sequence (tail call version)

Variables

Memory Accesses

Input Operators

Tarai Function

Tarai function is often used when benchmarking programming languages.

Language Specification

Operator Precedence

The rules of operator precedence in Calc4 are as follows:

This is the reason why 1 + 2 * 3 is evaluated to 9 rather than 7.

Conditional Operators

When using conditional operators in Calc4, you should be aware of their associativity. All operators are left-associative, and conditional operators are no exception to this rule. The next two pieces of code will output different execution results.

Since all operators in Calc4 are left-associative, the code can be rewritten to:

(1 == 1 ? 2 ? 3 == 4) ? 5 ? 6

In contrast, common programming languages including C have right-associative conditional operators. Therefore, the C code's condition is equivalent to:

1 == 1 ? 2 : (3 == 4 ? 5 : 6)

Most programmers will expect C behavior. If you wish to get that in Calc4, you have to explicitly write parentheses as follows.

> 1 == 1 ? 2 ? (3 == 4 ? 5 ? 6)
2

There are no plans to change this behavior at this time because the behavior is a natural extension of calculators and the language specification should be kept as simple as possible.

Supplementary Texts

You can specify the variable's name to S and L operators like S[abc] and L[abc]. How does Calc4's grammar treat this kind of strange syntax? You may have a similar question about D operators.

Every operator in Calc4 can have its supplementary text. The text should be located just after the operator. [abc] is one example of supplementary texts. These texts will be used in compilation time, and are NOT operands.

The following is a valid code in Calc4. [xyz], [Hello] and [qwerty] are supplementary texts of 1, + and 2 operators respectively. These operators simply ignore their supplementary texts. The output is of course "3".

1[xyz]+[Hello]2[qwerty]

Tail Recursion Optimization

In Calc4, which is missing loops, the programmer is forced to use recursive operators. If the depth of the recursion becomes very deep, the stack may overflow. To deal with this problem, the Calc4 runtime provides an optimization to eliminate tail recursion.

You can easily observe this optimization by infinite recursive operators.

D[x||{x}] {x}

The operator x clearly never stops. If you execute this without optimization, the program will crash.

On the other hand, if you enable optimization, the control flow will never return instead of causing a stack overflow. This means that the recursion was converted into a loop.

It is hard to describe this behavior in Markdown, so please try it on your machine. When the --dump option is specified, the Calc4 REPL displays internal representations of the given code. This information is useful for understanding optimizations.

Conclusion

As you can see from this README, Calc4 is far from a practical programming language. It is some kind of Esoteric programming languages (esolang). Calc4 was developed with the motivation that designing an original programming language is a lot of fun.

Copyright

Copyright (C) 2018-2024 Yuya Watari

License

MIT License