Skip to content

Commit af83cad

Browse files
committed
Initial commit
0 parents  commit af83cad

29 files changed

+1699
-0
lines changed

.github/dependabot.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
day: "tuesday"
8+
time: "19:30"
9+
timezone: "CET"
10+
- package-ecosystem: "github-actions"
11+
directory: "/"
12+
schedule:
13+
interval: "weekly"
14+
day: "tuesday"
15+
time: "19:30"
16+
timezone: "CET"

.github/workflows/python-package.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Python package
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
python-version: ["3.11"]
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
- name: Set up Python ${{ matrix.python-version }}
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
- name: Install dependencies
25+
run: |
26+
python -m pip install --upgrade pip
27+
python -m pip install autopep8 flake8 coverage pytest mypy
28+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
29+
- name: Lint with autopep8 and get statistics from flake8
30+
run: |
31+
# exit-zero treats all errors as warnings.
32+
# show statistics for Python syntax errors or undefined names.
33+
# the GitHub editor is 127 chars wide.
34+
flake8 . --count --exit-zero --extend-ignore E402 --max-complexity=10 --max-line-length=127 --show-source --statistics
35+
# stop the build if there are Python syntax errors.
36+
autopep8 . --ignore E402 --recursive --diff --exit-code
37+
- name: Test with pytest
38+
run: |
39+
coverage run -m pytest
40+
- name: Report coverage statistics on modules
41+
run: |
42+
coverage report --fail-under=80 --show-missing
43+
- name: Type checking with mypy
44+
run: |
45+
mypy --strict .

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__pycache__/
2+
dist/
3+
.coverage
4+
src/bytecorecompiler.egg-info/

.gitpod.Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FROM gitpod/workspace-full
2+
3+
RUN pyenv install 3.11 \
4+
&& pyenv global 3.11

.gitpod.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
image:
2+
file: .gitpod.Dockerfile
3+
tasks:
4+
- init: pip3 install -r requirements.txt
5+
command: autopep8 . --recursive --in-place && (pytest || true) && mypy --strict .
6+
vscode:
7+
extensions:
8+
- streetsidesoftware.code-spell-checker # The Code Spell Checker extension is GPLv3-licensed, separate from this project. See its docs for details.
9+
- ms-toolsai.jupyter # The Jupyter extension is MIT-licensed, separate from this project. See its docs for details.
10+
- ms-toolsai.jupyter-keymap # The Jupyter Keymap extension is MIT-licensed, separate from this project. See its docs for details.
11+
- ms-toolsai.jupyter-renderers # The Jupyter Notebook Renderers extension is MIT-licensed, separate from this project. See its docs for details.
12+
- ms-toolsai.vscode-jupyter-cell-tags # The Jupyter Cell Tags extension is MIT-licensed, separate from this project. See its docs for details.
13+
- ms-toolsai.vscode-jupyter-slideshow # The Jupyter Slide Show extension is MIT-licensed, separate from this project. See its docs for details.
14+
- ms-python.python # The Python extension is MIT-licensed, separate from this project. Dependencies: Jupyter (MIT), Pylance (Microsoft proprietary). See docs for details.

.pep8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[pycodestyle]
2+
ignore = E402

.vscode/settings.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"python.linting.mypyEnabled": true,
3+
"python.linting.mypyArgs": [
4+
"--strict"
5+
],
6+
"cSpell.words": [
7+
"bytecore",
8+
"bytecorecompiler",
9+
"subtractor",
10+
"setuptools",
11+
"pycache"
12+
]
13+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Joakim Winum Lien
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# ByteCoreCompiler
2+
3+
The ByteCoreCompiler transforms ByteCore assembly code into a 64KB memory byte array, compatible with the [ByteCore Emulator](https://github.com/joakimwinum/bytecore). It includes features to identify syntax errors and guide developers through debugging their code.
4+
5+
## Overview
6+
7+
The compiler process involves several steps to convert text-based assembly code into executable memory bytes:
8+
9+
1. **Lexical Analysis**: Converts raw text into tokens.
10+
2. **Syntax Analysis**: Checks token structure and builds a syntax tree.
11+
3. **Semantic Analysis**: Further inspects the syntax tree for logical consistency.
12+
13+
Successful compilation results in a memory byte array ready for emulation; errors during any stage will generate exceptions to highlight issues.
14+
15+
## ByteCore Assembly Language
16+
17+
The ByteCore assembly language represents instructions in a format that the ByteCore Emulator can execute directly, consisting of:
18+
19+
- **MSB (Most Significant Byte)**
20+
- **LSB (Least Significant Byte)**
21+
- **DATA**: Can be either a valid hexadecimal number or an opcode.
22+
23+
### Rules
24+
25+
The compiler adheres to specific rules to ensure the correct interpretation of ByteCore assembly:
26+
27+
- Strips leading, trailing, and extra spaces.
28+
- Treats line breaks (`\n`, `\r`, `\r\n`) as new lines.
29+
- Ignores text after a semicolon (`;`), which denotes a comment.
30+
- Requires lines to have exactly 0 or 3 tokens, not counting comments.
31+
- Expects the first two tokens of a line to represent numbers in hexadecimal format (0-255).
32+
- Requires the third token to be a valid opcode or a hexadecimal number corresponding to one of the specific opcodes (0, 1, 2, 4, 8, 16, 32).
33+
- Prohibits assigning data to a memory address that has already been set.
34+
35+
### Instructions
36+
37+
Refer to the [ByteCore Emulator README](https://github.com/joakimwinum/bytecore?tab=readme-ov-file#instructions) for a detailed list of supported instructions.
38+
39+
## Installation and Setup
40+
41+
### Prerequisites
42+
43+
Ensure Python 3.11 or newer is installed. Clone the repository and navigate to the root directory. Consider setting up a Python virtual environment to manage dependencies.
44+
45+
### Dependencies
46+
47+
Install required dependencies with:
48+
49+
```bash
50+
pip3 install -r requirements.txt
51+
```
52+
53+
### Gitpod
54+
55+
Alternatively, use Gitpod for a pre-configured environment by clicking [here](https://gitpod.io/#https://github.com/joakimwinum/bytecorecompiler).
56+
57+
## Usage
58+
59+
To compile ByteCore assembly code into memory bytes and execute it, follow these steps:
60+
61+
### Example 1: Simple Program
62+
63+
```python
64+
from bytecorecompiler.compiler import Compiler
65+
from bytecore.emulator import ByteCore
66+
67+
bytecore_assembly = """
68+
00 00 LOAD
69+
00 01 00
70+
00 02 0A
71+
00 03 ADD
72+
00 04 00
73+
00 05 0B
74+
00 06 STORE
75+
00 07 FF
76+
00 08 FF
77+
00 09 HALT
78+
00 0A 14; 20
79+
00 0B 1E; 30
80+
"""
81+
82+
memory_bytes = Compiler(bytecore_assembly).get_memory_bytes()
83+
byte_core = ByteCore(memory_bytes)
84+
byte_core.cycle_until_halt()
85+
dump = byte_core.dump()
86+
87+
dump.memory[-1] # equals 50
88+
```
89+
90+
### Example 2: Advanced Program
91+
92+
This example uses all defined opcodes to demonstrate the compiler's capabilities with a more complex program structure.
93+
94+
```python
95+
from bytecorecompiler.compiler import Compiler
96+
from bytecore.emulator import ByteCore
97+
98+
bytecore_assembly = """
99+
00 00 JMP
100+
00 01 FE
101+
00 02 00
102+
103+
01 00 37; 55
104+
01 01 14; 20
105+
01 02 02; 2
106+
01 03 01; 1
107+
108+
FE 00 LOAD
109+
FE 01 01
110+
FE 02 00
111+
FE 03 ADD
112+
FE 04 01
113+
FE 05 02
114+
FE 06 STORE
115+
FE 07 01
116+
FE 08 00
117+
FE 09 LOAD
118+
FE 0A 01
119+
FE 0B 01
120+
FE 0C SUB
121+
FE 0D 01
122+
FE 0E 03
123+
FE 0F STORE
124+
FE 10 01
125+
FE 11 01
126+
FE 12 LOAD
127+
FE 13 01
128+
FE 14 01
129+
FE 15 JZ
130+
FE 16 FF
131+
FE 17 00
132+
FE 18 JMP
133+
FE 19 FE
134+
FE 1A 00
135+
136+
FF 00 LOAD
137+
FF 01 01
138+
FF 02 00
139+
FF 03 STORE
140+
FF 04 FF
141+
FF 05 FF
142+
FF 06 HALT
143+
"""
144+
145+
memory_bytes = Compiler(bytecore_assembly).get_memory_bytes()
146+
byte_core = ByteCore(memory_bytes)
147+
byte_core.cycle_until_halt()
148+
dump = byte_core.dump()
149+
150+
dump.memory[-1] # equals 95
151+
```
152+
153+
## License
154+
155+
This project is licensed under the terms of the MIT License. See the [LICENSE](https://github.com/joakimwinum/bytecorecompiler/blob/main/LICENSE) file for the full text.

pyproject.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "bytecorecompiler"
7+
version = "1.0.0"
8+
authors = [
9+
{ name="Joakim Winum Lien", email="joakim@winum.xyz" },
10+
]
11+
description = "A compiler that transforms ByteCore assembly code into executable memory bytes, seamlessly bridging the gap between high-level assembly instructions and the ByteCore Emulator's low-level functionality."
12+
readme = "README.md"
13+
requires-python = ">=3.11"
14+
classifiers = [
15+
"Programming Language :: Python :: 3",
16+
"License :: OSI Approved :: MIT License",
17+
"Operating System :: OS Independent",
18+
]
19+
20+
[project.urls]
21+
"Homepage" = "https://github.com/joakimwinum/bytecorecompiler"
22+
"Bug Tracker" = "https://github.com/joakimwinum/bytecorecompiler/issues"
23+
24+
[tool.setuptools.packages.find]
25+
where = ["src"]
26+
27+
[tool.setuptools.package-data]
28+
bytecore = ["py.typed"]

requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pytest>=8.1.1,<8.2.0
2+
autopep8>=2.1.0,<2.2.0
3+
mypy>=1.9.0,<1.10.0
4+
bytecore>=1.1.0,<1.2.0

src/bytecorecompiler/__init__.py

Whitespace-only changes.

src/bytecorecompiler/compiler.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from bytecore.byte import Byte
2+
from bytecore.memory import Memory
3+
from bytecorecompiler.parser import Parser
4+
from bytecorecompiler.exception import ByteCoreCompilerException
5+
6+
7+
class Compiler:
8+
def __init__(self, string: str) -> None:
9+
parser = Parser(string)
10+
self._syntax_trees = parser.syntax_trees
11+
self._memory_bytes = self._convert_syntax_trees_to_memory_bytes()
12+
13+
def _convert_syntax_trees_to_memory_bytes(self) -> list[Byte]:
14+
memory_bytes = Memory.get_default_memory_bytes()
15+
16+
for syntax_tree in self._syntax_trees:
17+
memory_address = syntax_tree.get_memory_address()
18+
data = syntax_tree.get_data()
19+
20+
if memory_address is None or data is None:
21+
raise ConvertException(
22+
'Should not be missing these data.')
23+
24+
memory_bytes[memory_address] = Byte(data)
25+
26+
return memory_bytes
27+
28+
def get_memory_bytes(self) -> list[Byte]:
29+
return self._memory_bytes
30+
31+
32+
class ConvertException(ByteCoreCompilerException):
33+
def __init__(self, message: str) -> None:
34+
super().__init__(message)

src/bytecorecompiler/exception.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class ByteCoreCompilerException(Exception):
2+
def __init__(self, message: str) -> None:
3+
super().__init__(message)

0 commit comments

Comments
 (0)