mirror of
https://github.com/irmen/prog8.git
synced 2024-12-11 04:50:05 +00:00
92 lines
3.7 KiB
Python
92 lines
3.7 KiB
Python
|
"""
|
||
|
Programming Language for 6502/6510 microprocessors, codename 'Sick'
|
||
|
This is the tinyvm stack based program generator.
|
||
|
|
||
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||
|
"""
|
||
|
|
||
|
# @todo
|
||
|
|
||
|
import os
|
||
|
import datetime
|
||
|
import pickle
|
||
|
from typing import BinaryIO, List, Tuple, Dict, Optional
|
||
|
from ..shared import CodeGenerationError, sanitycheck
|
||
|
from ...plyparse import Module, Block, Scope, VarDef, Expression, LiteralValue
|
||
|
from ...datatypes import VarType, DataType
|
||
|
import tinyvm.core
|
||
|
import tinyvm.program
|
||
|
|
||
|
|
||
|
class AssemblyGenerator:
|
||
|
def __init__(self, module: Module, enable_floats: bool) -> None:
|
||
|
self.module = module
|
||
|
self.floats_enabled = enable_floats
|
||
|
|
||
|
def generate(self, filename: str) -> None:
|
||
|
with open(filename+".pickle", "wb") as stream:
|
||
|
self._generate(stream)
|
||
|
|
||
|
def _generate(self, out: BinaryIO) -> None:
|
||
|
sanitycheck(self.module)
|
||
|
program = self.header()
|
||
|
program.blocks = self.blocks(self.module.nodes[0], None) # type: ignore
|
||
|
pickle.dump(program, out, pickle.HIGHEST_PROTOCOL)
|
||
|
|
||
|
def header(self) -> tinyvm.program.Program:
|
||
|
return tinyvm.program.Program([])
|
||
|
|
||
|
def blocks(self, scope: Scope, parentblock_vm: Optional[tinyvm.program.Block]) -> List[tinyvm.program.Block]:
|
||
|
blocks = []
|
||
|
for node in scope.nodes:
|
||
|
if isinstance(node, Block):
|
||
|
variables = self.make_vars(node)
|
||
|
labels, instructions = self.make_instructions(node)
|
||
|
vmblock = tinyvm.program.Block(node.name, parentblock_vm, variables, instructions, labels)
|
||
|
print(vmblock)
|
||
|
blocks.append(vmblock)
|
||
|
vmblock.blocks = self.blocks(node.nodes[0], vmblock) # type: ignore
|
||
|
return blocks
|
||
|
|
||
|
def make_vars(self, block: Block) -> List[tinyvm.program.Variable]:
|
||
|
variables = []
|
||
|
for vardef in block.all_nodes(VarDef):
|
||
|
assert isinstance(vardef, VarDef)
|
||
|
dtype = self.translate_datatype(vardef.datatype)
|
||
|
value = self.translate_value(vardef.value, dtype)
|
||
|
if vardef.vartype == VarType.CONST:
|
||
|
const = True
|
||
|
elif vardef.vartype == VarType.VAR:
|
||
|
const = False
|
||
|
else:
|
||
|
raise CodeGenerationError("unsupported vartype", vardef.vartype)
|
||
|
variables.append(tinyvm.program.Variable(vardef.name, dtype, value, const))
|
||
|
return variables
|
||
|
|
||
|
def make_instructions(self, block: Block) -> Tuple[Dict[str, tinyvm.program.Instruction], List[tinyvm.program.Instruction]]:
|
||
|
# returns a dict with the labels (named instruction pointers),
|
||
|
# and a list of the program instructions.
|
||
|
return {}, []
|
||
|
|
||
|
def translate_datatype(self, datatype: DataType) -> tinyvm.core.DataType:
|
||
|
table = {
|
||
|
DataType.BYTE: tinyvm.core.DataType.BYTE,
|
||
|
DataType.WORD: tinyvm.core.DataType.WORD,
|
||
|
DataType.FLOAT: tinyvm.core.DataType.FLOAT,
|
||
|
DataType.BYTEARRAY: tinyvm.core.DataType.ARRAY_BYTE,
|
||
|
DataType.WORDARRAY: tinyvm.core.DataType.ARRAY_WORD,
|
||
|
DataType.MATRIX: tinyvm.core.DataType.MATRIX_BYTE
|
||
|
}
|
||
|
dt = table.get(datatype, None)
|
||
|
if dt:
|
||
|
return dt
|
||
|
raise CodeGenerationError("unsupported datatype", datatype)
|
||
|
|
||
|
def translate_value(self, expr: Expression, dtypehint: Optional[tinyvm.core.DataType]) -> tinyvm.program.Value:
|
||
|
if isinstance(expr, LiteralValue):
|
||
|
dtype = dtypehint or tinyvm.core.DataType.guess_datatype_for(expr.value)
|
||
|
return tinyvm.program.Value(dtype, expr.value)
|
||
|
else:
|
||
|
raise CodeGenerationError("cannot yet generate value for expression node", expr)
|
||
|
|