Compare commits
	
		
			22 Commits
		
	
	
		
			5188784a11
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e853195cc3 | |||
| 4bcbc6c650 | |||
| 5e9c2273a9 | |||
| 976e9dfaa0 | |||
| 89065711ce | |||
| 9ad3bdbc92 | |||
| 176c07151a | |||
| 1ceecbb99e | |||
| 0710369871 | |||
| 5fa47dc377 | |||
| c98f248245 | |||
| 333a1241e8 | |||
| 74494711f6 | |||
| ea8d651171 | |||
| f2336c8463 | |||
| ea55468a10 | |||
| 11f708a9fd | |||
| 937cdfa3ef | |||
| 91f090dc12 | |||
| 3ccf7f845f | |||
| e180adea8c | |||
| ae37d8deab | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					src/__pycache__
 | 
				
			||||||
 | 
					test.bf
 | 
				
			||||||
@@ -1,3 +0,0 @@
 | 
				
			|||||||
## create var = Value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Creates the variable "var" and initialises its value.
 | 
					 | 
				
			||||||
							
								
								
									
										35
									
								
								readme.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								readme.md
									
									
									
									
									
								
							@@ -1,3 +1,36 @@
 | 
				
			|||||||
## Welcome to BrainAssembly!
 | 
					## Welcome to BrainAssembly!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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. Enjoy!
 | 
					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.
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 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 the 'create' test program.
 | 
				
			||||||
							
								
								
									
										387
									
								
								src/codegen.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								src/codegen.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,387 @@
 | 
				
			|||||||
 | 
					from error import error, warn
 | 
				
			||||||
 | 
					import math as m
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					class Variable:
 | 
				
			||||||
 | 
					    def __init__(self, name: str, bytes: int, type: int):
 | 
				
			||||||
 | 
					        self.name: str = name
 | 
				
			||||||
 | 
					        self.bytes: int = bytes
 | 
				
			||||||
 | 
					        self.type: int = type
 | 
				
			||||||
 | 
					    def __repr__(self) -> str:
 | 
				
			||||||
 | 
					        return f"[{self.name}, {self.bytes}, {self.type}]"
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					variables: list[Variable] = []
 | 
				
			||||||
 | 
					bytesum: int = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool = {
 | 
				
			||||||
 | 
					    "true": 1,
 | 
				
			||||||
 | 
					    "false": 0,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getIndex(name: str) -> int:
 | 
				
			||||||
 | 
					    varnames = []
 | 
				
			||||||
 | 
					    for var in variables:
 | 
				
			||||||
 | 
					        varnames.append(var.name)
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return varnames.index(name)
 | 
				
			||||||
 | 
					    except IndexError:
 | 
				
			||||||
 | 
					        return -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generateCode(line: list[str], offset: int) -> str:
 | 
				
			||||||
 | 
					    keyword = line[0]
 | 
				
			||||||
 | 
					    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 line[2] == 'false':
 | 
				
			||||||
 | 
					            return ''
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            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) + '>'
 | 
				
			||||||
 | 
					            for char in range(int(line[2])-len(line[3])):
 | 
				
			||||||
 | 
					                returnval += '>'
 | 
				
			||||||
 | 
					        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(line[2])
 | 
				
			||||||
 | 
					            if abs(input) > 4294967295:
 | 
				
			||||||
 | 
					                warn(f'Input {line[2]} is too large for int. Overflowing...')
 | 
				
			||||||
 | 
					            input %= 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:
 | 
				
			||||||
 | 
					            if num < 128:
 | 
				
			||||||
 | 
					                returnval += '+' * num + '>'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                returnval += '-' * (256-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
 | 
				
			||||||
 | 
					    elif keyword == 'print':
 | 
				
			||||||
 | 
					        if len(line) != 2:
 | 
				
			||||||
 | 
					            error(f'Print command requires 1 argument (got {len(line)-1})')
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        returnval = '>' * offset + '[>]'
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        idx = getIndex(line[1])
 | 
				
			||||||
 | 
					        if idx != -1:
 | 
				
			||||||
 | 
					            for var in variables[:idx]:
 | 
				
			||||||
 | 
					                if var.bytes >= 0:
 | 
				
			||||||
 | 
					                    returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					                elif var.bytes == -1:
 | 
				
			||||||
 | 
					                    returnval += '>[>]'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    error()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            var = variables[idx]
 | 
				
			||||||
 | 
					            if var.type != 1:
 | 
				
			||||||
 | 
					                error(f'Can\'t print {var.name}: Invalid type')
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '>' + '.>' * var.bytes + '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[.>]' + '<[<]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            for var in reversed(variables[:idx]):
 | 
				
			||||||
 | 
					                if var.bytes >= 0:
 | 
				
			||||||
 | 
					                    returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					                elif var.bytes == -1:
 | 
				
			||||||
 | 
					                    returnval += '<[<]'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    error()
 | 
				
			||||||
 | 
					            returnval += '<[<]' + '<' * (offset-1)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            error(f'{line[1]} is not a variable')
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return returnval
 | 
				
			||||||
 | 
					    elif keyword == 'inc':
 | 
				
			||||||
 | 
					        if len(line) != 2:
 | 
				
			||||||
 | 
					            error(f'Inc command requires 1 argument (got {len(line)-1})')    
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        returnval = '>' * offset + '[>]'
 | 
				
			||||||
 | 
					        idx = getIndex(line[1])
 | 
				
			||||||
 | 
					        if variables[idx].type != 2:
 | 
				
			||||||
 | 
					            error(f'Cannot increment {line[1]}: Invalid type')
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for var in variables[:idx]:
 | 
				
			||||||
 | 
					            if var.bytes > 0:
 | 
				
			||||||
 | 
					                returnval += '>' * (var.bytes + 1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[>]'
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        # Increment logic        
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        The logic in pseudo-python is like this:
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            byte[3]++
 | 
				
			||||||
 | 
					            carry = 1
 | 
				
			||||||
 | 
					            if byte[3] != 0:
 | 
				
			||||||
 | 
					                carry = 0
 | 
				
			||||||
 | 
					            if carry == 1:
 | 
				
			||||||
 | 
					                byte[2]++
 | 
				
			||||||
 | 
					                if byte[2] != 0:
 | 
				
			||||||
 | 
					                    carry = 0
 | 
				
			||||||
 | 
					                if carry == 1:
 | 
				
			||||||
 | 
					                    byte[1]++
 | 
				
			||||||
 | 
					                    if byte[1] != 0:
 | 
				
			||||||
 | 
					                        carry = 0
 | 
				
			||||||
 | 
					                    if carry == 1:
 | 
				
			||||||
 | 
					                        byte[0]++
 | 
				
			||||||
 | 
					                        carry = 0
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        # Carry will be stored to the immediate right of cells
 | 
				
			||||||
 | 
					        # byte[3]++; carry = 1
 | 
				
			||||||
 | 
					        returnval += '>>>>+>+'
 | 
				
			||||||
 | 
					        # If byte[3] != 0: carry = 0
 | 
				
			||||||
 | 
					        returnval += '<[>-<[<<<<+>>>>-]]<<<<[>>>>+<<<<-]>>>>'
 | 
				
			||||||
 | 
					        # If carry == 1
 | 
				
			||||||
 | 
					        returnval += '>['
 | 
				
			||||||
 | 
					        # byte[2]++
 | 
				
			||||||
 | 
					        returnval += '<<+'
 | 
				
			||||||
 | 
					        # if byte[2] != 0: carry = 0
 | 
				
			||||||
 | 
					        returnval += '[>>-<<[<<<+>>>-]]'
 | 
				
			||||||
 | 
					        returnval += '<<<[>>>+<<<-]>>>'
 | 
				
			||||||
 | 
					        # if carry == 1
 | 
				
			||||||
 | 
					        returnval += '>>['
 | 
				
			||||||
 | 
					        # byte[1]++
 | 
				
			||||||
 | 
					        returnval += '<<<+'
 | 
				
			||||||
 | 
					        # if byte[1] != 0: carry = 0
 | 
				
			||||||
 | 
					        returnval += '[>>>-<<<[<<+>>-]]<<[>>+<<-]>>'
 | 
				
			||||||
 | 
					        # if carry == 1
 | 
				
			||||||
 | 
					        returnval += '>>>['
 | 
				
			||||||
 | 
					        # byte[0]++; carry = 0
 | 
				
			||||||
 | 
					        returnval += '<<<<+>>>>-]]]'
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Return to start
 | 
				
			||||||
 | 
					        returnval += '<<<<<'
 | 
				
			||||||
 | 
					        for var in reversed(variables[:idx]):
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '<[<]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        returnval += '<[<]' + '<' * (offset-1)
 | 
				
			||||||
 | 
					        return returnval
 | 
				
			||||||
 | 
					    elif keyword == 'equal':
 | 
				
			||||||
 | 
					        if len(line) != 4:
 | 
				
			||||||
 | 
					            error(f'Equal command requires 3 arguments (got {len(line)-1})')
 | 
				
			||||||
 | 
					        returnval = '>' * offset + '[>]'
 | 
				
			||||||
 | 
					        idx = getIndex(line[1])
 | 
				
			||||||
 | 
					        for var in variables[:idx]:
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[>]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					        returnval += '>'
 | 
				
			||||||
 | 
					        for i in range(4):
 | 
				
			||||||
 | 
					            returnval += '[-'
 | 
				
			||||||
 | 
					            returnval += '>' * (4-i)
 | 
				
			||||||
 | 
					            for var in variables[(idx+1):]:
 | 
				
			||||||
 | 
					                if var.bytes >= 0:
 | 
				
			||||||
 | 
					                    returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					                elif var.bytes == -1:
 | 
				
			||||||
 | 
					                    returnval += '>[>]'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    error()
 | 
				
			||||||
 | 
					            returnval += '>' * (i+1) + '+' + '<' * (i+1)
 | 
				
			||||||
 | 
					            for var in reversed(variables[(idx+1):]):
 | 
				
			||||||
 | 
					                if var.bytes >= 0:
 | 
				
			||||||
 | 
					                    returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					                elif var.bytes == -1:
 | 
				
			||||||
 | 
					                    returnval += '<[<]'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    error()
 | 
				
			||||||
 | 
					            returnval += '<<<<<+' + '>' * (i+1) + ']'
 | 
				
			||||||
 | 
					            returnval += '<' * (i+1) + '[' + '>' * (i+1) + '+' + '<' * (i+1) + '-]' + '>' * (i+2)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        # Copy the above, but subtract from duplicate
 | 
				
			||||||
 | 
					        idx2 = getIndex(line[2])
 | 
				
			||||||
 | 
					        for var in variables[(idx+1):idx2]:
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[>]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        returnval += '>'
 | 
				
			||||||
 | 
					        for i in range(4):
 | 
				
			||||||
 | 
					            returnval += '[-'
 | 
				
			||||||
 | 
					            returnval += '>' * (4-i)
 | 
				
			||||||
 | 
					            for var in variables[(idx2+1):]:
 | 
				
			||||||
 | 
					                if var.bytes >= 0:
 | 
				
			||||||
 | 
					                    returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					                elif var.bytes == -1:
 | 
				
			||||||
 | 
					                    returnval += '>[>]'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    error()
 | 
				
			||||||
 | 
					            returnval += '>' * (i+1) + '-' + '<' * (i+1)
 | 
				
			||||||
 | 
					            for var in reversed(variables[(idx2+1):]):
 | 
				
			||||||
 | 
					                if var.bytes >= 0:
 | 
				
			||||||
 | 
					                    returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					                elif var.bytes == -1:
 | 
				
			||||||
 | 
					                    returnval += '<[<]'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    error()
 | 
				
			||||||
 | 
					            returnval += '<<<<<+' + '>' * (i+1) + ']'
 | 
				
			||||||
 | 
					            returnval += '<' * (i+1) + '[' + '>' * (i+1) + '+' + '<' * (i+1) + '-]' + '>' * (i+2)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for var in variables[(idx2+1):]:
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[>]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        returnval += '>[<+>[-]]>[<<+>>[-]]>[<<<+>>>[-]]>[<<<<+>>>>[-]]<<<+<[>-<[-]]'
 | 
				
			||||||
 | 
					        for var in reversed(variables):
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '<[<]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        returnval += '<[<]' + '<' * (offset-1)
 | 
				
			||||||
 | 
					        variables.append(Variable(line[3], 1, 0))
 | 
				
			||||||
 | 
					        return returnval
 | 
				
			||||||
 | 
					    elif keyword == 'if':
 | 
				
			||||||
 | 
					        if len(line) != 2:
 | 
				
			||||||
 | 
					            error(f'If command requires 1 argument (got {len(line)-1})')
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        returnval = '>' * offset + '[>]'
 | 
				
			||||||
 | 
					        idx = getIndex(line[1])
 | 
				
			||||||
 | 
					        for var in variables[:idx]:
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[>]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        returnval += '>[<+>->+<]<[>+<-]>>[<<'
 | 
				
			||||||
 | 
					        for var in reversed(variables[:idx]):
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '<[<]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        returnval += '<[<]<+>>[>]'
 | 
				
			||||||
 | 
					        for var in variables[:idx]:
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '>' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '>[>]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        returnval += '>>-]<<'
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for var in reversed(variables[:idx]):
 | 
				
			||||||
 | 
					            if var.bytes >= 0:
 | 
				
			||||||
 | 
					                returnval += '<' * (var.bytes+1)
 | 
				
			||||||
 | 
					            elif var.bytes == -1:
 | 
				
			||||||
 | 
					                returnval += '<[<]'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                error()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					        returnval += '<[<]<[' + '<' * (offset-2) + '+' + '>' * (offset-2) + '-]' + '<' * (offset-2) + '[-'
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return returnval
 | 
				
			||||||
 | 
					    elif keyword == 'end':
 | 
				
			||||||
 | 
					        if len(line) != 2:
 | 
				
			||||||
 | 
					            error(f'End command requires 2 arguments (got {len(line)-1})')
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if line[1] == 'if':
 | 
				
			||||||
 | 
					            return ']'
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            error(f'Invalid argument for end: {line[1]}')
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        error(f'Invalid keyword: {line[0]}')
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/error.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/error.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					def error(message: str = "This is a bugged error message. Please report this issue."):
 | 
				
			||||||
 | 
					    exit(f"\033[91mError: \033[0m{message}")
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					def warn(message: str):
 | 
				
			||||||
 | 
					    print(f"\033[33mWarning: {message}\033[0m")
 | 
				
			||||||
							
								
								
									
										77
									
								
								src/main.py
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								src/main.py
									
									
									
									
									
								
							@@ -1,55 +1,40 @@
 | 
				
			|||||||
import string
 | 
					# Hopefully this code is actually decent lol
 | 
				
			||||||
 | 
					# Note: cells in bf are | 0 | inputs | 0 | variables |
 | 
				
			||||||
from sys import argv
 | 
					from sys import argv
 | 
				
			||||||
file = open(argv[1]).readlines();
 | 
					from preprocess import preprocess
 | 
				
			||||||
bfcode = ""
 | 
					from error import error
 | 
				
			||||||
def removeChar(str, char):
 | 
					from codegen import generateCode
 | 
				
			||||||
    ans = ""
 | 
					 | 
				
			||||||
    for i in str:
 | 
					 | 
				
			||||||
        if (i != char):
 | 
					 | 
				
			||||||
            ans += i
 | 
					 | 
				
			||||||
    return ans
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def removeEnd(string, num):
 | 
					if (len(argv) < 3):
 | 
				
			||||||
    ans = ""
 | 
					    print(f"Usage: python {argv[0]} file.basm file.bf")
 | 
				
			||||||
    for i in range(len(string)-1):
 | 
					    quit()
 | 
				
			||||||
        ans += string[i]
 | 
					 | 
				
			||||||
    return ans
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def ord2(char):
 | 
					# Check if correct argument count
 | 
				
			||||||
    if (len(char) == 1):
 | 
					if (len(argv) != 3) | (argv[1][-5:] != ".basm") | (argv[2][-3:] != ".bf"):
 | 
				
			||||||
        return ord(char)
 | 
					    print(f"Usage: python {argv[0]} file.basm file.bf")
 | 
				
			||||||
    elif (len(char == 0)):
 | 
					    quit()
 | 
				
			||||||
        return(0)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
for i in file:
 | 
					# Get contents of files
 | 
				
			||||||
    if (i.split(" ")[0] == "create"):
 | 
					try:
 | 
				
			||||||
        if (i[len(i)-1] == "\n"):
 | 
					    with open(argv[1], 'r') as file:
 | 
				
			||||||
            i = removeEnd(i, 1)
 | 
					        content : str = file.read()
 | 
				
			||||||
        bfcode += ">>>>>>>>>>>>[[>>]>>]"
 | 
					except FileNotFoundError:
 | 
				
			||||||
 | 
					    error(f"File '{argv[1]}' not found.")
 | 
				
			||||||
 | 
					    quit()
 | 
				
			||||||
 | 
					except IOError:
 | 
				
			||||||
 | 
					    error(f"Cannot read file '{argv[1]}'.")
 | 
				
			||||||
 | 
					    quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bytes = int(removeChar(i.split("*", 1)[1].split("=", 1)[0], " "))
 | 
					# Pre-processing of the basm file, from preprocess.py
 | 
				
			||||||
 | 
					code = preprocess(content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        a = i.split("=", 1)[1]
 | 
					offset: int = 5
 | 
				
			||||||
        if (a[0] == " "):
 | 
					bfcode: str = '>' * offset + ',[>,]<[<]' + '<' * (offset-1)
 | 
				
			||||||
            a = a.split(" ", 1)[1]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Get type
 | 
					open(argv[2], 'w').write('')
 | 
				
			||||||
        if ((a[0] == "\"") & (a[len(a)-1] == "\"")):
 | 
					 | 
				
			||||||
            type = "string"
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            type = "undefined"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (type == "string"):
 | 
					for line in code:
 | 
				
			||||||
            a = a.split("\"", 1)[1]
 | 
					    bfcode += generateCode(line, offset)
 | 
				
			||||||
            a = removeEnd(a, 1)
 | 
					 | 
				
			||||||
            for j in range(bytes):
 | 
					 | 
				
			||||||
                bfcode += "+++>"
 | 
					 | 
				
			||||||
                if (j < len(a)):
 | 
					 | 
				
			||||||
                    bfcode += "+" * ord(a[j]) + ">"
 | 
					 | 
				
			||||||
            bfcode += "<[[<<]<<]<<<<<<<<<"
 | 
					 | 
				
			||||||
        print(type)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        print("what the sigma")
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
with open(argv[2], "w") as file:
 | 
					with open(argv[2], 'w') as f:
 | 
				
			||||||
    file.write(bfcode)
 | 
					    print(f"{f.write(bfcode)} characters successfully compiled!")
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/preprocess.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/preprocess.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					def preprocess(code: str) -> list[list[str]]:
 | 
				
			||||||
 | 
					    token : str = ''
 | 
				
			||||||
 | 
					    tokenise : list[list[str]] = [[]]
 | 
				
			||||||
 | 
					    isString : bool = False
 | 
				
			||||||
 | 
					    isComment : bool = False
 | 
				
			||||||
 | 
					    for i in code:
 | 
				
			||||||
 | 
					        if i == '\n':
 | 
				
			||||||
 | 
					            isComment = False
 | 
				
			||||||
 | 
					            if token != '':
 | 
				
			||||||
 | 
					                tokenise[-1].append(token)
 | 
				
			||||||
 | 
					            if tokenise[-1]:
 | 
				
			||||||
 | 
					                tokenise.append([])
 | 
				
			||||||
 | 
					                token = ''
 | 
				
			||||||
 | 
					        elif isComment:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        elif i == '#':
 | 
				
			||||||
 | 
					            isComment = True
 | 
				
			||||||
 | 
					        elif (i != ' ') | isString:
 | 
				
			||||||
 | 
					            token += i
 | 
				
			||||||
 | 
					            if (i == '\"'):
 | 
				
			||||||
 | 
					                isString = not(isString)
 | 
				
			||||||
 | 
					        elif token != '':
 | 
				
			||||||
 | 
					            tokenise[-1].append(token)
 | 
				
			||||||
 | 
					            token = ''
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					    if token != '':
 | 
				
			||||||
 | 
					        tokenise[-1].append(token)
 | 
				
			||||||
 | 
					        token = ''
 | 
				
			||||||
 | 
					    if tokenise[-1] == []:
 | 
				
			||||||
 | 
					        tokenise = tokenise[:-1]
 | 
				
			||||||
 | 
					    return tokenise
 | 
				
			||||||
							
								
								
									
										30
									
								
								syntax.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								syntax.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					## Work in Progress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To create a comment, begin a line with a hash (#) symbol, like python.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Create a string: `string name value bytes`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Create a boolean: `bool name value`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Create an integer: `int name value`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Note**: A string of dynamic length can be created by setting the bytes to -1.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Print a string: `print name`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Increment an int: `inc name`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Check if two numbers are equal, and store the result in `cond`: `equal num1 num2 cond`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If statement: 
 | 
				
			||||||
 | 
					```py
 | 
				
			||||||
 | 
					if bool
 | 
				
			||||||
 | 
					    # Code here
 | 
				
			||||||
 | 
					end if
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example program (prints "Hello, World"):
 | 
				
			||||||
 | 
					```py
 | 
				
			||||||
 | 
					string var 13 "Hello, world!" # Or -1 bytes for a dynamic string
 | 
				
			||||||
 | 
					print var
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
@@ -1,3 +0,0 @@
 | 
				
			|||||||
create str *5 = "Hello, world!"
 | 
					 | 
				
			||||||
create str *5 = "World, hello!"
 | 
					 | 
				
			||||||
create str *6 = "Sigma!"
 | 
					 | 
				
			||||||
							
								
								
									
										13
									
								
								tests/test.basm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								tests/test.basm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					int num1 796
 | 
				
			||||||
 | 
					string str1 -1 "Hello, world!"
 | 
				
			||||||
 | 
					int num2 795
 | 
				
			||||||
 | 
					string str2 -1 "World, hello?"
 | 
				
			||||||
 | 
					equal num1 num2 cond
 | 
				
			||||||
 | 
					if cond
 | 
				
			||||||
 | 
					    print str1
 | 
				
			||||||
 | 
					end if
 | 
				
			||||||
 | 
					inc num2
 | 
				
			||||||
 | 
					equal num1 num2 cond2
 | 
				
			||||||
 | 
					if cond2
 | 
				
			||||||
 | 
					    print str2
 | 
				
			||||||
 | 
					end if
 | 
				
			||||||
		Reference in New Issue
	
	Block a user