ir+semantic: init intermediate representation generation

This commit is contained in:
Antoine Viallon 2023-05-08 23:14:53 +02:00
parent caffa92c1e
commit 4bc481ed54
Signed by: aviallon
GPG key ID: D126B13AB555E16F
4 changed files with 257 additions and 7 deletions

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import sys
from pprint import pprint
from . import semantic
from .logger import rootLogger, LogLevel
from .parser import Parser, ParsingError
from .tokenizer import Tokenizer, Tokens
@ -23,7 +24,24 @@ def main():
parser = Parser(tokens)
try:
parser.parse().pprint(depth=3)
ast = parser.parse()
ast.pprint(depth=10)
context = semantic.Context()
intermediate_representation = ast.intermediate_representation(context=context)
messages = []
for ir_item in intermediate_representation:
ir_item.location.source = data
prefix = f"{str(ir_item.location) + ':':<30}"
source_info = ir_item.location.source_substring.splitlines(keepends=False)
messages += [f"# {prefix} {source_info.pop(0)}"]
while len(source_info) > 0:
messages += [f"# {' ' * len(prefix)} {source_info.pop(0)}"]
messages += [f"{repr(ir_item)}\n"]
print("\n".join(messages))
except ParsingError as e:
e.location.source = data
print(f"{e}\n{e.location.show_in_source()}", file=sys.stderr)

141
compiler/ir.py Normal file
View file

@ -0,0 +1,141 @@
from __future__ import annotations
import abc
from abc import abstractmethod
from beartype import beartype
from .logger import Logger
from .source import SourceLocation
logger = Logger(__name__)
class IRItem:
def __init__(self, location: SourceLocation):
self.location = location
@abstractmethod
def codegen(self) -> str:
raise NotImplementedError(f"Please override {self.__class__.__name__}.{__name__}")
@abstractmethod
def destination(self) -> IRValue:
raise NotImplementedError(f"Please override {self.__class__.__name__}.{__name__}")
def __repr__(self):
return f"{self.codegen()}"
class IRAction(IRItem, abc.ABC):
pass
class IRValue(IRItem, abc.ABC):
def destination(self) -> IRValue:
return self
class IRMove(IRAction):
@beartype
def __init__(self, location: SourceLocation, dest: IRRegister, source: IRValue):
super().__init__(location)
self.dest = dest
self.source = source
def destination(self) -> IRValue:
return self.dest
def codegen(self) -> str:
return f"MOVE {self.source} -> {self.dest}"
class IRImmediate(IRValue):
@beartype
def __init__(self, location: SourceLocation, value: int | float | str):
super().__init__(location)
self.value = value
def codegen(self):
return f"{self.value}"
class IRRegister(IRValue):
register_id = 0
def __init__(self, location: SourceLocation):
super().__init__(location)
self.id = IRRegister.register_id
IRRegister.register_id += 1
def codegen(self):
return f"%r{self.id}"
class IRAdd(IRAction):
@beartype
def __init__(self, location: SourceLocation, dest: IRRegister, *values: IRValue):
super().__init__(location)
assert all(isinstance(v, IRValue) for v in values)
self.values = values
self.dest = dest
def destination(self) -> IRValue:
return self.dest
def codegen(self) -> str:
values = [repr(value) for value in self.values]
return f"ADD {', '.join(values)} -> {self.dest}"
class IRMul(IRAction):
@beartype
def __init__(self, location: SourceLocation, dest: IRRegister, *values: IRValue):
super().__init__(location)
assert all(isinstance(v, IRValue) for v in values)
self.values = values
self.dest = dest
def destination(self) -> IRValue:
return self.dest
def codegen(self) -> str:
values = [repr(value) for value in self.values]
return f"MUL {', '.join(values)} -> {self.dest}"
class IRNegation(IRAction):
@beartype
def __init__(self, location: SourceLocation, dest: IRRegister, source: IRValue):
super().__init__(location)
self.source = source
self.dest = dest
def destination(self) -> IRValue:
return self.dest
def codegen(self) -> str:
return f"NEG {self.source} -> {self.dest}"
class IRInvert(IRAction):
@beartype
def __init__(self, location: SourceLocation, dest: IRRegister, source: IRValue):
super().__init__(location)
self.source = source
self.dest = dest
def destination(self) -> IRValue:
return self.dest
def codegen(self) -> str:
return f"INVERT {self.source} -> {self.dest}"

View file

@ -1,11 +1,14 @@
from __future__ import annotations
from abc import abstractmethod
from typing import Any
import functools
from abc import abstractmethod, ABC
from typing import Any, Iterable
from beartype import beartype
from . import ir, semantic
from .logger import Logger
from .source import SourceLocation
logger = Logger(__name__)
@ -57,6 +60,19 @@ class Node:
return result
@abstractmethod
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
raise NotImplementedError(f"Please implement {self.__class__.__name__}.{__name__}")
@staticmethod
def _prepare_sources_ir(result: list[ir.IRAction],
context: semantic.Context, values: Iterable[Value]) -> list[ir.IRValue]:
vals = [value.intermediate_representation(context) for value in values]
for value in vals:
result += value
return [value[-1].destination() for value in vals]
class Literal(Node, ABC):
def __init__(self, location: SourceLocation, value: Any):
@ -72,8 +88,23 @@ class Literal(Node, ABC):
def _pprint(self, depth: int | None, indent: str, _depth: int = 0) -> list[str]:
return [f"{indent}{repr(self)}"]
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
dest = ir.IRRegister(location=self.location())
immediate = ir.IRImmediate(location=self.location(), value=self.value)
result = [ir.IRMove(location=self.location(), dest=dest, source=immediate)]
return result
class Sum(Node):
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
result: list[ir.IRAction] = []
values_results = Node._prepare_sources_ir(result=result, context=context, values=self.values)
dest = ir.IRRegister(location=self.location())
result += [ir.IRAdd(self.location(), dest, *values_results)]
return result
def __init__(self, *values: Value):
self.values = values
@ -82,14 +113,42 @@ class Sum(Node):
class Sub(Node):
def __init__(self, *values: Value):
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
result: list[ir.IRAction] = []
first_val = self.first_value.intermediate_representation(context)
result += first_val
values_results = Node._prepare_sources_ir(result=result, context=context, values=self.values)
for i, value_result in enumerate(values_results):
d = ir.IRRegister(location=self.location())
result += [ir.IRNegation(location=self.location(), dest=d, source=value_result)]
values_results[i] = result[-1].destination()
values_results += [first_val[-1].destination()]
dest = ir.IRRegister(location=self.location())
result += [ir.IRAdd(self.location(), dest, *values_results)]
return result
def __init__(self, first_value: Value, *values: Value):
self.first_value = first_value
self.values = values
def _values(self) -> Any | list[Node]:
return self.values
return [self.first_value] + list(self.values)
class Product(Node):
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
result: list[ir.IRAction] = []
values_results = Node._prepare_sources_ir(result=result, context=context, values=self.values)
dest = ir.IRRegister(location=self.location())
result += [ir.IRMul(self.location(), dest, *values_results)]
return result
def __init__(self, *values: Value):
self.values = values
@ -98,11 +157,31 @@ class Product(Node):
class Division(Node):
def __init__(self, *values: Value):
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
result: list[ir.IRAction] = []
first_val = self.first_value.intermediate_representation(context)
result += first_val
values_results = Node._prepare_sources_ir(result=result, context=context, values=self.values)
for i, value_result in enumerate(values_results):
d = ir.IRRegister(location=self.location())
result += [ir.IRInvert(location=self.location(), dest=d, source=value_result)]
values_results[i] = result[-1].destination()
values_results += [first_val[-1].destination()]
dest = ir.IRRegister(location=self.location())
result += [ir.IRMul(self.location(), dest, *values_results)]
return result
def __init__(self, first_value: Value, *values: Value):
self.first_value = first_value
self.values = values
def _values(self) -> Any | list[Node]:
return self.values
return [self.first_value] + list(self.values)
BinaryOperation = Sum | Sub | Product | Division
@ -122,6 +201,9 @@ class Integer(Literal):
class Expression(Node):
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
return self.node.intermediate_representation(context)
def __init__(self, node: Node):
self.node = node

9
compiler/semantic.py Normal file
View file

@ -0,0 +1,9 @@
from __future__ import annotations
from .logger import Logger
logger = Logger(__name__)
class Context:
pass