{"id":13608598,"url":"https://github.com/proprowataya/calc4","last_synced_at":"2025-04-12T17:32:12.857Z","repository":{"id":231043357,"uuid":"131559337","full_name":"proprowataya/calc4","owner":"proprowataya","description":"The Calc4 Programming Language - Every code element is an operator, allowing programming in the style of a calculator","archived":false,"fork":false,"pushed_at":"2025-01-01T08:18:48.000Z","size":5663,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-01T09:19:39.680Z","etag":null,"topics":["compiler","compilers","interpreter","jit","language","llvm","llvm-ir","programming-language"],"latest_commit_sha":null,"homepage":"https://proprowataya.github.io/calc4/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/proprowataya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-30T05:30:54.000Z","updated_at":"2025-01-01T08:18:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"255ca275-8ff9-410a-9cd8-0b4dba811d27","html_url":"https://github.com/proprowataya/calc4","commit_stats":null,"previous_names":["proprowataya/calc4"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/proprowataya%2Fcalc4","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/proprowataya%2Fcalc4/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/proprowataya%2Fcalc4/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/proprowataya%2Fcalc4/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/proprowataya","download_url":"https://codeload.github.com/proprowataya/calc4/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248605213,"owners_count":21132128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler","compilers","interpreter","jit","language","llvm","llvm-ir","programming-language"],"created_at":"2024-08-01T19:01:28.535Z","updated_at":"2025-04-12T17:32:07.845Z","avatar_url":"https://github.com/proprowataya.png","language":"C++","readme":"# The Calc4 Programming Language\n\nCalc4 is a programming language where everything in its code is an operator.\n\n## Try It Out\n\nTo try Calc4 via your web browser, please visit [Try Calc4](https://proprowataya.github.io/calc4/). This website allows you to run the Calc4 source code you type on the fly.\n\n## Overview\n\nThe 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.\n\n* Arithmetic operation\n    ```\n    46 + 2\n    ```\n* The Fibonacci sequence\n    ```\n    38{fib}\n    ```\n\nThe 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:\n\n1. Create a new Fibonacci button on a calculator\n1. Press the \"3\" button\n1. Press the \"8\" button\n1. Press the Fibonacci button\n\nTo 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.\n\nDespite 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](sample/MandelbrotSet.txt).\n\n#### Mandelbrot Set Drawn by Calc4\n![Mandelbrot set drawn by Calc4](image/MandelbrotSet.png)\n\n## Key Features of Calc4\n\n### Everything is an Operator\n\nThe 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.\n\n* Calc4 Sample Code 1\n    ```\n    46 + 2\n    ```\n\nThe ```+``` 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```.\n\nThat is to say, code 1 is equivalent to the following C code.\n\n```c\nint operator2(int operand) {\n    return (operand * 10) + 2;\n}\n\nint operator4(int operand) {\n    return (operand * 10) + 4;\n}\n\nint operator6(int operand) {\n    return (operand * 10) + 6;\n}\n\nint zeroOperator() {\n    return 0;\n}\n\nreturn operator6(operator4(zeroOperator())) + operator2(zeroOperator());\n```\n* **NOTE:** The operator ```2``` and ```4``` in code 1 implicitly take a constant value 0, namely zero operators, as their operands.\n\nSince 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.\n\n### Highly Expressiveness Powered by Recursive Operators\n\nEverything 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.\n\n```\nD[myadd|x, y|x + y] 12{myadd}23\n```\n\nPopular 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.\n\n```\nD[fib|n|n \u003c= 1? n ? (n-1){fib} + (n-2){fib}] 38{fib}\n```\n\nA more complex example is [the image at the beginning of this README](#mandelbrot-set-drawn-by-calc4), the Mandelbrot set drawn by Calc4. The program is available [here](sample/MandelbrotSet.txt). It utilizes [tail recursions](https://en.wikipedia.org/wiki/Tail_call) instead of loops.\n\nAnother sample code is also available.\n* [Printing prime numbers up to 100](sample/PrintPrimes.txt)\n\n## Getting Started\n\nIf you wish to simply try Calc4, the [Try Calc4](https://proprowataya.github.io/calc4/) website is the best choice. Below are the steps to build a native Calc4 environment.\n\n### Requirements\n\n* C++ compiler supporting C++17\n* [CMake](https://cmake.org/) (\u003e= 3.8)\n* (git)\n\n### Building Calc4\n\n1. Install CMake\n    * dnf\n        ```\n        sudo dnf install cmake -y\n        ```\n    * apt\n        ```\n        sudo apt update\n        sudo apt install cmake -y\n        ```\n    * Binary\n        * https://cmake.org/\n1. Build and run\n    * Unix-like systems\n        ```\n        git clone https://github.com/proprowataya/calc4.git\n        mkdir calc4-build\n        cd calc4-build\n        cmake ../calc4\n        cmake --build .\n        ./calc4 ../calc4/sample/MandelbrotSet.txt\n        ```\n    * Windows\n        ```\n        git clone https://github.com/proprowataya/calc4.git\n        mkdir calc4-build\n        cd calc4-build\n        cmake ..\\calc4\n        cmake --build . --config Release\n        .\\Release\\calc4.exe ..\\calc4\\sample\\MandelbrotSet.txt\n        ```\n\nIf nothing is specified as a command-line argument, Calc4 works as REPL. Please input what you want to evaluate.\n\n```\n$ ./calc4\nCalc4 REPL\n    Integer size: 64\n    Executor: StackMachine\n    Optimize: on\n\n\u003e 72P101P108P108P111P32P119P111P114P108P100P33P10P\nHello world!\n0\nElapsed: 0.1183 ms\n\n\u003e D[fib|n|n \u003c= 1? n ? (n-1){fib} + (n-2){fib}] 38{fib}\n39088169\nElapsed: 1457.58 ms\n\n\u003e\n```\n\n### JIT Compilation (Optional)\n\nYou can use the JIT compiler supported by LLVM. The steps to enable JIT compilation are as follows.\n\n1. Install [LLVM](https://llvm.org/)\n    * apt\n        ```\n        sudo apt update\n        sudo apt install llvm-dev -y\n        ```\n    * dnf\n        ```\n        sudo dnf install llvm-devel -y\n        ```\n    * Windows\n        * You need to build the LLVM from the source code. Please follow [the official instructions](https://llvm.org/docs/GettingStartedVS.html).\n        * Make sure that ```llvm-config.exe``` is added to the PATH.\n1. Build again with an option\n    * Unix-like systems\n        ```\n        cmake ../calc4 -DENABLE_JIT=ON\n        cmake --build .\n        ./calc4\n        ```\n    * Windows\n        ```\n        cmake ..\\calc4 -DENABLE_JIT=ON\n        cmake --build . --config Release\n        .\\Release\\calc4.exe\n        ```\n\n## Sample Codes\n\n### Hello world\n\n* Calc4 Sample Code\n    ```\n    72P101P108P108P111P32P119P111P114P108P100P33P10P\n    ```\n* Equivalent to the following C code\n    ```c\n    putchar('H');\n    putchar('e');\n    putchar('l');\n    putchar('l');\n    putchar('o');\n    putchar(' ');\n    putchar('w');\n    putchar('o');\n    putchar('r');\n    putchar('l');\n    putchar('d');\n    putchar('!');\n    putchar('\\n');\n    return 0;\n    ```\n* Result\n    ```\n    \u003e 72P101P108P108P111P32P119P111P114P108P100P33P10P\n    Hello world!\n    0\n    Elapsed: 0.1312 ms\n    ```\n* The ```P``` operator prints the given operand as a character to the console. The value of the ```P``` operator itself is zero.\n\n### Addition\n\n* Calc4 Sample Code\n    ```\n    12 + 23\n    ```\n* Equivalent to\n    ```c\n    return 12 + 23;\n    ```\n* Result\n    ```\n    \u003e 12 + 23\n    35\n    Elapsed: 0.0216 ms\n    ```\n\n### Addition and Multiplication\n\n* Calc4 Sample Code\n    ```\n    1 + 2 * 3\n    ```\n* Equivalent to\n    ```c\n    return (1 + 2) * 3;\n    ```\n    * Not `1 + (2 * 3)`.\n* Result\n    ```\n    \u003e 1 + 2 * 3\n    9\n    Elapsed: 0.0193 ms\n    ```\n* This code is not evaluated to 7. The reason for this will be explained [later](#operator-precedence).\n\n### Defining Custom Operators\n\n* Calc4 Sample Code\n    ```\n    D[myadd|x, y|x + y] 12{myadd}23\n    ```\n* Equivalent to\n    ```c\n    int myadd(int x, int y) {\n        return x + y;\n    }\n\n    return myadd(12, 23);\n    ```\n* Result\n    ```\n    \u003e D[myadd|x, y|x + y] 12{myadd}23\n    35\n    Elapsed: 0.0765 ms\n    ```\n\n### Conditional Operators\n\n* Calc4 Sample Code\n    ```\n    1 == 2 ? 10 ? 20\n    ```\n* Equivalent to\n    ```c\n    return 1 == 2 ? 10 : 20;\n    ```\n* Result\n    ```\n    \u003e 1 == 2 ? 10 ? 20\n    20\n    Elapsed: 0.0727 ms\n    ```\n\n### Operators with Many Operands\n\n* Calc4 Sample Code\n    ```\n    D[sum|a, b, c, d, e|a + b + c + d + e] 1{sum}2{sum}3{sum}4{sum}5\n    ```\n* Equivalent to\n    ```c\n    int sum(int a, int b, int c, int d, int c) {\n        return a + b + c + d + e;\n    }\n\n    return sum(1, 2, 3, 4, 5);\n    ```\n* Result\n    ```\n    \u003e D[sum|a, b, c, d, e|a + b + c + d + e] 1{sum}2{sum}3{sum}4{sum}5\n    15\n    Elapsed: 0.1059 ms\n    ```\n* Calc4 allows operators with many operands.\n\n### Fibonacci Sequence (naïve version)\n\n* Calc4 Sample Code\n    ```\n    D[fib|n|n \u003c= 1? n ? (n-1){fib} + (n-2){fib}] 38{fib}\n    ```\n* Equivalent to\n    ```c\n    int fib(int n) {\n        return n \u003c= 1 ? n : fib(n - 1) + fib(n - 2);\n    }\n\n    return fib(38);\n    ```\n* Result (with JIT compilation)\n    ```\n    \u003e D[fib|n|n \u003c= 1? n ? (n-1){fib} + (n-2){fib}] 38{fib}\n    39088169\n    Elapsed: 158.858 ms\n    ```\n* `fib` is slow because its order is exponential.\n\n### Fibonacci Sequence (tail call version)\n\n* Calc4 Sample Code\n    ```\n    D[fib2|x, a, b|x ? ((x-1) ? ((x-1) {fib2} (a+b) {fib2}a) ? a) ? b] 38{fib2}1{fib2}0\n    ```\n* Equivalent to\n    ```c\n    int fib2(int x, int a, int b) {\n        if (x == 0) {\n            return b;\n        } else if (x == 1) {\n            return a;\n        } else {\n            return fib2(x - 1, a + b, a);\n        }\n    }\n\n    return fib2(38, 1, 0);\n    ```\n* Result (with JIT compilation)\n    ```\n    \u003e D[fib2|x, a, b|x ? ((x-1) ? ((x-1) {fib2} (a+b) {fib2}a) ? a) ? b] 38{fib2}1{fib2}0\n    39088169\n    Elapsed: 7.289 ms\n    ```\n* `fib2` is much faster than `fib`.\n\n### Variables\n\n* Calc4 Sample Code\n    ```\n    (123S)\n    (L)\n    ```\n* Equivalent to\n    ```c\n    int __default_var;\n\n    /* 123S */\n    __default_var = 123;\n\n    /* L */\n    return __default_var;\n    ```\n* Result\n    ```\n    \u003e 123S\n    123\n    Elapsed: 0.068 ms\n\n    \u003e L\n    123\n    Elapsed: 0.032 ms\n    ```\n* The operator ```S``` stores the given operand to the variable, and ```L``` loads it. The previous example loads and stores the default variable. To specify the variable name, write like ```S[abc]```, ```L[abc]```.\n* All variables are global, so their values are shared among operator calls.\n\n### Memory Accesses\n\n* Calc4 Sample Code\n    ```\n    (123-\u003e10)\n    (10@)\n    ```\n* Equivalent to\n    ```c\n    int __memory[VERY_LARGE_SIZE];\n\n    /* 123-\u003e10 */\n    __memory[10] = 123;\n\n    /* 10@ */\n    return __memory[10];\n    ```\n* Result\n    ```\n    \u003e 123-\u003e10\n    123\n    Elapsed: 0.0493 ms\n\n    \u003e 10@\n    123\n    Elapsed: 0.0389 ms\n    ```\n* Calc4 has a very large memory accessible from anywhere. The operator ```-\u003e``` and ```@``` accesses the memory. The ```-\u003e``` operator stores the left operand's value to the memory of the location of the right one.\n* The negative indices are also allowed.\n* The parentheses in the above code are required. If they are missing, the code will be interpreted as ```123-\u003e1010@```. This incomprehensible behavior is due to the handling of line breaks, which should be reconsidered in the future.\n\n### Input Operators\n\n* Calc4 Sample Code\n    ```\n    I\n    ```\n* Equivalent to\n    ```c\n    return getchar();\n    ```\n* Standard Input\n    ```\n    A\n    ```\n* Result\n    ```\n    \u003e I\n    A\n    65\n    Elapsed: 633.161 ms\n    ```\n* The operator ```I``` reads a character from standard input and returns it. In the above example, the user pressed the \"A\" key and the program displays 65, an ASCII code for \"A\".\n* [A sample calculator program](./sample/calculator.txt) uses this feature. The program reads an expression from standard input and prints the result.\n    * Usage\n        ```\n        $ echo \"1 + 2 * 3\" | calc4 calculator.txt\n        7\n        ```\n\n### Tarai Function\n\n[Tarai function](https://en.wikipedia.org/wiki/Tak_(function)) is often used when benchmarking programming languages.\n\n* Calc4 Sample Code\n    ```\n    D[tarai|x, y, z|x \u003c= y ? y ? (((x - 1){tarai}y{tarai}z){tarai}((y - 1){tarai}z{tarai}x){tarai}((z - 1){tarai}x{tarai}y))] 18{tarai}15{tarai}5\n    ```\n* Equivalent to\n    ```c\n    int tarai(int x, int y, int z) {\n        if (x \u003c= y) {\n            return y;\n        } else {\n            return tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y));\n        }\n    }\n\n    return tarai(18, 15, 5);\n    ```\n* Result (with JIT compilation)\n    ```\n    \u003e D[tarai|x, y, z|x \u003c= y ? y ? (((x - 1){tarai}y{tarai}z){tarai}((y - 1){tarai}z{tarai}x){tarai}((z - 1){tarai}x{tarai}y))] 18{tarai}15{tarai}5\n    18\n    Elapsed: 280.528 ms\n    ```\n* **NOTE:** The above C program took 225 ms to execute on my machine (compiled by clang with `-Ofast` option). Calc4's performance seems to be closer to native C.\n\n## Language Specification\n\n### Operator Precedence\n\nThe rules of operator precedence in Calc4 are as follows:\n* Operators with fewer operands have higher precedence.\n* Operators with the same number of operands have equal precedence. They are left-associative.\n\nThis is the reason why ``1 + 2 * 3`` is evaluated to 9 rather than 7.\n\n#### Conditional Operators\n\nWhen 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.\n\n* Calc4\n    * Code\n        ```\n        1 == 1 ? 2 ? 3 == 4 ? 5 ? 6\n        ```\n    * Result\n        ```\n        \u003e 1 == 1 ? 2 ? 3 == 4 ? 5 ? 6\n        5\n        ```\n* C\n    * Code\n        ```c\n        #include \u003cstdio.h\u003e\n\n        int main()\n        {\n            printf(\"%d\\n\", 1 == 1 ? 2 : 3 == 4 ? 5 : 6);\n            return 0;\n        }\n        ```\n    * Result\n        ```\n        $ ./a.out\n        2\n        ```\n\nSince all operators in Calc4 are left-associative, the code can be rewritten to:\n```\n(1 == 1 ? 2 ? 3 == 4) ? 5 ? 6\n```\n\nIn contrast, common programming languages including C have right-associative conditional operators. Therefore, the C code's condition is equivalent to:\n```c\n1 == 1 ? 2 : (3 == 4 ? 5 : 6)\n```\n\nMost programmers will expect C behavior. If you wish to get that in Calc4, you have to explicitly write parentheses as follows.\n\n```\n\u003e 1 == 1 ? 2 ? (3 == 4 ? 5 ? 6)\n2\n```\n\nThere 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.\n\n### Supplementary Texts\n\nYou 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.\n\nEvery 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.\n\nThe 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\".\n\n```\n1[xyz]+[Hello]2[qwerty]\n```\n\n## Tail Recursion Optimization\n\nIn 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.\n\nYou can easily observe this optimization by infinite recursive operators.\n\n```\nD[x||{x}] {x}\n```\n\nThe operator ```x``` clearly never stops. If you execute this without optimization, the program will crash.\n\n* Without optimization\n    ```\n    $ ./calc4 -O0\n    Calc4 REPL\n        Integer size: 64\n        Executor: StackMachine\n        Optimize: off\n\n    \u003e D[x||{x}] {x}\n    Error: Stack overflow\n    ```\n    * When using the JIT compiler, a segmentation fault will occur.\n\nOn 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.\n\n* With optimization\n    ```\n    $ ./calc4\n    Calc4 REPL\n        Integer size: 64\n        Executor: StackMachine\n        Optimize: on\n\n    \u003e D[x||{x}] {x}\n\n    ```\n\nIt 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.\n\n## Conclusion\n\nAs you can see from this README, Calc4 is far from a practical programming language. It is some kind of [Esoteric programming languages (esolang)](https://en.wikipedia.org/wiki/Esoteric_programming_language). Calc4 was developed with the motivation that designing an original programming language is a lot of fun.\n\n## Copyright\n\nCopyright (C) 2018-2024 Yuya Watari\n\n## License\n\nMIT License\n","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproprowataya%2Fcalc4","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fproprowataya%2Fcalc4","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproprowataya%2Fcalc4/lists"}