Create variables
This commit is contained in:
@@ -1,18 +1,11 @@
|
||||
## Work in Progress
|
||||
|
||||
To create a comment, begin a line with a hash (#) symbol, like python.
|
||||
|
||||
So far, the supported types are `bool` and `string`.
|
||||
Create a string: `string name value bytes`
|
||||
|
||||
## create name type bytes value
|
||||
Create a boolean: `bool name value`
|
||||
|
||||
Creates the variable "var" with a set number of bytes allocated to it, and initialises its value.
|
||||
**IMPORTANT:** The number of bytes cannot be modified later.
|
||||
Create an integer: `int name value`
|
||||
|
||||
Example: `create var bool 1 true`
|
||||
|
||||
To set a variable to an input byte, use: `create var string 1 i[idx]`.
|
||||
|
||||
## print var
|
||||
|
||||
Prints the value of `var` to the console, where `var` is a variable.
|
||||
|
||||
Example: `print var`
|
||||
**Note**: A string of dynamic length can be created by setting the bytes to -1.
|
||||
21
readme.md
21
readme.md
@@ -2,6 +2,12 @@
|
||||
|
||||
BrainAssembly is a language that compiles to Brainfuck. Similar to Assembly languages, it has simple syntax, and is designed to make Brainfuck easier to write code for. Heavily inspired by Ground. Enjoy!
|
||||
|
||||
## Features
|
||||
|
||||
- Simple syntax: The language is designed to be very simple, and a framework for larger projects. This also means that the syntax is quite easy to learn.
|
||||
|
||||
**NOTE:** Due to the current lack of optimisation in the compiled code, we recommend an optimising intepreter such as [this one](https://copy.sh/brainfuck).
|
||||
|
||||
To run:
|
||||
|
||||
- First clone this repository and install python.
|
||||
@@ -10,10 +16,21 @@ git clone https://chookspace.com/DiamondNether90/BrainAssembly
|
||||
```
|
||||
|
||||
- Next, run the following command to compile a .basm file to Brainfuck:
|
||||
```
|
||||
```bash
|
||||
python3 src/main.py path/to/file.basm path/to/file.bf
|
||||
```
|
||||
|
||||
(Replace path/to/file.basm with the actual path to your desired .basm file, and replace path/to/file.bf with where you want the compiled file to be created.)
|
||||
|
||||
This will create or replace the contents of path/to/file.bf with the compiled BrainAssembly code.
|
||||
This will create or replace the contents of path/to/file.bf with the compiled BrainAssembly code.
|
||||
|
||||
## Test the compiler with our in-built test programs!
|
||||
|
||||
You can access our test programs in the test folder.
|
||||
|
||||
Example:
|
||||
```bash
|
||||
python src/main.py tests/create.basm test.bf
|
||||
```
|
||||
|
||||
This will create a Brainfuck file named test.bf that contains the compiled code of our test programs.
|
||||
196
src/codegen.py
196
src/codegen.py
@@ -2,115 +2,121 @@ from error import error
|
||||
import math as m
|
||||
|
||||
class Variable:
|
||||
def __init__(self, name: str, bytes: int, startByte: int, type: int):
|
||||
def __init__(self, name: str, bytes: int, type: int):
|
||||
self.name: str = name
|
||||
self.bytes: int = bytes
|
||||
self.startByte: int = startByte
|
||||
self.type: int = type
|
||||
def __repr__(self) -> str:
|
||||
return f"[{self.name}, {self.bytes}, {self.startByte}, {self.type}]"
|
||||
return f"[{self.name}, {self.bytes}, {self.type}]"
|
||||
|
||||
variables: list[Variable] = []
|
||||
bytesum: int = 0
|
||||
|
||||
types = {
|
||||
"bool": 0,
|
||||
"string": 1,
|
||||
"int": 2,
|
||||
}
|
||||
|
||||
bool = {
|
||||
"true": 1,
|
||||
"false": 0,
|
||||
}
|
||||
|
||||
def generateCode(line: list[str], offset: int) -> str:
|
||||
try:
|
||||
bytesum = variables[-1].startByte + variables[-1].bytes
|
||||
except IndexError:
|
||||
bytesum = 0
|
||||
keyword = line[0]
|
||||
if keyword == 'create':
|
||||
if len(line) != 5:
|
||||
error(f"Create command requires 4 arguments (got {len(line)-1})")
|
||||
name = line[1]
|
||||
try:
|
||||
type = types[line[2]]
|
||||
except KeyError:
|
||||
error(f"Invalid type: {line[2]}")
|
||||
quit()
|
||||
bytes = int(line[3])
|
||||
value = line[4]
|
||||
|
||||
if type == 0:
|
||||
variables.append(Variable(name, bytes, bytesum, type))
|
||||
if (value == 'true'):
|
||||
return '>' * offset + '[>]' + '>' * (bytesum + 1) + '+' + '<' * (bytesum + 1) + '<[<]' + '<' * (offset - 1)
|
||||
elif (value == 'false'):
|
||||
return ''
|
||||
else:
|
||||
error(f'Invalid bool: {value}')
|
||||
elif type == 1:
|
||||
if value[0] == value[-1] == '"':
|
||||
value = value[1:-1]
|
||||
variables.append(Variable(name, bytes, bytesum, type))
|
||||
returnval = '>' * offset + '[>]' + '>' * (bytesum + 1)
|
||||
for i in range(bytes):
|
||||
try:
|
||||
returnval += '+' * ord(value[i]) + '>'
|
||||
except IndexError:
|
||||
returnval += '>'
|
||||
returnval += '<' * (bytes+bytesum+2) + '[<]' + '<' * (offset - 1)
|
||||
return returnval
|
||||
elif (value[:2] == 'i[') & (value[-1] == ']'):
|
||||
try:
|
||||
validx: int = int(value[2:-1])
|
||||
except ValueError:
|
||||
error(f'Invalid input index: {value[2:-1]}')
|
||||
quit()
|
||||
variables.append(Variable(name, bytes, bytesum, type))
|
||||
returnval = '>' * (offset + validx)
|
||||
returnval += '[[>]' + '>' * (bytesum+1) + '+' + '<' * (bytesum+2) + '[<]<+' + '>' * (validx+2) + '-]'
|
||||
returnval += '<[<]<[' + '>' * (validx+2) + '+<[<]<-]<<<'
|
||||
|
||||
return returnval
|
||||
else:
|
||||
error(f"Invalid string: {value}")
|
||||
elif type == 2:
|
||||
# I hate integers
|
||||
error('Integers are not yet implemented')
|
||||
else:
|
||||
error(f"Type {type} not yet implemented")
|
||||
|
||||
error()
|
||||
quit()
|
||||
elif keyword == 'print':
|
||||
if len(line) != 2:
|
||||
error(f"Print command requires 1 argument (got {len(line)-1})")
|
||||
|
||||
# Find value of variable
|
||||
var: Variable | str = ''
|
||||
for v in variables:
|
||||
if v.name == line[1]:
|
||||
var = v
|
||||
|
||||
if var == '':
|
||||
error(f'Could not find variable {line[1]}')
|
||||
quit()
|
||||
|
||||
if var.type == 0:
|
||||
# Create copy
|
||||
returnval = '>' * offset + '[>]' + '>' * (var.startByte + 1) + '[' + '<' * (var.startByte+2) + '[<]<+<+>>>' + '[>]>' + '>' * var.startByte + '-]' + '<' * (var.startByte + 2) + '[<]<' + '[>>[>]' + '>' * (var.startByte + 1) + '+' + '<' * (var.startByte + 2) + '[<]<-]'
|
||||
# If true
|
||||
returnval += '+<[>-<' + '+' * 115 + '.--.+++.----------------.[-]' + ']'
|
||||
# else false
|
||||
returnval += '>[' + '+' * 101 + '.-----.+++++++++++.+++++++.--------------.[-]' + ']<<<'
|
||||
if keyword == 'bool':
|
||||
if len(line) != 3:
|
||||
error(f'Bool command requires 2 arguments (got {len(line)-1})')
|
||||
variables.append(Variable(line[1], 1, 0))
|
||||
if line[2] == 'true':
|
||||
returnval = '>' * offset + '[>]'
|
||||
for var in variables[:-1]:
|
||||
if var.bytes >= 0:
|
||||
returnval += '>' * (var.bytes+1)
|
||||
elif var.bytes == -1:
|
||||
returnval += '>[>]'
|
||||
else:
|
||||
error()
|
||||
returnval += '>+<'
|
||||
for var in reversed(variables[:-1]):
|
||||
if var.bytes >= 0:
|
||||
returnval += '<' * (var.bytes+1)
|
||||
elif var.bytes == -1:
|
||||
returnval += '<[<]'
|
||||
else:
|
||||
error()
|
||||
returnval += '<[<]' + '<' * (offset-1)
|
||||
return returnval
|
||||
elif var.type == 1:
|
||||
return '>' * offset + '[>]' + '>' * (var.startByte + 1) + '.>' * var.bytes + '<' * (var.startByte+var.bytes+2) + '[<]' + '<' * (offset - 1)
|
||||
elif line[2] == 'false':
|
||||
return ''
|
||||
else:
|
||||
error('Type not yet supported')
|
||||
quit()
|
||||
else:
|
||||
error(f"Invalid token: {keyword}")
|
||||
quit()
|
||||
error(f"Invalid bool: {line[2]}")
|
||||
elif keyword == 'string':
|
||||
if len(line) != 4:
|
||||
error(f'String command requires 3 arguments (got {len(line)-1})')
|
||||
try:
|
||||
variables.append(Variable(line[1], int(line[2]), 1))
|
||||
except ValueError:
|
||||
error(f'Unexpected bytes for string: {line[2]}')
|
||||
returnval = '>' * offset + '[>]'
|
||||
for var in variables[:-1]:
|
||||
if var.bytes >= 0:
|
||||
returnval += '>' * (var.bytes + 1)
|
||||
elif var.bytes == -1:
|
||||
returnval += '>[>]'
|
||||
else:
|
||||
error('Cannot have negative byte count (excluding -1)')
|
||||
|
||||
returnval += '>'
|
||||
# Normal string
|
||||
if line[3][0] == line[3][-1] == '"':
|
||||
line[3] = line[3][1:-1]
|
||||
if (len(line[3]) > int(line[2])) & (line[2] != '-1'):
|
||||
line[3] = line[3][:(int(line[2])-len(line[3]))]
|
||||
for char in line[3]:
|
||||
returnval += '+' * ord(char) + '>'
|
||||
else:
|
||||
error(f'Invalid string: {line[3]}')
|
||||
|
||||
# Return to start
|
||||
for var in reversed(variables):
|
||||
if var.bytes >= 0:
|
||||
returnval += '<' * (var.bytes + 1)
|
||||
elif var.bytes == -1:
|
||||
returnval += '<[<]'
|
||||
else:
|
||||
error()
|
||||
returnval += '<[<]' + '<' * (offset-1)
|
||||
|
||||
return returnval
|
||||
elif keyword == 'int':
|
||||
if len(line) != 3:
|
||||
error(f'Int requires 2 arguments (got {len(line)-1})')
|
||||
variables.append(Variable(line[1], 4, 2))
|
||||
returnval: str = '>' * offset + '[>]'
|
||||
for var in variables[:-1]:
|
||||
if var.bytes >= 0:
|
||||
returnval += '>' * (var.bytes+1)
|
||||
elif var.bytes == -1:
|
||||
returnval += '>[>]'
|
||||
else:
|
||||
error()
|
||||
returnval += '>'
|
||||
try:
|
||||
input: int = int(line[2]) % 4294967296
|
||||
except ValueError:
|
||||
error(f'Invalid integer: {line[2]}')
|
||||
|
||||
values: list[int] = []
|
||||
for i in reversed(range(4)):
|
||||
values.append(m.floor(input/(256**i)))
|
||||
input -= values[-1] * (256**i)
|
||||
for num in values:
|
||||
returnval += '+' * num + '>'
|
||||
returnval += '<<<<<'
|
||||
for var in reversed(variables[:-1]):
|
||||
if var.bytes >= 0:
|
||||
returnval += '<' * (var.bytes + 1)
|
||||
elif var.bytes == -1:
|
||||
returnval += '<[<]'
|
||||
else:
|
||||
error()
|
||||
returnval += '<[<]' + '<' * (offset-1)
|
||||
|
||||
return returnval
|
||||
error()
|
||||
@@ -1,2 +1,5 @@
|
||||
def error(message: str = "This is a bugged error message. Please report this issue."):
|
||||
exit(f"\033[91mError: \033[0m{message}")
|
||||
exit(f"\033[91mError: \033[0m{message}")
|
||||
|
||||
def warn(message: str):
|
||||
print(f"\033[33mWarning: {message}")
|
||||
@@ -31,11 +31,7 @@ code = preprocess(content)
|
||||
offset: int = 5
|
||||
bfcode: str = '>' * offset + ',[>,]<[<]' + '<' * (offset-1)
|
||||
|
||||
def find(str: str, char: str):
|
||||
if (char in str):
|
||||
return str.find(char)
|
||||
else:
|
||||
return len(str)
|
||||
open(argv[2], 'w').write('')
|
||||
|
||||
for line in code:
|
||||
bfcode += generateCode(line, offset)
|
||||
|
||||
@@ -1,2 +1,8 @@
|
||||
create i3 string 1 i[3]
|
||||
print i3
|
||||
bool var true
|
||||
bool var2 false
|
||||
string str1 -1 "Hell"
|
||||
bool var3 true
|
||||
int num1 -1736671613
|
||||
int num2 9182364129
|
||||
string str2 5 "World!"
|
||||
bool var4 true
|
||||
Reference in New Issue
Block a user