-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
38 changed files
with
1,494 additions
and
517 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from base.ActivationRecord import ActivationRecord | ||
from base.ScopedSymbolTable import ScopedSymbolTable | ||
|
||
|
||
class ARNode: | ||
def __init__(self, scope): | ||
self.scope: ScopedSymbolTable = scope | ||
self.ar_records: list[ActivationRecord] = [] | ||
self.children: list[ARNode] = [] | ||
|
||
def __str__(self): | ||
return f'{self.scope.scope_name} {self.scope.scope_level} <- {self.scope.enclosing_scope.scope_name if self.scope.enclosing_scope else None}' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
from base.ActivationRecord import ActivationRecord | ||
from base.ARNode import ARNode | ||
|
||
|
||
class ARTree: | ||
def __init__(self): | ||
self.root: ARNode | ||
self._size: int = 0 | ||
|
||
def build_tree(self, scopes): | ||
""" | ||
Builds the tree from the list of scopes. The first scope in the list is | ||
built-in scope and the root of the tree. Its only child is second scope in the list | ||
- the global scope. Other scopes are children or ancestors of the global scope. It | ||
is guaranteed that that each scope is unique and that at least built-in and global | ||
scopes are present in the list. | ||
""" | ||
self.root = ARNode(scopes[0]) | ||
self._size = 1 | ||
|
||
for scope in scopes[1:]: | ||
node = ARNode(scope) | ||
parent = self._find_parent(scope, self.root) | ||
parent.children.append(node) | ||
self._size += 1 | ||
|
||
def _find_parent(self, scope, root: ARNode) -> ARNode: | ||
""" | ||
Finds the parent of the given scope. It is guaranteed that the scope has a parent. | ||
""" | ||
|
||
if scope.enclosing_scope == root.scope and scope.scope_level == root.scope.scope_level + 1: | ||
return root | ||
else: | ||
for child in root.children: | ||
node = self._find_parent(scope, child) | ||
if node: | ||
return node | ||
|
||
return ARNode(None) | ||
|
||
def _find_node(self, name: str, level: int, root: ARNode) -> ARNode: | ||
""" | ||
Finds the node with the given name and level. It is guaranteed that the node exists. | ||
""" | ||
if root.scope.scope_name == name and root.scope.scope_level == level: | ||
return root | ||
else: | ||
for child in root.children: | ||
node = self._find_node(name, level, child) | ||
if node: | ||
return node | ||
|
||
return ARNode(None) | ||
|
||
def find(self, name: str, level: int) -> list[ActivationRecord]: | ||
""" | ||
Finds the activation record with the given name and level. It is guaranteed that the | ||
record exists. | ||
""" | ||
node = self._find_node(name, level, self.root) | ||
return node.ar_records | ||
|
||
def push(self, AR: ActivationRecord) -> None: | ||
node = self._find_node(AR.scope_name, AR.nesting_level, self.root) | ||
node.ar_records.append(AR) | ||
|
||
def __str__(self): | ||
return '\n'.join([i.__str__() for i in self._bf_traverse(self.root)]) | ||
|
||
def preorder_traverse(self, root: ARNode) -> list[ARNode]: | ||
""" | ||
Performs a pre-order traversal of the tree. | ||
Returns a list of nodes in the order they were visited. | ||
""" | ||
nodes = [root] | ||
|
||
for child in root.children: | ||
nodes += self.preorder_traverse(child) | ||
|
||
return nodes | ||
|
||
def bf_traverse(self) -> list[ARNode]: | ||
return self._bf_traverse(self.root) | ||
|
||
def _bf_traverse(self, root: ARNode) -> list[ARNode]: | ||
""" | ||
Performs a breadth-first traversal of the tree. | ||
Returns a list of nodes in the order they were visited. | ||
""" | ||
nodes = [root] | ||
queue = [root] | ||
|
||
while queue: | ||
node = queue.pop(0) | ||
for child in node.children: | ||
nodes.append(child) | ||
queue.append(child) | ||
|
||
return nodes | ||
|
||
def __len__(self) -> int: | ||
return self._size | ||
|
||
@property | ||
def size(self) -> int: | ||
return self._size |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from enum import Enum | ||
|
||
|
||
class ARType(Enum): | ||
PROGRAM = 'PROGRAM' | ||
PROCEDURE = 'PROCEDURE' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
class ActivationRecord: | ||
def __init__(self, name, scope_name, type, nesting_level, execution_order, outer_scope): | ||
self.name = name | ||
self.scope_name = scope_name | ||
self.type = type | ||
self.nesting_level = nesting_level | ||
self.execution_order = execution_order | ||
self.members = {} | ||
self.outer_scope = outer_scope | ||
|
||
def __setitem__(self, key, value): | ||
self.members[key] = value | ||
|
||
def __getitem__(self, key): | ||
val = self.members.get(key) | ||
|
||
if not val: | ||
val = self.outer_scope[key] | ||
|
||
return val | ||
|
||
def __str__(self): | ||
lines = [ | ||
'{level}: {type} {name} (execution order: {execution_order})'.format( | ||
level=self.nesting_level, | ||
type=self.type.name, | ||
name=self.name, | ||
execution_order=self.execution_order, | ||
), | ||
] | ||
for name, val in self.members.items(): | ||
lines.append(f' {name:<20}: {val}') | ||
|
||
s = '\n'.join(lines) | ||
return s | ||
|
||
def __repr__(self): | ||
return self.__str__() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
class CallStack: | ||
def __init__(self): | ||
self._records = [] | ||
|
||
def push(self, ar): | ||
self._records.append(ar) | ||
|
||
def pop(self): | ||
return self._records.pop() | ||
|
||
def peek(self): | ||
return self._records[-1] | ||
|
||
def __len__(self): | ||
return len(self._records) | ||
|
||
@property | ||
def size(self): | ||
return self.__len__() | ||
|
||
def __str__(self): | ||
s = '\n'.join(repr(ar) for ar in reversed(self._records)) | ||
s = f'CALL STACK\n{s}\n' | ||
return s | ||
|
||
def __repr__(self): | ||
return self.__str__() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from enum import Enum | ||
|
||
|
||
class ErrorCode(Enum): | ||
UNEXPECTED_TOKEN = 'Unexpected token' | ||
ID_NOT_FOUND = 'Identifier not found' | ||
DUPLICATE_ID = 'Duplicate id found' | ||
WRONG_ARGUMENTS_NUMBER = 'Wrong number of arguments' | ||
MAX_RECURSION_DEPTH_REACHED = 'RecursionError' | ||
|
||
|
||
class Error(Exception): | ||
def __init__(self, error_code=None, token=None, message=None): | ||
self.error_code = error_code | ||
self.token = token | ||
self.message = f'{self.__class__.__name__}: {message}' | ||
|
||
def __str__(self): | ||
return self.message | ||
|
||
|
||
class LexerError(Error): | ||
pass | ||
|
||
|
||
class ParserError(Error): | ||
pass | ||
|
||
|
||
class SemanticError(Error): | ||
pass | ||
|
||
|
||
class InterpreterError(Error): | ||
pass |
Oops, something went wrong.