242 lines
7.8 KiB
Python
242 lines
7.8 KiB
Python
|
|
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]}')
|