ir+semantic: init intermediate representation generation
This commit is contained in:
parent
caffa92c1e
commit
4bc481ed54
4 changed files with 257 additions and 7 deletions
|
|
@ -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
141
compiler/ir.py
Normal 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}"
|
||||||
|
|
@ -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
9
compiler/semantic.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .logger import Logger
|
||||||
|
|
||||||
|
logger = Logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Context:
|
||||||
|
pass
|
||||||
Loading…
Add table
Add a link
Reference in a new issue