├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 99_COFFEE_TIME.md │ ├── 20_BUG_REPORT.md │ └── 10_FEATURE_REQUEST.md ├── workflows │ ├── compiler-clang.yaml │ ├── automatic-lint.yaml │ ├── compiler-gcc.yaml │ ├── compiler-avr-gcc.yaml │ ├── automatic-tests.yaml │ ├── compiler-cc65.yaml │ ├── compiler-xtensa-gcc.yaml │ └── automatic-publish.yaml ├── PULL_REQUEST_TEMPLATE.md └── CODE_OF_CONDUCT.md ├── programs ├── libary.c ├── interpreter.c └── tests.c ├── docs ├── 404.html ├── favicon.ico ├── images │ ├── 3bc-logo-mid.png │ ├── 3bc-logo-large.png │ ├── 3bc-logo-menu.png │ ├── 3bc-logo-small.png │ ├── structure-en-us.png │ ├── structure-pt-br.png │ └── 3bc-logo-extra-large.png ├── _data │ └── main_plataforms.yml ├── _includes │ ├── download_btn.rhtml │ ├── download_list.rhtml │ ├── nav.rhtml │ └── head.rhtml ├── Gemfile ├── _layouts │ └── default.html ├── guide │ ├── install.md │ └── errors.md ├── manual.html ├── download.html ├── _config.yml ├── extra │ ├── advice.md │ ├── references.md │ ├── early-adopters.md │ └── roadmap.md ├── assets │ └── style.css ├── index.html └── support.md ├── .npmignore ├── .gitattributes ├── go.mod ├── examples ├── olamundo.3bc ├── pointers.3bc ├── heloworld.3bc ├── loop.3bc ├── loops │ └── where.3bc ├── loop_do_while.3bc ├── invert_helper.3bc ├── invert_default.3bc ├── procedure.3bc ├── ArduinoBlink │ └── ArduinoBlink.ino ├── invert_text.3bc ├── ArduinoHelloworld │ └── ArduinoHelloworld.ino ├── input_login.3bc ├── fibonacci.3bc ├── ArduinoInfo │ └── ArduinoInfo.ino └── math_basics.3bc ├── .commit-msg ├── Dockerfile ├── .clang-format ├── .gitignore ├── package.json ├── scripts ├── cc_interpreter.rb ├── cc_dynamiclib.rb ├── install_vm.sh └── commit_message_hook.rb ├── library.properties ├── PKGBUILD ├── tests ├── fulltest.fails.rb ├── fulltest.sleep.rb ├── fulltest.version.rb ├── fulltest.commit_message.rb ├── fulltest.extra.rb ├── fasttest.examples.rb └── fasttest.fails.rb ├── src ├── driver_accumulator.c ├── driver_mode.c ├── cpu_common.c ├── 3bc_errors.h ├── cpu_jump.c ├── ds_procedure_lifo.c ├── cpu_sleep.c ├── cpu_string.c ├── interpreter_readln.c ├── ds_label_hash.c ├── driver_custom.c ├── ds_hypervisor_darray.c ├── cpu_procedure.c ├── driver_interrupt.c ├── cpu_boolean.c ├── cpu_memory.c ├── interpreter_tokens.c ├── interpreter_ticket.c ├── driver_gpio.c ├── ds_program_fifo.c ├── driver_power.c ├── 3bc.h ├── driver_memory.c ├── cpu_math.c ├── driver_program.c ├── interpreter_parser.c └── driver_tty.c ├── README.md └── Makefile /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: rodrigodornelles 2 | -------------------------------------------------------------------------------- /programs/libary.c: -------------------------------------------------------------------------------- 1 | #include "../src/3bc.h" 2 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | redirect_to: / 4 | --- -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !examples/*.3bc 3 | !glue/*.js 4 | !full/*.js 5 | !bin/*.wasm 6 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /docs/images/3bc-logo-mid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/3bc-logo-mid.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=C 2 | Gemfile linguist-detectable=false 3 | Gemfile.lock linguist-detectable=false -------------------------------------------------------------------------------- /docs/images/3bc-logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/3bc-logo-large.png -------------------------------------------------------------------------------- /docs/images/3bc-logo-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/3bc-logo-menu.png -------------------------------------------------------------------------------- /docs/images/3bc-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/3bc-logo-small.png -------------------------------------------------------------------------------- /docs/images/structure-en-us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/structure-en-us.png -------------------------------------------------------------------------------- /docs/images/structure-pt-br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/structure-pt-br.png -------------------------------------------------------------------------------- /docs/images/3bc-logo-extra-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/HEAD/docs/images/3bc-logo-extra-large.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rodrigodornelles/3bc-lang 2 | 3 | require ( 4 | github.com/cc65/cc65 V2.19 // indirect 5 | github.com/ziglang/zig 0.10.0 // indirect 6 | ) 7 | -------------------------------------------------------------------------------- /docs/_data/main_plataforms.yml: -------------------------------------------------------------------------------- 1 | - name: windows-i386-interpreter-3bc.zip 2 | title: Windows 3 | 4 | - name: linux-i386-interpreter-3bc.tar.gz 5 | title: Linux 6 | 7 | - name: macos-x86_64-interpreter-3bc.tar.gz 8 | title: Mac OSX 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/99_COFFEE_TIME.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Anything 3 | about: "I would like to have a coffee and talk \u2615" 4 | title: "" 5 | labels: "" 6 | assignees: "rodrigodornelles" 7 | 8 | --- 9 | 10 | Hi, @rodrigodornelles! 11 | 12 | -------------------------------------------------------------------------------- /examples/olamundo.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | mode nill 0d2 3 | strc nill 'o' 4 | strc nill 'l' 5 | strc nill 'a' 6 | strc nill ' ' 7 | strc nill 'm' 8 | strc nill 'u' 9 | strc nill 'n' 10 | strc nill 'd' 11 | strc nill 'o' 12 | strc nill '!' -------------------------------------------------------------------------------- /examples/pointers.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | MODE NILL 0d06 3 | ALOC :a1 0d07 4 | ALOC :a2 0d00 5 | ALOC :p1 :a1 6 | ALOC :p2 :a2 7 | 8 | MODE NILL 0d07 9 | PUSH :p1 NILL 10 | PULL :p2 NILL 11 | 12 | MODE NILL 0d02 13 | STRI :a2 NILL -------------------------------------------------------------------------------- /.commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require './scripts/commit_message_hook' 4 | 5 | message = File.read(ARGV[0]) 6 | 7 | response = CommitMessageHook.call(message) 8 | 9 | response.fetch(:errors).each { |error| puts error } 10 | 11 | exit 0 if response.fetch(:success) 12 | exit 1 13 | -------------------------------------------------------------------------------- /examples/heloworld.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | mode nill 0d2 3 | strc nill 'h' 4 | strc nill 'e' 5 | strc nill 'l' 6 | strc nill 'l' 7 | strc nill 'o' 8 | strc nill 0x20 9 | strc nill 'w' 10 | strc nill 'o' 11 | strc nill 'r' 12 | strc nill 'l' 13 | strc nill 'd' 14 | strc nill '!' 15 | strc nill 0x0A 16 | -------------------------------------------------------------------------------- /examples/loop.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | MODE 0 6 3 | ALOC 'i' 3 4 | 5 | MODE 0 0d02 6 | NILL 0 0x1 7 | STRC 0 'H' 8 | STRC 0 'I' 9 | STRC 0 '!' 10 | STRC 0 0xA 11 | 12 | MODE 0 0d08 13 | PUSH 'i' 0 14 | 15 | MODE 0 0d12 16 | MATH 0 1 17 | 18 | MODE 0 0d08 19 | PULL 'i' 0 20 | 21 | MODE 0 9 22 | FGTO 0 0x1 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Stage 1 2 | from debian:11.5-slim as compiler 3 | 4 | COPY . /src 5 | RUN apt -y update && apt install -y musl-tools 6 | RUN musl-gcc src/programs/interpreter.c -Os -lm --static -o /tbc 7 | RUN strip /tbc 8 | 9 | # Stage 2 10 | FROM scratch 11 | COPY --from=compiler /tbc /tbc 12 | ENTRYPOINT ["/tbc"] 13 | -------------------------------------------------------------------------------- /docs/_includes/download_btn.rhtml: -------------------------------------------------------------------------------- 1 | {% assign size = asset.size | divided_by: 1024 %} 2 | 3 | 4 | 5 | {{ size }} KB 6 | 7 | 8 | file_download 9 | 10 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "jekyll", "~> 3.9.0" 4 | 5 | group :jekyll_plugins do 6 | gem "github-pages", "~> 209" 7 | gem 'jekyll-optional-front-matter' 8 | end 9 | 10 | platforms :mingw, :x64_mingw, :mswin, :jruby do 11 | gem "tzinfo", "~> 1.2" 12 | gem "tzinfo-data" 13 | end 14 | 15 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 16 | -------------------------------------------------------------------------------- /examples/loops/where.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | 3 | MODE NILL 0d6 4 | ALOC :var 3 5 | 6 | MODE NILL 0d8 7 | NILL NILL :where_entry 8 | PUSH :var NILL 9 | MODE NILL 0d9 10 | ZGTO NILL :where_exit 11 | 12 | MODE NILL 0d2 13 | STRC NILL '.' 14 | 15 | MODE NILL 0d8 16 | PUSH :var NILL 17 | MODE NILL 0d12 18 | MATH NILL 1 19 | MODE NILL 0d8 20 | PULL :var NILL 21 | 22 | MODE NILL 0d9 23 | GOTO NILL :where_entry 24 | NILL NILL :where_exit 25 | -------------------------------------------------------------------------------- /examples/loop_do_while.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | MODE NILL 0d2 3 | NILL NILL :do 4 | STRC NILL '\n' 5 | STRC NILL 'R' 6 | STRC NILL 'E' 7 | STRC NILL 'P' 8 | STRC NILL 'E' 9 | STRC NILL 'A' 10 | STRC NILL 'T' 11 | STRC NILL '?' 12 | STRC NILL ' ' 13 | STRC NILL '[' 14 | STRC NILL 'y' 15 | STRC NILL '/' 16 | STRC NILL 'n' 17 | STRC NILL ']' 18 | 19 | # while key = yes 20 | MODE NILL 0d4 21 | STRB :key NILL 22 | MODE NILL 0d9 23 | FGTO NILL :do 24 | -------------------------------------------------------------------------------- /examples/invert_helper.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | MODE NILL 0x6 #MODE_MEMORY 3 | ALOC 0X01 'A' 4 | ALOC 0X02 'B' 5 | ALOC 0X03 'C' 6 | 7 | MODE NILL 0x02 #MODE_STRING 8 | STRC 0X01 NILL 9 | STRC 0X02 NILL 10 | STRC 0X03 NILL 11 | STRC NILL 0x20 12 | 13 | MODE NILL 0d08 #MODE_MEM_AUX 14 | PUSH 0x01 NILL 15 | SPIN 0x03 NILL 16 | PULL 0x01 NILL 17 | 18 | MODE NILL 0d02 #MODE_STRING 19 | STRC 0X01 NILL 20 | STRC 0X02 NILL 21 | STRC 0X03 NILL 22 | STRC NILL 0x0A -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head.rhtml%} 5 | 6 | 7 | {% include nav.rhtml %} 8 | 9 |
10 | {{ content }} 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/20_BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: 'rodrigodornelles' 7 | --- 8 | 9 | ## Describe the bug 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | ## To Reproduce 14 | 15 | ## Expected behavior 16 | 17 | A clear and concise description of what you expected to happen. 18 | 19 | ## Additional context 20 | 21 | Add any other context about the problem here. 22 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # Classic style like webkit, but fits in an oldschool tty. 3 | BasedOnStyle: WebKit 4 | ColumnLimit: 80 5 | IndentWidth: 4 6 | UseTab: Never 7 | --- 8 | # Nobody likes everything in a row unless you're a rubyist. 9 | Language: Cpp 10 | AllowShortBlocksOnASingleLine: Empty 11 | AllowShortFunctionsOnASingleLine: Empty 12 | AllowShortIfStatementsOnASingleLine: Never 13 | # Force pointers to the type for C++. blyat! 14 | DerivePointerAlignment: false 15 | PointerAlignment: Left 16 | PointerAlignment: Left 17 | ... 18 | -------------------------------------------------------------------------------- /examples/invert_default.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | MODE NILL 0d6 #MODE_MEMORY 3 | ALOC 0X01 'A' 4 | ALOC 0X02 'B' 5 | ALOC 0X03 'C' 6 | 7 | MODE NILL 0d02 #MODE_STRING 8 | STRC 0X01 NILL 9 | STRC 0X02 NILL 10 | STRC 0X03 NILL 11 | STRC NILL 0x20 12 | 13 | MODE NILL 0d08 #MODE_MEM_AUX 14 | PUSH 0x01 NILL 15 | PULL 0x0A NILL 16 | PUSH 0x03 NILL 17 | PULL 0x01 NILL 18 | PUSH 0x0A NILL 19 | PULL 0x03 NILL 20 | 21 | MODE NILL 0d02 #MODE_STRING 22 | STRC 0X01 NILL 23 | STRC 0X02 NILL 24 | STRC 0X03 NILL 25 | STRC NILL 0x0A -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OSX Files 2 | .DS_Store 3 | 4 | # Windows Files 5 | Thumbs.db 6 | 7 | # Binary Files 8 | bin/ 9 | *.bin 10 | *.app 11 | *.exe 12 | *.nes 13 | *.obj 14 | *.out 15 | *.o 16 | *.s 17 | *.so 18 | *.dll 19 | *.dylib 20 | 3bc 21 | programs/* 22 | !programs/*.c 23 | 24 | # Jekyll files 25 | .jekyll-cache/ 26 | .sass-cache/ 27 | .jekyll-metadata 28 | Gemfile.lock 29 | _site/ 30 | 31 | # Log reports 32 | *.log 33 | 34 | # Compressed files 35 | *.tar.gz 36 | *.zip 37 | 38 | # IDE FILES 39 | .vscode 40 | 41 | # Tests files 42 | *.test.bin 43 | *.gcov 44 | *.gcno 45 | *.gcda -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "3bc-lang", 3 | "version": "0.1.4", 4 | "author": "RodrigoDornelles", 5 | "license": "GPL-3.0-or-later", 6 | "homepage": "https://3bc-lang.org", 7 | "repository": "github:rodrigodornelles/3bc-lang", 8 | "funding": "https://github.com/sponsors/RodrigoDornelles", 9 | "bugs": "https://github.com/RodrigoDornelles/3bc-lang/issues", 10 | "keywords": ["language", "native", "c", "c++", "virtual machine"], 11 | "description": "Low level language, tiny virtual machine that works on browser or nodejs. (Friendly Punched cards)" 12 | } 13 | -------------------------------------------------------------------------------- /docs/guide/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: How to install simply in just one step 3 | --- 4 | 5 | Installation guide 6 | ================== 7 | 8 | 9 | Linux / Mac OSX 10 | --------------- 11 | 12 | > simple vm lets execute programs with the `3bc` command. 13 | 14 | To install just run this command in terminal to install only the virtual machine 15 | 16 | ```BASH 17 | sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/master/scripts/install_vm.sh || curl -fsSL https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/master/scripts/install_vm.sh)" 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/procedure.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | # goto entry point 3 | MODE NILL 0d9 4 | GOTO NILL :main 5 | 6 | # procedure print world 7 | MODE NILL 0d2 8 | NILL NILL :world 9 | STRC NILL 'W' 10 | STRC NILL 'o' 11 | STRC NILL 'r' 12 | STRC NILL 'l' 13 | STRC NILL 'd' 14 | MODE NILL 0d41 15 | BACK NILL NILL 16 | 17 | # procedure print hello 18 | MODE NILL 0d2 19 | NILL NILL :hello 20 | STRC NILL 'H' 21 | STRC NILL 'e' 22 | STRC NILL 'l' 23 | STRC NILL 'l' 24 | STRC NILL 'o' 25 | MODE NILL 0d41 26 | BACK NILL NILL 27 | 28 | # entry point 29 | MODE NILL 0d42 30 | NILL NILL :main 31 | CALL NILL :hello 32 | CALL NILL :world -------------------------------------------------------------------------------- /scripts/cc_interpreter.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # Cross compiler interpreter's binaries 3 | for target in ENV["TARGETS"].split(" ") do 4 | done, error = "\u{2705}", "\u{274c}" 5 | name = target.split("-").slice(0,2).reverse.join("-").concat("-interpreter") 6 | ext = target["windows"]? ".exe": "" 7 | zip = target["windows"]? "ZIP": "TAR" 8 | cmd = <<-BASH.strip.delete "\n" 9 | make build 10 | CC_OUTPUT="3bc#{ext}" 11 | CC_LD_TARGET="#{target}" 12 | #{zip}="#{name}-3bc" 13 | BASH 14 | cmd = system cmd, :out => File::NULL, :err => (open "#{name}.log", 'a') 15 | puts "#{(cmd)? done: error} #{name}" 16 | end 17 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name = 3BC Language Virtual Machine 2 | version = 0.1.4 3 | author = Rodrigo Dornelles 4 | maintainer = Rodrigo Dornelles 5 | sentence = 3BC Language Virtual Machine 6 | paragraph = is a low-level and easy-to-learn programming language that works in the form of a virtual machine similar to a computer from the 60s, but with a surprising architecture that has only 3 bits. Despite having an aspect to be an esoteric language, it has a good general use capability to solve computational problems and advantages with implementation in embedded and microcontrollers. 7 | category = Other 8 | url = https://3bc-lang.org 9 | architectures = * 10 | includes= 3bc.h 11 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Rodrigo Dornelles 2 | # Contributor: yxqsnz 3 | pkgname="3bc-lang-git" 4 | pkgver="0.1.4" 5 | license=('GPL3') 6 | pkgrel=1 7 | pkgdesc="Low level language, tiny virtual machine that works on computers and microcontrollers. (Friendly Punched cards)" 8 | source=("3bc::git+https://github.com/RodrigoDornelles/3bc-lang.git#branch=master") 9 | makedepends=(gcc) 10 | arch=('i686' 'pentium4' 'x86_64' 'arm' 'armv7h' 'armv6h' 'aarch64') 11 | md5sums=("SKIP") 12 | 13 | build() { 14 | cd "${srcdir}/3bc" 15 | gcc -o 3bc -O2 -lm programs/interpreter.c 16 | } 17 | package() { 18 | cd "${srcdir}/3bc" 19 | install -Dm755 3bc "${pkgdir}/usr/bin/3bc" 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/compiler-clang.yaml: -------------------------------------------------------------------------------- 1 | name: Compiler clang 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | wasm: 11 | runs-on: ubuntu-latest 12 | container: emscripten/emsdk 13 | steps: 14 | - name: Checkout project 15 | uses: actions/checkout@v2 16 | 17 | - name: Build project 18 | run: emcc programs/interpreter.c -lm -O0 -s WASM=1 19 | asmjs: 20 | runs-on: ubuntu-latest 21 | container: emscripten/emsdk 22 | steps: 23 | - name: Checkout project 24 | uses: actions/checkout@v2 25 | 26 | - name: Build project 27 | run: emcc programs/interpreter.c -lm -O0 -s WASM=0 28 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the changes and the related issue. Please also include relevant motivation and context. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | # How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 19 | -------------------------------------------------------------------------------- /docs/manual.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Manual 3 | description: Complete manual with all the documentation available on the website. 4 | --- 5 | 6 |
7 | 8 |

9 |

Complete Manual

10 |

3BC LANGUAGE

11 |

12 | 13 | 3BC LOGO 18 |
19 | 20 | {% capture allcontent %} 21 | {% include_relative guide/tutorial-en-us.md %} 22 | {% include_relative guide/cheatsheet.md %} 23 | {% include_relative guide/errors.md %} 24 | {% include_relative extra/roadmap.md %} 25 | {% include_relative extra/early-adopters.md %} 26 | {% include_relative extra/references.md %} 27 | {% endcapture %} 28 | {{ allcontent | markdownify }} 29 | -------------------------------------------------------------------------------- /docs/download.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Download 3 | description: See all changelogs and download the latest version of 3BC language. 4 | click_here: https://3bc-lang.org/download 5 | redirect_from: ['changelogs', 'docs/changelogs', 'extra/changelogs'] 6 | --- 7 | 8 | {% assign first_release = site.github.releases | first %} 9 | {% for release in site.github.releases %} 10 | 11 |

{{ release.name }}

12 | 13 | {% if first_release.tag_name == release.tag_name %} 14 |

CLI Interpreter

15 | {% include download_list.rhtml type='interpreter' %} 16 | 17 |

Dynamic Libary

18 | {% include download_list.rhtml type='libary' %} 19 | {% else %} 20 |
21 | Download 22 | {% include download_list.rhtml %} 23 |
24 | {% endif %} 25 |

26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /scripts/cc_dynamiclib.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # Cross compiler dynamic libaries 3 | for target in ENV["TARGETS"].split(" ") do 4 | done, error = "\u{2705}", "\u{274c}" 5 | name = target.split("-").slice(0,2).reverse.join("-").concat("-libary-dynamic") 6 | ext = {"windows" => ".dll", "macos" => ".dylib", "linux" => ".so"} 7 | ext = ext[name.split("-").first] 8 | zip = target["windows"]? "ZIP": "TAR" 9 | cmd = <<-BASH.strip.delete "\n" 10 | make build 11 | CC_OUTPUT="3bc#{ext}" 12 | CC_SOURCES="programs/libary.c" 13 | CC_FLAGS="-fPIC -Os -lm" 14 | CC_LD_TARGET="#{target}" 15 | LD_FLAGS="-shared" 16 | #{zip}="#{name}-3bc" 17 | BASH 18 | cmd = system cmd, :out => File::NULL, :err => (open "#{name}.log", 'a') 19 | puts "#{(cmd)? done: error} #{name}" 20 | end 21 | -------------------------------------------------------------------------------- /examples/ArduinoBlink/ArduinoBlink.ino: -------------------------------------------------------------------------------- 1 | #define _3BC_DISABLE_INTERPRETER 2 | #include <3bc.h> 3 | 4 | struct app_3bc_s* VM; 5 | 6 | void setup() 7 | { 8 | VM = lang_3bc_init(); 9 | 10 | lang_3bc_line(VM, MODE, NILL, MODE_MEMORY); 11 | lang_3bc_line(VM, MUSE, LED_BUILTIN, MEM_CONFIG_GPIO_SEND); 12 | lang_3bc_line(VM, NILL, NILL, LED_BUILTIN); 13 | lang_3bc_line(VM, ALOC, LED_BUILTIN, HIGH); 14 | lang_3bc_line(VM, MODE, NILL, MODE_SLEEP); 15 | lang_3bc_line(VM, MILI, NILL, 250); 16 | lang_3bc_line(VM, MODE, NILL, MODE_MEMORY); 17 | lang_3bc_line(VM, ALOC, LED_BUILTIN, LOW); 18 | lang_3bc_line(VM, MODE, NILL, MODE_SLEEP); 19 | lang_3bc_line(VM, MILI, NILL, 250); 20 | lang_3bc_line(VM, MODE, NILL, MODE_JUMP); 21 | lang_3bc_line(VM, GOTO, NILL, LED_BUILTIN); 22 | } 23 | 24 | void loop() { 25 | lang_3bc_update(VM); 26 | } 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/10_FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: 'rodrigodornelles' 7 | 8 | --- 9 | 10 | ## Please Describe The Problem To Be Solved 11 | 12 | (Replace This Text: Please present a concise description of the problem to be addressed by this feature request. Please be clear what parts of the problem are considered to be in-scope and out-of-scope.) 13 | 14 | ## (Optional): Suggest A Solution 15 | 16 | (Replace This Text: A concise description of your preferred solution. Things to address include: 17 | 18 | - Details of the technical implementation 19 | - Tradeoffs made in design decisions 20 | - Caveats and considerations for the future 21 | 22 | If there are multiple solutions, please present each one separately. Save comparisons for the very end.) 23 | -------------------------------------------------------------------------------- /examples/invert_text.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | MODE NILL 0d9 3 | GOTO NILL :entry 4 | 5 | MODE NILL 0d7 6 | NILL NILL :print 7 | PUSH :ptr NILL 8 | MODE NILL 0d41 9 | ZRET NILL NILL 10 | MODE NILL 0d8 11 | PULL :buf NILL 12 | MODE NILL 0d2 13 | STRC :buf NILL 14 | MODE NILL 0d8 15 | PUSH :ptr NILL 16 | MODE NILL 0d11 17 | MATH NILL -1 18 | MODE NILL 0d8 19 | PULL :ptr NILL 20 | MODE NILL 0d9 21 | GOTO NILL :print 22 | 23 | MODE NILL 0d8 24 | NILL NILL :input 25 | PUSH :ptr NILL 26 | MODE NILL 0d11 27 | MATH NILL 1 28 | MODE NILL 0d8 29 | PULL :ptr NILL 30 | MODE NILL 0d3 31 | STRC :buf NILL 32 | MODE NILL 0d8 33 | PUSH :buf NILL 34 | MODE NILL 0d7 35 | PULL :ptr NILL 36 | MODE NILL 0d12 37 | MATH NILL '.' 38 | MODE NILL 0d41 39 | ZRET NILL NILL 40 | MODE NILL 0d9 41 | GOTO NILL :input 42 | 43 | MODE NILL 0d6 44 | NILL NILL :entry 45 | ALOC :ptr 0x01 46 | MODE NILL 0d42 47 | CALL NILL :input 48 | CALL NILL :print 49 | -------------------------------------------------------------------------------- /programs/interpreter.c: -------------------------------------------------------------------------------- 1 | #include "../src/3bc.h" 2 | 3 | int main(int argc, char** argv) 4 | { 5 | struct app_3bc_s* const VM = lang_3bc_init(argc, argv); 6 | /** 7 | * put transpiled program here. 8 | * @example:* 9 | lang_3bc_line(VM, MODE, NILL, MODE_STRING); 10 | lang_3bc_line(VM, STRC, NILL, 'H'); 11 | lang_3bc_line(VM, STRC, NILL, 'E'); 12 | lang_3bc_line(VM, STRC, NILL, 'L'); 13 | lang_3bc_line(VM, STRC, NILL, 'L'); 14 | lang_3bc_line(VM, STRC, NILL, 'O'); 15 | lang_3bc_line(VM, STRC, NILL, 0x20); 16 | lang_3bc_line(VM, STRC, NILL, 'W'); 17 | lang_3bc_line(VM, STRC, NILL, 'O'); 18 | lang_3bc_line(VM, STRC, NILL, 'R'); 19 | lang_3bc_line(VM, STRC, NILL, 'L'); 20 | lang_3bc_line(VM, STRC, NILL, 'D'); 21 | lang_3bc_line(VM, STRC, NILL, '!'); 22 | lang_3bc_line(VM, STRC, NILL, '\n'); 23 | */ 24 | 25 | while (lang_3bc_update(VM)) 26 | ; 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /docs/_includes/download_list.rhtml: -------------------------------------------------------------------------------- 1 | 2 | {% if include.type %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% assign assets = release.assets | where_exp: "item", "item.name contains include.type" %} 10 | {% for asset in assets %} 11 | {% assign plataform = asset.name | split: "-" | first | capitalize %} 12 | {% assign architeture = asset.name | split: "-" | slice: 1 %} 13 | 14 | 15 | 16 | 17 | 18 | {% endfor %} 19 |
SystemArchitetureDownload
{{ plataform }}{{ architeture }}{% include download_btn.rhtml %}
20 | {% else %} 21 | 22 | 23 | 24 | 25 | 26 | {% for asset in release.assets %} 27 | 28 | 29 | 30 | 31 | {% endfor %} 32 |
File nameDownload
{{ asset.name }}{% include download_btn.rhtml %}
33 | {% endif %} -------------------------------------------------------------------------------- /examples/ArduinoHelloworld/ArduinoHelloworld.ino: -------------------------------------------------------------------------------- 1 | #define _3BC_DISABLE_INTERPRETER 2 | #include <3bc.h> 3 | 4 | struct app_3bc_s* VM; 5 | 6 | void setup() 7 | { 8 | Serial.begin(9600); 9 | 10 | VM = lang_3bc_init(); 11 | 12 | lang_3bc_print(VM, tty_output, [](char* output){ 13 | Serial.write(output); 14 | }); 15 | 16 | lang_3bc_line(VM, MODE, NILL, 2); 17 | lang_3bc_line(VM, STRC, NILL, 'H'); 18 | lang_3bc_line(VM, STRC, NILL, 'e'); 19 | lang_3bc_line(VM, STRC, NILL, 'l'); 20 | lang_3bc_line(VM, STRC, NILL, 'l'); 21 | lang_3bc_line(VM, STRC, NILL, 'o'); 22 | lang_3bc_line(VM, STRC, NILL, ' '); 23 | lang_3bc_line(VM, STRC, NILL, 'w'); 24 | lang_3bc_line(VM, STRC, NILL, 'o'); 25 | lang_3bc_line(VM, STRC, NILL, 'r'); 26 | lang_3bc_line(VM, STRC, NILL, 'l'); 27 | lang_3bc_line(VM, STRC, NILL, 'd'); 28 | lang_3bc_line(VM, STRC, NILL, '!'); 29 | lang_3bc_line(VM, STRC, NILL, '\n'); 30 | } 31 | 32 | void loop() { 33 | lang_3bc_update(VM); 34 | } 35 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: 3BC LANG 2 | author: Rodrigo Dornelles 3 | locale: en 4 | baseurl: "/" 5 | url: "https://3bc-lang.org" 6 | description: >- 7 | 3BC Lang is Low-level language, 8 | tiny virtual machine, intermediate representation, 9 | embeddable, easy for beginners. (Friendly Punched cards) 10 | 11 | description_pt: >- 12 | 3BC Lang é 13 | uma linguagem de baixo nível, 14 | incorporável,
15 | micro-máquinavirtual, 16 | representação intermediária, 17 | fácil para iniciantes. 18 | (amigável para cartões perfurados) 19 | 20 | defaults: 21 | - 22 | scope: 23 | path: "" 24 | values: 25 | layout: "default" 26 | 27 | plugins: 28 | - jekyll-optional-front-matter 29 | - jekyll-titles-from-headings 30 | - jekyll-github-metadata 31 | - jekyll-default-layout 32 | - jekyll-relative-links 33 | - jekyll-redirect-from 34 | - jekyll-seo-tag 35 | - jekyll-sitemap 36 | - jekyll-feed 37 | - jemoji 38 | -------------------------------------------------------------------------------- /.github/workflows/automatic-lint.yaml: -------------------------------------------------------------------------------- 1 | name: Automatic lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | arduino: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: arduino/arduino-lint-action@v1 17 | with: 18 | library-manager: update 19 | 20 | clang-format: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: test format 25 | run: clang-format --dry-run -ferror-limit=1 --Werror --verbose -i programs/*.c src/*.c src/*.h 26 | 27 | clang-tidy: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | - name: test lint 32 | run: clang-tidy programs/interpreter.c --warnings-as-errors=* -- 33 | 34 | gomod-tidy: 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v3 38 | - name: test lint 39 | run: go mod tidy 40 | -------------------------------------------------------------------------------- /.github/workflows/compiler-gcc.yaml: -------------------------------------------------------------------------------- 1 | name: Compiler gcc 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | linux: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout project 14 | uses: actions/checkout@v2 15 | 16 | - name: Build project 17 | run: gcc programs/interpreter.c -lm -O0 18 | 19 | macos10: 20 | runs-on: macos-10.15 21 | steps: 22 | - name: Checkout project 23 | uses: actions/checkout@v2 24 | 25 | - name: Build project 26 | run: gcc programs/interpreter.c -O0 27 | 28 | macos11: 29 | runs-on: macos-11 30 | steps: 31 | - name: Checkout project 32 | uses: actions/checkout@v2 33 | 34 | - name: Build project 35 | run: gcc programs/interpreter.c -O0 36 | 37 | windows: 38 | runs-on: windows-latest 39 | steps: 40 | - name: Checkout project 41 | uses: actions/checkout@v2 42 | 43 | - name: Build project 44 | run: gcc programs/interpreter.c -O0 45 | -------------------------------------------------------------------------------- /.github/workflows/compiler-avr-gcc.yaml: -------------------------------------------------------------------------------- 1 | name: Compiler avr-gcc 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | arduino: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout project 14 | uses: actions/checkout@v2 15 | with: 16 | path: project 17 | 18 | - name: Checkout arduino-cli 19 | run: curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh 20 | 21 | - name: Configure arduino-cli 22 | run: | 23 | ./bin/arduino-cli config init 24 | ./bin/arduino-cli config set library.enable_unsafe_install true 25 | ./bin/arduino-cli core install arduino:avr 26 | 27 | - name: Prepare project 28 | run: | 29 | zip -r lib.zip project/* 30 | mv ./project/examples/ArduinoHelloworld/ArduinoHelloworld.ino ./bin/bin.ino 31 | ./bin/arduino-cli lib install --zip-path lib.zip 32 | 33 | - name: Build project 34 | run: | 35 | cd bin/ 36 | ./arduino-cli compile --fqbn arduino:avr:uno 37 | -------------------------------------------------------------------------------- /tests/fulltest.fails.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | require 'minitest/spec' 3 | require 'minitest/autorun' 4 | 5 | class TestFails < Minitest::Test 6 | def test_error_unkown 7 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.10,5.0.0") 8 | assert_match /ERROR CODE\:(\t| )?(0x000000)/, stderr 9 | assert_equal 0, status.exitstatus 10 | end 11 | 12 | def test_seg_fault 13 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "7.0.10,1.0.11") 14 | assert_match /ERROR CODE\:(\t| )?(0x00000B)/, stderr 15 | assert_equal 11, status.exitstatus 16 | end 17 | 18 | def test_none_tty 19 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.10,2.0.0") 20 | assert_match /ERROR CODE\:(\t| )?(0x3BC015)/, stderr 21 | assert_equal 15, status.exitstatus 22 | end 23 | 24 | def test_unsupported 25 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.10,3.0.0") 26 | assert_match /ERROR CODE\:(\t| )?(0x3BC016)/, stderr 27 | assert_equal 15, status.exitstatus 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /docs/_includes/nav.rhtml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /.github/workflows/automatic-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Automatic tests 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | fast: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout project 14 | uses: actions/checkout@v2 15 | 16 | - name: Run fast tests suite 17 | run: make tests 18 | full: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout project 22 | uses: actions/checkout@v2 23 | 24 | - name: Run full tests suite 25 | run: make tests-full 26 | 27 | - name: "Report tests (TODO: replace to codacy)" 28 | if: false 29 | run: | 30 | gcov unit.c 31 | bash <(curl -s https://codecov.io/bash) 32 | 33 | install_vm_test: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Install 3bc vm 37 | run: sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/rodrigodornelles/3bc-lang/master/scripts/install_vm.sh || curl -fsSL https://raw.githubusercontent.com/rodrigodornelles/3bc-lang/master/scripts/install_vm.sh)" 38 | 39 | - name: Run test 40 | run: echo '7.0.2,1.0.1'| 3bc 41 | -------------------------------------------------------------------------------- /examples/input_login.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | mode nill 0d02 3 | strc nill 0x0A 4 | strc nill '[' 5 | strc nill '?' 6 | strc nill ']' 7 | strc nill 0x20 8 | strc nill 'l' 9 | strc nill 'o' 10 | strc nill 'g' 11 | strc nill 'i' 12 | strc nill 'n' 13 | strc nill ':' 14 | strc nill 0x20 15 | 16 | mode nill 0d03 17 | strc 0x01 nill 18 | strc 0x02 nill 19 | strc 0x03 nill 20 | 21 | mode nill 0d02 22 | strc nill 0x0A 23 | strc nill '[' 24 | strc nill '?' 25 | strc nill ']' 26 | strc nill 0x20 27 | strc nill 'p' 28 | strc nill 'a' 29 | strc nill 's' 30 | strc nill 's' 31 | strc nill 'w' 32 | strc nill 'o' 33 | strc nill 'r' 34 | strc nill 'd' 35 | strc nill ':' 36 | strc nill 0x20 37 | 38 | mode nill 0d05 39 | strc 0x04 nill 40 | strc 0x05 nill 41 | strc 0x06 nill 42 | 43 | mode nill 0d02 44 | strc nill 0x0A 45 | strc nill 0x0A 46 | strc nill '[' 47 | strc nill '!' 48 | strc nill ']' 49 | strc nill 0x20 50 | strc nill 'p' 51 | strc nill 'r' 52 | strc nill 'e' 53 | strc nill 's' 54 | strc nill 's' 55 | strc nill 0x20 56 | strc nill 'a' 57 | strc nill 'n' 58 | strc nill 'y' 59 | strc nill 0x20 60 | strc nill 'k' 61 | strc nill 'e' 62 | strc nill 'y' 63 | strc nill '.' 64 | strc nill 0x0A 65 | 66 | mode nill 0d4 67 | strc full nill 68 | -------------------------------------------------------------------------------- /scripts/install_vm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function req { 4 | wget -qo- -O - "$1" 2>/dev/null || curl -fsSL "$1" 5 | } 6 | function get_release() { 7 | req https://api.github.com/repos/rodrigodornelles/3bc-lang/releases/latest -s | grep "tag_name" | sed 's/[^0-9.]*//g' 8 | } 9 | function get_arch { 10 | case $(uname -m) in 11 | x86_64) 12 | echo "x86_64" 13 | ;; 14 | i*86) 15 | echo "i386" 16 | ;; 17 | *) 18 | echo "x86_64" 19 | ;; 20 | esac 21 | } 22 | function get_os() { 23 | case $(uname) in 24 | Darwin) 25 | echo "macos" 26 | ;; 27 | Linux) 28 | echo "linux" 29 | ;; 30 | esac 31 | } 32 | 33 | function main { 34 | RELEASE=$(get_release) 35 | echo "info: installing release ${RELEASE}" 36 | DOWNLOAD_URL="https://github.com/RodrigoDornelles/3bc-lang/releases/download/${RELEASE}/$(get_os)-$(get_arch)-interpreter-3bc.tar.gz" 37 | echo "info: downloading ${DOWNLOAD_URL}" 38 | req "${DOWNLOAD_URL}" | tar -xz -C /usr/local/bin 39 | chmod +x /usr/local/bin/3bc 40 | echo "info: 3bc is now installed, great!" 41 | } 42 | # check if user is root 43 | if [ "$(id -u)" != "0" ]; then 44 | echo "error: this script must be run as root" 1>&2 45 | exit 1 46 | fi 47 | main 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/extra/advice.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: some warnings about decisions made in language development, or remarks on important considerations. 3 | --- 4 | 5 | Advice 6 | ======== 7 | 8 | some warnings about decisions made in language development, or remarks on important considerations. 9 | 10 | Why the codacy was removed? 11 | ----------------- 12 | codacity was removed for showing false positives in functions with variable parameter amounts. 13 | 14 | Why the codecov was removed? 15 | ------------------ 16 | Codecov has a bad implementation to deal with calculating coverage coefficient in projects above 99.9% where adding and removing **comments** can trigger loss of coverage error. 17 | 18 | * see the old history here: 19 | 20 | Does the official website make an apology for Bolsonaro? 21 | -------------------------------------------------------- 22 | 23 | **NOT!** :fist_raised: 24 | 25 | The opposite, the founder of the language is a militant against the fascist government. 26 | 27 | Brazilian flags buttons also green and yellow colors are to show pride in being a national technology like [Lua](https://lua.org) and [Elixir](https://elixir-lang.org). 28 | 29 | Is a way of protest against the distorted values of our nationalism. 30 | -------------------------------------------------------------------------------- /examples/fibonacci.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | # PRINT STREAM "FIB:" 3 | MODE NILL 0d02 4 | STRC NILL 'F' 5 | STRC NILL 'I' 6 | STRC NILL 'B' 7 | STRC NILL ':' 8 | 9 | # INPUT VAR :FIB 10 | MODE NILL 0d03 11 | STRI :FIB NILL 12 | 13 | # FUNCTION :FIB_FUNC 14 | # PRINT VAR :NEXT 15 | MODE NILL 2 16 | NILL NILL :FIB_FUNC 17 | STRC NILL '\n' 18 | STRI :NEXT NILL 19 | 20 | # :NEXT = :NEXT + :PREV 21 | MODE NILL 0d08 22 | PUSH :NEXT NILL 23 | MODE NILL 0d11 24 | MATH :PREV NILL 25 | MODE NILL 0d08 26 | PULL :NEXT NILL 27 | 28 | # :PREV = :PREV - :NEXT 29 | MODE NILL 0d08 30 | PUSH :NEXT NILL 31 | MODE NILL 0d12 32 | MATH :PREV NILL 33 | MODE NILL 0d08 34 | PULL :PREV NILL 35 | 36 | # IF :NEXT == 0 37 | # :NEXT = 1 38 | MODE NILL 0d08 39 | PUSH :NEXT NILL 40 | MODE NILL 0d09 41 | PGTO NILL SKIP 42 | MODE NILL 0d06 43 | ALOC :NEXT 1 44 | NILL NILL SKIP 45 | 46 | # :FIB = :FIB - 1 47 | # IF :FIB > 0 48 | # CALL :FIB_FUNC RECURSIVE 49 | MODE NILL 0d08 50 | PUSH :FIB NILL 51 | MODE NILL 0d12 52 | MATH NILL 1 53 | MODE NILL 0d08 54 | PULL :FIB NILL 55 | MODE NILL 0d09 56 | PGTO NILL :FIB_FUNC -------------------------------------------------------------------------------- /docs/extra/references.md: -------------------------------------------------------------------------------- 1 | References 2 | ========== 3 | 4 | ## Bibliography ## 5 | 6 | ### C Language ### 7 | * Schildt. Hebert (1997) _C Completo e total 3. rev._ (Mayer. Roberto Carlos Trad.) Editora Pearson Education do Brasil 8 | 9 | ### Data Structures ### 10 | 11 | * [Eric Rowell](https://twitter.com/ericdrowell) (2016) _Big-O Algorithm Complexity Cheat Sheet (Know Thy Complexities!) @ericdrowell_
12 | 13 | ### Left Leaning Red Black Tree ### 14 | 15 | * [Kundu. Arnab](https://auth.geeksforgeeks.org/user/andrew1234); [Rai. Akanksha](https://auth.geeksforgeeks.org/user/Akanksha_Rai) (2019) _Left Leaning Red Black Tree (Insertion)_
16 | 17 | * [Backes André](https://programacaodescomplicada.wordpress.com/) (2013) _[ED] Aula 106 - Árvore Rubro Negra Caída para a Esquerda (LLRB)_
18 | 19 | ### Tests ### 20 | 21 | * [Otavio Lemos](https://otaviolemos.github.io/) (2021) _162 - Pirâmide ou Troféu de Testes? \| theWiseDev Testing_
22 | 23 | ## Extra subjects ## 24 | 25 | ### Compilers & Interpreters ### 26 | 27 | * [Robert Nystrom](http://journal.stuffwithstuff.com/) (2015) _Crafting Interpreters_
28 | -------------------------------------------------------------------------------- /programs/tests.c: -------------------------------------------------------------------------------- 1 | #define _3BC_ENABLE_CUSTOM 2 | #include "../src/3bc.h" 3 | 4 | void print_char(char* buffer) 5 | { 6 | fprintf(stdout, "%02X", *buffer); 7 | } 8 | 9 | void cpu_test_signal(PARAMS_DEFINE) 10 | { 11 | driver_power_signal(value); 12 | } 13 | 14 | void cpu_test_error(PARAMS_DEFINE) 15 | { 16 | driver_program_error(app, (enum error_3bc_e)value); 17 | } 18 | 19 | void cpu_test_none_tty(PARAMS_DEFINE) 20 | { 21 | app->tty_output.type = STREAM_TYPE_NONE; 22 | driver_tty_output_raw(app, app->tty_output, NULL); 23 | } 24 | 25 | void cpu_test_unsupported(PARAMS_DEFINE) 26 | { 27 | driver_program_error(app, ERROR_UNSUPPORTED); 28 | } 29 | 30 | void cpu_test_scape_characters(PARAMS_DEFINE) 31 | { 32 | app->tty_output.type = STREAM_TYPE_FUNCTION_CALL; 33 | app->tty_output.io.lambda = &print_char; 34 | } 35 | 36 | int main(int argc, char** argv) 37 | { 38 | struct app_3bc_s* const VM = lang_3bc_init(argc, argv); 39 | lang_3bc_custom(VM, MODE_CUSTOM_1, 1, &cpu_test_signal); 40 | lang_3bc_custom(VM, MODE_CUSTOM_1, 2, &cpu_test_none_tty); 41 | lang_3bc_custom(VM, MODE_CUSTOM_1, 3, &cpu_test_unsupported); 42 | lang_3bc_custom(VM, MODE_CUSTOM_1, 4, &cpu_test_scape_characters); 43 | lang_3bc_custom(VM, MODE_CUSTOM_1, 5, &cpu_test_error); 44 | while (lang_3bc_update(VM)) 45 | ; 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /examples/ArduinoInfo/ArduinoInfo.ino: -------------------------------------------------------------------------------- 1 | #define _3BC_DISABLE_INTERPRETER 2 | #include <3bc.h> 3 | 4 | 5 | void setup() 6 | { 7 | app_3bc_id count = 0; 8 | struct app_3bc_s** apps; 9 | 10 | /** starts serial **/ 11 | Serial.begin(TBC_SERIAL_SPEED); 12 | while(!Serial); 13 | 14 | /** count limit of virtual machines **/ 15 | for(;lang_3bc_init() != NULL; count++); 16 | for(apps = ds_hypervisor_darray_get_all(); *apps != NULL; free(*apps++)); 17 | 18 | /** depurate results **/ 19 | Serial.write("\n3BC Machines limit: "); 20 | Serial.println(count); 21 | 22 | Serial.write("Machine size: "); 23 | Serial.print(sizeof(struct app_3bc_s)); 24 | Serial.println(" bytes"); 25 | 26 | Serial.write("Line size: "); 27 | Serial.print(sizeof(struct line_node_s)); 28 | Serial.println(" bytes"); 29 | 30 | Serial.write("Label size: "); 31 | Serial.print(sizeof(struct label_node_s)); 32 | Serial.println(" bytes"); 33 | 34 | Serial.write("Address size: "); 35 | Serial.print(sizeof(struct memory_node_s)); 36 | Serial.println(" bytes"); 37 | Serial.write("Address limit: "); 38 | Serial.println(sizeof(address_3bc_t) * 255); 39 | 40 | Serial.write("Value maximum: "); 41 | Serial.println((((sizeof(data_3bc_t)*255)/2)-1)); 42 | Serial.write("Value minimum: -"); 43 | Serial.println((((sizeof(data_3bc_t)*255)/2))); 44 | 45 | while(1); 46 | } 47 | 48 | void loop() {} 49 | -------------------------------------------------------------------------------- /tests/fulltest.sleep.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | require 'benchmark' 3 | require 'minitest/spec' 4 | require 'minitest/autorun' 5 | require 'minitest/parallel' 6 | 7 | class TestSleep < Minitest::Test 8 | def test_sleep_seconds 9 | skip "dont work correctly :/" 10 | exectuion = Benchmark.measure do 11 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => 'mode.0.43,seco.0.1,mode.0.2,stri.0.0') 12 | assert_equal "0", stdout 13 | assert_equal 0, status 14 | end 15 | assert_in_delta 1, exectuion.real, 0.05, 'minimum 50 millisecond precision' 16 | end 17 | 18 | def test_sleep_miliseconds 19 | exectuion = Benchmark.measure do 20 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => 'mode.0.43,mili.0.100,mode.0.2,stri.0.0') 21 | assert_equal "0", stdout 22 | assert_equal 0, status 23 | end 24 | assert_in_delta 0.1, exectuion.real, 0.04, 'minimum 40 millisecond precision' 25 | end 26 | 27 | def test_sleep_microseconds 28 | exectuion = Benchmark.measure do 29 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => 'mode.0.6,aloc.1.200,mode.0.8,0.0.1,push.1.0,mode.0.12,math.0.1,mode.0.8,pull.1.0,mode.0.43,micro.0.100,mode.0.9,fgto.0.1,mode.0.2,stri.0.0') 30 | assert_equal "0", stdout 31 | assert_equal 0, status 32 | end 33 | assert_in_delta 0.02, exectuion.real, 0.02, 'minimum 20 millisecond precision' 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /src/driver_accumulator.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the auxiliary memory. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | data_aux_3bc_t driver_accumulator_get(struct app_3bc_s* const app) 39 | { 40 | return app->mem_aux; 41 | } 42 | 43 | void driver_accumulator_set(struct app_3bc_s* const app, data_aux_3bc_t value) 44 | { 45 | app->mem_aux = value; 46 | } -------------------------------------------------------------------------------- /scripts/commit_message_hook.rb: -------------------------------------------------------------------------------- 1 | class CommitMessageHook 2 | COMMIT_TYPES = %w[feat fix chore test ci docs] 3 | 4 | def self.call(message) 5 | new(message).call 6 | end 7 | 8 | def call 9 | return { success: true, errors: [] } if valid_message? 10 | 11 | { success: false, errors: errors } 12 | end 13 | 14 | private 15 | 16 | attr_reader :message 17 | 18 | def initialize(message) 19 | @message = message 20 | end 21 | 22 | def valid_message? 23 | errors.push('Invalid commit title format') unless title_regex.match?(title) 24 | errors.push('Invalid commit title max size (80)') unless title.size <= 80 25 | errors.push('Second line must be empty') unless second_line.size == 0 26 | 27 | validate_breaking_changes 28 | 29 | errors.count == 0 30 | end 31 | 32 | def title 33 | @title ||= commit_lines.first 34 | end 35 | 36 | def second_line 37 | @second_line ||= commit_lines[1] || '' 38 | end 39 | 40 | def commit_lines 41 | @commit_lines ||= message.split("\n").filter { |line| !%r[^#].match?(line) } 42 | end 43 | 44 | def title_regex 45 | %r[^(#{types})(\(.+\))?!?: .+] 46 | end 47 | 48 | def validate_breaking_changes 49 | lowercase_regex = %r[breaking change] 50 | errors.push('Breaking changes footer must be uppercase') if lowercase_regex.match?(message) 51 | 52 | breaking_changes_format = %r[BREAKING CHANGE: .+] 53 | 54 | return unless breaking_changes_format.match?(message) 55 | 56 | breaking_changes_title_regex = %r[^(#{types})(\(.+\))?!: .+] 57 | errors.push('Commit tile must append `!` for breaking changes') unless breaking_changes_title_regex.match?(message) 58 | end 59 | 60 | def types 61 | COMMIT_TYPES.join('|') 62 | end 63 | 64 | def errors 65 | @errors ||= [] 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /.github/workflows/compiler-cc65.yaml: -------------------------------------------------------------------------------- 1 | name: Compiler cc65 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | apple2: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout project 14 | uses: actions/checkout@v2 15 | 16 | - name: Checkout cc65 17 | uses: actions/checkout@v2 18 | with: 19 | repository: cc65/cc65 20 | path: cc65 21 | 22 | - name: Build cc65 23 | run: | 24 | cd cc65 25 | make 26 | 27 | - name: Build project 28 | run: >- 29 | ./cc65/bin/cl65 -t apple2 -D_3BC_DISABLE_INTERPRETER 30 | programs/interpreter.c 31 | 32 | commodore64: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - name: Checkout project 36 | uses: actions/checkout@v2 37 | 38 | - name: Checkout cc65 39 | uses: actions/checkout@v2 40 | with: 41 | repository: cc65/cc65 42 | path: cc65 43 | 44 | - name: Build cc65 45 | run: | 46 | cd cc65 47 | make 48 | 49 | - name: Build project 50 | run: >- 51 | ./cc65/bin/cl65 -t c64 -D_3BC_DISABLE_INTERPRETER 52 | programs/interpreter.c 53 | 54 | nes: 55 | runs-on: ubuntu-latest 56 | steps: 57 | - name: Checkout project 58 | uses: actions/checkout@v2 59 | 60 | - name: Checkout cc65 61 | uses: actions/checkout@v2 62 | with: 63 | repository: cc65/cc65 64 | path: cc65 65 | 66 | - name: Build cc65 67 | run: | 68 | cd cc65 69 | make 70 | 71 | - name: Build project 72 | run: >- 73 | ./cc65/bin/cl65 -t nes -D_3BC_DISABLE_INTERPRETER -D__NES__ 74 | programs/interpreter.c 75 | -------------------------------------------------------------------------------- /src/driver_mode.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers cpu mode management in virtual machine. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | /** 39 | * switch between cpu mode channels 40 | */ 41 | void driver_mode_set(struct app_3bc_s* const app, cpumode_3bc_t value) 42 | { 43 | if (value >= MODE_END) { 44 | driver_program_error(app, ERROR_INVALID_CPU_MODE); 45 | } 46 | 47 | /** after cpu mode change **/ 48 | switch (app->cpu_mode) { 49 | } 50 | 51 | /** before cpu mode change **/ 52 | switch (value) { 53 | } 54 | 55 | /** apply cpu mode **/ 56 | app->cpu_mode = value; 57 | } -------------------------------------------------------------------------------- /src/cpu_common.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the common's registers for all cpu modes. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_null(PARAMS_DEFINE) { } 39 | 40 | void cpu_mode(PARAMS_DEFINE) 41 | { 42 | VALIDATE_NOT_ADRESS 43 | driver_mode_set(app, value); 44 | } 45 | 46 | void cpu_not_mode(PARAMS_DEFINE) 47 | { 48 | driver_program_error(app, ERROR_CPU_ZERO); 49 | } 50 | 51 | void cpu_not_exist(PARAMS_DEFINE) 52 | { 53 | driver_program_error(app, ERROR_INVALID_REGISTER); 54 | } 55 | 56 | void cpu_mode_reserved(PARAMS_DEFINE) 57 | { 58 | driver_custom_call(app, reg, address, value); 59 | } 60 | -------------------------------------------------------------------------------- /docs/extra/early-adopters.md: -------------------------------------------------------------------------------- 1 | List of early developers 2 | ======================== 3 | 4 | Hall of fame with everyone who dedicated to **just learning 3bc language**, this list is open until the day that version **0.1** will be released. 5 | 6 | 7 | | :trophy: | date | developer | who? | 8 | | :------: | :--: | :-------: | :--: | 9 | | **1º** | 26 November 2020 | Rodrigo Dornelles | [![](https://avatars.githubusercontent.com/rodrigodornelles?size=64)](https://github.com/rodrigodornelles) | 10 | | **2º** | 28 November 2020 | Carlos Eduardo | [![](https://avatars.githubusercontent.com/kadu?size=64)](https://github.com/kadu) | 11 | | **3º** | 23 December 2020 | Robson Soares | [![](https://avatars.githubusercontent.com/robsondrs?size=64)](https://github.com/robsondrs) | 12 | | **4º** | 28 December 2020 | Guilherme Neves | | 13 | | **5º** | 30 December 2020 | Marcus Paulo | [![](https://avatars.githubusercontent.com/marcusmmmz?size=64)](https://github.com/marcusmmmz) | 14 | | **6º** | 30 December 2020 | Takeshi Ishikawa | [![](https://avatars.githubusercontent.com/keshizin?size=64)](https://github.com/keshizin) | 15 | | **7º** | 31 December 2020 | André Luis | [![avatar](https://avatars.githubusercontent.com/andreluispy?size=64)](https://github.com/andreluispy) | 16 | | **8º** | 2 January 2021 | Francisco Noble | [![](https://avatars.githubusercontent.com/guridev?size=64)](https://github.com/guridev) | 17 | | **9º** | 5 February 2021 | Lucas Rangel | [![](https://avatars.githubusercontent.com/lrv-dev?size=64)](https://github.com/lrv-dev) | 18 | | **10º** | 6 February 2021 | Otávio Burato | [![](https://avatars.githubusercontent.com/otavio-burato?size=64)](https://github.com/otavio-burato) | 19 | | **11º** | 21 July 2021 | Github Copilot _(IA)_ | [![copilot sucks](https://avatars.githubusercontent.com/github?size=64)](https://copilot.github.com/) | 20 | | **12º** | 14 August 2021 | Moizes Sousa | [![](https://avatars.githubusercontent.com/yxqsnz?size=64)](https://github.com/yxqsnzo) | 21 | | **13º** | 30 October 2021 | Anderson Costa | [![](https://avatars.githubusercontent.com/arcostasi?size=64)](https://github.com/arcostasi) | 22 | -------------------------------------------------------------------------------- /docs/extra/roadmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Roadmap 3 | description: The expected future for language and community. (aka to do list) 4 | --- 5 | 6 | ## Year 2020 roadmap 7 | 8 | - [X] VM Memory auxiliary 9 | - [X] VM Output characters 10 | - [X] VM Memory Allocation 11 | - [X] VM Input characters 12 | - [X] VM Memory Allocation 13 | - [X] VM Mathematic Basics 14 | - [X] VM Labels 15 | - [X] VM Conditional Jumps 16 | - [X] Textual Interpreter 17 | - [X] Support amd64 _(macos, linux, windows)_ 18 | - [X] Support i686 _(linux, windows)_ 19 | - [X] Support avr _(arduino)_ 20 | 21 | ## Year 2021 roadmap 22 | 23 | - [X] VM Mathematic Boolean 24 | - [X] VM Procedure calls 25 | - [X] VM Memory Pointers 26 | - [X] Documentation 27 | - [X] Full tests suite 28 | - [X] Support Framework Arduino 29 | - [X] Support WebAssembly _(emscripten)_ 30 | - [X] Support arm _(linux)_ 31 | - [X] Support riscv _(arduino)_ 32 | 33 | ## Year 2022 roadmap 34 | 35 | - [ ] VM Function calls 36 | - [ ] VM Stack management 37 | - [X] Support arm _(docker linux)_ 38 | - [X] Support z390x _(docker linux)_ 39 | - [X] Support riscv64 _(linux, docker linux)_ 40 | - [X] Support mips _(linux)_ 41 | - [X] Support mips64 _(docker linux)_ 42 | - [X] Support powerpc _(linux)_ 43 | - [X] Support powerpc64 _(linux, docker linux)_ 44 | - [X] Support aarch64 _(macos, linux, docker linux, windows)_ 45 | - [X] Support amd64 _(bsd, docker linux)_ 46 | - [X] Support i386 _(bsd, linux, docker linux, windows)_
_better portability backwards compared with i686_ 47 | 48 | ## come soon roadmap 49 | 50 | - [ ] VM Sockets 51 | - [ ] VM Files IO 52 | - [ ] Support MOS6502 (Nes, Commodore 64, Apple 2) 53 | - [ ] Support Visual environment 54 | - [ ] Support Cuda cores 55 | - [ ] Programming IDE 56 | - [ ] Playground WEB 57 | 58 | ## Comunity roadmap 59 | 60 | - [X] First sponsor 61 | - [ ] List 3bc on 62 | - [ ] Real product using 3bc as firmware or libary 63 | - [ ] Some professor use 3bc in compiler labs during college 64 | - [ ] 99+ unique owners of repository in 3bc on github 65 | - [ ] 199+ projects in 3bc on github 66 | - [ ] 999+ stars 3bc project on github 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 3BC Language 2 | ============ 3 | [![sponsors](https://img.shields.io/github/sponsors/rodrigodornelles?color=ff69b4&logo=github)](https://github.com/sponsors/RodrigoDornelles) 4 | [![version](https://img.shields.io/github/v/release/rodrigodornelles/3bc-lang?sort=semver&logo=github)](https://github.com/RodrigoDornelles/3bc-lang/releases) 5 | [![license](https://img.shields.io/github/license/rodrigodornelles/3bc-lang?logo=gnu)](https://github.com/RodrigoDornelles/3bc-lang/blob/master/LICENSE.txt) 6 | [![covarage](https://img.shields.io/badge/coverage-99%25-brightgreen?logo=codecov)](docs/guide/warnings.md) 7 | 8 | > Low-level language, tiny virtual machine, intermediate representation, embeddable, easy for beginners. (Friendly Punched cards) 9 | 10 | ## Documentation ## 11 | 12 | * **[Tutorial :us:](docs/guide/tutorial-en-us.md)** 13 | * **[Tutorial :brazil:](docs/guide/tutorial-pt-br.md)** 14 | * **[Cheatsheet :book:](docs/guide/cheatsheet.md)** 15 | * **[List of early developers :trophy:](docs/extra/early-adopters.md)** 16 | * **[Visit the official website :globe_with_meridians:](https://3bc-lang.org)** 17 | 18 | ## Directory structure ## 19 | 20 | If you are interested in exploring or contributing to the language, follow the monolithic organization. 21 | 22 | ``` 23 | docs/ Website made with jekyll (Ruby) 24 | examples/ Syntax sampling codes (3bc, Arduino with C++) 25 | programs/ Embbed programs sampling codes (C) 26 | scripts/ Development and installation tools (Bash, Ruby) 27 | src/ Library source code (C) 28 | tests/ Language work check (Ruby) 29 | ``` 30 | 31 | ## How to build ## 32 | 33 | Download interpreter **source code** and manually compile from scratch. 34 | 35 | ```BASH 36 | git clone https://github.com/RodrigoDornelles/3bc-lang 37 | make build 38 | ``` 39 | 40 | ## How to install ## 41 | 42 | Directly download interpreter as **executable** command for mac/linux/bsd. 43 | 44 | ```BASH 45 | sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/master/scripts/install_vm.sh || curl -fsSL https://raw.githubusercontent.com/RodrigoDornelles/3bc-lang/master/scripts/install_vm.sh)" 46 | ``` 47 | 48 | ------------------------------------------------- 49 | ![3bc lang logo](/docs/images/3bc-logo-small.png) 50 | This project is licensed under **GNU GPL 3.0 or higher**, please read the [LICENSE.txt](LICENSE.txt) file. 51 | -------------------------------------------------------------------------------- /src/3bc_errors.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Header refers to errors codes and messages. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | enum error_3bc_e { 36 | ERROR_CPU_ZERO = 0x3BC000, 37 | ERROR_CPU_RESERVED, 38 | ERROR_INVALID_REGISTER, 39 | ERROR_INVALID_ADDRESS, 40 | ERROR_INVALID_CONSTANT, 41 | ERROR_INVALID_CPU_MODE, 42 | ERROR_INVALID_LABEL, 43 | ERROR_INVALID_RETURN, 44 | ERROR_PARAM_DUALITY, 45 | ERROR_PARAM_REQUIRE_ANY, 46 | ERROR_PARAM_REQUIRE_VALUE, 47 | ERROR_PARAM_REQUIRE_ADDRESS, 48 | ERROR_PARAM_BLOCKED_VALUE, 49 | ERROR_PARAM_BLOCKED_ADDRESS, 50 | ERROR_NUMBER_NO_DIGITS, 51 | ERROR_NUMBER_UNDERFLOW, 52 | ERROR_NUMBER_OVERFLOW, 53 | ERROR_NUMBER_WRONG_BASE, 54 | ERROR_NUMBER_NEGATIVE, 55 | ERROR_NUMBER_ZERO, 56 | ERROR_OUT_OF_MEMORY, 57 | ERROR_NONE_TTY, 58 | ERROR_UNSUPPORTED, 59 | ERROR_MEMORY_CONFIG, 60 | ERROR_OPEN_FILE, 61 | ERROR_NULL_POINTER, 62 | ERROR_CHAR_SCAPE, 63 | ERROR_CHAR_SIZE, 64 | ERROR_COLUMNS 65 | }; -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Merit 2 | 3 | 1. The project creators, lead developers, core team, constitute 4 | the managing members of the project and have final say in every decision 5 | of the project, technical or otherwise, including overruling previous decisions. 6 | There are no limitations to this decisional power. 7 | 8 | 2. Contributions are an expected result of your membership on the project. 9 | Don't expect others to do your work or help you with your work forever. 10 | 11 | 3. All members have the same opportunities to seek any challenge they want 12 | within the project. 13 | 14 | 4. Authority or position in the project will be proportional 15 | to the accrued contribution. Seniority must be earned. 16 | 17 | 5. Software is evolutive: the better implementations must supersede lesser 18 | implementations. Technical advantage is the primary evaluation metric. 19 | 20 | 6. This is a space for technical prowess; topics outside of the project 21 | will not be tolerated. 22 | 23 | 7. Non technical conflicts will be discussed in a separate space. Disruption 24 | of the project will not be allowed. 25 | 26 | 8. Individual characteristics, including but not limited to, 27 | body, sex, sexual preference, race, language, religion, nationality, 28 | or political preferences are irrelevant in the scope of the project and 29 | will not be taken into account concerning your value or that of your contribution 30 | to the project. 31 | 32 | 9. Discuss or debate the idea, not the person. 33 | 34 | 10. There is no room for ambiguity: Ambiguity will be met with questioning; 35 | further ambiguity will be met with silence. It is the responsibility 36 | of the originator to provide requested context. 37 | 38 | 11. If something is illegal outside the scope of the project, it is illegal 39 | in the scope of the project. This Code of Merit does not take precedence over 40 | governing law. 41 | 42 | 12. This Code of Merit governs the technical procedures of the project not the 43 | activities outside of it. 44 | 45 | 13. Participation on the project equates to agreement of this Code of Merit. 46 | 47 | 14. No objectives beyond the stated objectives of this project are relevant 48 | to the project. Any intent to deviate the project from its original purpose 49 | of existence will constitute grounds for remedial action which may include 50 | expulsion from the project. 51 | 52 | This document is adapted from the Code of Merit, version 1.0. 53 | See: https://codeofmerit.org/. 54 | -------------------------------------------------------------------------------- /src/cpu_jump.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for conditional jumps. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_jump_goto(PARAMS_DEFINE) 39 | { 40 | REQUIRED_VALUE 41 | VALIDATE_NOT_ADRESS 42 | app->program.label_target = value; 43 | } 44 | 45 | void cpu_jump_fgto(PARAMS_DEFINE) 46 | { 47 | REQUIRED_VALUE 48 | VALIDATE_NOT_ADRESS 49 | if (AUX != 0) { 50 | app->program.label_target = value; 51 | } 52 | } 53 | 54 | void cpu_jump_zgto(PARAMS_DEFINE) 55 | { 56 | REQUIRED_VALUE 57 | VALIDATE_NOT_ADRESS 58 | if (AUX == 0) { 59 | app->program.label_target = value; 60 | } 61 | } 62 | 63 | void cpu_jump_pgto(PARAMS_DEFINE) 64 | { 65 | REQUIRED_VALUE 66 | VALIDATE_NOT_ADRESS 67 | if (0 < AUX) { 68 | app->program.label_target = value; 69 | } 70 | } 71 | 72 | void cpu_jump_ngto(PARAMS_DEFINE) 73 | { 74 | REQUIRED_VALUE 75 | VALIDATE_NOT_ADRESS 76 | if (0 > AUX) { 77 | app->program.label_target = value; 78 | } 79 | } -------------------------------------------------------------------------------- /docs/assets/style.css: -------------------------------------------------------------------------------- 1 | .anim-dark { 2 | transition: color 1s ease, background-color 1s ease; 3 | } 4 | 5 | .dark { 6 | background-color: #202123; 7 | color: #fff; 8 | } 9 | 10 | .theme { 11 | cursor: pointer; 12 | user-select: none; 13 | } 14 | 15 | h1 { 16 | font-size: 2em; 17 | line-height: 80%; 18 | margin-top: 1.8rem; 19 | margin-bottom: 1.8rem; 20 | } 21 | 22 | h2 {font-size: 1.5em;} 23 | h3 {font-size: 1.17em;} 24 | h4 {font-size: 1.12em;} 25 | h5 {font-size: .83em;} 26 | h6 {font-size: .75em;} 27 | blockquote p {text-align: left;} 28 | a {color: #008234;} 29 | p {text-align: justify;} 30 | ul {text-align: left;} 31 | pre {text-align: left;} 32 | 33 | li strong a { 34 | gap: 0.3rem; 35 | display: flex; 36 | } 37 | 38 | .btn { 39 | display: flex; 40 | overflow: hidden; 41 | position: relative; 42 | background-color: #008234; 43 | } 44 | 45 | .btn span { 46 | z-index: 10; 47 | } 48 | 49 | .btn::after { 50 | top: 0; 51 | right: 0; 52 | z-index: 5; 53 | content: ""; 54 | display: block; 55 | position: absolute; 56 | border-top: 16px solid transparent; 57 | border-right: 32px solid #f0d313; 58 | border-bottom: 16px solid transparent; 59 | } 60 | 61 | .btn::before{ 62 | top: 6px; 63 | right: -10px; 64 | z-index: 7; 65 | content: ""; 66 | display: block; 67 | position: absolute; 68 | border: 10px solid #00349e; 69 | border-radius: 100%; 70 | } 71 | 72 | /** materialize roadmap fix **/ 73 | [type="checkbox"]:not(:checked), [type="checkbox"]:checked { 74 | position: initial; 75 | opacity: initial; 76 | pointer-events: initial; 77 | margin-right: 8px; 78 | } 79 | 80 | nav { 81 | background: linear-gradient(-45deg, #f0d313, #008234,#00349e, #008234, #f0d313, #008234); 82 | animation: 3s linear 0s infinite running brazil-anim; 83 | background-size: 600% 600%; 84 | } 85 | 86 | @keyframes brazil-anim { 87 | from {background-position: 100% 100%;} 88 | to {background-position: 4% 4%;} 89 | } 90 | 91 | img[alt$=">"] { 92 | float: right; 93 | margin-left: 20px; 94 | max-width: 30%; 95 | } 96 | 97 | img[alt$="<"] { 98 | float: left; 99 | margin-right: 20px; 100 | max-width: 30%; 101 | } 102 | 103 | img[alt$="><"] { 104 | display: block; 105 | max-width: 50vmax; 106 | height: auto; 107 | margin: auto; 108 | float: none; 109 | } 110 | 111 | @media print { 112 | .dont-print { 113 | display: none; 114 | } 115 | } -------------------------------------------------------------------------------- /tests/fulltest.version.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'net/http' 3 | require 'minitest/spec' 4 | require 'minitest/autorun' 5 | 6 | class TestVersion < Minitest::Test 7 | def setup 8 | @npm = File.read('./package.json').scan(/\"version\"\: \"(\d+\.\d+\.\d+)\"/).first.first rescue nil 9 | @arduino = File.read('./library.properties').scan(/version = (\d+\.\d+\.\d+)/).first.first rescue nil 10 | @pkgbuild = File.read('./PKGBUILD').scan(/pkgver\=\"(\d+.\d+.\d+)\"/).first.first rescue nil 11 | @oficial = File.read('./src/3bc.h').scan(/\#define VERSION_3BC \"(\d+\.\d+\.\d+)\"/).first.first rescue nil 12 | @oficial_major = File.read('./src/3bc.h').scan(/\#define VERSION_3BC_MAJOR (\d+)/).first.first rescue nil 13 | @oficial_minor = File.read('./src/3bc.h').scan(/\#define VERSION_3BC_MINOR (\d+)/).first.first rescue nil 14 | @oficial_patch = File.read('./src/3bc.h').scan(/\#define VERSION_3BC_PATCH (\d+)/).first.first rescue nil 15 | end 16 | 17 | def test_verify_version 18 | refute_equal @npm, nil, "Invalid npm version" 19 | refute_equal @arduino, nil, "Invalid arduino version" 20 | refute_equal @pkgbuild, nil, "Invalid pkgbuild version" 21 | refute_equal @oficial, nil, "Invalid oficial version" 22 | refute_equal @oficial_major, nil, "Invalid oficial major version" 23 | refute_equal @oficial_minor, nil, "Invalid oficial minor version" 24 | refute_equal @oficial_patch, nil, "Invalid oficial patch version" 25 | end 26 | 27 | def test_some_version 28 | assert_equal @oficial, @npm, "Wrong npm version" 29 | assert_equal @oficial, @arduino, "Wrong arduino version" 30 | assert_equal @oficial, @pkgbuild, "Wrong pkgbuild version" 31 | assert_equal @oficial, "#{@oficial_major}.#{@oficial_minor}.#{@oficial_patch}", "Wrong oficial version" 32 | end 33 | 34 | def test_newer_version 35 | for release in (JSON.parse Net::HTTP.get URI 'https://api.github.com/repos/rodrigodornelles/3bc-lang/releases').collect {|value|value['tag_name']} 36 | refute_equal release, @oficial, "Github tag '#{@oficial}' already exist." 37 | end rescue skip warn "Skiped:\nGithub API is not available.\n\n" 38 | 39 | for release in (JSON.parse Net::HTTP.get URI 'https://registry.npmjs.org/3bc-lang')['versions'].collect {|key,_|key} 40 | refute_equal release, @oficial, "NPM tag '#{@oficial}' already exist." 41 | end rescue skip warn "Skiped:\nNPM API is not available.\n\n" 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /.github/workflows/compiler-xtensa-gcc.yaml: -------------------------------------------------------------------------------- 1 | name: Compiler xtensa-gcc 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | esp8266: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout project 14 | uses: actions/checkout@v2 15 | with: 16 | path: project 17 | 18 | - name: Checkout arduino-cli 19 | run: curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh -s 0.27.0 20 | 21 | - name: Configure arduino-cli 22 | run: | 23 | ./bin/arduino-cli config init 24 | ./bin/arduino-cli config set library.enable_unsafe_install true 25 | ./bin/arduino-cli config add board_manager.additional_urls https://arduino.esp8266.com/stable/package_esp8266com_index.json 26 | ./bin/arduino-cli core install esp8266:esp8266 27 | 28 | - name: Prepare project 29 | run: | 30 | zip -r lib.zip project/* 31 | mv ./project/examples/ArduinoHelloworld/ArduinoHelloworld.ino ./bin/bin.ino 32 | ./bin/arduino-cli lib install --zip-path lib.zip 33 | 34 | - name: Build project 35 | run: | 36 | cd bin/ 37 | ./arduino-cli compile --fqbn esp8266:esp8266:generic --verbose --log-level trace 38 | 39 | esp32: 40 | runs-on: ubuntu-latest 41 | steps: 42 | - name: Checkout project 43 | uses: actions/checkout@v2 44 | with: 45 | repository: rodrigodornelles/3bc-lang 46 | path: project 47 | 48 | - name: Checkout arduino-cli 49 | run: curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh -s 0.27.0 50 | 51 | - name: Configure arduino-cli 52 | run: | 53 | ./bin/arduino-cli config init 54 | ./bin/arduino-cli config set library.enable_unsafe_install true 55 | ./bin/arduino-cli config add board_manager.additional_urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 56 | ./bin/arduino-cli core install esp32:esp32@1.0.6 57 | 58 | - name: Prepare project 59 | run: | 60 | zip -r lib.zip project/* 61 | mv ./project/examples/ArduinoHelloworld/ArduinoHelloworld.ino ./bin/bin.ino 62 | ./bin/arduino-cli lib install --zip-path lib.zip 63 | 64 | - name: Build project 65 | run: | 66 | cd bin/ 67 | ./arduino-cli compile --fqbn esp32:esp32:esp32 --verbose --log-level trace 68 | -------------------------------------------------------------------------------- /src/ds_procedure_lifo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers stacking of called procedures. 12 | * 13 | * DATASTRUCT: 14 | * Linked list, last in, first out. 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | void ds_procedure_lifo_push(struct app_3bc_s* const app) 42 | { 43 | struct procedure_3bc_s* procedure 44 | = (struct procedure_3bc_s*)malloc(sizeof(struct procedure_3bc_s)); 45 | 46 | if (procedure == NULL) { 47 | driver_program_error(app, ERROR_OUT_OF_MEMORY); 48 | } 49 | 50 | procedure->prev = app->program.stack; 51 | procedure->remember = app->program.curr; 52 | 53 | app->program.stack = procedure; 54 | } 55 | 56 | struct line_node_s* ds_procedure_lifo_pop(struct app_3bc_s* const app) 57 | { 58 | struct line_node_s* line_node; 59 | struct procedure_3bc_s* procedure; 60 | 61 | if (app->program.stack == NULL) { 62 | driver_program_error(app, ERROR_INVALID_RETURN); 63 | } 64 | 65 | procedure = app->program.stack->prev; 66 | line_node = app->program.stack->remember; 67 | free(app->program.stack); 68 | 69 | app->program.stack = procedure; 70 | 71 | return line_node; 72 | } 73 | -------------------------------------------------------------------------------- /src/cpu_sleep.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for processor idle. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_sleep_real(PARAMS_DEFINE) 39 | { 40 | REQUIRED_ANY 41 | VALIDATE_NOT_DUALITY 42 | VALIDATE_NOT_NEGATIVES 43 | app->cache_l1.sleep_mode = SLEEP_3BC_REAL_TICK; 44 | app->cache_l2.sleep_period = GET_ANY_PARAM; 45 | } 46 | 47 | void cpu_sleep_fake(PARAMS_DEFINE) 48 | { 49 | REQUIRED_ANY 50 | VALIDATE_NOT_DUALITY 51 | VALIDATE_NOT_NEGATIVES 52 | app->cache_l1.sleep_mode = SLEEP_3BC_FAKE_TICK; 53 | app->cache_l2.sleep_period = GET_ANY_PARAM; 54 | } 55 | 56 | void cpu_sleep_micr(PARAMS_DEFINE) 57 | { 58 | REQUIRED_ANY 59 | VALIDATE_NOT_DUALITY 60 | VALIDATE_NOT_NEGATIVES 61 | app->cache_l1.sleep_mode = SLEEP_3BC_MICROSECONDS; 62 | app->cache_l2.sleep_period = GET_ANY_PARAM; 63 | } 64 | 65 | void cpu_sleep_mili(PARAMS_DEFINE) 66 | { 67 | REQUIRED_ANY 68 | VALIDATE_NOT_DUALITY 69 | VALIDATE_NOT_NEGATIVES 70 | app->cache_l1.sleep_mode = SLEEP_3BC_MILLISECONDS; 71 | app->cache_l2.sleep_period = GET_ANY_PARAM; 72 | } 73 | 74 | void cpu_sleep_seco(PARAMS_DEFINE) 75 | { 76 | REQUIRED_ANY 77 | VALIDATE_NOT_DUALITY 78 | VALIDATE_NOT_NEGATIVES 79 | app->cache_l1.sleep_mode = SLEEP_3BC_SECONDS; 80 | app->cache_l2.sleep_period = GET_ANY_PARAM; 81 | } 82 | -------------------------------------------------------------------------------- /docs/_includes/head.rhtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {% if page.url == '/' %} 60 | {{ page.title }} 61 | {% seo title=false %} 62 | {% else %} 63 | {% seo %} 64 | {% endif %} 65 | -------------------------------------------------------------------------------- /src/cpu_string.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for text manipulation. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_string_debug(PARAMS_DEFINE) 39 | { 40 | VALIDATE_NOT_DUALITY 41 | driver_tty_output(app, app->tty_debug, reg, GET_ANY_PARAM); 42 | } 43 | 44 | void cpu_string_output(PARAMS_DEFINE) 45 | { 46 | VALIDATE_NOT_DUALITY 47 | driver_tty_output(app, app->tty_output, reg, GET_ANY_PARAM); 48 | } 49 | 50 | void cpu_string_input(PARAMS_DEFINE) 51 | { 52 | VALIDATE_NOT_VALUES 53 | { 54 | data_3bc_t aux = driver_tty_input(app, app->tty_input, reg); 55 | driver_accumulator_set(app, aux); 56 | driver_memory_data_set(app, address, aux); 57 | driver_tty_output(app, app->tty_keylog, reg, aux); 58 | } 59 | } 60 | 61 | void cpu_string_input_silent(PARAMS_DEFINE) 62 | { 63 | VALIDATE_NOT_VALUES 64 | { 65 | data_3bc_t aux = driver_tty_input(app, app->tty_input, reg); 66 | driver_accumulator_set(app, aux); 67 | driver_memory_data_set(app, address, aux); 68 | } 69 | } 70 | 71 | void cpu_string_input_password(PARAMS_DEFINE) 72 | { 73 | VALIDATE_NOT_VALUES 74 | { 75 | data_3bc_t aux = driver_tty_input(app, app->tty_input, reg); 76 | driver_accumulator_set(app, aux); 77 | driver_memory_data_set(app, address, aux); 78 | driver_tty_output(app, app->tty_keylog, STRC, '*'); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /docs/guide/errors.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: all error codes, description and how to resolve them. 3 | --- 4 | 5 | Errors 6 | ====== 7 | 8 | | Code | Description | Solution | 9 | | :--: | :---------- | :------- | 10 | | | UNKNOWN ERROR | report the problem! [click here](https://github.com/RodrigoDornelles/3bc-lang/issues/new) | 11 | | 0x00000B | SEGMENT FAULT | report the problem! [click here](https://github.com/RodrigoDornelles/3bc-lang/issues/new) | 12 | | 0x3BC000 | CPU MODE IS NOT DEFINED | You need to set a CPU mode to use any register | 13 | | 0x3BC001 | CPU MODE IS RESERVED | Custom register has been added or has another opcode | 14 | | 0x3BC002 | INVALID CPU REGISTER | Enter a valid value in the first column | 15 | | 0x3BC003 | INVALID CPU ADDRESS | Enter a valid value in the second column | 16 | | 0x3BC004 | INVALID CPU CONSTANT | Enter a valid value in the thirdy column | 17 | | 0x3BC005 | INVALID CPU MODE | Check cpu mode [click here](https://3bc-lang.org/guide/cheatsheet) | 18 | | 0x3BC006 | INVALID LABEL | Repeat markup, conflict with a hash literal or an unexpected negative number. | 19 | | 0x3BC007 | INVALID PROCEDURE RETURN | Check if you are calling procedures and returning correctly. | 20 | | 0x3BC008 | DUALITY ADDRES WITH VALUE IS NOT ALLOWED | Use only an address or a constant. | 21 | | 0x3BC009 | VALUE OR ADDRESS IS REQUIRE | Important use some constant value or address. | 22 | | 0x3BC00A | VALUE IS REQUIRED | Set a constant value. | 23 | | 0x3BC00B | ADDRESS IS REQUIRED | Set a memory address. | 24 | | 0x3BC00C | VALUE IS NOT ALLOWED | Unexpected constant value. | 25 | | 0x3BC00D | ADDRESS IS NOT ALLOWED | Not expected a memory address. | 26 | | 0x3BC00E | NUMBER WHIOUT DIGITS | Missing numeric digits. | 27 | | 0x3BC00F | NUMBER UNDERFLOW | Unexpected number because the value is too small. | 28 | | 0x3BC010 | NUMBER OVERFLOW | Unexpected number because the value is too large. | 29 | | 0x3BC011 | NUMBER WRONG BASE | Digit does not match number base | 30 | | 0x3BC012 | NUMBER NEGATIVE IS NOT EXPECTED | Mem. Aux, Mem. Main or constant has a negative irregular number. | 31 | | 0x3BC013 | NUMBER ZERO IS NOT EXPECTED | An irregular null value found. (example: divide by zero) | 32 | | 0x3BC014 | OUT OF MEMORY | Check for stack or buffer overflow. | 33 | | 0x3BC015 | NONE TTY | To use a teleprompter you must define the input or output. | 34 | | 0x3BC016 | UNSUPPORTED FEATURE | This feature is not supported by the architecture. | 35 | | 0x3BC017 | MEMORY CONFIG | Resolving conflicts in memory usage. | 36 | | 0x3BC018 | CANNOT OPEN FILE | File does not exist, or system does not have permission. | 37 | | 0x3BC019 | NULL POINTER | Point to a valid memory address. | 38 | | 0x3BC01A | INVALID CHARACTER ESCAPE | Control character not supported by the language. | 39 | | 0x3BC01B | INVALID CHARACTER SIZE | Control character not supported by the language. | 40 | | 0x3BC01C | WRONG NUMBER OF COLUMNS | Every row must strictly have 3 columns. | 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: docs tests 2 | 3 | CXX_SOURCES ?= programs/tests.c 4 | CC_SOURCES ?= programs/interpreter.c 5 | CC_OUTPUT ?= 3bc 6 | CC_FLAGS ?= -Os 7 | CC_OBJECTS ?= $(CC_SOURCES:.c=.o) 8 | LD_FLAGS ?= -lc -lm 9 | ifdef CC_LD_TARGET 10 | CC_TARGET := $(CC_LD_TARGET) 11 | LD_TARGET := $(CC_LD_TARGET) 12 | endif 13 | ifdef CC_LD 14 | CC := ${CC_LD} 15 | LD := ${CC_LD} 16 | endif 17 | ifdef CC_TARGET 18 | CC_TARGET_PREFIX := $(addprefix -target , ${CC_TARGET}) 19 | endif 20 | ifdef LD_TARGET 21 | LD_TARGET_PREFIX := $(addprefix -target , ${LD_TARGET}) 22 | endif 23 | ifdef ZIP 24 | ZIP_COMMAND := zip ${ZIP} ${CC_OUTPUT} && make clean-build 25 | endif 26 | ifdef TAR 27 | ZIP_COMMAND := tar -czf ${TAR}.tar.gz ${CC_OUTPUT} && make clean-build 28 | endif 29 | 30 | all: 31 | ################################## 32 | ## ## ## ## [3BC Language] 33 | ## ## ## ## 34 | ## ## ## ###### Choose a target: 35 | ############ ## ## ###### 36 | ############ ## ## ###### > make build 37 | ## ## ## ## > make tests 38 | ## ## ## ## > make clean 39 | ## ## ############ > make docs 40 | ############ ## ## 41 | ############ ## ## 42 | ## ## ###### ## 43 | ## ## ###### ## 44 | ## ## ## 45 | ################################## 46 | 47 | build: 48 | (${CC} ${CC_FLAGS} ${CC_TARGET_PREFIX} -c ${CC_SOURCES} -o ${CC_OBJECTS}) || (make clean-objects && false) 49 | (${LD} ${CC_OBJECTS} ${LD_TARGET_PREFIX} ${LD_FLAGS} -o ${CC_OUTPUT}) || (make clean-objects && false) 50 | ${ZIP_COMMAND} 51 | make clean-objects 52 | make install-hooks 53 | 54 | docs: clean-docs 55 | @cd docs && jekyll build 56 | 57 | docs-serve: clean-docs 58 | @cd docs && bundle exec jekyll serve --watch --livereload 59 | 60 | clean: clean-zip clean-objects clean-build clean-test clean-docs clean-test 61 | @rm -f *.log 2>/dev/null; true 62 | @echo done! 63 | 64 | clean-objects: 65 | @rm -f *.o *.obj src/*.o src/*.obj main/*.o main/*.obj 2>/dev/null; true 66 | 67 | clean-build: 68 | @rm -f *.bin *.out *.s *.bin *.exe *.a *.so *.dylib *.wasm *.js *.html 3bc main unit 2>/dev/null; true 69 | 70 | clean-zip: 71 | @rm -f *.zip *.tar *.tar.* 2>/dev/null; true 72 | 73 | clean-docs: 74 | @rm -Rf docs/_site/* 2>/dev/null; true 75 | 76 | clean-test: 77 | @rm *.gcda *.gcno 2>/dev/null; true 78 | 79 | tests: clean-test 80 | @echo " > running fasts tests...\n > to use the full test suite, run: make tests-full\n" 81 | @${CXX} -w -coverage ${CXX_SOURCES} -O0 -lm -o 3bc.test.bin 82 | @ruby -Ilib -e 'ARGV.each { |f| require f }' ./tests/fasttest.*.rb 83 | 84 | tests-full: clean-test 85 | @echo " > running full tests suite...\n" 86 | @${CXX} -w -coverage ${CXX_SOURCES} -O0 -lm -o 3bc.test.bin 87 | @ruby -Ilib -e 'ARGV.each { |f| require f }' ./tests/*.*.rb 88 | 89 | install-hooks: 90 | @cp .commit-msg .git/hooks/commit-msg 91 | -------------------------------------------------------------------------------- /examples/math_basics.3bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 3bc 2 | ########################################### 3 | # examples comparing with python with 3bc # 4 | ########################################### 5 | 6 | # a, b = 5, 2 7 | # c = a + b; print('a + b =', c) 8 | # c = a - b; print('a - b =', c) 9 | # c = a * b; print('a * b =', c) 10 | # c = a / b; print('a / b =', c) 11 | 12 | # equivalent to alocate variables (a, b) 13 | MODE NILL 0x06 # MODE_MEM 14 | ALOC 'a' 5 15 | ALOC 'b' 2 16 | 17 | ########################################### 18 | # equivalent to print (f'a, b = {a}, {b}') 19 | MODE NILL 0x02 # MODE_STRING 20 | STRC NILL 'a' 21 | STRC NILL ',' 22 | STRC NILL 'b' 23 | STRC NILL '=' 24 | STRI 'a' NILL 25 | STRC NILL ',' 26 | STRI 'b' NILL 27 | STRC NILL 0xA 28 | 29 | ########################################### 30 | # equivalent to sum (a + b) 31 | MODE NILL 0x08 # MODE_MEM_AUX 32 | PUSH 'a' NILL 33 | 34 | MODE NILL 0x0b # MODE_MATH_SUM 35 | MATH 'b' NILL 36 | 37 | MODE NILL 0x08 # MODE_MEM_AUX 38 | PULL 'c' NILL 39 | 40 | # equivalent to print('a + b =', c) 41 | MODE NILL 0x02 # MODE_STRING 42 | STRC NILL 'a' 43 | STRC NILL '+' 44 | STRC NILL 'b' 45 | STRC NILL '=' 46 | STRI 'c' NILL 47 | STRC NILL 0xA 48 | 49 | ########################################### 50 | # equivalent to sub (a - b) 51 | MODE NILL 0x08 # MODE_MEM_AUX 52 | PUSH 'a' NILL 53 | 54 | MODE NILL 0x0c # MODE_MATH_SUB 55 | MATH 'b' NILL 56 | 57 | MODE NILL 0x08 # MODE_MEM_AUX 58 | PULL 'c' NILL 59 | 60 | # equivalent to print('a - b =', c) 61 | MODE NILL 0x02 # MODE_STRING 62 | STRC NILL 'a' 63 | STRC NILL '-' 64 | STRC NILL 'b' 65 | STRC NILL '=' 66 | STRI 'c' NILL 67 | STRC NILL 0xA 68 | 69 | ########################################### 70 | # equivalent to sum (a * b) 71 | MODE NILL 0x08 # MODE_MEM_AUX 72 | PUSH 'a' NILL 73 | 74 | MODE NILL 0x0d # MODE_MATH_MUL 75 | MATH 'b' NILL 76 | 77 | MODE NILL 0x08 # MODE_MEM_AUX 78 | PULL 'c' NILL 79 | 80 | # equivalent to print('a * b =', c) 81 | MODE NILL 0x02 # MODE_STRING 82 | STRC NILL 'a' 83 | STRC NILL '*' 84 | STRC NILL 'b' 85 | STRC NILL '=' 86 | STRI 'c' NILL 87 | STRC NILL 0xA 88 | 89 | ########################################### 90 | # equivalent to sub (a / b) 91 | MODE NILL 0x08 # MODE_MEM_AUX 92 | PUSH 'a' NILL 93 | 94 | MODE NILL 0x0e # MODE_MATH_DIV 95 | MATH 'b' NILL 96 | 97 | MODE NILL 0x08 # MODE_MEM_AUX 98 | PULL 'c' NILL 99 | 100 | # equivalent to print('a / b =', c) 101 | MODE NILL 0x02 # MODE_STRING 102 | STRC NILL 'a' 103 | STRC NILL '/' 104 | STRC NILL 'b' 105 | STRC NILL '=' 106 | STRI 'c' NILL 107 | STRC NILL 0xA -------------------------------------------------------------------------------- /tests/fulltest.commit_message.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/spec' 2 | require 'minitest/autorun' 3 | require 'minitest/parallel' 4 | require './scripts/commit_message_hook' 5 | 6 | class CommitMessageHookTest < Minitest::Test 7 | def test_valid_feature_commit 8 | message = 'feat: awesome feature' 9 | response = CommitMessageHook.call(message) 10 | 11 | assert_equal true, response.fetch(:success) 12 | assert_equal [], response.fetch(:errors) 13 | end 14 | 15 | def test_valid_scoped_commit 16 | message = 'docs(readme): awesome docs' 17 | response = CommitMessageHook.call(message) 18 | 19 | assert_equal true, response.fetch(:success) 20 | assert_equal [], response.fetch(:errors) 21 | end 22 | 23 | def test_valid_breaking_changes_footer 24 | message = "chore!: drop support\n\nBREAKING CHANGE: drop support" 25 | response = CommitMessageHook.call(message) 26 | 27 | assert_equal true, response.fetch(:success) 28 | assert_equal [], response.fetch(:errors) 29 | end 30 | 31 | def test_must_ignore_comments 32 | message = "docs(readme): awesome docs\n# comments must be ignored" 33 | response = CommitMessageHook.call(message) 34 | 35 | assert_equal true, response.fetch(:success) 36 | assert_equal [], response.fetch(:errors) 37 | end 38 | 39 | def test_invalid_commit 40 | message = 'invalid commit' 41 | response = CommitMessageHook.call(message) 42 | 43 | assert_equal false, response.fetch(:success) 44 | assert_includes response.fetch(:errors), 'Invalid commit title format' 45 | end 46 | 47 | def test_invalid_size 48 | message = 'feat: commit title max characters are 80 characters, here we have more than 80, we have 90' 49 | response = CommitMessageHook.call(message) 50 | 51 | assert_equal false, response.fetch(:success) 52 | assert_includes response.fetch(:errors), 'Invalid commit title max size (80)' 53 | end 54 | 55 | def test_missing_semicolon 56 | message = 'feat awesome feature' 57 | response = CommitMessageHook.call(message) 58 | 59 | assert_equal false, response.fetch(:success) 60 | assert_includes response.fetch(:errors), 'Invalid commit title format' 61 | end 62 | 63 | def test_not_empty_second_line 64 | message = "feat: awesome feature\nmust be empty" 65 | response = CommitMessageHook.call(message) 66 | 67 | assert_equal false, response.fetch(:success) 68 | assert_includes response.fetch(:errors), 'Second line must be empty' 69 | end 70 | 71 | def test_breaking_changes_lowercase 72 | message = "chore!: drop support\n\nbreaking change: drop support" 73 | response = CommitMessageHook.call(message) 74 | 75 | assert_equal false, response.fetch(:success) 76 | assert_includes response.fetch(:errors), 'Breaking changes footer must be uppercase' 77 | end 78 | 79 | def test_breaking_changes_title_without_bang 80 | message = "chore: drop support\n\nBREAKING CHANGE: drop support" 81 | response = CommitMessageHook.call(message) 82 | 83 | assert_equal false, response.fetch(:success) 84 | assert_includes response.fetch(:errors), 'Commit tile must append `!` for breaking changes' 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3BC Language 3 | --- 4 | 5 |

{{ page.title }}

6 | 7 |
8 |
9 | 3BC LANGUAGE LOGO 15 |
16 |
17 |

Download last version!

18 | {% assign release = site.github.releases | first %} 19 | 34 | 35 |
36 | {% for main in site.data.main_plataforms %} 37 | {% assign asset = release.assets | where: "name", main.name | first %} 38 |
39 | {{ main.title }}
40 | {% include download_btn.rhtml title=main.title %} 41 |
42 | {% endfor %} 43 |
44 |
45 |
46 | 47 |
48 |
49 |

Documentation

50 | 87 |
88 |
89 |

About

90 |

{{ site.description }}

91 |
92 |

{{ site.description_pt }}

93 |
94 |
95 | -------------------------------------------------------------------------------- /src/interpreter_readln.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the interpreter where it reads a line, checks for problems, 12 | * and converts it to bytecode for use. 13 | * 14 | * DATASTRUCT: 15 | * Linked list, first in, first out. 16 | * 17 | * BRIEF: 18 | * Low-level language, tiny virtual machine, intermediate representation, 19 | * embeddable, easy for beginners. (Friendly Punched cards) 20 | * 21 | * AUTHOR: 22 | * Copyright (C) 2020 Rodrigo Dornelles. 23 | * 24 | * LICENSE: 25 | * This program is free software: you can redistribute it and/or modify 26 | * it under the terms of the GNU General Public License as published by 27 | * the Free Software Foundation, either version 3 of the License, 28 | * or any later version. 29 | * 30 | * This program is distributed in the hope that it will be useful, 31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33 | * GNU General Public License for more details. 34 | * 35 | * You should have received a copy of the GNU General Public License 36 | * along with this program. If not, see . 37 | */ 38 | 39 | #define TBC_SOURCE_ENTRY 40 | #include "3bc.h" 41 | 42 | #if defined(TBC_INTERPRETER) && !defined(TBC_SCU_OPTIONAL_FIX) 43 | /** 44 | * Interpret text and insert to virtual machine. 45 | * 46 | * TODO: refactor single point of return, no implicit outputs. 47 | * EXAMPLE: interpreter_compiler(app, "MODE 0 2"); 48 | * RETURN: NULL if the entire string is compiled. 49 | * RETURN: Pointer to the rest of the string that can be compiled. 50 | */ 51 | char* interpreter_readln(struct app_3bc_s* const app, char* line) 52 | { 53 | char *text_reg, *text_mem, *text_val; 54 | signed long int reg, mem, val; 55 | 56 | /** scan more 1 line**/ 57 | if (!interpreter_tokens(line, &text_reg, &text_mem, &text_val, &line)) { 58 | driver_program_error(app, ERROR_COLUMNS); 59 | } 60 | /** blank line **/ 61 | if (text_reg == NULL) { 62 | return line; 63 | } 64 | /** parse string to register and validate **/ 65 | if (!interpreter_syntax_registers(app, text_reg, ®)) { 66 | driver_program_error(app, ERROR_INVALID_REGISTER); 67 | } 68 | /** parse string to address and validate **/ 69 | else if (!interpreter_syntax_constants(app, text_mem, &mem)) { 70 | driver_program_error(app, ERROR_INVALID_ADDRESS); 71 | } 72 | /** parse string to constant and validate **/ 73 | else if (!interpreter_syntax_constants(app, text_val, &val)) { 74 | driver_program_error(app, ERROR_INVALID_CONSTANT); 75 | } else { 76 | /** add new line **/ 77 | ds_program_fifo_line_add(app, reg, mem, val); 78 | } 79 | 80 | return line; 81 | } 82 | #endif 83 | -------------------------------------------------------------------------------- /src/ds_label_hash.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers reference labels for the code. 12 | * 13 | * DATASTRUCT: 14 | * Hash map. 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | /** 42 | * mark point to logical jumps 43 | */ 44 | void ds_label_hash_insert(struct app_3bc_s* const app, label_3bc_t label) 45 | { 46 | unsigned char hash; 47 | struct label_node_s* new_node; 48 | struct label_node_s* last_node; 49 | 50 | /** label already exists **/ 51 | if (ds_label_hash_search(app, label) != NULL) { 52 | driver_program_error(app, ERROR_INVALID_LABEL); 53 | } 54 | 55 | new_node = (struct label_node_s*)malloc(sizeof(struct label_node_s)); 56 | hash = label % LABEL_HASH_SIZE; 57 | 58 | /** was not possible expand labels **/ 59 | if (new_node == NULL) { 60 | driver_program_error(app, ERROR_OUT_OF_MEMORY); 61 | } 62 | 63 | new_node->label = label; 64 | new_node->point = app->program.tail; 65 | new_node->cpumode = app->program.last_cpu; 66 | 67 | if (app->program.label_table[hash] == NULL) { 68 | app->program.label_table[hash] = new_node; 69 | new_node->next = NULL; 70 | return; 71 | } 72 | 73 | last_node = app->program.label_table[hash]; 74 | while (last_node->next != NULL) { 75 | last_node = last_node->next; 76 | } 77 | last_node->next = new_node; 78 | } 79 | 80 | /** 81 | * find label in hash tabel 82 | */ 83 | struct label_node_s* ds_label_hash_search( 84 | struct app_3bc_s* const app, label_3bc_t label) 85 | { 86 | struct label_node_s* last_node 87 | = app->program.label_table[label % LABEL_HASH_SIZE]; 88 | 89 | while (last_node != NULL) { 90 | if (last_node->label == label) { 91 | return last_node; 92 | } 93 | 94 | last_node = last_node->next; 95 | } 96 | 97 | return NULL; 98 | } 99 | -------------------------------------------------------------------------------- /src/driver_custom.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers customization of registers by the user. 12 | * 13 | * DATASTRUCT: 14 | * Dynamic Array 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | #if !defined(TBC_SCU_OPTIONAL_FIX) 42 | #if !defined(TBC_CUSTOM) 43 | void driver_custom_call(struct app_3bc_s* const app, register_3bc_t reg, 44 | address_3bc_t address, data_3bc_t value) 45 | { 46 | driver_program_error(app, ERROR_CPU_RESERVED); 47 | } 48 | 49 | #else 50 | function_3bc_t* custom_funcs = NULL; 51 | unsigned char last_func = 0; 52 | 53 | void driver_custom_set(struct app_3bc_s* const app, cpumode_3bc_t cpu_mode, 54 | register_3bc_t reg, function_3bc_t lambda) 55 | { 56 | unsigned char atual_func = ((cpu_mode / 10) - 1) * 6 + reg; 57 | 58 | /** expand array of functions **/ 59 | if (custom_funcs == NULL || last_func <= atual_func) { 60 | function_3bc_t* new_array = (function_3bc_t*)realloc( 61 | custom_funcs, sizeof(function_3bc_t) * atual_func + 1); 62 | 63 | if (new_array == NULL) { 64 | driver_program_error(app, ERROR_OUT_OF_MEMORY); 65 | } 66 | 67 | /** clean wild pointers **/ 68 | while (last_func <= atual_func) { 69 | new_array[last_func] = NULL; 70 | ++last_func; 71 | } 72 | 73 | custom_funcs = new_array; 74 | } 75 | 76 | /** update custom function **/ 77 | custom_funcs[atual_func] = lambda; 78 | } 79 | 80 | void driver_custom_call(struct app_3bc_s* const app, register_3bc_t reg, 81 | address_3bc_t address, data_3bc_t value) 82 | { 83 | unsigned char atual_func = ((app->cpu_mode / 10) - 1) * 6 + reg; 84 | 85 | /** custom function not found **/ 86 | if (custom_funcs == NULL || custom_funcs[atual_func] == NULL 87 | || atual_func >= last_func) { 88 | driver_program_error(app, ERROR_CPU_RESERVED); 89 | } 90 | 91 | custom_funcs[atual_func](app, reg, address, value); 92 | } 93 | #endif 94 | #endif 95 | -------------------------------------------------------------------------------- /tests/fulltest.extra.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | require 'minitest/spec' 3 | require 'minitest/autorun' 4 | 5 | class TestExtra < Minitest::Test 6 | def test_scapes 7 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.10,4.0.0,mode.0.2,strc.0.'\\0',strc.0.'\\a',strc.0.'\\b',strc.0.'\\t',strc.0.'\\n',strc.0.'\\'',strc.0.'\\\\'") 8 | assert_equal "", stderr 9 | assert_equal "000708090A275C", stdout 10 | assert_equal 0, status 11 | end 12 | 13 | def test_labels 14 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.9,goto.0.:entry,mode.0.2,0.0.1,strc.0.'e',0.0.2,strc.0.'d',0.0.129,strc.0.'c',0.0.128,strc.0.'b' ,0.0.127,strc.0.'a',strc.0.'.',mode.0.41,back.0.0,mode.0.42,0.0.:entry,call.0.127,call.0.128,call.0.129,call.0.2,call.0.1") 15 | assert_equal "", stderr 16 | assert_equal "a.ba.cba.dcba.edcba.", stdout 17 | assert_equal 0, status 18 | end 19 | 20 | def test_nop 21 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "0.0.0") 22 | assert_equal "", stderr 23 | assert_equal "", stdout 24 | assert_equal 0, status 25 | end 26 | 27 | def test_signal_sigint 28 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "7.0.10,1.0.2") 29 | assert_match "", stderr 30 | assert_equal 2, status.exitstatus 31 | end 32 | 33 | def test_memory_clean_unstarted 34 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.6,free.6.0") 35 | assert_equal "", stderr 36 | assert_equal "", stdout 37 | assert_equal 0, status 38 | end 39 | 40 | def test_memory_clean_right_unbalanced 41 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.6,aloc.1.0,aloc.2.0,aloc.3.0,aloc.4.0,free.2.0") 42 | assert_equal "", stderr 43 | assert_equal "", stdout 44 | assert_equal 0, status 45 | end 46 | 47 | def test_memory_clean_two_childrens 48 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.6,aloc.4.0,aloc.3.0,aloc.2.0,aloc.1.0,free.3.0") 49 | assert_equal "", stderr 50 | assert_equal "", stdout 51 | assert_equal 0, status 52 | end 53 | 54 | def test_memory_clean_left_unbalanced 55 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.6,aloc.5.0,aloc.4.0,aloc.3.0,aloc.2.0,aloc.1.0,free.3.0") 56 | assert_equal "", stderr 57 | assert_equal "", stdout 58 | assert_equal 0, status 59 | end 60 | 61 | def test_memory_node_child_left 62 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.6,aloc.2.0,aloc.1.0,free.2.0") 63 | assert_equal "", stderr 64 | assert_equal "", stdout 65 | assert_equal 0, status 66 | end 67 | 68 | def test_more_teen_skips 69 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.9," + ("goto.0.skip,0.0.skip," * 10) + "goto.0.skip,mode.0.2,stri.0.1,0.0.skip,stri.0.2") 70 | assert_equal "", stderr 71 | assert_equal "2", stdout 72 | assert_equal 0, status 73 | end 74 | 75 | def test_ignore_carrier_return 76 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mo\rde.0.2,stri.0.4\r2") 77 | assert_equal "", stderr 78 | assert_equal "42", stdout 79 | assert_equal 0, status 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /docs/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: List of all platforms that are working, or that will receive the support soon. 3 | --- 4 | 5 | Platform Support List 6 | ===================== 7 | 8 | Computers 9 | ------------------ 10 | 11 | | | i386 | amd64 | arm32 | arm64 | mips32 | mips64 | powerpc | powerpc64 | riscv | riscv64 | s390x | 12 | | :----------- | :---: | :---: | :---: | :---: | :----: | :----: | :-----: | :-------: | :---: | :-----: | :---: | 13 | | Android | _N/A_ | :ok: | :ok: | :ok: | _N/A_ | _N/A_ | _N/A_ | _N/A_ | _N/A_ | _N/A_ | _N/A_ | 14 | | Windows | :ok: | :ok: | _N/A_ | :ok: | _N/A_ | _N/A_ | _N/A_ | _N/A_ | _N/A_ | _N/A_ | _N/A_ | 15 | | Mac OS | :x: | :ok: | _N/A_ | :ok: | _N/A_ | _N/A_ | | _N/A_ | _N/A_ | _N/A_ | _N/A_ | 16 | | Docker Linux | :ok: | :ok: | :ok: | :ok: | | :ok: | | :ok: | | | :ok: | 17 | | GNU Linux | :ok: | :ok: | :ok: | :ok: | :ok: | | :ok: | :ok: | | :ok: | | 18 | | GNU Hurd | | | | | | | | | | | _N/A_ | 19 | | Plan 9 | | | | | | | | | | | _N/A_ | 20 | | Open BSD | | | | | | | | | | | _N/A_ | 21 | | Free BSD | :x: | :x: | | | | | | | | | _N/A_ | 22 | 23 | 1. **mac os** does not support 32-bit systems. 24 | 2. **windows** windows is not currently supporting cpu sleep mode. 25 | 3. **freebsd** currently does not support official publication. 26 | 27 | Integrations 28 | ------------ 29 | 30 | | | wasm | wasm.js
_(legacy)_ | emscripten
_(bloated)_ | typescript | 31 | | :------ | :--: | :--------------------: | :------------------------: | :--------: | 32 | | NodeJS | | | :ok: | | 33 | | Browser | | | | | 34 | 35 | 36 | | | C++ | NodeJS | Python | Rust | 37 | | :-------------- | :---: | :----: | :----: | :--: | 38 | | FFI | _N/A_ | | | | 39 | | Wrapper | | | | :ok: | 40 | | Dynamic Library | | | | | 41 | 42 | * **Rust** third-party support 43 | 44 | Embedded Systems 45 | ---------------- 46 | 47 | | | avr | riscv | arm | pic | 48 | | :-------- | :---: | :---: | :---: | :-: | 49 | | Arduino | :ok: | :ok: | :ok: | _N/A_ | 50 | | AVR Lib C | :ok: | _N/A_ | _N/A_ | _N/A_ | 51 | | ESP IDF | _N/A_ | :ok: | _N/A_ | _N/A_ | 52 | | ODroid | | | | _N/A_ | 53 | | Free RTOS | | :ok: | | _N/A_ | 54 | | Baremetal | | | | | 55 | 56 | Legacy Systems 57 | -------------- 58 | 59 | | | i386 | mos6502
NES | mos6502
Apple 2 | mos6502
C64 | 60 | | :------------ | :---: | :-------------: | :-----------------: | :-------------: | 61 | | Baremetal | _N/A_ | :ok: | :ok: | | 62 | | Microsoft Dos | | _N/A_ | | | 63 | 64 | * **MOS6502 / Nintendo Entertainment System** currently it only runs hello world compiled together with the virtual machine program. 65 | * **MOS6502 / Apple 2** runs programs that are compiled together with the virtual machine and without support interpreter or repl. 66 | -------------------------------------------------------------------------------- /tests/fasttest.examples.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | require 'minitest/spec' 3 | require 'minitest/autorun' 4 | 5 | class TestExample < Minitest::Test 6 | def test_fibonacci 7 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/fibonacci.3bc", :stdin_data => 9) 8 | assert_equal "", stderr 9 | assert_equal "FIB:9\n0\n1\n1\n2\n3\n5\n8\n13\n21", stdout 10 | assert_equal 0, status 11 | end 12 | 13 | def test_hello_world 14 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/heloworld.3bc") 15 | assert_equal "", stderr 16 | assert_equal "hello world!\n", stdout 17 | assert_equal 0, status 18 | end 19 | 20 | def test_input_login 21 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/input_login.3bc", :stdin_data => "XXXXXXX") 22 | assert_equal "", stderr 23 | assert_equal "\n[?] login: XXX\n[?] password: ***\n\n[!] press any key.\n", stdout 24 | assert_equal 0, status 25 | end 26 | 27 | def test_loop_do_while 28 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/loop_do_while.3bc", :stdin_data => "t1yYn") 29 | assert_equal "", stderr 30 | assert_equal "\nREPEAT? [y/n]\nREPEAT? [y/n]\nREPEAT? [y/n]\nREPEAT? [y/n]", stdout 31 | assert_equal 0, status 32 | end 33 | 34 | def test_loop 35 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/loop.3bc") 36 | assert_equal "", stderr 37 | assert_equal "HI!\nHI!\nHI!\n", stdout 38 | assert_equal 0, status 39 | end 40 | 41 | def test_invert_default 42 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/invert_default.3bc") 43 | assert_equal "", stderr 44 | assert_equal "ABC CBA\n", stdout 45 | assert_equal 0, status 46 | end 47 | 48 | def test_invert_helper 49 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/invert_default.3bc") 50 | assert_equal "", stderr 51 | assert_equal "ABC CBA\n", stdout 52 | assert_equal 0, status 53 | end 54 | 55 | def test_invert_helper 56 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/invert_text.3bc", :stdin_data => 'socorram me subi no onibus em marrocos.') 57 | assert_equal "", stderr 58 | assert_equal "socorram me subi no onibus em marrocos..socorram me subino on ibus em marrocos", stdout 59 | assert_equal 0, status 60 | end 61 | 62 | def test_math_basics 63 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/math_basics.3bc") 64 | assert_equal "", stderr 65 | assert_equal "a,b=5,2\na+b=7\na-b=3\na*b=10\na/b=2\n", stdout 66 | assert_equal 0, status 67 | end 68 | 69 | def test_pointers 70 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/pointers.3bc") 71 | assert_equal "", stderr 72 | assert_equal "7", stdout 73 | assert_equal 0, status 74 | end 75 | 76 | def test_procedure 77 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/procedure.3bc") 78 | assert_equal "", stderr 79 | assert_equal "HelloWorld", stdout 80 | assert_equal 0, status 81 | end 82 | 83 | def test_ola_mundo 84 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "./examples/olamundo.3bc") 85 | assert_equal "", stderr 86 | assert_equal "ola mundo!", stdout 87 | assert_equal 0, status 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /src/ds_hypervisor_darray.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the virtual machine's launcher. 12 | * 13 | * DATASTRUCT: 14 | * Dynamic Array 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | static app_3bc_id machines_count; 42 | static struct app_3bc_s** machines_array; 43 | 44 | /** 45 | * Expand number of virtual machines 46 | */ 47 | struct app_3bc_s* const ds_hypervisor_darray_new() 48 | { 49 | struct app_3bc_s* new_vm 50 | = (struct app_3bc_s* const)malloc(sizeof(struct app_3bc_s)); 51 | 52 | /** successful craete new machine **/ 53 | if (new_vm != NULL) { 54 | /** expand hypervisor **/ 55 | struct app_3bc_s** new_array = (struct app_3bc_s**)realloc( 56 | machines_array, (sizeof(struct app_3bc_s*) * (machines_count + 2))); 57 | 58 | /** not possible expand array **/ 59 | if (new_array == NULL) { 60 | free(new_vm); 61 | return NULL; 62 | } 63 | 64 | /** setup hypervisor **/ 65 | machines_array = new_array; 66 | machines_array[machines_count] = new_vm; 67 | machines_array[machines_count + 1] = NULL; 68 | memset(new_vm, 0, sizeof(struct app_3bc_s)); 69 | 70 | /** basic setup machine **/ 71 | new_vm->id = machines_count++; 72 | new_vm->memory.data_get = &ds_memory_llrbt_data_get; 73 | new_vm->memory.conf_get = &ds_memory_llrbt_conf_get; 74 | new_vm->memory.data_set = &ds_memory_llrbt_data_set; 75 | new_vm->memory.conf_set = &ds_memory_llrbt_conf_set; 76 | 77 | return new_vm; 78 | } 79 | 80 | return NULL; 81 | } 82 | 83 | /** 84 | * RETURN: virutal machine by id 85 | */ 86 | struct app_3bc_s* const ds_hypervisor_darray_get_one(app_3bc_id app) 87 | { 88 | return machines_array[app]; 89 | } 90 | 91 | /** 92 | * RETURN: array of virtual machines 93 | */ 94 | struct app_3bc_s** ds_hypervisor_darray_get_all() 95 | { 96 | return machines_array; 97 | } 98 | 99 | void ds_hypervisor_darray_kill_all() 100 | { 101 | do { 102 | /** free each machine **/ 103 | free(machines_array[--machines_count]); 104 | } while (machines_count); 105 | 106 | /** reset hypervisor **/ 107 | free(machines_array); 108 | machines_array = NULL; 109 | } -------------------------------------------------------------------------------- /src/cpu_procedure.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for calling procedures. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_procedure_call(PARAMS_DEFINE) 39 | { 40 | REQUIRED_VALUE 41 | VALIDATE_NOT_ADRESS 42 | ds_procedure_lifo_push(app); 43 | app->program.label_target = value; 44 | } 45 | 46 | void cpu_procedure_back(PARAMS_DEFINE) 47 | { 48 | VALIDATE_NOT_VALUES 49 | VALIDATE_NOT_ADRESS 50 | app->program.curr = ds_procedure_lifo_pop(app); 51 | driver_mode_set(app, MODE_PROCEDURE); 52 | } 53 | 54 | void cpu_procedure_fcal(PARAMS_DEFINE) 55 | { 56 | REQUIRED_VALUE 57 | VALIDATE_NOT_ADRESS 58 | if (AUX != 0) { 59 | ds_procedure_lifo_push(app); 60 | app->program.label_target = value; 61 | } 62 | } 63 | 64 | void cpu_procedure_zcal(PARAMS_DEFINE) 65 | { 66 | REQUIRED_VALUE 67 | VALIDATE_NOT_ADRESS 68 | if (AUX == 0) { 69 | ds_procedure_lifo_push(app); 70 | app->program.label_target = value; 71 | } 72 | } 73 | 74 | void cpu_procedure_pcal(PARAMS_DEFINE) 75 | { 76 | REQUIRED_VALUE 77 | VALIDATE_NOT_ADRESS 78 | if (AUX > 0) { 79 | ds_procedure_lifo_push(app); 80 | app->program.label_target = value; 81 | } 82 | } 83 | 84 | void cpu_procedure_ncal(PARAMS_DEFINE) 85 | { 86 | REQUIRED_VALUE 87 | VALIDATE_NOT_ADRESS 88 | if (AUX < 0) { 89 | ds_procedure_lifo_push(app); 90 | app->program.label_target = value; 91 | } 92 | } 93 | 94 | void cpu_procedure_fret(PARAMS_DEFINE) 95 | { 96 | VALIDATE_NOT_VALUES 97 | VALIDATE_NOT_ADRESS 98 | if (AUX != 0) { 99 | app->program.curr = ds_procedure_lifo_pop(app); 100 | driver_mode_set(app, MODE_PROCEDURE); 101 | } 102 | } 103 | 104 | void cpu_procedure_zret(PARAMS_DEFINE) 105 | { 106 | VALIDATE_NOT_VALUES 107 | VALIDATE_NOT_ADRESS 108 | if (AUX == 0) { 109 | app->program.curr = ds_procedure_lifo_pop(app); 110 | driver_mode_set(app, MODE_PROCEDURE); 111 | } 112 | } 113 | 114 | void cpu_procedure_pret(PARAMS_DEFINE) 115 | { 116 | VALIDATE_NOT_VALUES 117 | VALIDATE_NOT_ADRESS 118 | if (AUX > 0) { 119 | app->program.curr = ds_procedure_lifo_pop(app); 120 | driver_mode_set(app, MODE_PROCEDURE); 121 | } 122 | } 123 | 124 | void cpu_procedure_nret(PARAMS_DEFINE) 125 | { 126 | VALIDATE_NOT_VALUES 127 | VALIDATE_NOT_ADRESS 128 | if (AUX < 0) { 129 | app->program.curr = ds_procedure_lifo_pop(app); 130 | driver_mode_set(app, MODE_PROCEDURE); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/driver_interrupt.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the managing contexts and interrupt's of the virtual machine. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | * 34 | * JOKE: 35 | * _\|/_ weedend alert! _\|/_ 36 | * this code was written in a 4:20 mode. 37 | */ 38 | 39 | #define TBC_SOURCE_ENTRY 40 | #include "3bc.h" 41 | 42 | /** 43 | * VM processor context manager, allows asychronism. 44 | */ 45 | bool driver_interrupt(struct app_3bc_s* const app) 46 | { 47 | switch (app->state) { 48 | /** 49 | * INITIAL CONTEXT 50 | */ 51 | case FSM_3BC_DEFAULT: 52 | app->state = FSM_3BC_RUNNING; 53 | return true; 54 | 55 | /** 56 | * INTERPRETER CONTEXT 57 | */ 58 | case FSM_3BC_READING: 59 | switch (interpreter_ticket(app)) { 60 | case 1: 61 | app->state = FSM_3BC_RUNNING; 62 | return true; 63 | 64 | case EOF: 65 | app->state = FSM_3BC_EXITING; 66 | return true; 67 | } 68 | return true; 69 | 70 | /** 71 | * PROCESS CONTEXT 72 | */ 73 | case FSM_3BC_RUNNING: 74 | if (!ds_program_fifo_avaliable(app)) { 75 | app->state = FSM_3BC_READING; 76 | } else if (app->cpu_mode == MODE_SLEEP 77 | && app->cache_l1.sleep_mode != SLEEP_3BC_NONE) { 78 | app->state = FSM_3BC_WAITING; 79 | } 80 | /** TODO 81 | else if (app->cache_l3.direction < 0) { 82 | app->state = FSM_3BC_IO_READ; 83 | } 84 | else if (app->cache_l3.direction > 0) { 85 | app->state = FSM_3BC_IO_SEND; 86 | }*/ 87 | else { 88 | driver_program_tick(app); 89 | } 90 | return true; 91 | 92 | /** 93 | * SLEEP CONTEXT 94 | */ 95 | case FSM_3BC_WAITING: 96 | if (!driver_idle(app)) { 97 | app->state = FSM_3BC_RUNNING; 98 | app->cache_l1.sleep_mode = SLEEP_3BC_NONE; 99 | app->cache_l2.sleep_period = 0; 100 | app->cache_l3.sleep_called = 0; 101 | } 102 | return true; 103 | 104 | /** 105 | * INPUT CONTEXT 106 | * TODO: this 107 | case FSM_3BC_IO_READ: 108 | app->state = FSM_3BC_RUNNING; 109 | return true;*/ 110 | 111 | /** 112 | * OUTPUT CONTEXT 113 | * TODO: this 114 | case FSM_3BC_IO_SEND: 115 | app->state = FSM_3BC_RUNNING; 116 | return true;*/ 117 | 118 | /** 119 | * EXIT CONTEXT 120 | */ 121 | case FSM_3BC_EXITING: 122 | driver_power_exit(app); 123 | return true; 124 | } 125 | 126 | return false; 127 | } -------------------------------------------------------------------------------- /src/cpu_boolean.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for the boolean logic unit. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_bitwise_not(PARAMS_DEFINE) 39 | { 40 | VALIDATE_NOT_ADRESS 41 | VALIDATE_NOT_VALUES 42 | driver_accumulator_set(app, ~AUX); 43 | } 44 | 45 | void cpu_bitwise_and(PARAMS_DEFINE) 46 | { 47 | VALIDATE_NOT_DUALITY 48 | driver_accumulator_set(app, AUX & GET_ANY_PARAM); 49 | } 50 | 51 | void cpu_bitwise_or(PARAMS_DEFINE) 52 | { 53 | VALIDATE_NOT_DUALITY 54 | driver_accumulator_set(app, AUX | GET_ANY_PARAM); 55 | } 56 | 57 | void cpu_bitwise_xor(PARAMS_DEFINE) 58 | { 59 | VALIDATE_NOT_DUALITY 60 | driver_accumulator_set(app, AUX ^ GET_ANY_PARAM); 61 | } 62 | 63 | void cpu_bitwise_nand(PARAMS_DEFINE) 64 | { 65 | VALIDATE_NOT_DUALITY 66 | driver_accumulator_set(app, ~(AUX & GET_ANY_PARAM)); 67 | } 68 | 69 | void cpu_bitwise_nor(PARAMS_DEFINE) 70 | { 71 | VALIDATE_NOT_DUALITY 72 | driver_accumulator_set(app, ~(AUX | GET_ANY_PARAM)); 73 | } 74 | 75 | void cpu_bitwise_xnor(PARAMS_DEFINE) 76 | { 77 | VALIDATE_NOT_DUALITY 78 | driver_accumulator_set(app, ~(AUX ^ GET_ANY_PARAM)); 79 | } 80 | 81 | void cpu_bitwise_left(PARAMS_DEFINE) 82 | { 83 | VALIDATE_NOT_DUALITY 84 | VALIDATE_NOT_NEGATIVES 85 | driver_accumulator_set(app, AUX << GET_ANY_PARAM); 86 | } 87 | 88 | void cpu_bitwise_right(PARAMS_DEFINE) 89 | { 90 | VALIDATE_NOT_DUALITY 91 | VALIDATE_NOT_NEGATIVES 92 | driver_accumulator_set(app, AUX >> GET_ANY_PARAM); 93 | } 94 | 95 | void cpu_bool_not(PARAMS_DEFINE) 96 | { 97 | VALIDATE_NOT_ADRESS 98 | VALIDATE_NOT_VALUES 99 | driver_accumulator_set(app, !AUX); 100 | } 101 | 102 | void cpu_bool_and(PARAMS_DEFINE) 103 | { 104 | VALIDATE_NOT_DUALITY 105 | VALIDATE_NOT_NEGATIVES 106 | driver_accumulator_set(app, AUX && GET_ANY_PARAM); 107 | } 108 | 109 | void cpu_bool_or(PARAMS_DEFINE) 110 | { 111 | VALIDATE_NOT_DUALITY 112 | VALIDATE_NOT_NEGATIVES 113 | driver_accumulator_set(app, AUX || GET_ANY_PARAM); 114 | } 115 | 116 | void cpu_bool_xor(PARAMS_DEFINE) 117 | { 118 | VALIDATE_NOT_DUALITY 119 | VALIDATE_NOT_NEGATIVES 120 | driver_accumulator_set(app, (!!AUX) ^ (!!GET_ANY_PARAM)); 121 | } 122 | 123 | void cpu_bool_nand(PARAMS_DEFINE) 124 | { 125 | VALIDATE_NOT_DUALITY 126 | VALIDATE_NOT_NEGATIVES 127 | driver_accumulator_set(app, !(AUX && GET_ANY_PARAM)); 128 | } 129 | 130 | void cpu_bool_nor(PARAMS_DEFINE) 131 | { 132 | VALIDATE_NOT_DUALITY 133 | VALIDATE_NOT_NEGATIVES 134 | driver_accumulator_set(app, !(AUX || GET_ANY_PARAM)); 135 | } 136 | 137 | void cpu_bool_xnor(PARAMS_DEFINE) 138 | { 139 | VALIDATE_NOT_DUALITY 140 | VALIDATE_NOT_NEGATIVES 141 | driver_accumulator_set(app, !((!!AUX) ^ (!!GET_ANY_PARAM))); 142 | } 143 | -------------------------------------------------------------------------------- /src/cpu_memory.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for memory manipulation. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_memory_free(PARAMS_DEFINE) 39 | { 40 | REQUIRED_ADDRESS 41 | VALIDATE_NOT_VALUES 42 | driver_memory_free(app, address); 43 | } 44 | 45 | void cpu_memory_aloc(PARAMS_DEFINE) 46 | { 47 | REQUIRED_ADDRESS 48 | driver_memory_data_set(app, address, value); 49 | } 50 | 51 | void cpu_memory_moff(PARAMS_DEFINE) 52 | { 53 | REQUIRED_ADDRESS 54 | /** config remove mask (and not) */ 55 | driver_memory_conf_set( 56 | app, address, driver_memory_conf_get(app, address) & ~value); 57 | } 58 | 59 | void cpu_memory_muse(PARAMS_DEFINE) 60 | { 61 | REQUIRED_ADDRESS 62 | /** config append mask (or) */ 63 | driver_memory_conf_set( 64 | app, address, driver_memory_conf_get(app, address) | value); 65 | } 66 | 67 | void cpu_memory_ptr_free(PARAMS_DEFINE) 68 | { 69 | REQUIRED_ADDRESS 70 | VALIDATE_NOT_VALUES 71 | driver_memory_free(app, POINTER(address)); 72 | } 73 | 74 | void cpu_memory_ptr_aloc(PARAMS_DEFINE) 75 | { 76 | REQUIRED_ADDRESS 77 | driver_memory_data_set(app, POINTER(address), value); 78 | } 79 | 80 | void cpu_memory_ptr_pull(PARAMS_DEFINE) 81 | { 82 | VALIDATE_NOT_VALUES 83 | driver_memory_data_set(app, POINTER(address), AUX); 84 | } 85 | 86 | void cpu_memory_ptr_push(PARAMS_DEFINE) 87 | { 88 | VALIDATE_NOT_VALUES 89 | driver_accumulator_set(app, driver_memory_data_get(app, POINTER(address))); 90 | } 91 | 92 | void cpu_memory_ptr_spin(PARAMS_DEFINE) 93 | { 94 | VALIDATE_NOT_VALUES 95 | { 96 | data_3bc_t aux_old = AUX; 97 | address = POINTER(address); 98 | driver_accumulator_set(app, driver_memory_data_get(app, address)); 99 | driver_memory_data_set(app, address, aux_old); 100 | } 101 | } 102 | 103 | void cpu_memory_aux_free(PARAMS_DEFINE) 104 | { 105 | VALIDATE_NOT_ADRESS 106 | VALIDATE_NOT_VALUES 107 | driver_accumulator_set(app, NILL); 108 | } 109 | 110 | void cpu_memory_aux_aloc(PARAMS_DEFINE) 111 | { 112 | VALIDATE_NOT_ADRESS 113 | driver_accumulator_set(app, value); 114 | } 115 | 116 | void cpu_memory_aux_pull(PARAMS_DEFINE) 117 | { 118 | VALIDATE_NOT_VALUES 119 | driver_memory_data_set(app, address, AUX); 120 | } 121 | 122 | void cpu_memory_aux_push(PARAMS_DEFINE) 123 | { 124 | VALIDATE_NOT_VALUES 125 | driver_accumulator_set(app, driver_memory_data_get(app, address)); 126 | } 127 | 128 | /** 129 | * invert values inner AUX & Memory 130 | */ 131 | void cpu_memory_aux_spin(PARAMS_DEFINE) 132 | { 133 | VALIDATE_NOT_VALUES 134 | { 135 | data_3bc_t aux_old = AUX; 136 | driver_accumulator_set(app, driver_memory_data_get(app, address)); 137 | driver_memory_data_set(app, address, aux_old); 138 | } 139 | } -------------------------------------------------------------------------------- /src/interpreter_tokens.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the interpreter where slice row into columns. 12 | * 13 | * DATASTRUCT: 14 | * Linked list, first in, first out. 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | #if defined(TBC_INTERPRETER) && !defined(TBC_SCU_OPTIONAL_FIX) 42 | /** 43 | * Separator in columns and rows. 44 | * 45 | * REFERENCE: 'reg' receive the first column 46 | * REFERENCE: 'mem' receive the second column 47 | * REFERENCE: 'val' receive the thirdy column 48 | * REFERENCE: 'line_end' NULL if the string is used completely. 49 | * REFERENCE: 'line_end' Pointer to the rest of the text if there are still 50 | * other lines. RETURN: true if the number of columns is valid. RETURN: true if 51 | * the number of columns is valid. 52 | * 53 | */ 54 | bool interpreter_tokens( 55 | char* line, char** reg, char** mem, char** val, char** line_end) 56 | { 57 | unsigned char columns = 0; 58 | char* pointer = line; 59 | 60 | /** reset strings **/ 61 | *line_end = NULL; 62 | *reg = NULL; 63 | *mem = NULL; 64 | *val = NULL; 65 | 66 | do { 67 | /** search for the beginning of the column **/ 68 | while (strchr("\t. ", *pointer) != NULL && pointer[0] != '\0') { 69 | ++pointer; 70 | } 71 | 72 | /** skip comments **/ 73 | if (strchr("#;", *pointer) != NULL) { 74 | while ( 75 | pointer[0] != '\n' && pointer[0] != '\0' && pointer[0] != EOF) { 76 | ++pointer; 77 | } 78 | 79 | break; 80 | } 81 | 82 | /** end of line **/ 83 | if ((pointer[0] == '\n' && pointer[1] == '\0') || pointer[0] == '\0') { 84 | break; 85 | } 86 | 87 | /** partial end of line **/ 88 | if (pointer[0] == '\n' || pointer[0] == ',') { 89 | pointer[0] = '\0'; 90 | *line_end = ++pointer; 91 | break; 92 | } 93 | 94 | /** insert columun **/ 95 | switch (++columns) { 96 | case 1: 97 | *reg = pointer; 98 | break; 99 | 100 | case 2: 101 | *mem = pointer; 102 | break; 103 | 104 | case 3: 105 | *val = pointer; 106 | break; 107 | } 108 | 109 | /** skip literal char **/ 110 | if (pointer[0] == '\'') { 111 | do { 112 | pointer++; 113 | if (pointer[0] == '\\') { 114 | pointer++; 115 | } 116 | } while (pointer[0] != '\'' && pointer[0] != '\0'); 117 | } 118 | 119 | /** skip other literals **/ 120 | while (strchr("\t,. ", *pointer) == NULL && pointer[0] != '\0') { 121 | ++pointer; 122 | } 123 | 124 | /** mark end of column **/ 125 | if (pointer[0] != '\0' && pointer[0] != ',') { 126 | pointer[0] = '\0'; 127 | pointer++; 128 | } 129 | } while (pointer[0] != '\0'); 130 | 131 | /** validate number of columns **/ 132 | return columns == 3 || columns == 0; 133 | } 134 | #endif 135 | -------------------------------------------------------------------------------- /src/interpreter_ticket.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the interpreter where accumulates buffer per machine cycle. 12 | * 13 | * DATASTRUCT: 14 | * Linked list, first in, first out. 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | #if !defined(TBC_SCU_OPTIONAL_FIX) 42 | /** 43 | * JOKE: rest in peace spaghetti code, I won't miss you. 44 | */ 45 | #if !defined(TBC_INTERPRETER) 46 | /** 47 | * When interpreter disabled, always returns end of file. 48 | */ 49 | int interpreter_ticket(struct app_3bc_s* const app) 50 | { 51 | return EOF; 52 | } 53 | #else 54 | /** 55 | * Default entry point to the interpreter, works asynchronously. 56 | * 57 | * RETURN: CR if does nothing. 58 | * RETURN: EOF if there is nothing else to read. 59 | * RETURN: 1 if the interpretation was successful. 60 | * TODO: refactor single point of return, no implicit outputs. 61 | */ 62 | int interpreter_ticket(struct app_3bc_s* const app) 63 | { 64 | int character = fgetc(app->tty_source.io.stream); 65 | 66 | #if defined(_3BC_NUTTX) 67 | if (app->tty_source.type == STREAM_TYPE_COMPUTER_STD) { 68 | driver_tty_output(app, app->tty_keylog, STRC, character); 69 | } 70 | #endif 71 | 72 | /** does nothing **/ 73 | if (character == '\r') { 74 | return '\r'; 75 | } 76 | 77 | /** end of file **/ 78 | if ((character == EOF || character == -1) 79 | && app->cache_l3.buffer.storage == NULL) { 80 | return EOF; 81 | } 82 | 83 | /** end of line **/ 84 | if (character == '\n' || character == '\0' || character == EOF) { 85 | 86 | /** mark end of string **/ 87 | { 88 | char* new_buffer = (char*)realloc(app->cache_l3.buffer.storage, 89 | sizeof(char) * (++app->cache_l3.buffer.size)); 90 | if (new_buffer == NULL) { 91 | driver_program_error(app, ERROR_OUT_OF_MEMORY); 92 | } else { 93 | app->cache_l3.buffer.storage = new_buffer; 94 | app->cache_l3.buffer.storage[app->cache_l3.buffer.size - 1] 95 | = '\0'; 96 | } 97 | } 98 | 99 | /** insert to vm **/ 100 | char* line = app->cache_l3.buffer.storage; 101 | do { 102 | app->program.last_line += 1; 103 | line = interpreter_readln(app, line); 104 | } while (line != NULL); 105 | 106 | /** reset buffer **/ 107 | { 108 | free(app->cache_l3.buffer.storage); 109 | app->cache_l3.buffer.storage = NULL; 110 | app->cache_l3.buffer.size = 0; 111 | } 112 | 113 | return 1; 114 | } 115 | 116 | /** expand the buffer **/ 117 | { 118 | char* new_buffer = (char*)realloc(app->cache_l3.buffer.storage, 119 | sizeof(char) * (++app->cache_l3.buffer.size)); 120 | 121 | if (new_buffer == NULL) { 122 | driver_program_error(app, ERROR_OUT_OF_MEMORY); 123 | } else { 124 | app->cache_l3.buffer.storage = new_buffer; 125 | app->cache_l3.buffer.storage[app->cache_l3.buffer.size - 1] 126 | = character; 127 | } 128 | } 129 | 130 | return 0; 131 | } 132 | #endif 133 | #endif 134 | -------------------------------------------------------------------------------- /src/driver_gpio.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to input and outputs of generic prouposes connecting pins. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | * 34 | * TODO: 35 | * Support raspberry pico 36 | * Support raspberry pi 37 | * Support microbit 38 | * Support ESP IDF 39 | */ 40 | 41 | #define TBC_SOURCE_ENTRY 42 | #include "3bc.h" 43 | 44 | void driver_gpio_setup( 45 | struct app_3bc_s* const app, memory_conf_t conf, address_3bc_t pin) 46 | { 47 | /** nothing use gpio´s pins */ 48 | if (conf == 0 49 | || (conf & (MEM_CONFIG_GPIO_SEND | MEM_CONFIG_GPIO_READ)) == 0) { 50 | return; 51 | } 52 | 53 | /** digital output **/ 54 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_SEND)) { 55 | #if defined(_3BC_ARDUINO) 56 | pinMode(pin, OUTPUT); 57 | #endif 58 | } 59 | /** digital input pull up **/ 60 | else if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_PULL | MEM_CONFIG_GPIO_READ)) { 61 | #if defined(_3BC_ARDUINO) 62 | pinMode(pin, INPUT_PULLUP); 63 | #endif 64 | } 65 | /** digitial input **/ 66 | else if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_READ)) { 67 | #if defined(_3BC_ARDUINO) 68 | pinMode(pin, INPUT); 69 | #endif 70 | } 71 | } 72 | 73 | void driver_gpio_output(struct app_3bc_s* const app, memory_conf_t conf, 74 | address_3bc_t pin, data_3bc_t data) 75 | { 76 | if (conf == 0) { 77 | return; 78 | } 79 | 80 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_SEND | MEM_CONFIG_GPIO_ANAL)) { 81 | #if defined(_3BC_ARDUINO) && defined(ESP32) 82 | driver_program_error(app, ERROR_UNSUPPORTED); 83 | #elif defined(_3BC_ARDUINO) 84 | analogWrite(pin, data); 85 | #endif 86 | } else if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_SEND)) { 87 | #if defined(_3BC_ARDUINO) 88 | digitalWrite(pin, data > 0); 89 | #endif 90 | } 91 | } 92 | 93 | data_3bc_t driver_gpio_input(struct app_3bc_s* const app, memory_conf_t conf, 94 | address_3bc_t pin, data_3bc_t default_data) 95 | { 96 | if (conf == 0) { 97 | return default_data; 98 | } 99 | 100 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_READ | MEM_CONFIG_GPIO_ANAL)) { 101 | #if defined(_3BC_ARDUINO) 102 | /** 103 | * analogicRead returng values between 0 and 1024 104 | * abstract precision to go from 0 to 255. 105 | */ 106 | return analogRead(pin) / 4; 107 | #else 108 | /** when gpio is not implemented **/ 109 | return 0; 110 | #endif 111 | } 112 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_READ)) { 113 | #if defined(_3BC_ARDUINO) 114 | return digitalRead(pin); 115 | #else 116 | /** when gpio is not implemented **/ 117 | return 0; 118 | #endif 119 | } 120 | 121 | return default_data; 122 | } 123 | 124 | /** 125 | * JOKE: 126 | * I hate to do two inline conditional branches (if), 127 | * it makes me feel like a bad code writer, 128 | * but this is for optimization purposes, 129 | * so I shouldn't be so dirty! 130 | * 131 | * NOTE: 132 | * this joke is very good, but this one is outdated, 133 | * I'll keep it because it's funny! 134 | * 135 | * CODE: 136 | * if (MEM_CONFIG_GPIO_SEND == (node->conf & MEM_CONFIG_GPIO_SEND)) { 137 | * if (MEM_CONFIG_GPIO_ANAL == (node->conf & MEM_CONFIG_GPIO_ANAL)) {} 138 | * else {} 139 | * ... 140 | * ... 141 | */ 142 | -------------------------------------------------------------------------------- /src/ds_program_fifo.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the program storage. 12 | * 13 | * DATASTRUCT: 14 | * Linked list, first in, first out. 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | /** 42 | * record program memory, 43 | * similar to writing a line on the punch card. 44 | */ 45 | void ds_program_fifo_line_add(struct app_3bc_s* const app, register_3bc_t reg, 46 | address_3bc_t mem, data_3bc_t val) 47 | { 48 | /** register point label for jumps logical **/ 49 | if (reg == NILL && mem == NILL && val != NILL) { 50 | ds_label_hash_insert(app, val); 51 | return; 52 | } 53 | 54 | /** remember last cpu change interpreted **/ 55 | if (reg == MODE) { 56 | app->program.last_cpu = val; 57 | } 58 | 59 | /** register program bytecode **/ 60 | ds_program_fifo_resize(app); 61 | app->program.tail->column.reg = reg; 62 | app->program.tail->column.adr = mem; 63 | app->program.tail->column.dta = val; 64 | } 65 | 66 | /** 67 | * Expand program memory, 68 | * provide more punch card lines. 69 | */ 70 | void ds_program_fifo_resize(struct app_3bc_s* const app) 71 | { 72 | struct line_node_s* prev_line_node = app->program.tail; 73 | struct line_node_s* new_line_node 74 | = (struct line_node_s*)malloc(sizeof(struct line_node_s)); 75 | 76 | /** was not possible expand program **/ 77 | if (new_line_node == NULL) { 78 | driver_program_error(app, ERROR_OUT_OF_MEMORY); 79 | } 80 | 81 | /** first line program **/ 82 | if (app->program.head == NULL) { 83 | app->program.head = new_line_node; 84 | } 85 | 86 | /** current line program **/ 87 | if (app->program.curr == NULL) { 88 | app->program.curr = new_line_node; 89 | } 90 | 91 | /** link line program **/ 92 | if (prev_line_node != NULL) { 93 | prev_line_node->next = new_line_node; 94 | } 95 | 96 | /** last line program **/ 97 | app->program.tail = new_line_node; 98 | app->program.tail->next = NULL; 99 | app->program.tail->line = app->program.last_line; 100 | } 101 | 102 | /** 103 | * eject punch card program 104 | */ 105 | void ds_program_fifo_destroy(struct app_3bc_s* const app) 106 | { 107 | struct line_node_s* node = app->program.head; 108 | struct line_node_s* prev; 109 | while (node != NULL) { 110 | prev = node; 111 | node = node->next; 112 | free(prev); 113 | } 114 | } 115 | 116 | /** 117 | * check if there is tape program available 118 | */ 119 | bool ds_program_fifo_avaliable(struct app_3bc_s* const app) 120 | { 121 | /** waits for a label **/ 122 | if (app->program.label_target != NILL) { 123 | struct label_node_s* label_node 124 | = ds_label_hash_search(app, app->program.label_target); 125 | 126 | /** cooming label **/ 127 | if (label_node == NULL) { 128 | return false; 129 | } 130 | 131 | /** cooming next step after jump **/ 132 | if (label_node->point->next == NULL) { 133 | return false; 134 | } 135 | 136 | /** jump to point **/ 137 | driver_mode_set(app, label_node->cpumode); 138 | app->program.curr = label_node->point->next; 139 | app->program.label_target = NILL; 140 | return true; 141 | } 142 | 143 | /** end of program **/ 144 | return app->program.curr != NULL; 145 | } 146 | -------------------------------------------------------------------------------- /src/driver_power.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers startup, shutdown and system signals 12 | * received by virtual machines. 13 | * 14 | * BRIEF: 15 | * Low-level language, tiny virtual machine, intermediate representation, 16 | * embeddable, easy for beginners. (Friendly Punched cards) 17 | * 18 | * AUTHOR: 19 | * Copyright (C) 2020 Rodrigo Dornelles. 20 | * 21 | * LICENSE: 22 | * This program is free software: you can redistribute it and/or modify 23 | * it under the terms of the GNU General Public License as published by 24 | * the Free Software Foundation, either version 3 of the License, 25 | * or any later version. 26 | * 27 | * This program is distributed in the hope that it will be useful, 28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | * GNU General Public License for more details. 31 | * 32 | * You should have received a copy of the GNU General Public License 33 | * along with this program. If not, see . 34 | */ 35 | 36 | #define TBC_SOURCE_ENTRY 37 | #include "3bc.h" 38 | 39 | /** 40 | * MACRO: lang_3bc_init 41 | */ 42 | #if !defined(TBC_NOT_ARGCV) 43 | struct app_3bc_s* const driver_power_init(int argc, char** argv) 44 | #else 45 | struct app_3bc_s* const driver_power_init() 46 | #endif 47 | { 48 | struct app_3bc_s* const app = ds_hypervisor_darray_new(); 49 | 50 | #if defined(TBC_P_COMPUTER) 51 | /** TODO: move to driver_tty_init() **/ 52 | app->tty_source.type = STREAM_TYPE_COMPUTER_STD; 53 | app->tty_source.io.file = stdin; 54 | app->tty_debug.type = STREAM_TYPE_COMPUTER_STD; 55 | app->tty_debug.io.stream = stderr; 56 | app->tty_output.type = STREAM_TYPE_COMPUTER_STD; 57 | app->tty_output.io.stream = stdout; 58 | app->tty_keylog.type = STREAM_TYPE_CLONE_TTY; 59 | app->tty_keylog.io.tty = &app->tty_output; 60 | app->tty_error.type = STREAM_TYPE_COMPUTER_STD; 61 | app->tty_error.io.stream = stderr; 62 | #endif 63 | 64 | driver_tty_init(); 65 | 66 | #if defined(TBC_P_COMPUTER) 67 | /** 68 | * Capture computer signals 69 | */ 70 | #if defined(SIGINT) 71 | signal(SIGINT, driver_power_signal); 72 | #endif 73 | 74 | #if defined(SIGSEGV) 75 | signal(SIGSEGV, driver_power_signal); 76 | #endif 77 | #if !defined(TBC_NOT_ARGCV) && !defined(TBC_NOT_FILES) 78 | if (argc > 1) { 79 | app->tty_source.type = STREAM_TYPE_COMPUTER_FILE; 80 | app->tty_source.io.file = fopen(argv[argc - 1], "r"); 81 | } 82 | 83 | /** file not found | forbidden **/ 84 | if (app->tty_source.type == STREAM_TYPE_COMPUTER_FILE 85 | && app->tty_source.io.file == NULL) { 86 | driver_program_error(app, ERROR_OPEN_FILE); 87 | } 88 | #endif 89 | #endif 90 | 91 | return app; 92 | } 93 | 94 | /** 95 | * JOKE: 96 | * 97 | * The Hypervisor is crazy!! 98 | * anything dangerous, everything is down!! 99 | */ 100 | void driver_power_signal(int sig) 101 | { 102 | struct app_3bc_s** apps = ds_hypervisor_darray_get_all(); 103 | 104 | /** 105 | * JOKE: 106 | * 107 | * Finally, C ANSI FOREACH!!!! 108 | */ 109 | while (*apps) { 110 | switch (sig) { 111 | case SIGTERM: 112 | driver_power_exit(*apps); 113 | break; 114 | 115 | #if defined(SIGINT) 116 | case SIGINT: 117 | driver_power_exit(*apps); 118 | break; 119 | #endif 120 | 121 | #if defined(SIGSEGV) 122 | case SIGSEGV: 123 | driver_program_error(*apps, (enum error_3bc_e)sig); 124 | break; 125 | #endif 126 | } 127 | ++apps; 128 | } 129 | 130 | ds_hypervisor_darray_kill_all(); 131 | #if defined(SIGINT) 132 | exit(sig); 133 | #endif 134 | } 135 | 136 | void driver_power_exit(struct app_3bc_s* const app) 137 | { 138 | if (app->state != FSM_3BC_STOPED) { 139 | /** TODO: move driver_tty_exit **/ 140 | #if !defined(TBC_NOT_FILES) 141 | if (app->tty_source.type == STREAM_TYPE_COMPUTER_FILE 142 | && app->tty_source.io.file != NULL) { 143 | fclose(app->tty_source.io.file); 144 | } 145 | #endif 146 | /** deallocate occupied memory **/ 147 | ds_memory_llrbt_destroy(app); 148 | ds_program_fifo_destroy(app); 149 | 150 | driver_tty_exit(); 151 | app->state = FSM_3BC_STOPED; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/3bc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Library entry point. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #ifndef _LANG_3BC_H 36 | #define _LANG_3BC_H 37 | 38 | /** library info **/ 39 | #define VERSION_3BC "0.1.4" 40 | #define VERSION_3BC_MAJOR 0 41 | #define VERSION_3BC_MINOR 1 42 | #define VERSION_3BC_PATCH 4 43 | 44 | /** environment check **/ 45 | #include "3bc_detect.h" 46 | 47 | /** prepare **/ 48 | #include "3bc_macros.h" 49 | 50 | /** 51 | * ___ ______ _____ 52 | * / _ \ | ___ \_ _| 53 | * / /_\ \| |_/ / | | 54 | * | _ || ___ \ | | 55 | * | | | || |_/ /_| |_ 56 | * \_| |_/\____/ \___/ 57 | * 58 | * BRIEF: The Application binary interface helps 59 | * to integrate virtual machine drivers with host system modules. 60 | */ 61 | #if !defined(TBC_NOT_MATH) 62 | #include 63 | #endif 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #if defined(TBC_P_COMPUTER) 73 | #include 74 | #include 75 | #endif 76 | #if defined(TBC_USE_POSIX) 77 | #include 78 | #endif 79 | #if defined(TBC_USE_CONIO) 80 | #include 81 | #endif 82 | #if defined(TBC_USE_ARDUINO) 83 | #include 84 | #endif 85 | #if defined(TBC_KERNEL_NUTTX) 86 | #include 87 | #endif 88 | 89 | /** TODO: move to supporting file **/ 90 | #ifndef SIGTERM 91 | #define SIGTERM (15) 92 | #endif 93 | 94 | /** 95 | * _ _ _ 96 | * | | | | | | 97 | * | |_| | ___ __ _ __| | ___ _ __ ___ 98 | * | _ |/ _ \/ _` |/ _` |/ _ \ '__/ __| 99 | * | | | | __/ (_| | (_| | __/ | \__ \ 100 | * \_| |_/\___|\__,_|\__,_|\___|_| |___/ 101 | */ 102 | 103 | /** consts and types **/ 104 | #include "3bc_errors.h" 105 | #include "3bc_types.h" 106 | 107 | /** functions prototypes **/ 108 | #include "3bc_header.h" 109 | 110 | /* opcodes and witchcraft **/ 111 | #include "3bc_register.h" 112 | 113 | /** 114 | * _____ _____ _ 115 | * / ___| / __ \ | | 116 | * \ `--. ___ _ _ _ __ ___ ___ | / \/ ___ __| | ___ 117 | * `--. \/ _ \| | | | '__/ __/ _ \ | | / _ \ / _` |/ _ \ 118 | * /\__/ / (_) | |_| | | | (_| __/ | \__/\ (_) | (_| | __/ 119 | * \____/ \___/ \__,_|_| \___\___| \____/\___/ \__,_|\___| 120 | */ 121 | 122 | /** default source **/ 123 | #if !defined(TBC_SCU) 124 | #include "cpu_boolean.c" 125 | #include "cpu_common.c" 126 | #include "cpu_jump.c" 127 | #include "cpu_math.c" 128 | #include "cpu_memory.c" 129 | #include "cpu_procedure.c" 130 | #include "cpu_sleep.c" 131 | #include "cpu_string.c" 132 | #include "driver_accumulator.c" 133 | #include "driver_custom.c" 134 | #include "driver_gpio.c" 135 | #include "driver_idle.c" 136 | #include "driver_interrupt.c" 137 | #include "driver_memory.c" 138 | #include "driver_mode.c" 139 | #include "driver_power.c" 140 | #include "driver_program.c" 141 | #include "driver_tty.c" 142 | #include "ds_hypervisor_darray.c" 143 | #include "ds_label_hash.c" 144 | #include "ds_memory_llrbt.c" 145 | #include "ds_procedure_lifo.c" 146 | #include "ds_program_fifo.c" 147 | #include "interpreter_parser.c" 148 | #include "interpreter_readln.c" 149 | #include "interpreter_syntax.c" 150 | #include "interpreter_ticket.c" 151 | #include "interpreter_tokens.c" 152 | #endif 153 | /** customizable source **/ 154 | #if defined(TBC_SCU_FORCE) 155 | #include "driver_custom.c" 156 | #include "interpreter_ticket.c" 157 | #endif 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /src/driver_memory.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers main memory access. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void driver_memory_data_set( 39 | struct app_3bc_s* const app, address_3bc_t address, data_3bc_t value) 40 | { 41 | memory_conf_t conf = app->memory.conf_get(app->id, address); 42 | 43 | driver_gpio_output(app, conf, address, value); 44 | 45 | app->memory.data_set(app->id, address, value); 46 | } 47 | 48 | void driver_memory_conf_set( 49 | struct app_3bc_s* const app, address_3bc_t address, data_3bc_t conf) 50 | { 51 | data_3bc_t value = app->memory.data_get(app->id, address); 52 | 53 | driver_memory_validate(app, conf); 54 | driver_gpio_setup(app, conf, address); 55 | driver_gpio_output(app, conf, address, value); 56 | value = driver_gpio_input(app, conf, address, value); 57 | 58 | app->memory.conf_set(app->id, address, conf); 59 | app->memory.data_set(app->id, address, value); 60 | } 61 | 62 | data_3bc_t driver_memory_data_get( 63 | struct app_3bc_s* const app, address_3bc_t address) 64 | { 65 | data_3bc_t value = app->memory.data_get(app->id, address); 66 | memory_conf_t conf = app->memory.conf_get(app->id, address); 67 | 68 | /** read gpios if necessary **/ 69 | value = driver_gpio_input(app, conf, address, value); 70 | 71 | return value; 72 | } 73 | 74 | data_3bc_t driver_memory_conf_get( 75 | struct app_3bc_s* const app, address_3bc_t address) 76 | { 77 | return app->memory.conf_get(app->id, address); 78 | } 79 | 80 | /** 81 | * MACRO: POINTER 82 | */ 83 | address_3bc_t driver_memory_pointer( 84 | struct app_3bc_s* const app, address_3bc_t address) 85 | { 86 | data_3bc_t ptr = driver_memory_data_get(app, address); 87 | 88 | /** 89 | * JOKE: 90 | * 91 | * JAVA PROGRAMMER BE LIKE 92 | * omg i'm scared with null pointer! 93 | */ 94 | if (ptr == NILL) { 95 | /** also apply to microsoft java devs (aka C#) */ 96 | driver_program_error(app, ERROR_NULL_POINTER); 97 | } else if (ptr < 0) { 98 | driver_program_error(app, ERROR_NUMBER_NEGATIVE); 99 | } 100 | 101 | return (address_3bc_t)ptr; 102 | } 103 | 104 | void driver_memory_validate(struct app_3bc_s* const app, memory_conf_t conf) 105 | { 106 | /** optimize **/ 107 | if (conf == 0) { 108 | return; 109 | } 110 | /** not allow pullup and analogic some times **/ 111 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_ANAL | MEM_CONFIG_GPIO_PULL)) { 112 | driver_program_error(app, ERROR_MEMORY_CONFIG); 113 | } 114 | /** not allow pullup and output some times **/ 115 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_SEND | MEM_CONFIG_GPIO_PULL)) { 116 | driver_program_error(app, ERROR_MEMORY_CONFIG); 117 | } 118 | /** not allow input and output some times **/ 119 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_SEND | MEM_CONFIG_GPIO_READ)) { 120 | driver_program_error(app, ERROR_MEMORY_CONFIG); 121 | } 122 | /** analogic required input or output **/ 123 | if (BITFIELD_HAS(conf, MEM_CONFIG_GPIO_ANAL) 124 | && !(BITFIELD_HAS(conf, MEM_CONFIG_GPIO_READ) 125 | || BITFIELD_HAS(conf, MEM_CONFIG_GPIO_SEND))) { 126 | driver_program_error(app, ERROR_MEMORY_CONFIG); 127 | } 128 | } 129 | 130 | void driver_memory_free(struct app_3bc_s* const app, address_3bc_t address) 131 | { 132 | /** clear cache level 0 **/ 133 | if (app->memory.cache != NULL && app->memory.cache->address == address) { 134 | app->memory.cache = NULL; 135 | } 136 | 137 | /** clear memory node **/ 138 | /** TODO: move to ds_memory_llrbt **/ 139 | app->memory.root = ds_memory_llrbt_clear(address, app->memory.root); 140 | } -------------------------------------------------------------------------------- /src/cpu_math.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers registers for the arithmetic logic unit. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #include "3bc.h" 37 | 38 | void cpu_math_sum(PARAMS_DEFINE) 39 | { 40 | VALIDATE_NOT_DUALITY 41 | driver_accumulator_set(app, AUX + GET_ANY_PARAM); 42 | } 43 | 44 | void cpu_math_sub(PARAMS_DEFINE) 45 | { 46 | VALIDATE_NOT_DUALITY 47 | driver_accumulator_set(app, AUX - GET_ANY_PARAM); 48 | } 49 | 50 | void cpu_math_mul(PARAMS_DEFINE) 51 | { 52 | VALIDATE_NOT_DUALITY 53 | driver_accumulator_set(app, AUX * GET_ANY_PARAM); 54 | } 55 | 56 | void cpu_math_div(PARAMS_DEFINE) 57 | { 58 | VALIDATE_NOT_DUALITY 59 | { 60 | data_3bc_t divisor = GET_ANY_PARAM; 61 | if (divisor == 0) { 62 | driver_program_error(app, ERROR_NUMBER_ZERO); 63 | } else { 64 | driver_accumulator_set(app, AUX / divisor); 65 | } 66 | } 67 | } 68 | 69 | void cpu_math_mod(PARAMS_DEFINE) 70 | { 71 | VALIDATE_NOT_DUALITY 72 | driver_accumulator_set(app, AUX % GET_ANY_PARAM); 73 | } 74 | 75 | void cpu_math_power(PARAMS_DEFINE) 76 | { 77 | VALIDATE_NOT_DUALITY 78 | #if defined(TBC_NOT_MATH) 79 | driver_program_error(app, ERROR_UNSUPPORTED); 80 | #else 81 | /** TODO: remove this "gambiarra" tecnical debt **/ 82 | driver_accumulator_set(app, 83 | (data_aux_3bc_t)trunc(pow((double)(AUX), (double)(GET_ANY_PARAM)))); 84 | #endif 85 | } 86 | 87 | void cpu_math_root(PARAMS_DEFINE) 88 | { 89 | VALIDATE_NOT_DUALITY 90 | #if defined(TBC_NOT_MATH) 91 | driver_program_error(app, ERROR_UNSUPPORTED); 92 | #else 93 | driver_accumulator_set(app, 94 | 95 | (data_aux_3bc_t)trunc( 96 | pow((double)(AUX), (1 / (double)(GET_ANY_PARAM))))); 97 | #endif 98 | } 99 | 100 | void cpu_math_abs(PARAMS_DEFINE) 101 | { 102 | VALIDATE_NOT_ADRESS 103 | VALIDATE_NOT_VALUES 104 | driver_accumulator_set(app, labs(AUX)); 105 | } 106 | 107 | /** 108 | * logarithm with base 109 | */ 110 | void cpu_math_logb(PARAMS_DEFINE) 111 | { 112 | VALIDATE_NOT_DUALITY 113 | REQUIRED_ANY 114 | if (AUX == 0) { 115 | driver_program_error(app, ERROR_NUMBER_ZERO); 116 | } else { 117 | int base = GET_ANY_PARAM; 118 | switch (base) { 119 | #if !defined(TBC_NOT_LOG2) 120 | case 2: 121 | driver_accumulator_set( 122 | app, (data_aux_3bc_t)trunc(log2((double)AUX))); 123 | break; 124 | #endif 125 | 126 | #if !defined(TBC_NOT_LOG10) 127 | case 10: 128 | driver_accumulator_set( 129 | app, (data_aux_3bc_t)trunc(log10((double)AUX))); 130 | break; 131 | #endif 132 | 133 | #if defined(TBC_NOT_LOG) 134 | default: 135 | driver_program_error(app, ERROR_UNSUPPORTED); 136 | #else 137 | default: 138 | driver_accumulator_set(app, 139 | (data_aux_3bc_t)trunc(log((double)AUX) / log((double)base))); 140 | break; 141 | #endif 142 | } 143 | } 144 | } 145 | 146 | /** 147 | * logarithm natural 148 | */ 149 | void cpu_math_logn(PARAMS_DEFINE) 150 | { 151 | VALIDATE_NOT_ADRESS 152 | VALIDATE_NOT_VALUES 153 | #if defined(TBC_NOT_MATH) 154 | /** TODO: support logarithm on 6502 **/ 155 | driver_program_error(app, ERROR_UNSUPPORTED); 156 | #else 157 | if (AUX == 0) { 158 | driver_program_error(app, ERROR_NUMBER_ZERO); 159 | } 160 | 161 | driver_accumulator_set(app, (data_aux_3bc_t)trunc(log((double)AUX))); 162 | #endif 163 | } 164 | 165 | void cpu_math_mul_add(PARAMS_DEFINE) 166 | { 167 | VALIDATE_NOT_DUALITY 168 | { 169 | char base = 0; 170 | 171 | if (reg == NB02) { 172 | base = 2; 173 | } else if (reg == NB08) { 174 | base = 8; 175 | } else if (reg == NB10) { 176 | base = 10; 177 | } else if (reg == NB16) { 178 | base = 16; 179 | } 180 | 181 | driver_accumulator_set(app, (AUX * base) + GET_ANY_PARAM); 182 | } 183 | } -------------------------------------------------------------------------------- /.github/workflows/automatic-publish.yaml: -------------------------------------------------------------------------------- 1 | name: Automatic publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*.*.*" 7 | 8 | jobs: 9 | desktop: 10 | runs-on: macos-latest 11 | env: 12 | CC_LD: "./zig cc" 13 | TARGETS: >- 14 | i386-linux-gnu x86_64-linux-gnu arm-linux-musleabi aarch64-linux-gnu powerpc-linux-musl 15 | powerpc64-linux-musl riscv64-linux-musl mips-linux-musl x86_64-macos aarch64-macos 16 | i386-windows x86_64-windows aarch64-windows 17 | 18 | steps: 19 | - name: Checkout project 20 | uses: actions/checkout@v3 21 | 22 | - name: Checkout zig lang 23 | run: >- 24 | wget -qO- https://ziglang.org/download/0.9.1/zig-macos-x86_64-0.9.1.tar.xz | 25 | tar xvz --strip-components 1 26 | 27 | - name: Building interpreter's binaries 28 | run: ./scripts/cc_interpreter.rb 29 | 30 | - name: Building dynamic libaries 31 | run: ./scripts/cc_dynamiclib.rb 32 | 33 | - name: General report 34 | run: tail -n +1 *.log 35 | 36 | - name: Upload binaries and libaries to github (tarballs) 37 | uses: softprops/action-gh-release@v1 38 | with: 39 | files: "*.tar.gz" 40 | 41 | - name: Upload binaries and libaries to github (zippies) 42 | uses: softprops/action-gh-release@v1 43 | with: 44 | files: "*.zip" 45 | 46 | docker: 47 | runs-on: ubuntu-latest 48 | steps: 49 | - name: Checkout project 50 | uses: actions/checkout@v3 51 | 52 | - name: Set up QEMU 53 | uses: docker/setup-qemu-action@v2 54 | 55 | - name: Set up Docker Buildx 56 | uses: docker/setup-buildx-action@v2 57 | 58 | - name: Login to DockerHub 59 | uses: docker/login-action@v2 60 | with: 61 | username: rodrigodornelles 62 | password: ${{ secrets.DOCKERHUB_TOKEN }} 63 | 64 | - name: Build and push 65 | uses: docker/build-push-action@v3 66 | with: 67 | context: . 68 | push: true 69 | tags: rodrigodornelles/3bc-lang:${{github.ref_name}},rodrigodornelles/3bc-lang:latest 70 | platforms: > 71 | linux/386,linux/amd64,linux/arm/v5,linux/arm/v7,linux/arm64/v8, 72 | linux/mips64le,linux/ppc64le,linux/s390x 73 | 74 | freebsd: 75 | if: false 76 | runs-on: macos-10.15 77 | steps: 78 | - name: Checkout project 79 | uses: actions/checkout@v2 80 | 81 | - name: Building x86 32/64bits project 82 | uses: vmactions/freebsd-vm@v0.1.5 83 | with: 84 | usesh: true 85 | run: | 86 | mkdir 32bits 64bits 87 | clang programs/interpreter.c -m32 -Os -lm -o ./32bits/3bc 88 | clang programs/interpreter.c -m64 -Os -lm -o ./64bits/3bc 89 | strip ./32bits/3bc 90 | strip ./64bits/3bc 91 | 92 | - name: Packaging project 93 | run: | 94 | tar -czf bsd-i386-interpreter-3bc.tar.gz ./32bits/3bc 95 | tar -czf bsd-x86_64-interpreter-3bc.tar.gz ./64bits/3bc 96 | 97 | 98 | - name: Upload binaries to github 99 | uses: softprops/action-gh-release@v1 100 | with: 101 | files: | 102 | *.tar.gz 103 | 104 | emscripten: 105 | runs-on: ubuntu-latest 106 | container: emscripten/emsdk 107 | steps: 108 | - name: Checkout project 109 | uses: actions/checkout@v2 110 | 111 | - name: Checkout libaries 112 | run: sudo apt search zip; sudo apt install -y zip 113 | 114 | - name: Prepare project folders 115 | run: mkdir bin glue full 116 | 117 | - name: Build webassembly binary 118 | run: emcc programs/interpreter.c -lm -Os -s WASM=1 -o bin/vm.wasm 119 | 120 | - name: Build full javascript app 121 | run: emcc programs/interpreter.c -lm -O0 -s WASM=0 -s MODULARIZE=0 -s EXIT_RUNTIME=1 -s FORCE_FILESYSTEM=1 -s WASM_ASYNC_COMPILATION=0 -o full/app.js 122 | 123 | - name: Build full javascript module 124 | run: emcc programs/interpreter.c -lm -O0 -s WASM=0 -s MODULARIZE=1 -s EXIT_RUNTIME=1 -s EXPORT_ES6=1 -s FORCE_FILESYSTEM=1 -s WASM_ASYNC_COMPILATION=0 -o full/module.js 125 | 126 | - name: Made javascript glue app 127 | run: emcc programs/interpreter.c -lm -O0 -s WASM=1 -s MODULARIZE=0 -s EXIT_RUNTIME=1 -s FORCE_FILESYSTEM=1 -s WASM_ASYNC_COMPILATION=0 -o glue/app.js 128 | 129 | - name: Made javascript glue module 130 | run: emcc programs/interpreter.c -lm -O0 -s WASM=1 -s MODULARIZE=1 -s EXIT_RUNTIME=1 -s EXPORT_ES6=1 -s FORCE_FILESYSTEM=1 -s WASM_ASYNC_COMPILATION=0 -o glue/module.js 131 | 132 | - name: Made links with binary 133 | run: | 134 | sed -i 's/module.wasm/..\/bin\/vm.wasm/' ./*/module.js 135 | sed -i 's/app.wasm/..\/bin\/vm.wasm/' ./*/app.js 136 | - uses: actions/setup-node@v2 137 | with: 138 | node-version: '16.x' 139 | registry-url: 'https://registry.npmjs.org' 140 | 141 | - name: Publish project 142 | run: npm publish 143 | env: 144 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 145 | 146 | - name: Packaging project 147 | run: | 148 | mkdir npm 149 | mv bin npm 150 | mv glue npm 151 | mv full npm 152 | tar -czf 3bc-web-emscripten.tar.gz ./npm/* 153 | zip -r 3bc-web-emscripten.zip ./npm/* 154 | 155 | - name: Upload binaries to github 156 | uses: softprops/action-gh-release@v1 157 | with: 158 | files: "*.tar.gz" 159 | -------------------------------------------------------------------------------- /src/driver_program.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the counter program executor and error handler. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | */ 34 | 35 | #define TBC_SOURCE_ENTRY 36 | #define TBC_SOURCE_REGISTERS 37 | #include "3bc.h" 38 | 39 | /** 40 | * header used before error description. 41 | * 42 | * TODO: 43 | * more readable and move to 3bc_errors.h 44 | * 45 | * NOTE: 46 | * the size of the ID depends on the architecture. 47 | * 48 | * NOTE: 49 | * there is _3BC_COMPACT which makes information simpler (takes up less space). 50 | * 51 | */ 52 | #if defined(TBC_OPT_COMPACT) 53 | static const char error_header[] 54 | = "\n\n[3BC] %3d Fatal error 0x%06X in line: %06u\n"; 55 | #else 56 | static const char error_header[] 57 | = "\n[3BC] CRITICAL ERROR ABORTED THE PROGRAM\n> MACHINE ID:\t" 58 | #if defined(TBC_ID_64_BITS) || defined(TBC_ID_32_BITS) 59 | "%08lu" 60 | #elif defined(TBC_ID_16_BITS) || defined(TBC_ID_8_BITS) 61 | "%08u" 62 | #endif 63 | "\n> ERROR LINE:\t%08u\n> ERROR CODE:\t0x%06X\n> DESCRIPTION: "; 64 | #endif 65 | 66 | void driver_program_error( 67 | struct app_3bc_s* const app, enum error_3bc_e error_code) 68 | { 69 | /** 70 | * NOTE: if the current line does not exist, 71 | * it was because it was interpreting a line which failed. 72 | * 73 | * TODO: 74 | * safer and remove ternaries. 75 | */ 76 | line_3bc_t error_line 77 | = app->program.curr != NULL && error_code >= ERROR_CPU_ZERO 78 | ? app->program.curr->line 79 | : app->program.last_line; 80 | 81 | /** print header of error**/ 82 | char error_code_string[sizeof(error_header) + 11]; 83 | snprintf(error_code_string, sizeof(error_header), error_header, app->id, 84 | error_line, error_code); 85 | driver_tty_output_raw(app, app->tty_error, error_code_string); 86 | 87 | /** TODO: not use macros and move to 3bc_errors.h **/ 88 | #if !defined(TBC_OPT_COMPACT) 89 | switch ((long)(error_code)) { 90 | #if defined(SIGSEGV) 91 | ERROR_LOG_3BC(SIGSEGV, "SEGMENT FAULT"); 92 | #endif 93 | ERROR_LOG_3BC(ERROR_CPU_ZERO, "CPU MODE IS NOT DEFINED"); 94 | ERROR_LOG_3BC(ERROR_CPU_RESERVED, "CPU MODE IS RESERVED"); 95 | ERROR_LOG_3BC(ERROR_INVALID_REGISTER, "INVALID CPU REGISTER"); 96 | ERROR_LOG_3BC(ERROR_INVALID_ADDRESS, "INVALID ADDRESS"); 97 | ERROR_LOG_3BC(ERROR_INVALID_CONSTANT, "INVALID CONSTANT"); 98 | ERROR_LOG_3BC(ERROR_INVALID_CPU_MODE, "INVALID CPU MODE"); 99 | ERROR_LOG_3BC(ERROR_INVALID_LABEL, "INVALID LABEL"); 100 | ERROR_LOG_3BC(ERROR_INVALID_RETURN, "INVALID PROCEDURE RETURN"); 101 | ERROR_LOG_3BC( 102 | ERROR_PARAM_DUALITY, "DUALITY ADDRES WITH VALUE IS NOT ALLOWED"); 103 | ERROR_LOG_3BC(ERROR_PARAM_REQUIRE_ANY, "VALUE OR ADDRESS IS REQUIRED"); 104 | ERROR_LOG_3BC(ERROR_PARAM_REQUIRE_VALUE, "VALUE IS REQUIRED"); 105 | ERROR_LOG_3BC(ERROR_PARAM_REQUIRE_ADDRESS, "ADDRESS IS REQUIRED"); 106 | ERROR_LOG_3BC(ERROR_PARAM_BLOCKED_VALUE, "VALUE IS NOT ALLOWED"); 107 | ERROR_LOG_3BC(ERROR_PARAM_BLOCKED_ADDRESS, "ADDRESS IS NOT ALLOWED"); 108 | ERROR_LOG_3BC(ERROR_NUMBER_NO_DIGITS, "NUMBER WHIOUT DIGITS"); 109 | ERROR_LOG_3BC(ERROR_NUMBER_UNDERFLOW, "NUMBER UNDERFLOW"); 110 | ERROR_LOG_3BC(ERROR_NUMBER_OVERFLOW, "NUMBER OVERFLOW"); 111 | ERROR_LOG_3BC(ERROR_NUMBER_WRONG_BASE, "NUMBER WRONG BASE"); 112 | ERROR_LOG_3BC(ERROR_NUMBER_NEGATIVE, "NUMBER NEGATIVE IS NOT EXPECTED"); 113 | ERROR_LOG_3BC(ERROR_NUMBER_ZERO, "NUMBER ZERO IS NOT EXPECTED"); 114 | ERROR_LOG_3BC(ERROR_OUT_OF_MEMORY, "OUT OF MEMORY"); 115 | ERROR_LOG_3BC(ERROR_NONE_TTY, "NONE TTY"); 116 | ERROR_LOG_3BC(ERROR_UNSUPPORTED, "UNSUPPORTED FEATURE"); 117 | ERROR_LOG_3BC(ERROR_MEMORY_CONFIG, "MEMORY CONFIG"); 118 | ERROR_LOG_3BC(ERROR_OPEN_FILE, "CANNOT OPEN FILE"); 119 | ERROR_LOG_3BC(ERROR_NULL_POINTER, "NULL POINTER"); 120 | ERROR_LOG_3BC(ERROR_CHAR_SCAPE, "INVALID CHARACTER ESCAPE"); 121 | ERROR_LOG_3BC(ERROR_CHAR_SIZE, "INVALID CHARACTER SIZE"); 122 | ERROR_LOG_3BC(ERROR_COLUMNS, "WRONG NUMBER OF COLUMNS"); 123 | default: 124 | driver_tty_output_raw(app, app->tty_error, "UNKNOWN ERROR"); 125 | } 126 | 127 | driver_tty_output_raw(app, app->tty_error, "\n"); 128 | #endif 129 | 130 | /** TODO: no closign when else **/ 131 | if (error_code >= ERROR_CPU_ZERO) { 132 | driver_power_signal(SIGTERM); 133 | } 134 | } 135 | 136 | /** 137 | * run processor instructions, 138 | * this is a core of virtual machine 139 | */ 140 | void driver_program_tick(struct app_3bc_s* const app) 141 | { 142 | instruction_3bc(app, app->program.curr->column.reg, 143 | app->program.curr->column.adr, app->program.curr->column.dta); 144 | 145 | /** go next line **/ 146 | app->program.curr = app->program.curr->next; 147 | } -------------------------------------------------------------------------------- /src/interpreter_parser.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to the interpreter where it translates literals to data. 12 | * 13 | * DATASTRUCT: 14 | * Linked list, first in, first out. 15 | * 16 | * BRIEF: 17 | * Low-level language, tiny virtual machine, intermediate representation, 18 | * embeddable, easy for beginners. (Friendly Punched cards) 19 | * 20 | * AUTHOR: 21 | * Copyright (C) 2020 Rodrigo Dornelles. 22 | * 23 | * LICENSE: 24 | * This program is free software: you can redistribute it and/or modify 25 | * it under the terms of the GNU General Public License as published by 26 | * the Free Software Foundation, either version 3 of the License, 27 | * or any later version. 28 | * 29 | * This program is distributed in the hope that it will be useful, 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 | * GNU General Public License for more details. 33 | * 34 | * You should have received a copy of the GNU General Public License 35 | * along with this program. If not, see . 36 | */ 37 | 38 | #define TBC_SOURCE_ENTRY 39 | #include "3bc.h" 40 | 41 | #if defined(TBC_INTERPRETER) && !defined(TBC_SCU_OPTIONAL_FIX) 42 | /** 43 | * convert string in any numeric base 44 | */ 45 | bool interpreter_parser_strtol( 46 | struct app_3bc_s* const app, const char* string, signed long int* value) 47 | { 48 | char* endptr = NULL; 49 | char decode[32]; 50 | char type; 51 | 52 | /** verify valid number **/ 53 | if (string[0] != '-' && !isdigit(string[0])) { 54 | return false; 55 | } 56 | 57 | /** protect original string **/ 58 | strcpy(decode, string); 59 | 60 | /** custom base with sign **/ 61 | if (decode[0] == '-' && decode[1] == '0' && !isdigit(decode[2]) 62 | && decode[2] != '\0') { 63 | type = tolower(decode[2]); 64 | memmove(&decode[2], &decode[3], sizeof(decode) - 3); 65 | } 66 | /** custom base whiout sign **/ 67 | else if (decode[0] == '0' && !isdigit(decode[1]) && decode[1] != '\0') { 68 | type = tolower(decode[1]); 69 | memmove(&decode[1], &decode[2], sizeof(decode) - 2); 70 | } 71 | /** decimal base **/ 72 | else { 73 | type = 'd'; 74 | } 75 | 76 | /** reset error **/ 77 | errno = 0; 78 | 79 | /** convert string to number **/ 80 | switch (type) { 81 | case 'x': 82 | /** base hexadecimal **/ 83 | *value = strtol(decode, &endptr, 16); 84 | break; 85 | 86 | case 'i': 87 | case 'd': 88 | /** base decimal **/ 89 | *value = strtol(decode, &endptr, 10); 90 | break; 91 | 92 | case 'o': 93 | /** base octal **/ 94 | *value = strtol(decode, &endptr, 8); 95 | break; 96 | 97 | case 'b': 98 | /** base binary **/ 99 | *value = strtol(decode, &endptr, 2); 100 | break; 101 | 102 | default: 103 | /** base invalid **/ 104 | driver_program_error(app, ERROR_NUMBER_WRONG_BASE); 105 | } 106 | 107 | if (decode == endptr) { 108 | driver_program_error(app, ERROR_NUMBER_NO_DIGITS); 109 | } else if (errno == ERANGE && *value == LONG_MIN) { 110 | driver_program_error(app, ERROR_NUMBER_UNDERFLOW); 111 | } else if (errno == ERANGE && *value == LONG_MAX) { 112 | driver_program_error(app, ERROR_NUMBER_OVERFLOW); 113 | } 114 | #if defined(EINVAL) 115 | /** not in all c99 implementations **/ 116 | else if (errno == EINVAL) { 117 | driver_program_error(app, ERROR_NUMBER_WRONG_BASE); 118 | } 119 | #endif 120 | else if (errno != 0 && *value == 0) { 121 | driver_program_error(app, ERROR_NUMBER_WRONG_BASE); 122 | } else if (errno == 0 && *endptr != 0) { 123 | driver_program_error(app, ERROR_NUMBER_WRONG_BASE); 124 | } 125 | 126 | return true; 127 | } 128 | 129 | bool interpreter_parser_strchar( 130 | struct app_3bc_s* const app, const char* string, signed long int* value) 131 | { 132 | /** not init with (') **/ 133 | if (string[0] != 0x27) { 134 | return false; 135 | } 136 | 137 | /** not ends with (') **/ 138 | if (string[2] != 0x27 && string[3] != 0x27) { 139 | driver_program_error(app, ERROR_CHAR_SIZE); 140 | } 141 | 142 | /** single char **/ 143 | if (string[3] != 0x27) { 144 | *value = string[1]; 145 | return true; 146 | } 147 | 148 | /** not scape **/ 149 | if (string[1] != '\\') { 150 | driver_program_error(app, ERROR_CHAR_SIZE); 151 | } 152 | 153 | /** scape controll char **/ 154 | switch (string[2]) { 155 | case '0': 156 | *value = 0x00; 157 | break; 158 | case 'a': 159 | *value = 0x07; 160 | break; 161 | case 'b': 162 | *value = 0x08; 163 | break; 164 | case 't': 165 | *value = 0x09; 166 | break; 167 | case 'n': 168 | *value = 0x0A; 169 | break; 170 | case '\'': 171 | *value = 0x27; 172 | break; 173 | case '\\': 174 | *value = 0x5c; 175 | break; 176 | default: 177 | driver_program_error(app, ERROR_CHAR_SCAPE); 178 | } 179 | 180 | return true; 181 | } 182 | 183 | /** 184 | * Text Equivalent Hash Generator. 185 | */ 186 | bool interpreter_parser_strhash(const char* string, signed long int* value) 187 | { 188 | unsigned long hash = 5381; 189 | int c; 190 | 191 | /** is not hash **/ 192 | if (string[0] != ':') { 193 | return false; 194 | } 195 | 196 | /** djb2 algorithm **/ 197 | while ((c = *string)) { 198 | 199 | /** ignore break line **/ 200 | if (c == '\n') { 201 | continue; 202 | } 203 | 204 | /** (hash * 33) + c **/ 205 | hash = ((hash << 5) + hash) + c; 206 | ++string; 207 | } 208 | 209 | *value = hash % SHRT_MAX; 210 | 211 | return true; 212 | } 213 | 214 | /** 215 | * algorithm of djb2 hash to string "skip" + count every two calls 216 | */ 217 | int interpreter_parser_skip() 218 | { 219 | static int counter = 0; 220 | unsigned long hash = 15376; /* hash to skip */ 221 | int c = (counter++) / 2; /** count after 2 calls **/ 222 | 223 | do { 224 | hash = ((hash << 5) + hash) + (c % 10) + '0'; 225 | c /= 10; 226 | } while (c > 0); 227 | 228 | return hash % SHRT_MAX; 229 | } 230 | #endif 231 | -------------------------------------------------------------------------------- /tests/fasttest.fails.rb: -------------------------------------------------------------------------------- 1 | require 'open3' 2 | require 'minitest/spec' 3 | require 'minitest/autorun' 4 | 5 | class TestFails < Minitest::Test 6 | def test_cpu_zero 7 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "strc 0 0") 8 | assert_match /ERROR CODE\:(\t| )?(0x3BC000)/, stderr 9 | assert_equal 15, status.exitstatus 10 | end 11 | 12 | def test_cpu_reserved 13 | for cpu_mode in (20..40).step(10) 14 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 #{cpu_mode}\n1 0 0") 15 | assert_match /ERROR CODE\:(\t| )?(0x3BC001)/, stderr 16 | assert_equal 15, status.exitstatus 17 | end 18 | end 19 | 20 | def test_invalid_register 21 | for console_input in ["baaz 0 0", "7.0.11,2.0.0"] 22 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 23 | assert_match /ERROR CODE\:(\t| )?(0x3BC002)/, stderr 24 | assert_equal 15, status.exitstatus 25 | end 26 | end 27 | 28 | def test_invalid_address 29 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode e nill") 30 | assert_match /ERROR CODE\:(\t| )?(0x3BC003)/, stderr 31 | assert_equal 15, status.exitstatus 32 | end 33 | 34 | def test_invalid_constant 35 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode nill e") 36 | assert_match /ERROR CODE\:(\t| )?(0x3BC004)/, stderr 37 | assert_equal 15, status.exitstatus 38 | end 39 | 40 | def test_invalid_cpu_mode 41 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode nill full") 42 | assert_match /ERROR CODE\:(\t| )?(0x3BC005)/, stderr 43 | assert_equal 15, status.exitstatus 44 | end 45 | 46 | def test_invalid_label 47 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "nill nill 1\nnill nill 1") 48 | assert_match /ERROR CODE\:(\t| )?(0x3BC006)/, stderr 49 | assert_equal 15, status.exitstatus 50 | end 51 | 52 | def test_invalid_return 53 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.41,back.0.0") 54 | assert_match /ERROR CODE\:(\t| )?(0x3BC007)/, stderr 55 | assert_equal 15, status.exitstatus 56 | end 57 | 58 | def test_param_ambiguous 59 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 2\nstri 1 1") 60 | assert_match /ERROR CODE\:(\t| )?(0x3BC008)/, stderr 61 | assert_equal 15, status.exitstatus 62 | end 63 | 64 | def test_param_required_any 65 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.43,fake.0.0") 66 | assert_match /ERROR CODE\:(\t| )?(0x3BC009)/, stderr 67 | assert_equal 15, status.exitstatus 68 | end 69 | 70 | def test_param_required_value 71 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 9\ngoto 0 0") 72 | assert_match /ERROR CODE\:(\t| )?(0x3BC00A)/, stderr 73 | assert_equal 15, status.exitstatus 74 | end 75 | 76 | def test_param_required_address 77 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 6\nfree 0 0") 78 | assert_match /ERROR CODE\:(\t| )?(0x3BC00B)/, stderr 79 | assert_equal 15, status.exitstatus 80 | end 81 | 82 | def test_param_blocked_value 83 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 6\nfree 1 1") 84 | assert_match /ERROR CODE\:(\t| )?(0x3BC00C)/, stderr 85 | assert_equal 15, status.exitstatus 86 | end 87 | 88 | def test_param_blocked_address 89 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 9\ngoto 1 1") 90 | assert_match /ERROR CODE\:(\t| )?(0x3BC00D)/, stderr 91 | assert_equal 15, status.exitstatus 92 | end 93 | 94 | def test_number_no_digits 95 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode 0 --") 96 | assert_match /ERROR CODE\:(\t| )?(0x3BC00E)/, stderr 97 | assert_equal 15, status.exitstatus 98 | end 99 | 100 | def test_number_underflow 101 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.2,strx.0.-0xFFFFFFFFFFFFFFFF") 102 | assert_match /ERROR CODE\:(\t| )?(0x3BC00F)/, stderr 103 | assert_equal 15, status.exitstatus 104 | end 105 | 106 | def test_number_overflow 107 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "mode.0.2,strx.0.0xFFFFFFFFFFFFFFFF") 108 | assert_match /ERROR CODE\:(\t| )?(0x3BC010)/, stderr 109 | assert_equal 15, status.exitstatus 110 | end 111 | 112 | def test_number_wrong_base 113 | for console_input in ["mode.0.0o8", "0.0.0k0"] 114 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 115 | assert_match /ERROR CODE\:(\t| )?(0x3BC011)/, stderr 116 | assert_equal 15, status.exitstatus 117 | end 118 | end 119 | 120 | def test_number_negative 121 | for console_input in ['mode.0.32,math.0.-1', 'mode.0.6,aloc.1.-1,mode.0.7,pull.1.0'] 122 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 123 | assert_match /ERROR CODE\:(\t| )?(0x3BC012)/, stderr 124 | assert_equal 15, status.exitstatus 125 | end 126 | end 127 | 128 | def test_number_zero 129 | for console_input in ['mode.0.14,math.0.0,', 'mode.0.38,math.0.2', 'mode.0.39,math.0.0'] 130 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 131 | assert_match /ERROR CODE\:(\t| )?(0x3BC013)/, stderr 132 | assert_equal 15, status.exitstatus 133 | end 134 | end 135 | 136 | def test_invalid_memory_config 137 | for console_input in ['mode.0.6,muse.1.48','mode.0.6,muse.1.20','mode.0.6,muse.1.12','mode.0.6,muse.1.32'] 138 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 139 | assert_match /ERROR CODE\:(\t| )?(0x3BC017)/, stderr 140 | assert_equal 15, status.exitstatus 141 | end 142 | end 143 | 144 | def test_no_such_file 145 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", "none.3bc") 146 | assert_match /ERROR CODE\:(\t| )?(0x3BC018)/, stderr 147 | assert_equal 15, status.exitstatus 148 | end 149 | 150 | def test_null_pointer_exception 151 | for console_input in [ 152 | "mode 0 7\naloc 'p' nill", "mode 0 7\nfree 'p' nill", "mode 0 7\npull 'p' nill", "mode 0 7\nspin 'p' nill", "mode 0 7\npush 'p' nill" 153 | ] 154 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 155 | assert_match /ERROR CODE\:(\t| )?(0x3BC019)/, stderr 156 | assert_equal 15, status.exitstatus 157 | end 158 | end 159 | 160 | def test_invalid_char_scape 161 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => "0.0.'\\N'") 162 | assert_match /ERROR CODE\:(\t| )?(0x3BC01A)/, stderr 163 | assert_equal 15, status.exitstatus 164 | end 165 | 166 | def test_invalid_char_size 167 | for console_input in ["0.0.'aaa'", "0.0.'aa"] 168 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 169 | assert_match /ERROR CODE\:(\t| )?(0x3BC01B)/, stderr 170 | assert_equal 15, status.exitstatus 171 | end 172 | end 173 | 174 | def test_columns 175 | for console_input in [ 176 | "nill", "nill nill", "nill nill nill nill" 177 | ] 178 | stdout, stderr, status = Open3.capture3("./3bc.test.bin", :stdin_data => console_input) 179 | assert_match /ERROR CODE\:(\t| )?(0x3BC01C)/, stderr 180 | assert_equal 15, status.exitstatus 181 | end 182 | end 183 | end 184 | -------------------------------------------------------------------------------- /src/driver_tty.c: -------------------------------------------------------------------------------- 1 | /** 2 | * ___________ _____ _ 3 | * |____ | ___ \/ __ \ | | 4 | * / / |_/ /| / \/ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ 5 | * \ \ ___ \| | | |/ _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ 6 | * .___/ / |_/ /| \__/\ | | (_| | | | | (_| | |_| | (_| | (_| | __/ 7 | * \____/\____/ \____/ |_|\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| 8 | * __/ | __/ | 9 | * |___/ |___/ 10 | * DESCRIPTION: 11 | * Code refers to input and outputs texts or buffers in teletype terminals. 12 | * 13 | * BRIEF: 14 | * Low-level language, tiny virtual machine, intermediate representation, 15 | * embeddable, easy for beginners. (Friendly Punched cards) 16 | * 17 | * AUTHOR: 18 | * Copyright (C) 2020 Rodrigo Dornelles. 19 | * 20 | * LICENSE: 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, 24 | * or any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | * 34 | * JOKE: 35 | * _\|/_ weedend alert! _\|/_ 36 | * this code was written in a 4:20 mode. 37 | */ 38 | 39 | #define TBC_SOURCE_ENTRY 40 | #include "3bc.h" 41 | 42 | #if defined(TBC_USE_POSIX) 43 | struct termios term_old_attr; 44 | struct termios term_new_attr; 45 | #endif 46 | 47 | void driver_tty_init() 48 | { 49 | #if defined(TBC_USE_POSIX) 50 | /** 51 | * Turn possible terminal uncannonical mode 52 | * without conio.h in linux/unix builds 53 | */ 54 | tcgetattr(0, &term_old_attr); 55 | tcgetattr(0, &term_new_attr); 56 | 57 | term_new_attr.c_lflag &= ~ICANON; 58 | term_new_attr.c_lflag &= ~ECHO; 59 | 60 | term_new_attr.c_cc[VTIME] = 0; 61 | term_new_attr.c_cc[VMIN] = 1; 62 | #endif 63 | } 64 | 65 | void driver_tty_exit() 66 | { 67 | #if defined(TBC_P_COMPUTER) 68 | /** clear buffers **/ 69 | fflush(stderr); 70 | fflush(stdout); 71 | #endif 72 | 73 | #if defined(TBC_USE_POSIX) 74 | /** reset terminal to default mode (linux/unix) **/ 75 | tcsetattr(STDIN_FILENO, TCSANOW, &term_old_attr); 76 | #endif 77 | } 78 | 79 | /** 80 | * detect keyboard input 81 | * 82 | * TODO: More compatible tty 83 | */ 84 | data_3bc_t driver_tty_input( 85 | struct app_3bc_s* const app, struct tty_3bc_s tty, register_3bc_t type) 86 | { 87 | signed int value; 88 | char c[2] = "\0"; 89 | bool invalid; 90 | 91 | do { 92 | invalid = false; 93 | 94 | /** capture input **/ 95 | #if defined(TBC_NOT_FILES) 96 | 97 | #elif defined(TBC_P_COMPUTER_OLD) 98 | c[0] = cgetc(); 99 | #elif defined(TBC_USE_POSIX) 100 | tcsetattr(STDIN_FILENO, TCSANOW, &term_new_attr); 101 | c[0] = getchar(); 102 | tcsetattr(STDIN_FILENO, TCSANOW, &term_old_attr); 103 | #elif defined(TBC_USE_CONIO) 104 | /** exclusive function of the conio.h library **/ 105 | c[0] = getch(); 106 | #endif 107 | 108 | /** validate input **/ 109 | switch (type) { 110 | case STRB: 111 | /** made boolean confirmation **/ 112 | switch (c[0]) { 113 | /** pressed YES or TRUE **/ 114 | case 'Y': 115 | case 'y': 116 | case '1': 117 | value = 1; 118 | break; 119 | /** pressed YES or FALSE **/ 120 | case 'N': 121 | case 'n': 122 | case '0': 123 | value = 0; 124 | break; 125 | /** pressed incorrect option **/ 126 | default: 127 | invalid |= true; 128 | break; 129 | } 130 | break; 131 | 132 | case STRC: 133 | /** verify is a ASCII alphabet's letter/symbol **/ 134 | invalid |= (c[0] < 0x20 || c[0] > 0x7E); 135 | value = c[0]; 136 | break; 137 | 138 | case STRI: 139 | /** verify is a decimal number and cast **/ 140 | invalid |= (c[0] < 0x30 || c[0] > 0x39); 141 | value = (c[0] - '0'); 142 | break; 143 | 144 | case STRO: 145 | /** verify is a octal number and cast **/ 146 | invalid = (c[0] < 0x30 || c[0] > 0x37); 147 | value = (c[0] - '0'); 148 | break; 149 | 150 | case STRX: 151 | /** add upcase bit **/ 152 | c[0] |= 0x20; 153 | /** [0-9] casting hexadecimal**/ 154 | if (c[0] >= 0x30 && c[0] <= 0x39) { 155 | value = (c[0] - '0'); 156 | break; 157 | } 158 | /** [A-F] casting hexadecimal **/ 159 | if (c[0] >= 0x61 && c[0] <= 0x66) { 160 | value = (c[0] - 'a' + 0xa); 161 | break; 162 | } 163 | /** verified that it is wrong! */ 164 | invalid |= true; 165 | break; 166 | } 167 | } while (invalid); 168 | 169 | return (data_3bc_t)value; 170 | } 171 | 172 | /** 173 | * stream texts to outputs 174 | */ 175 | void driver_tty_output(struct app_3bc_s* const app, struct tty_3bc_s tty, 176 | register_3bc_t type, data_3bc_t val) 177 | { 178 | /** the size of the buffer is according to the memory */ 179 | char output[sizeof(data_3bc_t) * 8 + 1]; 180 | 181 | /** print negative symbol **/ 182 | if (val < 0 && type != STRC) { 183 | val = abs(val); 184 | driver_tty_output(app, tty, STRC, '-'); 185 | } 186 | 187 | switch (type) { 188 | case STRB: { 189 | #if defined(TBC_NOT_LOG2) 190 | #warning "[3BC] UNSUPPORTED: STRB OUTPUT" 191 | driver_program_error(app, ERROR_UNSUPPORTED); 192 | #else 193 | /** 194 | * C It doesn't have printing of numbers with binary base, 195 | * this is very very sad. makes me want to use java! 196 | */ 197 | int logarithm = val ? log2(val) : 0; 198 | int pos = 0; 199 | 200 | do { 201 | /** concat bitwise to string in reverse order **/ 202 | output[logarithm - pos] = '0' + ((val >> pos) & 1); 203 | } while (pos++ < logarithm); 204 | 205 | /** end of output **/ 206 | output[pos] = '\0'; 207 | break; 208 | #endif 209 | } 210 | 211 | case STRC: 212 | snprintf(output, sizeof(output), "%c", val); 213 | break; 214 | 215 | case STRX: 216 | snprintf(output, sizeof(output), "%x", val); 217 | break; 218 | 219 | case STRI: 220 | snprintf(output, sizeof(output), "%d", val); 221 | break; 222 | 223 | case STRO: 224 | snprintf(output, sizeof(output), "%o", val); 225 | break; 226 | } 227 | 228 | driver_tty_output_raw(app, tty, output); 229 | } 230 | 231 | void driver_tty_output_raw( 232 | struct app_3bc_s* const app, struct tty_3bc_s tty, const char* string) 233 | { 234 | #if defined(_3BC_NUTTX) && !defined(TBC_NOT_FILES) 235 | /** fix stream flush on nuttx when repl|output **/ 236 | if (tty.type == STREAM_TYPE_COMPUTER_STD) { 237 | fputs(string, tty.io.stream); 238 | fflush(tty.io.stream); 239 | return; 240 | } 241 | #endif 242 | #if defined(TBC_P_COMPUTER) && !defined(TBC_NOT_FILES) 243 | /** stream standard c output **/ 244 | if (tty.type == STREAM_TYPE_COMPUTER_STD) { 245 | fputs(string, tty.io.stream); 246 | return; 247 | } 248 | #endif 249 | if (tty.type == STREAM_TYPE_CLONE_TTY) { 250 | driver_tty_output_raw(app, *tty.io.tty, string); 251 | } else if (tty.type == STREAM_TYPE_FUNCTION_CALL) { 252 | tty.io.lambda((char*)string); 253 | return; 254 | } else if (tty.type == STREAM_TYPE_NONE) { 255 | driver_program_error(app, ERROR_NONE_TTY); 256 | } 257 | } 258 | --------------------------------------------------------------------------------