{"id":15517329,"url":"https://github.com/skx/math-compiler","last_synced_at":"2025-04-30T09:51:26.994Z","repository":{"id":57554062,"uuid":"168387802","full_name":"skx/math-compiler","owner":"skx","description":"A simple intel/AMD64 assembly-language compiler for mathematical operations","archived":false,"fork":false,"pushed_at":"2024-06-28T16:49:46.000Z","size":140,"stargazers_count":64,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-30T15:05:09.884Z","etag":null,"topics":["compiler","golang","maths","reverse-polish","toy","trivial"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"skx","custom":"https://steve.fi/donate/"}},"created_at":"2019-01-30T17:49:50.000Z","updated_at":"2025-03-10T13:15:06.000Z","dependencies_parsed_at":"2024-06-28T11:57:28.694Z","dependency_job_id":"10d0a27d-0de9-410e-8321-7ae4935f31e5","html_url":"https://github.com/skx/math-compiler","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fmath-compiler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fmath-compiler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fmath-compiler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fmath-compiler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skx","download_url":"https://codeload.github.com/skx/math-compiler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251679756,"owners_count":21626592,"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","golang","maths","reverse-polish","toy","trivial"],"created_at":"2024-10-02T10:12:33.392Z","updated_at":"2025-04-30T09:51:26.953Z","avatar_url":"https://github.com/skx.png","language":"Go","funding_links":["https://github.com/sponsors/skx","https://steve.fi/donate/"],"categories":[],"sub_categories":[],"readme":"[![Go Report Card](https://goreportcard.com/badge/github.com/skx/math-compiler)](https://goreportcard.com/report/github.com/skx/math-compiler)\n[![license](https://img.shields.io/github/license/skx/math-compiler.svg)](https://github.com/skx/math-compiler/blob/master/LICENSE)\n\nTable of Contents\n=================\n\n* [math-compiler](#math-compiler)\n* [Installation](#installation)\n* [Quick Overview](#quick-overview)\n* [About Our Output](#about-our-output)\n* [Test Cases](#test-cases)\n  * [Debugging the generated programs](#debugging-the-generated-programs)\n* [Possible Expansion?](#possible-expansion)\n  * [See Also](#see-also)\n* [Github Setup](#github-setup)\n\n\n\n\n# math-compiler\n\nThis project contains the simplest possible compiler, which converts mathematical operations into assembly language, allowing all the speed in your sums!\n\nBecause this is a simple project it provides only a small number of primitives:\n\n* `+` - Plus\n* `-` - Minus\n* `*` - Multiply\n* `/` - Divide\n* `^` - Raise to a power\n* `%` - Modulus\n* `!` - Factorial\n* `abs`\n* `sin`\n* `cos`\n* `tan`\n* `sqrt`\n* Stack operations:\n  * `swap` - Swap the top-two items on the stack\n  * `dup` - Duplicate the topmost stack-entry.\n* Built-in constants:\n  * `e`\n  * `pi`\n\nDespite this toy-functionality there is a lot going on, and we support:\n\n* Full RPN input\n* Floating-point numbers (i.e. one-third multipled by nine is 3)\n   * `1 3 / 9 *`\n* Negative numbers work as you'd expect.\n\nSome errors will be caught at run-time, as the generated code has support for:\n\n* Detecting, and preventing, division by zero.\n* Detecting insufficient arguments being present upon the stack.\n  * For example this program is invalid `3 +`, because the addition operator requires two operands.  (i.e. `3 4 +`)\n\n\n\n## Installation\n\nIf you just need a binary you can find them upon the [project release page](https://github.com/skx/math-compiler/releases), however if you wish to build and install locally you can do that in either of the standard ways:\n\n1. Install from the latest revision:\n\n```sh\n$ go install github.com/skx/math-compiler@master\n```\n\n2. Or you can clone the source, and build from it:\n\n```sh\n$ git clone https://github.com/skx/math-compiler\n$ cd math-compiler\n$ go install .\n```\n\n\n\n## Quick Overview\n\nThe intention of this project is mostly to say \"I wrote a compiler\", because I've already [experimented with a language](https://github.com/skx/monkey/), an [embedded evaluation engine](https://github.com/skx/evalfilter/), and [implemented a BASIC interpreter](https://github.com/skx/gobasic/).  The things learned from those projects were pretty useful, even if the actual results were not so obviously useful in themselves.\n\nBecause there are no shortages of toy-languages, and there is a lot of complexity in writing another for no real gain, I decided to just focus upon a simple core:\n\n* Allowing \"maths stuff\" to be \"compiled\".\n\nIn theory this would allow me to compile things like this:\n\n    2 + ( 4 * 54 )\n\nHowever I even simplified that, via the use of a \"[Reverse Polish](https://en.wikipedia.org/wiki/Reverse_Polish_notation)\" notation, so if you want to run that example you'd enter the expression as:\n\n    4 54 * 2 +\n\n\n\n## About Our Output\n\nThe output of `math-compiler` will be an assembly-language file, which then needs to be compiled before it may be executed.\n\nGiven our previous example of `2 + ( 4 * 54)` we can compile \u0026 execute that program like so:\n\n    $ math-compiler '4 54 * 2+' \u003e sample.s\n    $ gcc -static -o sample ./sample.s\n    $ ./sample\n    Result 218\n\nThere you see:\n\n* `math-compiler` was invoked, and the output written to the file `sample.s`.\n* `gcc` was used to assemble `sample.s` into the binary `sample`.\n* The actual binary was then executed, which showed the result of the calculation.\n\nIf you prefer you can also let the compiler do the heavy-lifting, and generate an executable for you directly.  Simply add `-compile`, and execute the generated `a.out` binary:\n\n    $ math-compiler -compile=true '2 8 ^'\n    $ ./a.out\n    Result 256\n\nOr to compile __and__ execute directly:\n\n    $ math-compiler -run '3 45 * 9 + 12 /'\n    Result 12\n\n\n\n## Test Cases\n\nThe codebase itself contains some simple test-cases, however these are not comprehensive as a large part of our operation is merely to populate a simple template-file, and it is hard to test that.\n\nTo execute the integrated tests use the standard go approach:\n\n    $ go test [-race] ./...\n\nIn addition to the internal test cases there are also some functional tests\ncontained in [test.sh](test.sh) - these perform some calculations and verify\nthey produce the correct result.\n\n    frodo ~/go/src/github.com/skx/math-compiler $ ./test.sh\n    ...\n    Expected output found for '2 0 ^' [0]\n    Expected output found for '2 1 ^' [2]\n    Expected output found for '2 2 ^' [4]\n    Expected output found for '2 3 ^' [8]\n    Expected output found for '2 4 ^' [16]\n    Expected output found for '2 5 ^' [32]\n    ...\n    Expected output found for '2 30 ^' [1073741824]\n    ...\n\n\n### Debugging the generated programs\n\nIf you run the compiler with the `-debug` flag a breakpoint will be generated\nimmediately at the start of the program.  You can use that breakpoint to easily\ndebug the generated binary via `gdb`.\n\nFor example you might generate a program \"`2 3 + 4 /`\" like so:\n\n    $ math-compiler -compile -debug '2 3 + 4 /'\n\nNow you can launch that binary under `gdb`, and run it:\n\n    $ gdb ./a.out\n    (gdb) run\n    ..\n    Program received signal SIGTRAP, Trace/breakpoint trap.\n    0x00000000006b20cd in main ()\n\nDissassemble the code via `disassemble`, and step over instructions one at a time via `stepi`.  If your program is long you might see a lot of output from the `disassemble` step:\n\n    (gdb) disassemble\n    Dump of assembler code for function main:\n       0x00000000006b20cb:\tpush   %rbp\n       0x00000000006b20cc:\tint3\n    =\u003e 0x00000000006b20cd:\tfldl   0x6b20b3\n       0x00000000006b20d4:\tfstpl  0x6b2090\n       0x00000000006b20db:\tmov    0x6b2090,%rax\n       0x00000000006b20e3:\tpush   %rax\n       0x00000000006b20e4:\tfldl   0x6b20bb\n       0x00000000006b20eb:\tfstpl  0x6b2090\n       0x00000000006b20f2:\tmov    0x6b2090,%rax\n       0x00000000006b20fa:\tpush   %rax\n       ...\n       ...\n\nYou can set a breakpoint at a line in the future, and continue running till\nyou hit it, with something like this:\n\n     (gdb) break *0x00000000006b20fa\n     (gdb) cont\n\nOnce there inspect the registers with commands like these two:\n\n     (gdb) print $rax\n     (gdb) info registers\n\nMy favourite is `info registers float`, which shows you the floating-point\nvalues as well as the raw values:\n\n     (gdb) info registers float\n     st0            0.140652076786443369638\t(raw 0x3ffc90071917a6263000)\n     st1            0\t(raw 0x00000000000000000000)\n     st2            0\t(raw 0x00000000000000000000)\n     ...\n     ...\n\nFurther documentation can be found in the `gdb` manual, which is worth reading\nif you've an interest in compilers, debuggers, and decompilers.\n\n\n\n## Possible Expansion?\n\nThe obvious thing to improve in this compiler is to add support for more operations.  At the moment support for the most obvious/common operations is present, but perhaps more functions could be added.\n\n\n\n## See Also\n\nIf you enjoyed this repository, then you might also enjoy my compiler for the [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) language.  The compiler there compiles brainfuck programs to x86-64 assembly-language:\n\n* [https://github.com/skx/bfcc](https://github.com/skx/bfcc)\n\n\n\n## Github Setup\n\nThis repository is configured to run tests upon every commit, and when\npull-requests are created/updated.  The testing is carried out via\n[.github/run-tests.sh](.github/run-tests.sh) which is used by the\n[github-action-tester](https://github.com/skx/github-action-tester) action.\n\nReleases are automated in a similar fashion via [.github/build](.github/build),\nand the [github-action-publish-binaries](https://github.com/skx/github-action-publish-binaries) action.\n\n\nSteve\n--\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskx%2Fmath-compiler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskx%2Fmath-compiler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskx%2Fmath-compiler/lists"}