104 lines
3.6 KiB
Python
104 lines
3.6 KiB
Python
"""
|
|
CAP, CodeGeneration, LinearCode API
|
|
Classes for a RiscV linear code.
|
|
"""
|
|
|
|
from typing import List
|
|
from Lib.Operands import (A0, Function, DataLocation)
|
|
from Lib.Statement import (
|
|
Instru3A, AbsoluteJump, ConditionalJump, Comment, Label
|
|
)
|
|
from Lib.RiscV import (mv, call)
|
|
from Lib.FunctionData import (FunctionData, _iter_statements, _print_code)
|
|
|
|
|
|
CodeStatement = Comment | Label | Instru3A | AbsoluteJump | ConditionalJump
|
|
|
|
|
|
class LinearCode:
|
|
"""
|
|
Representation of a RiscV program as a list of instructions.
|
|
|
|
:py:meth:`add_instruction` is repeatedly called in the codegen visitor
|
|
to build a complete list of RiscV instructions for the source program.
|
|
|
|
The :py:attr:`fdata` member variable contains some meta-information
|
|
on the program, for instance to allocate a new temporary.
|
|
See :py:class:`Lib.FunctionData.FunctionData`.
|
|
|
|
For debugging purposes, :py:meth:`print_code` allows to print
|
|
the RiscV program to a file.
|
|
"""
|
|
|
|
"""
|
|
The :py:attr:`fdata` member variable contains some meta-information
|
|
on the program, for instance to allocate a new temporary.
|
|
See :py:class:`Lib.FunctionData.FunctionData`.
|
|
"""
|
|
fdata: FunctionData
|
|
|
|
_listIns: List[CodeStatement]
|
|
|
|
def __init__(self, name: str):
|
|
self._listIns = []
|
|
self.fdata = FunctionData(name)
|
|
|
|
def add_instruction(self, i: CodeStatement) -> None:
|
|
"""
|
|
Utility function to add an instruction in the program.
|
|
|
|
See also :py:mod:`Lib.RiscV` to generate relevant instructions.
|
|
"""
|
|
self._listIns.append(i)
|
|
|
|
def iter_statements(self, f) -> None:
|
|
"""Iterate over instructions.
|
|
For each real instruction i (not label or comment), replace it
|
|
with the list of instructions given by f(i).
|
|
"""
|
|
new_list_ins = _iter_statements(self._listIns, f)
|
|
# TODO: we shoudn't need to split this assignment with intermediate
|
|
# variable new_list_ins, but at least pyright pyright 1.1.293
|
|
# raises an error here if we don't.
|
|
self._listIns = new_list_ins
|
|
|
|
def get_instructions(self) -> List[CodeStatement]:
|
|
"""Return the list of instructions of the program."""
|
|
return self._listIns
|
|
|
|
# each instruction has its own "add in list" version
|
|
def add_label(self, s: Label) -> None:
|
|
"""Add a label in the program."""
|
|
return self.add_instruction(s)
|
|
|
|
def add_comment(self, s: str) -> None:
|
|
"""Add a comment in the program."""
|
|
self.add_instruction(Comment(s))
|
|
|
|
def add_instruction_PRINTLN_INT(self, reg: DataLocation) -> None:
|
|
"""Print integer value, with newline. (see Expand)"""
|
|
# A print instruction generates the temp it prints.
|
|
self.add_instruction(mv(A0, reg))
|
|
self.add_instruction(call(Function('println_int')))
|
|
|
|
def __str__(self):
|
|
return '\n'.join(map(str, self._listIns))
|
|
|
|
def print_code(self, output, comment=None) -> None:
|
|
"""Outputs the RiscV program as text to a file at the given path."""
|
|
_print_code(self._listIns, self.fdata, output, init_label=None,
|
|
fin_label=None, fin_div0=True, comment=comment)
|
|
|
|
def print_dot(self, filename: str, DF=None, view=False) -> None: # pragma: no cover
|
|
"""Outputs the RiscV program as graph to a file at the given path."""
|
|
# import graphviz here so that students who don't have it can still work on lab4
|
|
from graphviz import Digraph
|
|
graph = Digraph()
|
|
# nodes
|
|
content = ""
|
|
for i in self._listIns:
|
|
content += str(i) + "\\l"
|
|
graph.node("Code", label=content, shape='rectangle')
|
|
# no edges
|
|
graph.render(filename, view=view)
|