├── .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 |

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 | | System |
6 | Architeture |
7 | Download |
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 | | {{ plataform }} |
15 | {{ architeture }} |
16 | {% include download_btn.rhtml %} |
17 |
18 | {% endfor %}
19 |
20 | {% else %}
21 |
22 |
23 | | File name |
24 | Download |
25 |
26 | {% for asset in release.assets %}
27 |
28 | | {{ asset.name }} |
29 | {% include download_btn.rhtml %} |
30 |
31 | {% endfor %}
32 |
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://github.com/rodrigodornelles) |
10 | | **2º** | 28 November 2020 | Carlos Eduardo | [](https://github.com/kadu) |
11 | | **3º** | 23 December 2020 | Robson Soares | [](https://github.com/robsondrs) |
12 | | **4º** | 28 December 2020 | Guilherme Neves | |
13 | | **5º** | 30 December 2020 | Marcus Paulo | [](https://github.com/marcusmmmz) |
14 | | **6º** | 30 December 2020 | Takeshi Ishikawa | [](https://github.com/keshizin) |
15 | | **7º** | 31 December 2020 | André Luis | [](https://github.com/andreluispy) |
16 | | **8º** | 2 January 2021 | Francisco Noble | [](https://github.com/guridev) |
17 | | **9º** | 5 February 2021 | Lucas Rangel | [](https://github.com/lrv-dev) |
18 | | **10º** | 6 February 2021 | Otávio Burato | [](https://github.com/otavio-burato) |
19 | | **11º** | 21 July 2021 | Github Copilot _(IA)_ | [](https://copilot.github.com/) |
20 | | **12º** | 14 August 2021 | Moizes Sousa | [](https://github.com/yxqsnzo) |
21 | | **13º** | 30 October 2021 | Anderson Costa | [](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 | [](https://github.com/sponsors/RodrigoDornelles)
4 | [](https://github.com/RodrigoDornelles/3bc-lang/releases)
5 | [](https://github.com/RodrigoDornelles/3bc-lang/blob/master/LICENSE.txt)
6 | [](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 | 
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 |

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 |
--------------------------------------------------------------------------------