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 import sys
from pprint import pprint from pprint import pprint
from . import semantic
from .logger import rootLogger, LogLevel from .logger import rootLogger, LogLevel
from .parser import Parser, ParsingError from .parser import Parser, ParsingError
from .tokenizer import Tokenizer, Tokens from .tokenizer import Tokenizer, Tokens
@ -23,7 +24,24 @@ def main():
parser = Parser(tokens) parser = Parser(tokens)
try: 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: except ParsingError as e:
e.location.source = data e.location.source = data
print(f"{e}\n{e.location.show_in_source()}", file=sys.stderr) 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 __future__ import annotations
from abc import abstractmethod import functools
from typing import Any from abc import abstractmethod, ABC
from typing import Any, Iterable
from beartype import beartype from beartype import beartype
from . import ir, semantic
from .logger import Logger from .logger import Logger
from .source import SourceLocation
logger = Logger(__name__) logger = Logger(__name__)
@ -57,6 +60,19 @@ class Node:
return result 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): class Literal(Node, ABC):
def __init__(self, location: SourceLocation, value: Any): 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]: def _pprint(self, depth: int | None, indent: str, _depth: int = 0) -> list[str]:
return [f"{indent}{repr(self)}"] 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): 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): def __init__(self, *values: Value):
self.values = values self.values = values
@ -82,14 +113,42 @@ class Sum(Node):
class Sub(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 self.values = values
def _values(self) -> Any | list[Node]: def _values(self) -> Any | list[Node]:
return self.values return [self.first_value] + list(self.values)
class Product(Node): 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): def __init__(self, *values: Value):
self.values = values self.values = values
@ -98,11 +157,31 @@ class Product(Node):
class Division(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 self.values = values
def _values(self) -> Any | list[Node]: def _values(self) -> Any | list[Node]:
return self.values return [self.first_value] + list(self.values)
BinaryOperation = Sum | Sub | Product | Division BinaryOperation = Sum | Sub | Product | Division
@ -122,6 +201,9 @@ class Integer(Literal):
class Expression(Node): class Expression(Node):
def intermediate_representation(self, context: semantic.Context) -> list[ir.IRItem]:
return self.node.intermediate_representation(context)
def __init__(self, node: Node): def __init__(self, node: Node):
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