├── .gitattributes ├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE.txt ├── LICENSE-MIT.txt ├── README.md ├── bf-examples ├── bench │ ├── bench.b │ ├── bench.in │ └── bench.out ├── inout │ ├── inout.b │ ├── inout.in │ └── inout.out ├── mandel │ ├── mandel.b │ ├── mandel.in │ └── mandel.out └── reverse │ ├── reverse.b │ ├── reverse.in │ └── reverse.out ├── build.rs ├── src ├── asm.rs ├── command.rs ├── config.rs ├── error.rs ├── fs.rs ├── main.rs └── optimized_command │ ├── mod.rs │ └── shift_elision.rs ├── test-utils ├── Cargo.lock ├── Cargo.toml └── src │ └── lib.rs └── tests └── integration.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | bf-examples/* linguist-vendored 2 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Install dependencies 13 | run: sudo apt install -y nasm 14 | - name: Build 15 | run: cargo build 16 | - name: Run tests 17 | run: cargo test -- --nocapture 18 | - name: Clippy 19 | run: cargo clippy --all-targets --all-features -- -D warnings 20 | - name: Format 21 | run: cargo fmt --all -- --check 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "c2-chacha" 5 | version = "0.2.2" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 10 | ] 11 | 12 | [[package]] 13 | name = "cfg-if" 14 | version = "0.1.9" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | 17 | [[package]] 18 | name = "getrandom" 19 | version = "0.1.11" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | dependencies = [ 22 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 25 | ] 26 | 27 | [[package]] 28 | name = "lazy_static" 29 | version = "1.4.0" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | 32 | [[package]] 33 | name = "libc" 34 | version = "0.2.62" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | 37 | [[package]] 38 | name = "nerve" 39 | version = "0.1.0" 40 | dependencies = [ 41 | "test-utils 0.1.0", 42 | ] 43 | 44 | [[package]] 45 | name = "ppv-lite86" 46 | version = "0.2.5" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | 49 | [[package]] 50 | name = "rand" 51 | version = "0.7.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | dependencies = [ 54 | "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", 55 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 56 | "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 59 | ] 60 | 61 | [[package]] 62 | name = "rand_chacha" 63 | version = "0.2.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | dependencies = [ 66 | "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 68 | ] 69 | 70 | [[package]] 71 | name = "rand_core" 72 | version = "0.5.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | dependencies = [ 75 | "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", 76 | ] 77 | 78 | [[package]] 79 | name = "rand_hc" 80 | version = "0.2.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | dependencies = [ 83 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 84 | ] 85 | 86 | [[package]] 87 | name = "redox_syscall" 88 | version = "0.1.56" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | 91 | [[package]] 92 | name = "remove_dir_all" 93 | version = "0.5.2" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | dependencies = [ 96 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "tempfile" 101 | version = "3.1.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | dependencies = [ 104 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 105 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 106 | "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 107 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 108 | "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 110 | ] 111 | 112 | [[package]] 113 | name = "test-utils" 114 | version = "0.1.0" 115 | dependencies = [ 116 | "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 117 | ] 118 | 119 | [[package]] 120 | name = "wasi" 121 | version = "0.5.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | 124 | [[package]] 125 | name = "winapi" 126 | version = "0.3.8" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | dependencies = [ 129 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 131 | ] 132 | 133 | [[package]] 134 | name = "winapi-i686-pc-windows-gnu" 135 | version = "0.4.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | 138 | [[package]] 139 | name = "winapi-x86_64-pc-windows-gnu" 140 | version = "0.4.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | 143 | [metadata] 144 | "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" 145 | "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" 146 | "checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" 147 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 148 | "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" 149 | "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" 150 | "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" 151 | "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" 152 | "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 153 | "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 154 | "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 155 | "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 156 | "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 157 | "checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" 158 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 159 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 160 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 161 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nerve" 3 | version = "0.1.0" 4 | authors = ["Josh Mcguigan"] 5 | edition = "2018" 6 | build = "build.rs" 7 | 8 | [dependencies] 9 | 10 | [dev-dependencies] 11 | test-utils = { path = "test-utils" } 12 | -------------------------------------------------------------------------------- /LICENSE-APACHE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 Josh Mcguigan 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Josh Mcguigan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nerve 2 | 3 | Nerve is a compiler for the esoteric programming language [brainfuck](https://esolangs.org/wiki/Brainfuck). 4 | 5 | ## Usage 6 | 7 | ```bash 8 | # compile `hello.b` to `hello.s` 9 | nerve hello.b 10 | 11 | # assemble `hello.s` to `hello.o` 12 | nasm hello.s -f elf64 -o hello.o 13 | 14 | # link `hello.o` to `hello` 15 | ld hello.o -o hello 16 | 17 | # run `hello` 18 | ./hello 19 | ``` 20 | 21 | ## Running the Nerve tests 22 | 23 | Nerve includes an integration test suite which requires `nasm` and `ld` to run. Once you have installed these dependencies, you can run the test suite with `cargo test`. 24 | 25 | ## Benchmarks 26 | 27 | Running `cargo test -- --nocapture` will print the run time of each binary produced by Nerve during integration testing. 28 | 29 | ## License 30 | 31 | Licensed under either of 32 | 33 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 34 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 35 | 36 | at your option. 37 | 38 | ### Contribution 39 | 40 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. 41 | -------------------------------------------------------------------------------- /bf-examples/bench/bench.b: -------------------------------------------------------------------------------- 1 | https://github dot com/kostya/benchmarks/blob/master/brainfuck/bench dot b 2 | >++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++ 3 | [>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++ 4 | ++++++++[>++++++++++[>++++++++++[>++++++++++[>+ 5 | +++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++. 6 | -------------------------------------------------------------------------------- /bf-examples/bench/bench.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshMcguigan/nerve/9167a62803460d5cc81624dcfd26b169e77ff5a5/bf-examples/bench/bench.in -------------------------------------------------------------------------------- /bf-examples/bench/bench.out: -------------------------------------------------------------------------------- 1 | ZYXWVUTSRQPONMLKJIHGFEDCBA 2 | -------------------------------------------------------------------------------- /bf-examples/inout/inout.b: -------------------------------------------------------------------------------- 1 | >+[>,] <[<] >>[.>] 2 | -------------------------------------------------------------------------------- /bf-examples/inout/inout.in: -------------------------------------------------------------------------------- 1 | abcd 2 | -------------------------------------------------------------------------------- /bf-examples/inout/inout.out: -------------------------------------------------------------------------------- 1 | abcd 2 | -------------------------------------------------------------------------------- /bf-examples/mandel/mandel.b: -------------------------------------------------------------------------------- 1 | A mandelbrot set fractal viewer written by Erik Bosman 2 | http://esoteric DOT sange DOT fi/brainfuck/utils/mandelbrot/ 3 | +++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[ 4 | >>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+ 5 | <<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>> 6 | >+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>> 7 | >>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>> 8 | >>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>> 9 | >>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>> 10 | [>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<< 11 | <<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[ 12 | >>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[ 13 | >+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[ 14 | -<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<< 15 | <<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<< 16 | [>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>> 17 | >>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+ 18 | <<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>> 19 | >>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<< 20 | +>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<< 21 | <]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>> 22 | >>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> 23 | >>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<< 24 | <<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<< 25 | <<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[-> 26 | >>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<< 27 | <<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++ 28 | +++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>- 29 | <<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>> 30 | [-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<< 31 | <+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[- 32 | ]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<< 33 | <<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]< 34 | <[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>> 35 | >>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>> 36 | [-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-< 37 | <<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>> 38 | ]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+ 39 | >>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> 40 | [->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- 41 | ]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> 42 | [>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 43 | ]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+> 44 | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++ 45 | +++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+ 46 | >>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[ 47 | -]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-< 48 | <<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<< 49 | [->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-] 50 | +>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<< 51 | <<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<< 52 | [<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<< 53 | <<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<< 54 | <<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<< 55 | <<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<< 56 | <<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<< 57 | <<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<< 58 | ]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<< 59 | [>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<< 60 | +>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<< 61 | <<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-< 62 | <<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[ 63 | [>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+ 64 | [>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->> 65 | [-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<< 66 | <[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[ 67 | >[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[ 68 | >>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]> 69 | >>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<< 70 | <<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<< 71 | <<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[- 72 | <<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>> 73 | >>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>> 74 | [-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<< 75 | +>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]> 76 | [-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>> 77 | >>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>> 78 | >>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<< 79 | ]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<< 80 | <+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>> 81 | >]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<< 82 | <<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<< 83 | <<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]< 84 | <<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]< 85 | <<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+ 86 | <]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>- 87 | <<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<< 88 | ]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+> 89 | >>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>- 90 | <<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[ 91 | ->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>> 92 | >>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>> 93 | >>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<< 94 | <<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<< 95 | <<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+ 96 | >>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>> 97 | ]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>> 98 | >>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>> 99 | >>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+ 100 | >>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[> 101 | [->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[- 102 | ]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>> 103 | [>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<< 104 | <<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>> 105 | >>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>> 106 | >>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+ 107 | <<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>> 108 | >>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>> 109 | >]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<] 110 | >>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<< 111 | ]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+< 112 | <<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]> 113 | >>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<< 114 | ->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[ 115 | >[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<< 116 | [<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<< 117 | <<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<< 118 | <<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<< 119 | <<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>> 120 | >+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<< 121 | <<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]< 122 | +<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>> 123 | >>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<< 124 | <<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<< 125 | <<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<< 126 | <<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-< 127 | <<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<< 128 | <<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<< 129 | <<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<< 130 | <<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>> 131 | >+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<< 132 | <<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>> 133 | >]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<< 134 | <<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>> 135 | >>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<- 136 | >>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<< 137 | <<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>> 138 | >>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<< 139 | <<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>> 140 | +>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+< 141 | <<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<< 142 | <<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>> 143 | -<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>> 144 | >>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++ 145 | +[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<< 146 | <<<<<]]>>>] 147 | -------------------------------------------------------------------------------- /bf-examples/mandel/mandel.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoshMcguigan/nerve/9167a62803460d5cc81624dcfd26b169e77ff5a5/bf-examples/mandel/mandel.in -------------------------------------------------------------------------------- /bf-examples/mandel/mandel.out: -------------------------------------------------------------------------------- 1 | AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDEGFFEEEEDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 2 | AAAAAAAAAAAAAAABBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDEEEFGIIGFFEEEDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBB 3 | AAAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEFFFI KHGGGHGEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBB 4 | AAAAAAAAAAAABBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEFFGHIMTKLZOGFEEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBB 5 | AAAAAAAAAAABBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEEFGGHHIKPPKIHGFFEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBBBB 6 | AAAAAAAAAABBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGHIJKS X KHHGFEEEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBB 7 | AAAAAAAAABBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGQPUVOTY ZQL[MHFEEEEEEEDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBB 8 | AAAAAAAABBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEFFFFFGGHJLZ UKHGFFEEEEEEEEDDDDDCCCCCCCCCCCCBBBBBBBBBBBB 9 | AAAAAAABBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEFFFFFFGGGGHIKP KHHGGFFFFEEEEEEDDDDDCCCCCCCCCCCBBBBBBBBBBB 10 | AAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEEFGGHIIHHHHHIIIJKMR VMKJIHHHGFFFFFFGSGEDDDDCCCCCCCCCCCCBBBBBBBBB 11 | AAAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDEEEEEEFFGHK MKJIJO N R X YUSR PLV LHHHGGHIOJGFEDDDCCCCCCCCCCCCBBBBBBBB 12 | AAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDEEEEEEEEEFFFFGH O TN S NKJKR LLQMNHEEDDDCCCCCCCCCCCCBBBBBBB 13 | AAAAABBCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDEEEEEEEEEEEEFFFFFGHHIN Q UMWGEEEDDDCCCCCCCCCCCCBBBBBB 14 | AAAABBCCCCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEFFFFFFGHIJKLOT [JGFFEEEDDCCCCCCCCCCCCCBBBBB 15 | AAAABCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEEFFFFFFGGHYV RQU QMJHGGFEEEDDDCCCCCCCCCCCCCBBBB 16 | AAABCCCCCCCCCCCCCCCCCDDDDDDDEEFJIHFFFFFFFFFFFFFFGGGGGGHIJN JHHGFEEDDDDCCCCCCCCCCCCCBBB 17 | AAABCCCCCCCCCCCDDDDDDDDDDEEEEFFHLKHHGGGGHHMJHGGGGGGHHHIKRR UQ L HFEDDDDCCCCCCCCCCCCCCBB 18 | AABCCCCCCCCDDDDDDDDDDDEEEEEEFFFHKQMRKNJIJLVS JJKIIIIIIJLR YNHFEDDDDDCCCCCCCCCCCCCBB 19 | AABCCCCCDDDDDDDDDDDDEEEEEEEFFGGHIJKOU O O PR LLJJJKL OIHFFEDDDDDCCCCCCCCCCCCCCB 20 | AACCCDDDDDDDDDDDDDEEEEEEEEEFGGGHIJMR RMLMN NTFEEDDDDDDCCCCCCCCCCCCCB 21 | AACCDDDDDDDDDDDDEEEEEEEEEFGGGHHKONSZ QPR NJGFEEDDDDDDCCCCCCCCCCCCCC 22 | ABCDDDDDDDDDDDEEEEEFFFFFGIPJIIJKMQ VX HFFEEDDDDDDCCCCCCCCCCCCCC 23 | ACDDDDDDDDDDEFFFFFFFGGGGHIKZOOPPS HGFEEEDDDDDDCCCCCCCCCCCCCC 24 | ADEEEEFFFGHIGGGGGGHHHHIJJLNY TJHGFFEEEDDDDDDDCCCCCCCCCCCCC 25 | A PLJHGGFFEEEDDDDDDDCCCCCCCCCCCCC 26 | ADEEEEFFFGHIGGGGGGHHHHIJJLNY TJHGFFEEEDDDDDDDCCCCCCCCCCCCC 27 | ACDDDDDDDDDDEFFFFFFFGGGGHIKZOOPPS HGFEEEDDDDDDCCCCCCCCCCCCCC 28 | ABCDDDDDDDDDDDEEEEEFFFFFGIPJIIJKMQ VX HFFEEDDDDDDCCCCCCCCCCCCCC 29 | AACCDDDDDDDDDDDDEEEEEEEEEFGGGHHKONSZ QPR NJGFEEDDDDDDCCCCCCCCCCCCCC 30 | AACCCDDDDDDDDDDDDDEEEEEEEEEFGGGHIJMR RMLMN NTFEEDDDDDDCCCCCCCCCCCCCB 31 | AABCCCCCDDDDDDDDDDDDEEEEEEEFFGGHIJKOU O O PR LLJJJKL OIHFFEDDDDDCCCCCCCCCCCCCCB 32 | AABCCCCCCCCDDDDDDDDDDDEEEEEEFFFHKQMRKNJIJLVS JJKIIIIIIJLR YNHFEDDDDDCCCCCCCCCCCCCBB 33 | AAABCCCCCCCCCCCDDDDDDDDDDEEEEFFHLKHHGGGGHHMJHGGGGGGHHHIKRR UQ L HFEDDDDCCCCCCCCCCCCCCBB 34 | AAABCCCCCCCCCCCCCCCCCDDDDDDDEEFJIHFFFFFFFFFFFFFFGGGGGGHIJN JHHGFEEDDDDCCCCCCCCCCCCCBBB 35 | AAAABCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEEFFFFFFGGHYV RQU QMJHGGFEEEDDDCCCCCCCCCCCCCBBBB 36 | AAAABBCCCCCCCCCCCCCCCCCCCCCCCCCDDDDEEEEEEEEEEEEEEEFFFFFFGHIJKLOT [JGFFEEEDDCCCCCCCCCCCCCBBBBB 37 | AAAAABBCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDEEEEEEEEEEEEFFFFFGHHIN Q UMWGEEEDDDCCCCCCCCCCCCBBBBBB 38 | AAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDEEEEEEEEEFFFFGH O TN S NKJKR LLQMNHEEDDDCCCCCCCCCCCCBBBBBBB 39 | AAAAAABBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDEEEEEEFFGHK MKJIJO N R X YUSR PLV LHHHGGHIOJGFEDDDCCCCCCCCCCCCBBBBBBBB 40 | AAAAAAABBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEEFGGHIIHHHHHIIIJKMR VMKJIHHHGFFFFFFGSGEDDDDCCCCCCCCCCCCBBBBBBBBB 41 | AAAAAAABBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEFFFFFFGGGGHIKP KHHGGFFFFEEEEEEDDDDDCCCCCCCCCCCBBBBBBBBBBB 42 | AAAAAAAABBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEFFFFFGGHJLZ UKHGFFEEEEEEEEDDDDDCCCCCCCCCCCCBBBBBBBBBBBB 43 | AAAAAAAAABBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGQPUVOTY ZQL[MHFEEEEEEEDDDDDDDCCCCCCCCCCCBBBBBBBBBBBBBB 44 | AAAAAAAAAABBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDEEEEEEFFGHIJKS X KHHGFEEEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBB 45 | AAAAAAAAAAABBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEEFGGHHIKPPKIHGFFEEEDDDDDDDDDCCCCCCCCCCBBBBBBBBBBBBBBBBBB 46 | AAAAAAAAAAAABBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDEEEEEFFGHIMTKLZOGFEEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBB 47 | AAAAAAAAAAAAABBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDEEEEFFFI KHGGGHGEDDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBB 48 | AAAAAAAAAAAAAAABBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDEEEFGIIGFFEEEDDDDDDDDCCCCCCCCCBBBBBBBBBBBBBBBBBBBBBBBBBB 49 | -------------------------------------------------------------------------------- /bf-examples/reverse/reverse.b: -------------------------------------------------------------------------------- 1 | +[->,----------]<[+++++++++++.<] 2 | -------------------------------------------------------------------------------- /bf-examples/reverse/reverse.in: -------------------------------------------------------------------------------- 1 | abcd 2 | -------------------------------------------------------------------------------- /bf-examples/reverse/reverse.out: -------------------------------------------------------------------------------- 1 | dcba 2 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | env, 3 | fs::{canonicalize, read_dir, File}, 4 | io::Write, 5 | path::Path, 6 | }; 7 | 8 | fn main() { 9 | let outfile_path = Path::new(&env::var("OUT_DIR").unwrap()).join("gen_tests.rs"); 10 | let mut outfile = File::create(outfile_path).unwrap(); 11 | for dir in read_dir("bf-examples").unwrap() { 12 | let dir = dir.unwrap().path(); 13 | let test_name = dir.file_name().unwrap().to_string_lossy(); 14 | 15 | // paths need to be converted to absolute paths with canonicalize 16 | // so they are still correct when used from a file in the OUT_DIR 17 | let mut source_file = dir.clone(); 18 | source_file.push(&format!("{}.b", test_name)); 19 | let source_file = canonicalize(source_file).unwrap(); 20 | 21 | let mut input_file = dir.clone(); 22 | input_file.push(&format!("{}.in", test_name)); 23 | let input_file = canonicalize(input_file).unwrap(); 24 | 25 | let mut output_file = dir.clone(); 26 | output_file.push(&format!("{}.out", test_name)); 27 | let output_file = canonicalize(output_file).unwrap(); 28 | 29 | write!( 30 | outfile, 31 | r#" 32 | #[test] 33 | fn {test_name}() {{ 34 | let compiled_binary = test_utils::CompiledBinary::new("{test_name}", include_str!("{source_file}")); 35 | compiled_binary.test(include_str!("{input_file}"), include_str!("{output_file}")); 36 | }} 37 | "#, 38 | test_name = test_name, 39 | source_file = source_file.to_string_lossy(), 40 | input_file = input_file.to_string_lossy(), 41 | output_file = output_file.to_string_lossy(), 42 | ) 43 | .unwrap(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/asm.rs: -------------------------------------------------------------------------------- 1 | use crate::OptimizedCommand; 2 | 3 | pub fn emit_asm(commands: &[OptimizedCommand]) -> String { 4 | let mut s = String::new(); 5 | 6 | s += "section .bss\n"; 7 | // define buffer of 30_000 bytes, initialized to zero 8 | s += "\tbuffer: resb 30000\n\n"; 9 | 10 | s += "section .text\n"; 11 | s += "\tglobal _start\n\n"; 12 | 13 | s += "_start:\n"; 14 | 15 | // store pointer to buffer in register R8 16 | s += "\tmov R8, buffer\n"; 17 | 18 | s = emit_asm_for_commands(s, &commands, 0).0; 19 | 20 | // exit with status code 0 21 | s += "\tmov rdi, 0\n"; 22 | s += "\tmov rax, 60\n"; 23 | s += "\tsyscall"; 24 | 25 | s 26 | } 27 | 28 | fn emit_asm_for_commands( 29 | mut s: String, 30 | commands: &[OptimizedCommand], 31 | mut next_loop_number: u16, 32 | ) -> (String, u16) { 33 | for command in commands { 34 | match command { 35 | OptimizedCommand::IncrementCell(value) => s += &format!("\tadd byte[R8], {}\n", value), 36 | OptimizedCommand::IncrementCellAtOffset(offset, value) => { 37 | s += &format!("\tadd byte[R8 + {}], {}\n", offset, value) 38 | } 39 | OptimizedCommand::DecrementCell(value) => s += &format!("\tsub byte[R8], {}\n", value), 40 | OptimizedCommand::IncrementPointer(num) => s += &format!("\tadd R8, {}\n", num), 41 | OptimizedCommand::DecrementPointer(num) => s += &format!("\tsub R8, {}\n", num), 42 | OptimizedCommand::Input => { 43 | // use syscall to read a single byte from std in 44 | s += "\tmov rdi, 0\n"; // 0 = std in 45 | s += "\tmov rsi, R8\n"; 46 | s += "\tmov rdx, 1\n"; // 1 = read a single byte 47 | s += "\tmov rax, 0\n"; // 0 = syscall id 48 | s += "\tsyscall\n"; 49 | } 50 | OptimizedCommand::Output => { 51 | // use syscall to write a single byte to std out 52 | s += "\tmov rdi, 1\n"; // 1 = std out 53 | s += "\tmov rsi, R8\n"; 54 | s += "\tmov rdx, 1\n"; // 1 = write a single byte 55 | s += "\tmov rax, 1\n"; // 1 = syscall id 56 | s += "\tsyscall\n"; 57 | } 58 | OptimizedCommand::While(commands) => { 59 | let this_loop_number = next_loop_number; 60 | next_loop_number += 1; 61 | s += "\tcmp byte[R8], 0\n"; 62 | s += &format!("\tje loop_{}_end\n", this_loop_number); 63 | s += &format!("\tloop_{}_start:\n", this_loop_number); 64 | let res = emit_asm_for_commands(s, commands, next_loop_number); 65 | s = res.0; 66 | next_loop_number = res.1; 67 | s += "\tcmp byte[R8], 0\n"; 68 | s += &format!("\tjne loop_{}_start\n", this_loop_number); 69 | s += &format!("\tloop_{}_end:\n", this_loop_number); 70 | } 71 | }; 72 | } 73 | 74 | (s, next_loop_number) 75 | } 76 | -------------------------------------------------------------------------------- /src/command.rs: -------------------------------------------------------------------------------- 1 | use crate::{CompilerError, Result}; 2 | 3 | #[derive(PartialEq)] 4 | pub enum Command { 5 | IncrementCell, 6 | DecrementCell, 7 | IncrementPointer, 8 | DecrementPointer, 9 | While(Vec), 10 | Output, 11 | Input, 12 | } 13 | 14 | pub fn parse(source_code: Vec) -> Result> { 15 | let (commands, remaining_source) = parse_block(&source_code); 16 | if remaining_source.is_empty() { 17 | Ok(commands) 18 | } else { 19 | Err(CompilerError::UnmatchedBracket) 20 | } 21 | } 22 | 23 | fn parse_block(mut remaining_source: &[u8]) -> (Vec, &[u8]) { 24 | let mut commands = vec![]; 25 | while let Some((byte, rem)) = remaining_source.split_first() { 26 | remaining_source = rem; 27 | let command = match byte { 28 | b'+' => Command::IncrementCell, 29 | b'-' => Command::DecrementCell, 30 | b'>' => Command::IncrementPointer, 31 | b'<' => Command::DecrementPointer, 32 | b'[' => { 33 | let (commands_in_the_loop, rem) = parse_block(remaining_source); 34 | remaining_source = rem; 35 | Command::While(commands_in_the_loop) 36 | } 37 | b']' => break, 38 | b'.' => Command::Output, 39 | b',' => Command::Input, 40 | _ => continue, // all other byte patterns ignored per language spec 41 | }; 42 | 43 | commands.push(command); 44 | } 45 | 46 | (commands, remaining_source) 47 | } 48 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use crate::{CompilerError, Result}; 2 | use std::path::PathBuf; 3 | 4 | pub struct CompilerConfig { 5 | pub source_file_path: PathBuf, 6 | } 7 | 8 | impl CompilerConfig { 9 | pub fn from_args() -> Result { 10 | let file_path = std::env::args().nth(1).ok_or(CompilerError::MissingArg)?; 11 | Ok(CompilerConfig { 12 | source_file_path: PathBuf::from(file_path), 13 | }) 14 | } 15 | 16 | pub fn output_file_path(&self) -> PathBuf { 17 | let mut output_file_path = self.source_file_path.clone(); 18 | output_file_path.set_extension("s"); 19 | output_file_path 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | pub type Result = std::result::Result; 2 | 3 | #[derive(Debug)] 4 | pub enum CompilerError { 5 | MissingArg, 6 | SourceFileRead, 7 | UnmatchedBracket, 8 | OutputFileWrite, 9 | } 10 | -------------------------------------------------------------------------------- /src/fs.rs: -------------------------------------------------------------------------------- 1 | use crate::{CompilerError, Result}; 2 | use std::{ 3 | fs::{write, File}, 4 | io::Read, 5 | path::Path, 6 | }; 7 | 8 | pub fn read_source(source_file_path: &Path) -> Result> { 9 | let mut f = File::open(source_file_path).map_err(|_| CompilerError::SourceFileRead)?; 10 | let mut buffer = Vec::new(); 11 | f.read_to_end(&mut buffer) 12 | .map_err(|_| CompilerError::SourceFileRead)?; 13 | 14 | Ok(buffer) 15 | } 16 | 17 | pub fn write_to_file(asm: String, file_path: &Path) -> Result<()> { 18 | write(file_path, asm).map_err(|_| CompilerError::OutputFileWrite) 19 | } 20 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod asm; 2 | use asm::emit_asm; 3 | 4 | mod command; 5 | use command::{parse, Command}; 6 | 7 | mod config; 8 | use config::CompilerConfig; 9 | 10 | mod error; 11 | use error::{CompilerError, Result}; 12 | 13 | mod fs; 14 | use fs::{read_source, write_to_file}; 15 | 16 | mod optimized_command; 17 | use optimized_command::{optimize, OptimizedCommand}; 18 | 19 | fn main() -> Result<()> { 20 | let config = CompilerConfig::from_args()?; 21 | let source_code: Vec = read_source(&config.source_file_path)?; 22 | let commands: Vec = parse(source_code)?; 23 | let optimized_commands: Vec = optimize(&commands); 24 | let asm: String = emit_asm(&optimized_commands); 25 | write_to_file(asm, &config.output_file_path())?; 26 | 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /src/optimized_command/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::Command; 2 | use std::{iter::Peekable, slice}; 3 | 4 | mod shift_elision; 5 | 6 | #[derive(Debug, PartialEq, Clone)] 7 | pub enum OptimizedCommand { 8 | IncrementCell(u16), 9 | IncrementCellAtOffset(u16, u16), 10 | DecrementCell(u16), 11 | IncrementPointer(u16), 12 | DecrementPointer(u16), 13 | While(Vec), 14 | Output, 15 | Input, 16 | } 17 | 18 | pub fn optimize(commands: &[Command]) -> Vec { 19 | let mut optimized_commands = vec![]; 20 | 21 | let mut iter = commands.iter().peekable(); 22 | while let Some(command) = iter.next() { 23 | let optimized_command = match command { 24 | Command::IncrementCell => { 25 | let mut num = 1; 26 | num += consume_commands(Command::IncrementCell, &mut iter); 27 | OptimizedCommand::IncrementCell(num) 28 | } 29 | Command::DecrementCell => { 30 | let mut num = 1; 31 | num += consume_commands(Command::DecrementCell, &mut iter); 32 | OptimizedCommand::DecrementCell(num) 33 | } 34 | Command::IncrementPointer => { 35 | let mut num = 1; 36 | num += consume_commands(Command::IncrementPointer, &mut iter); 37 | OptimizedCommand::IncrementPointer(num) 38 | } 39 | Command::DecrementPointer => { 40 | let mut num = 1; 41 | num += consume_commands(Command::DecrementPointer, &mut iter); 42 | OptimizedCommand::DecrementPointer(num) 43 | } 44 | Command::While(commands) => OptimizedCommand::While(optimize(&commands)), 45 | Command::Output => OptimizedCommand::Output, 46 | Command::Input => OptimizedCommand::Input, 47 | }; 48 | 49 | optimized_commands.push(optimized_command); 50 | } 51 | 52 | optimized_commands = shift_elision::apply(optimized_commands); 53 | 54 | optimized_commands 55 | } 56 | 57 | fn consume_commands(command_type: Command, iter: &mut Peekable>) -> u16 { 58 | let mut num = 0; 59 | while iter.peek() == Some(&&command_type) { 60 | iter.next(); 61 | num += 1; 62 | } 63 | 64 | num 65 | } 66 | -------------------------------------------------------------------------------- /src/optimized_command/shift_elision.rs: -------------------------------------------------------------------------------- 1 | use crate::OptimizedCommand; 2 | 3 | pub fn apply(commands: Vec) -> Vec { 4 | let mut optimized_commands = vec![]; 5 | let mut i = 0; 6 | 7 | while let Some(command1) = commands.get(i) { 8 | let mut output = match (command1, commands.get(i + 1), commands.get(i + 2)) { 9 | ( 10 | OptimizedCommand::IncrementPointer(pointer_increment), 11 | Some(OptimizedCommand::IncrementCell(cell_increment)), 12 | Some(OptimizedCommand::DecrementPointer(pointer_decrement)), 13 | ) => { 14 | let mut out = vec![OptimizedCommand::IncrementCellAtOffset( 15 | *pointer_increment, 16 | *cell_increment, 17 | )]; 18 | match pointer_increment.cmp(pointer_decrement) { 19 | std::cmp::Ordering::Less => { 20 | out.push(OptimizedCommand::DecrementPointer( 21 | pointer_decrement - pointer_increment, 22 | )); 23 | } 24 | // If the increment and decrement were equal, we 25 | // don't need to move the pointer at all 26 | std::cmp::Ordering::Equal => (), 27 | std::cmp::Ordering::Greater => { 28 | out.push(OptimizedCommand::IncrementPointer( 29 | pointer_increment - pointer_decrement, 30 | )); 31 | } 32 | } 33 | 34 | // in this case we are going to handle three instructions 35 | i += 3; 36 | 37 | out 38 | } 39 | (command, _, _) => { 40 | // in this branch we are handling a single instruction 41 | i += 1; 42 | vec![command.clone()] 43 | } 44 | }; 45 | 46 | optimized_commands.append(&mut output); 47 | } 48 | 49 | optimized_commands 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | 56 | #[test] 57 | fn pass_through_short_instruction_set() { 58 | let input = vec![OptimizedCommand::IncrementCell(1)]; 59 | let expected_output = input.clone(); 60 | 61 | assert_eq!(expected_output, apply(input)); 62 | } 63 | 64 | #[test] 65 | fn pass_through_non_relevant_instruction_set() { 66 | let input = vec![ 67 | OptimizedCommand::Output, 68 | OptimizedCommand::Output, 69 | OptimizedCommand::Output, 70 | ]; 71 | let expected_output = input.clone(); 72 | 73 | assert_eq!(expected_output, apply(input)); 74 | } 75 | 76 | #[test] 77 | fn equal_shift_of_one_increment_cell_by_one() { 78 | let input = vec![ 79 | OptimizedCommand::IncrementPointer(1), 80 | OptimizedCommand::IncrementCell(1), 81 | OptimizedCommand::DecrementPointer(1), 82 | ]; 83 | let expected_output = vec![OptimizedCommand::IncrementCellAtOffset(1, 1)]; 84 | 85 | assert_eq!(expected_output, apply(input)); 86 | } 87 | 88 | #[test] 89 | fn in_middle_of_program() { 90 | let input = vec![ 91 | OptimizedCommand::Output, 92 | OptimizedCommand::IncrementPointer(1), 93 | OptimizedCommand::IncrementCell(1), 94 | OptimizedCommand::DecrementPointer(1), 95 | OptimizedCommand::Output, 96 | OptimizedCommand::Output, 97 | OptimizedCommand::Output, 98 | ]; 99 | let expected_output = vec![ 100 | OptimizedCommand::Output, 101 | OptimizedCommand::IncrementCellAtOffset(1, 1), 102 | OptimizedCommand::Output, 103 | OptimizedCommand::Output, 104 | OptimizedCommand::Output, 105 | ]; 106 | 107 | assert_eq!(expected_output, apply(input)); 108 | } 109 | 110 | #[test] 111 | fn near_end_of_program() { 112 | let input = vec![ 113 | OptimizedCommand::Output, 114 | OptimizedCommand::IncrementPointer(1), 115 | OptimizedCommand::IncrementCell(1), 116 | OptimizedCommand::DecrementPointer(1), 117 | OptimizedCommand::Output, 118 | ]; 119 | let expected_output = vec![ 120 | OptimizedCommand::Output, 121 | OptimizedCommand::IncrementCellAtOffset(1, 1), 122 | OptimizedCommand::Output, 123 | ]; 124 | 125 | assert_eq!(expected_output, apply(input)); 126 | } 127 | 128 | #[test] 129 | fn equal_shift_of_one_increment_cell_by_two() { 130 | let input = vec![ 131 | OptimizedCommand::IncrementPointer(1), 132 | OptimizedCommand::IncrementCell(2), 133 | OptimizedCommand::DecrementPointer(1), 134 | ]; 135 | let expected_output = vec![OptimizedCommand::IncrementCellAtOffset(1, 2)]; 136 | 137 | assert_eq!(expected_output, apply(input)); 138 | } 139 | 140 | #[test] 141 | fn equal_shift_of_two_increment_cell_by_one() { 142 | let input = vec![ 143 | OptimizedCommand::IncrementPointer(2), 144 | OptimizedCommand::IncrementCell(1), 145 | OptimizedCommand::DecrementPointer(2), 146 | ]; 147 | let expected_output = vec![OptimizedCommand::IncrementCellAtOffset(2, 1)]; 148 | 149 | assert_eq!(expected_output, apply(input)); 150 | } 151 | 152 | #[test] 153 | fn net_positive_shift() { 154 | let input = vec![ 155 | OptimizedCommand::IncrementPointer(3), 156 | OptimizedCommand::IncrementCell(1), 157 | OptimizedCommand::DecrementPointer(2), 158 | ]; 159 | let expected_output = vec![ 160 | OptimizedCommand::IncrementCellAtOffset(3, 1), 161 | OptimizedCommand::IncrementPointer(1), 162 | ]; 163 | 164 | assert_eq!(expected_output, apply(input)); 165 | } 166 | 167 | #[test] 168 | fn net_negative_shift() { 169 | let input = vec![ 170 | OptimizedCommand::IncrementPointer(2), 171 | OptimizedCommand::IncrementCell(1), 172 | OptimizedCommand::DecrementPointer(3), 173 | ]; 174 | let expected_output = vec![ 175 | OptimizedCommand::IncrementCellAtOffset(2, 1), 176 | OptimizedCommand::DecrementPointer(1), 177 | ]; 178 | 179 | assert_eq!(expected_output, apply(input)); 180 | } 181 | 182 | // TODO handle decrement pointer followed by increment pointer 183 | // TODO handle decrement cell 184 | } 185 | -------------------------------------------------------------------------------- /test-utils/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "c2-chacha" 5 | version = "0.2.3" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "cfg-if" 13 | version = "0.1.10" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | 16 | [[package]] 17 | name = "getrandom" 18 | version = "0.1.13" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | dependencies = [ 21 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 24 | ] 25 | 26 | [[package]] 27 | name = "libc" 28 | version = "0.2.65" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | 31 | [[package]] 32 | name = "ppv-lite86" 33 | version = "0.2.6" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | 36 | [[package]] 37 | name = "rand" 38 | version = "0.7.2" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | dependencies = [ 41 | "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 42 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 46 | ] 47 | 48 | [[package]] 49 | name = "rand_chacha" 50 | version = "0.2.1" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | dependencies = [ 53 | "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 54 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 55 | ] 56 | 57 | [[package]] 58 | name = "rand_core" 59 | version = "0.5.1" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | dependencies = [ 62 | "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 63 | ] 64 | 65 | [[package]] 66 | name = "rand_hc" 67 | version = "0.2.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | dependencies = [ 70 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 71 | ] 72 | 73 | [[package]] 74 | name = "redox_syscall" 75 | version = "0.1.56" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | 78 | [[package]] 79 | name = "remove_dir_all" 80 | version = "0.5.2" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | dependencies = [ 83 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 84 | ] 85 | 86 | [[package]] 87 | name = "tempfile" 88 | version = "3.1.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | dependencies = [ 91 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 92 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 93 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 96 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "test-utils" 101 | version = "0.1.0" 102 | dependencies = [ 103 | "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 104 | ] 105 | 106 | [[package]] 107 | name = "wasi" 108 | version = "0.7.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | 111 | [[package]] 112 | name = "winapi" 113 | version = "0.3.8" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | dependencies = [ 116 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 117 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 118 | ] 119 | 120 | [[package]] 121 | name = "winapi-i686-pc-windows-gnu" 122 | version = "0.4.0" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | 125 | [[package]] 126 | name = "winapi-x86_64-pc-windows-gnu" 127 | version = "0.4.0" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | 130 | [metadata] 131 | "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" 132 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 133 | "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" 134 | "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" 135 | "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 136 | "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" 137 | "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" 138 | "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 139 | "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 140 | "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 141 | "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 142 | "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 143 | "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" 144 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 145 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 146 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 147 | -------------------------------------------------------------------------------- /test-utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-utils" 3 | version = "0.1.0" 4 | authors = ["Josh Mcguigan"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | tempfile = "3" 9 | -------------------------------------------------------------------------------- /test-utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | io::Write, 3 | path::PathBuf, 4 | process::{Command, Output, Stdio}, 5 | time::SystemTime, 6 | }; 7 | use tempfile::NamedTempFile; 8 | 9 | pub struct CompiledBinary { 10 | compiled_binary: PathBuf, 11 | test_name: &'static str, 12 | } 13 | 14 | impl CompiledBinary { 15 | pub fn new(test_name: &'static str, source_code: &str) -> Self { 16 | let mut source_file = NamedTempFile::new().expect("failed to create source file"); 17 | write!(source_file, "{}", source_code).expect("failed to write to source file"); 18 | 19 | // compile bf to asm 20 | assert!(Command::new("target/debug/nerve") 21 | .arg(format!("{}", source_file.path().to_string_lossy())) 22 | .status() 23 | .expect("Failed to execute process") 24 | .success()); 25 | 26 | let assembly_file = source_file.path().with_extension("s"); 27 | let object_file = assembly_file.with_extension("o"); 28 | // Using a non-standard ".bin" extension for the compiled binary here 29 | // because the tempfile has no extension. There isn't an easy way to 30 | // create the temp file with an extension, and if the compiled binary 31 | // overwrites the temp file, then it is deleted when the temp file goes 32 | // out of scope. 33 | let compiled_binary = object_file.clone().with_extension("bin"); 34 | 35 | // compile asm into object file 36 | assert!(Command::new("nasm") 37 | .args(&[ 38 | &assembly_file.to_string_lossy(), 39 | "-f", 40 | "elf64", 41 | "-o", 42 | &object_file.to_string_lossy(), 43 | ]) 44 | .status() 45 | .expect("Failed to execute process") 46 | .success()); 47 | 48 | // link asm object file into host binary 49 | assert!(Command::new("ld") 50 | .args(&[ 51 | &object_file.to_string_lossy(), 52 | "-o", 53 | &compiled_binary.to_string_lossy() 54 | ]) 55 | .status() 56 | .expect("Failed to execute process") 57 | .success()); 58 | 59 | Self { 60 | compiled_binary, 61 | test_name, 62 | } 63 | } 64 | 65 | fn run(&self, input: &str) -> Output { 66 | let mut child = Command::new(&self.compiled_binary) 67 | .stdin(Stdio::piped()) 68 | .stdout(Stdio::piped()) 69 | .spawn() 70 | .unwrap_or_else(|_| { 71 | panic!(format!( 72 | "Failed to spawn process {}", 73 | &self.compiled_binary.to_string_lossy() 74 | )) 75 | }); 76 | 77 | let stdin = child.stdin.as_mut().expect("Failed to open stdin"); 78 | stdin 79 | .write_all(input.as_bytes()) 80 | .expect("Failed to write to stdin"); 81 | 82 | child.wait_with_output().expect("Failed to read stdout") 83 | } 84 | 85 | pub fn test(&self, input: &str, expected_output: &str) { 86 | let start = SystemTime::now(); 87 | let output = self.run(input); 88 | let elapsed = start.elapsed().expect("system time error"); 89 | 90 | println!("{} completed in {:?}", &self.test_name, elapsed); 91 | 92 | // Trim end because we don't want to be picky about trailing newline 93 | assert_eq!( 94 | String::from_utf8_lossy(&output.stdout).trim_end(), 95 | expected_output.trim_end() 96 | ); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/integration.rs: -------------------------------------------------------------------------------- 1 | // See `build.rs` 2 | // One test is generated per program in the `bf-examples` directory 3 | include!(concat!(env!("OUT_DIR"), "/gen_tests.rs")); 4 | --------------------------------------------------------------------------------