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) + '>' 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': warn('Increment not correctly implemented yet, do not use this command.') returnval = '>' * offset + '[>]' idx = getIndex(line[1]) 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]): print(var.bytes) if var.bytes >= 0: returnval += '<' * (var.bytes+1) elif var.bytes == -1: returnval += '<[<]' else: error() returnval += '<[<]' + '<' * (offset-1) return returnval else: error(f'Invalid keyword: {line[0]}')