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