Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/skx/math-compiler
A simple intel/AMD64 assembly-language compiler for mathematical operations
https://github.com/skx/math-compiler
compiler golang maths reverse-polish toy trivial
Last synced: 7 days ago
JSON representation
A simple intel/AMD64 assembly-language compiler for mathematical operations
- Host: GitHub
- URL: https://github.com/skx/math-compiler
- Owner: skx
- License: gpl-2.0
- Created: 2019-01-30T17:49:50.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2024-06-28T16:49:46.000Z (6 months ago)
- Last Synced: 2024-12-18T18:08:12.165Z (15 days ago)
- Topics: compiler, golang, maths, reverse-polish, toy, trivial
- Language: Go
- Homepage:
- Size: 137 KB
- Stars: 63
- Watchers: 3
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
[![Go Report Card](https://goreportcard.com/badge/github.com/skx/math-compiler)](https://goreportcard.com/report/github.com/skx/math-compiler)
[![license](https://img.shields.io/github/license/skx/math-compiler.svg)](https://github.com/skx/math-compiler/blob/master/LICENSE)Table of Contents
=================* [math-compiler](#math-compiler)
* [Installation](#installation)
* [Quick Overview](#quick-overview)
* [About Our Output](#about-our-output)
* [Test Cases](#test-cases)
* [Debugging the generated programs](#debugging-the-generated-programs)
* [Possible Expansion?](#possible-expansion)
* [See Also](#see-also)
* [Github Setup](#github-setup)# math-compiler
This project contains the simplest possible compiler, which converts mathematical operations into assembly language, allowing all the speed in your sums!
Because this is a simple project it provides only a small number of primitives:
* `+` - Plus
* `-` - Minus
* `*` - Multiply
* `/` - Divide
* `^` - Raise to a power
* `%` - Modulus
* `!` - Factorial
* `abs`
* `sin`
* `cos`
* `tan`
* `sqrt`
* Stack operations:
* `swap` - Swap the top-two items on the stack
* `dup` - Duplicate the topmost stack-entry.
* Built-in constants:
* `e`
* `pi`Despite this toy-functionality there is a lot going on, and we support:
* Full RPN input
* Floating-point numbers (i.e. one-third multipled by nine is 3)
* `1 3 / 9 *`
* Negative numbers work as you'd expect.Some errors will be caught at run-time, as the generated code has support for:
* Detecting, and preventing, division by zero.
* Detecting insufficient arguments being present upon the stack.
* For example this program is invalid `3 +`, because the addition operator requires two operands. (i.e. `3 4 +`)## Installation
If 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:
1. Install from the latest revision:
```sh
$ go install github.com/skx/math-compiler@master
```2. Or you can clone the source, and build from it:
```sh
$ git clone https://github.com/skx/math-compiler
$ cd math-compiler
$ go install .
```## Quick Overview
The 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.
Because 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:
* Allowing "maths stuff" to be "compiled".
In theory this would allow me to compile things like this:
2 + ( 4 * 54 )
However 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:
4 54 * 2 +
## About Our Output
The output of `math-compiler` will be an assembly-language file, which then needs to be compiled before it may be executed.
Given our previous example of `2 + ( 4 * 54)` we can compile & execute that program like so:
$ math-compiler '4 54 * 2+' > sample.s
$ gcc -static -o sample ./sample.s
$ ./sample
Result 218There you see:
* `math-compiler` was invoked, and the output written to the file `sample.s`.
* `gcc` was used to assemble `sample.s` into the binary `sample`.
* The actual binary was then executed, which showed the result of the calculation.If 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:
$ math-compiler -compile=true '2 8 ^'
$ ./a.out
Result 256Or to compile __and__ execute directly:
$ math-compiler -run '3 45 * 9 + 12 /'
Result 12## Test Cases
The 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.
To execute the integrated tests use the standard go approach:
$ go test [-race] ./...
In addition to the internal test cases there are also some functional tests
contained in [test.sh](test.sh) - these perform some calculations and verify
they produce the correct result.frodo ~/go/src/github.com/skx/math-compiler $ ./test.sh
...
Expected output found for '2 0 ^' [0]
Expected output found for '2 1 ^' [2]
Expected output found for '2 2 ^' [4]
Expected output found for '2 3 ^' [8]
Expected output found for '2 4 ^' [16]
Expected output found for '2 5 ^' [32]
...
Expected output found for '2 30 ^' [1073741824]
...### Debugging the generated programs
If you run the compiler with the `-debug` flag a breakpoint will be generated
immediately at the start of the program. You can use that breakpoint to easily
debug the generated binary via `gdb`.For example you might generate a program "`2 3 + 4 /`" like so:
$ math-compiler -compile -debug '2 3 + 4 /'
Now you can launch that binary under `gdb`, and run it:
$ gdb ./a.out
(gdb) run
..
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000000006b20cd in main ()Dissassemble 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:
(gdb) disassemble
Dump of assembler code for function main:
0x00000000006b20cb: push %rbp
0x00000000006b20cc: int3
=> 0x00000000006b20cd: fldl 0x6b20b3
0x00000000006b20d4: fstpl 0x6b2090
0x00000000006b20db: mov 0x6b2090,%rax
0x00000000006b20e3: push %rax
0x00000000006b20e4: fldl 0x6b20bb
0x00000000006b20eb: fstpl 0x6b2090
0x00000000006b20f2: mov 0x6b2090,%rax
0x00000000006b20fa: push %rax
...
...You can set a breakpoint at a line in the future, and continue running till
you hit it, with something like this:(gdb) break *0x00000000006b20fa
(gdb) contOnce there inspect the registers with commands like these two:
(gdb) print $rax
(gdb) info registersMy favourite is `info registers float`, which shows you the floating-point
values as well as the raw values:(gdb) info registers float
st0 0.140652076786443369638 (raw 0x3ffc90071917a6263000)
st1 0 (raw 0x00000000000000000000)
st2 0 (raw 0x00000000000000000000)
...
...Further documentation can be found in the `gdb` manual, which is worth reading
if you've an interest in compilers, debuggers, and decompilers.## Possible Expansion?
The 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.
## See Also
If 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:
* [https://github.com/skx/bfcc](https://github.com/skx/bfcc)
## Github Setup
This repository is configured to run tests upon every commit, and when
pull-requests are created/updated. The testing is carried out via
[.github/run-tests.sh](.github/run-tests.sh) which is used by the
[github-action-tester](https://github.com/skx/github-action-tester) action.Releases are automated in a similar fashion via [.github/build](.github/build),
and the [github-action-publish-binaries](https://github.com/skx/github-action-publish-binaries) action.Steve
--