Failed attempt, just for reference
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
src/__pycache__
|
||||
test.bf
|
||||
tests/test.basm
|
||||
207
src/compiler.py
Normal file
207
src/compiler.py
Normal file
@@ -0,0 +1,207 @@
|
||||
import error as err
|
||||
from enum import Enum
|
||||
import sys
|
||||
|
||||
# Note: Layout of cells is as follows
|
||||
# [0] [input...] [0] [data start]
|
||||
# ptr_address is relative to the first cell of data
|
||||
|
||||
def compile(code: list[list[str]]):
|
||||
returnval = '>,[>,]>'
|
||||
used_bytes = 0
|
||||
ptr_address = 0
|
||||
|
||||
class Types(Enum):
|
||||
Bool = 'Boolean'
|
||||
Char = 'Character'
|
||||
Int = 'Integer'
|
||||
|
||||
types = {
|
||||
'bool': Types.Bool,
|
||||
'char': Types.Char,
|
||||
'int': Types.Int
|
||||
}
|
||||
|
||||
bytes = {
|
||||
Types.Bool: 1,
|
||||
Types.Char: 1,
|
||||
Types.Int: 4,
|
||||
}
|
||||
|
||||
class Variable:
|
||||
def __init__(self, name: str, dimensions: int, type: Types, address: int, malloc: list[int]):
|
||||
nonlocal used_bytes
|
||||
self.address = address
|
||||
self.malloc = malloc
|
||||
self.name = name
|
||||
self.dimensions = dimensions
|
||||
self.type = type
|
||||
used_bytes += malloc[0]
|
||||
# If the type is li2 int, then malloc might be [4, 100, 1000]
|
||||
# i.e. List has 1000 bytes, which stores lists that have 100 bytes, which stores 4-byte ints
|
||||
def __repr__(self):
|
||||
return f'({self.name}, {self.dimensions}, {self.type.value}, {hex(self.address)}, {self.malloc})'
|
||||
|
||||
class Constant:
|
||||
def __init__(self, name: str, type: Types):
|
||||
self.name = name
|
||||
self.type = type
|
||||
def __repr__(self):
|
||||
return f'({self.name}, {self.type.value})'
|
||||
|
||||
var: dict[str, Variable] = {
|
||||
|
||||
}
|
||||
|
||||
# Actually start code
|
||||
for line in code:
|
||||
# Check keyword (first token)
|
||||
keyword = line[0]
|
||||
args = len(line)
|
||||
if keyword[0] + keyword[1] == 'li':
|
||||
if len(line) < 3:
|
||||
sys.exit(err.error('li command syntax is "li(dim) <type: bool, char, int> <name> <bytes>"'))
|
||||
# Check dimensions
|
||||
try:
|
||||
dim = int(keyword[2::])
|
||||
except ValueError:
|
||||
exit(err.error(f'Invalid type: {keyword}'))
|
||||
|
||||
malloc: list[int] = []
|
||||
i = 0
|
||||
try:
|
||||
for i in range(dim):
|
||||
malloc.append(int(line[3+i]))
|
||||
malloc.append(bytes[types[line[1]]])
|
||||
except ValueError:
|
||||
sys.exit(err.error(f'Invalid byte allocation for variable: {line[3+i]} (bytes)'))
|
||||
except IndexError:
|
||||
sys.exit(err.error(f'Not enough byte declarations for variable {line[2]}'))
|
||||
except KeyError:
|
||||
sys.exit(err.error(f'Invalid type: {line[1]}'))
|
||||
|
||||
# Create new variable
|
||||
var[line[2]] = Variable(line[2], dim, types[line[1]], used_bytes, malloc)
|
||||
elif keyword == 'ptr':
|
||||
match line[1]:
|
||||
case 'mv':
|
||||
if len(line) < 3:
|
||||
sys.exit(err.error('ptr mv requires variable name or int'))
|
||||
target: str | int = line[2]
|
||||
try:
|
||||
target = int(target)
|
||||
except ValueError:
|
||||
try:
|
||||
vartarget = var[target]
|
||||
target = vartarget.address
|
||||
i = 0
|
||||
try:
|
||||
for i in range(vartarget.dimensions):
|
||||
target += vartarget.malloc[i+1] * int(line[3+i])
|
||||
except IndexError:
|
||||
sys.exit(err.error(f'ptr mv requires the same number of list indexes as dimensions (got {i})'))
|
||||
except ValueError:
|
||||
sys.exit(err.error(f'ptr mv: Expected list index, got {list[3+i]}'))
|
||||
except KeyError:
|
||||
sys.exit(err.error(f'ptr mv requires variable name or int (got {target})'))
|
||||
else:
|
||||
pass
|
||||
# Currently, target points to the start of the variable
|
||||
# For lists, we may want the start of a specific item
|
||||
|
||||
# Move pointer
|
||||
if ptr_address < target:
|
||||
returnval += '>' * (target - ptr_address)
|
||||
elif ptr_address > target:
|
||||
returnval += '<' * (ptr_address - target)
|
||||
ptr_address = target
|
||||
case 'add':
|
||||
if len(line) < 3:
|
||||
sys.exit(err.error('ptr add requires int'))
|
||||
|
||||
try:
|
||||
target = int(line[2])
|
||||
except ValueError:
|
||||
sys.exit(err.error(f'ptr add: Expected int, got {line[2]}'))
|
||||
|
||||
if target > 0:
|
||||
ptr_address += target
|
||||
returnval += '>' * target
|
||||
elif target < 0:
|
||||
ptr_address -= target
|
||||
returnval += '<' * target
|
||||
case 'subtract':
|
||||
if len(line) < 3:
|
||||
sys.exit(err.error('ptr subtract requires int'))
|
||||
|
||||
try:
|
||||
target = int(line[2])
|
||||
except ValueError:
|
||||
sys.exit(err.error(f'ptr subtract: Expected int, got {line[2]}'))
|
||||
|
||||
if target > 0:
|
||||
ptr_address -= target
|
||||
returnval += '<' * target
|
||||
elif target < 0:
|
||||
ptr_address += target
|
||||
returnval += '>' * target
|
||||
case 'back':
|
||||
if len(line) != 2:
|
||||
sys.exit(err.error(f'ptr back does not take additional arguments (got {line[2:]})'))
|
||||
case _:
|
||||
sys.exit(err.error(f'Expected pointer action, got {line[1]}'))
|
||||
elif keyword == 'set':
|
||||
# Get variable
|
||||
try:
|
||||
vartarget = var[line[1]]
|
||||
except KeyError:
|
||||
sys.exit(err.error(f'set: Expected var, got {line[1]}'))
|
||||
|
||||
if args != 3 + vartarget.dimensions:
|
||||
sys.exit(err.error('set syntax: set <var> <list index(s)> <value>'))
|
||||
|
||||
# Target cell for ptr is var.address + line[2] * var.malloc[0] + line[3] * var.malloc[1] + ...
|
||||
target = vartarget.address
|
||||
for i in range(vartarget.dimensions):
|
||||
try:
|
||||
target += int(line[i+2]) * vartarget.malloc[i+1]
|
||||
except ValueError:
|
||||
sys.exit(f'set: Expected list index, got {line[i+2]}')
|
||||
|
||||
# Move pointer
|
||||
if ptr_address < target:
|
||||
returnval += '>' * (target - ptr_address)
|
||||
elif ptr_address > target:
|
||||
returnval += '<' * (ptr_address - target)
|
||||
ptr_address = target
|
||||
|
||||
# Do stuff based on type
|
||||
match vartarget.type:
|
||||
case Types.Char:
|
||||
returnval += '[-]' + '+' * ord(line[-1])
|
||||
case _:
|
||||
sys.exit(err.error(f'set: {vartarget.type.value} type not implemented yet'))
|
||||
elif keyword == 'setbyte':
|
||||
if len(line) < 2:
|
||||
sys.exit(err.error('setbyte command requires two arguments'))
|
||||
try:
|
||||
returnval += '[-]' + '+' * int(line[1])
|
||||
except ValueError:
|
||||
try:
|
||||
returnval += '[-]' + '+' * ord(line[1])
|
||||
except TypeError:
|
||||
sys.exit(err.error(f'setbyte: Expected int or char, got {line[1]}'))
|
||||
elif keyword == 'print':
|
||||
try:
|
||||
type = types[line[1]]
|
||||
except KeyError:
|
||||
sys.exit(err.error(f'print: Invalid type: {line[1]}'))
|
||||
|
||||
if type == Types.Char:
|
||||
returnval += '.'
|
||||
else:
|
||||
sys.exit(err.error(f'print: {line[1]} not implemented'))
|
||||
else:
|
||||
sys.exit(err.error(f'Invalid command: {keyword}'))
|
||||
|
||||
return returnval
|
||||
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."):
|
||||
return f"\033[91mError: \033[0m{message}"
|
||||
|
||||
def warn(message: str):
|
||||
return f"\033[33mWarning: {message}\033[0m"
|
||||
33
src/lexer.py
Normal file
33
src/lexer.py
Normal file
@@ -0,0 +1,33 @@
|
||||
def tokenise(code: str) -> list[list[str]]:
|
||||
token: str = ''
|
||||
tokens: list[list[str]] = [[]]
|
||||
|
||||
isString = False
|
||||
isComment = False
|
||||
for char in code + ' ':
|
||||
if isString and char != ('\''):
|
||||
token += char
|
||||
elif isComment:
|
||||
if char == '\n':
|
||||
isComment = False
|
||||
else:
|
||||
match char:
|
||||
case ' ' | '\n':
|
||||
if token:
|
||||
tokens[-1].append(token)
|
||||
token = ''
|
||||
case '\'':
|
||||
isString = not isString
|
||||
case '#':
|
||||
isComment = True
|
||||
case ';':
|
||||
if token:
|
||||
tokens[-1].append(token)
|
||||
tokens.append([])
|
||||
token = ''
|
||||
case _:
|
||||
token += char
|
||||
|
||||
if not tokens[-1]:
|
||||
tokens.pop()
|
||||
return tokens
|
||||
22
src/main.py
Normal file
22
src/main.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import sys
|
||||
import lexer
|
||||
import compiler
|
||||
import error as err
|
||||
|
||||
def main(argc: int, argv: list[str]):
|
||||
if argc < 3:
|
||||
return f'Usage: python {argv[0]} (filename) (writefile) (flags)'
|
||||
|
||||
try:
|
||||
with open(argv[1], 'r') as file:
|
||||
content = file.read()
|
||||
except FileNotFoundError:
|
||||
return err.error(f'File {argv[1]} not found.')
|
||||
|
||||
tokens = lexer.tokenise(content)
|
||||
with open(argv[2], 'w') as f:
|
||||
f.write(compiler.compile(tokens))
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(len(sys.argv), sys.argv))
|
||||
Reference in New Issue
Block a user