From 59d33d53e80c58bb519826e8ab9bec636b313710 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Tue, 14 May 2024 23:39:34 +0200 Subject: [PATCH 01/31] Rename to avoid overload --- nand2tetris/projects/7/VMTranslator/src/parser/parser.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py index f879ded..53ed6f7 100644 --- a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py +++ b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py @@ -1,11 +1,11 @@ import importlib -dict_filepath = "nand2tetris/projects/7/VMTranslator/src/utils/dict/dict" -dict = importlib.import_module(dict_filepath.replace("/", ".")) +dicts_filepath = "nand2tetris/projects/7/VMTranslator/src/utils/dict/dict" +dicts = importlib.import_module(dicts_filepath.replace("/", ".")) -class Parser: +class parser: """ - Handles the parsing of a single .vm file. @@ -63,7 +63,6 @@ def advance(self) -> None: Returns ---- None - Function ---- Reads the next command from the input and makes it the current command. @@ -92,7 +91,7 @@ def commandType(self) -> str: """ try: - return dict.commandType[self.instruction[0]] + return dicts.commandType[self.instruction[0]] except: raise KeyError(f"Current command invalid: Cannot parse '{self.line.strip()}' on line {self.lineNo}.") From 56929d40846e586e6c38b7ce3de335716baf035a Mon Sep 17 00:00:00 2001 From: ATherkel Date: Tue, 14 May 2024 23:39:45 +0200 Subject: [PATCH 02/31] Initial codewriter work --- .../projects/7/VMTranslator/VMTranslator.py | 28 +++++++++++-------- .../VMTranslator/src/codewriter/codewriter.py | 10 ++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index 30a18d0..6cc9b70 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -5,22 +5,20 @@ #### ---- import ---- # https://stackoverflow.com/a/37867717/3560695 -import importlib.util -import sys +import importlib import re ## Import parser ## We have to use import_module since the path contains an illegal directory name (7). parser_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.parser.parser") +importlib.reload(parser_module) Parser = parser_module.parser writer_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.codewriter.codewriter") +importlib.reload(writer_module) codewriter = writer_module.codewriter - - - #### ---- main ---- #def main(): @@ -45,16 +43,22 @@ def main(filename): if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. continue print(f"---- Line {parser.lineNo} ----") - print(f"instruction = {parser.instruction}") - print(f"commandType() = {parser.commandType()}") - print(f"arg1() = {parser.arg1()}") - print(f"arg2() = {parser.arg2()}") + # print(f"instruction = {parser.instruction}") + # print(f"commandType() = {parser.commandType()}, type = {type(parser.commandType())}") + # print(f"arg1() = {parser.arg1()}") + # print(f"arg2() = {parser.arg2()}") + if parser.commandType() == "C_ARITHMETIC": # Write arithmetic from arithmetic.asm ... elif parser.commandType() in ["C_PUSH", "C_POP"]: - writer.writePushPop(parser.commandType(), parser.arg1(), parser.arg2()) + commandType = parser.commandType() + arg1 = parser.arg1() + arg2 = parser.arg2() +# return commandType + writer.writePushPop(commandType, arg1, arg2) + ... else: ... @@ -63,10 +67,10 @@ def main(filename): ## Testing filename = '/nand2tetris/projects/7/StackArithmetic/SimpleAdd/SimpleAdd.vm' - main(filename[1:]) - +1+1 +dict.commandType diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index d215886..b34ea1d 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -14,8 +14,9 @@ def writeArithmetic(command : str) -> None: Function Writes to the output file the assembly code that implements the given arithmetic command. """ + print(command) - def writePushPop(command : str, segment : str, index : int): + def writePushPop(command : str, segment : str, index : int, wtf): """ Arguments ---- @@ -28,12 +29,7 @@ def writePushPop(command : str, segment : str, index : int): where command is either C_PUSH or C_POP. """ # Write push and pop commands from push.asm and pop.asm - if parser.arg1().lower() == "constant": - print("constant.") - elif parser.arg1().lower == "static": - print("static.") - else: - print(parser.arg1()) + print(f"command = '{command}', segment = {segment}, index = {index}, wtf = {wtf}") def close(): From 6b7d18db1aad72ee8c6f590e8aab46e7a7063e42 Mon Sep 17 00:00:00 2001 From: Therkel Date: Tue, 14 May 2024 23:59:15 +0200 Subject: [PATCH 03/31] Update parser.py Attempt to fix object return --- nand2tetris/projects/7/VMTranslator/src/parser/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py index 53ed6f7..3549d94 100644 --- a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py +++ b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py @@ -89,9 +89,9 @@ def commandType(self) -> str: C_ARITHMETIC is returned for all the arithmetic/logical commands. """ - + command = self.instruction[0] try: - return dicts.commandType[self.instruction[0]] + return dicts.commandType[command] except: raise KeyError(f"Current command invalid: Cannot parse '{self.line.strip()}' on line {self.lineNo}.") From a919093408b7d568438ed00a77f4c863885ea465 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Wed, 15 May 2024 10:28:06 +0200 Subject: [PATCH 04/31] Clean up --- .../projects/7/VMTranslator/VMTranslator.py | 80 +------------------ 1 file changed, 1 insertion(+), 79 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index 6cc9b70..aff37c4 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -56,8 +56,7 @@ def main(filename): commandType = parser.commandType() arg1 = parser.arg1() arg2 = parser.arg2() -# return commandType - writer.writePushPop(commandType, arg1, arg2) + print(writer.writePushPop(commandType, arg1, arg2)) ... else: ... @@ -69,83 +68,6 @@ def main(filename): filename = '/nand2tetris/projects/7/StackArithmetic/SimpleAdd/SimpleAdd.vm' main(filename[1:]) -1+1 -dict.commandType - - - -## Below is probably redundant - - - - - - - -# https://chat.openai.com/share/40c7964c-0f2f-44d2-81c7-e88d6a1868a1 -def changeExtension(string : str, newExtension : str): - """ - """ - if not isinstance(string, str): - raise TypeError("Input must be a string") - if not isinstance(newExtension, str): - raise TypeError("Input must be a string") - - # Regex pattern to capture the base name and extension - # https://regex101.com/r/SkENd5/1 - regex = r"^(?P[^.].*\.)(?P\w+)$|(?P^.*$)" - - # Replace the extension with the new extension - new_string = re.sub( - regex, - lambda m: ( - m.group('base') + newExtension - if m.group('base') - else m.group('fullname') - ), - string) - - return new_string - - -def writelines(input_data : str | list, filename) -> None: - """ - Write the given string or list of strings to the specified file. - - Args: - input_data (str | list): The string or list of strings to write to the file. - filename (str): The name of the file to write to. - - Raises: - TypeError: If input_data is neither a string nor a list, or if filename is not a string. - ValueError: If filename is an empty string. - IOError: If there is an issue writing to the file. - - Returns: - None - """ - # Check input types - if not isinstance(input_data, (str, list)): - raise TypeError("Input data must be a string or a list of strings") - if not isinstance(filename, str): - raise TypeError("Filename must be a string") - - # Check filename is not empty - if not filename: - raise ValueError("Filename cannot be an empty string") - - # Open the file in write mode - try: - with open(filename, 'w') as file: - # Write data to the file - if isinstance(input_data, str): - file.write(input_data) - else: - file.writelines(input_data) - except IOError as e: - raise IOError("Error writing to file: " + str(e)) - - From db10a76c175dab82c31a3f9a7d4d133eaa8273cc Mon Sep 17 00:00:00 2001 From: ATherkel Date: Wed, 15 May 2024 10:28:17 +0200 Subject: [PATCH 05/31] Clean up --- .../7/VMTranslator/src/Archive/deprecated.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 nand2tetris/projects/7/VMTranslator/src/Archive/deprecated.py diff --git a/nand2tetris/projects/7/VMTranslator/src/Archive/deprecated.py b/nand2tetris/projects/7/VMTranslator/src/Archive/deprecated.py new file mode 100644 index 0000000..83a845a --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/Archive/deprecated.py @@ -0,0 +1,72 @@ + + +# https://chat.openai.com/share/40c7964c-0f2f-44d2-81c7-e88d6a1868a1 +def changeExtension(string : str, newExtension : str): + """ + """ + if not isinstance(string, str): + raise TypeError("Input must be a string") + if not isinstance(newExtension, str): + raise TypeError("Input must be a string") + + # Regex pattern to capture the base name and extension + # https://regex101.com/r/SkENd5/1 + regex = r"^(?P[^.].*\.)(?P\w+)$|(?P^.*$)" + + # Replace the extension with the new extension + new_string = re.sub( + regex, + lambda m: ( + m.group('base') + newExtension + if m.group('base') + else m.group('fullname') + ), + string) + + return new_string + + +def writelines(input_data : str | list, filename) -> None: + """ + Write the given string or list of strings to the specified file. + + Args: + input_data (str | list): The string or list of strings to write to the file. + filename (str): The name of the file to write to. + + Raises: + TypeError: If input_data is neither a string nor a list, or if filename is not a string. + ValueError: If filename is an empty string. + IOError: If there is an issue writing to the file. + + Returns: + None + """ + # Check input types + if not isinstance(input_data, (str, list)): + raise TypeError("Input data must be a string or a list of strings") + if not isinstance(filename, str): + raise TypeError("Filename must be a string") + + # Check filename is not empty + if not filename: + raise ValueError("Filename cannot be an empty string") + + # Open the file in write mode + try: + with open(filename, 'w') as file: + # Write data to the file + if isinstance(input_data, str): + file.write(input_data) + else: + file.writelines(input_data) + except IOError as e: + raise IOError("Error writing to file: " + str(e)) + + + + + + + + From df7ff277067e4a669a7d67e5c80735d0aed90c89 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Wed, 15 May 2024 10:28:29 +0200 Subject: [PATCH 06/31] Test --- nand2tetris/projects/7/VMTranslator/tests/test_path.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 nand2tetris/projects/7/VMTranslator/tests/test_path.py diff --git a/nand2tetris/projects/7/VMTranslator/tests/test_path.py b/nand2tetris/projects/7/VMTranslator/tests/test_path.py new file mode 100644 index 0000000..1d92730 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/tests/test_path.py @@ -0,0 +1,6 @@ + + + +import os + +print(os.getcwd()) \ No newline at end of file From 9e1f74f05d6350804c4bb7273c4a49e8143e50c3 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Wed, 15 May 2024 10:28:42 +0200 Subject: [PATCH 07/31] Corrected pointer --- .../projects/7/VMTranslator/src/utils/asm/pushSegment.asm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm index 58a418f..7caa1a2 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm @@ -6,8 +6,11 @@ // addr <- SegmentPointer + i @{index} D = A + +// Not used if segment is 'constant' @{segmentPointer} -D = D + M +A = D + M +D = M // RAM[SP] = RAM[addr] @SP From db4e6ed9c79410886f2a8eb8154a9c0ab4528bad Mon Sep 17 00:00:00 2001 From: ATherkel Date: Wed, 15 May 2024 10:28:56 +0200 Subject: [PATCH 08/31] Simplify --- nand2tetris/projects/7/VMTranslator/src/parser/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py index 3549d94..53ed6f7 100644 --- a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py +++ b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py @@ -89,9 +89,9 @@ def commandType(self) -> str: C_ARITHMETIC is returned for all the arithmetic/logical commands. """ - command = self.instruction[0] + try: - return dicts.commandType[command] + return dicts.commandType[self.instruction[0]] except: raise KeyError(f"Current command invalid: Cannot parse '{self.line.strip()}' on line {self.lineNo}.") From 028a81ab40e931ee52f799bd373b41157fd5baac Mon Sep 17 00:00:00 2001 From: ATherkel Date: Wed, 15 May 2024 10:29:11 +0200 Subject: [PATCH 09/31] writePushPop work --- .../VMTranslator/src/codewriter/codewriter.py | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index b34ea1d..7a0d9fb 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -1,4 +1,14 @@ +import importlib + +parser_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.parser.parser") +importlib.reload(parser_module) + +dicts_filepath = "nand2tetris/projects/7/VMTranslator/src/utils/dict/dict" +dicts = importlib.import_module(dicts_filepath.replace("/", ".")) + + + class codewriter: """ writes the assembly code that implements the parsed command. """ @@ -6,7 +16,7 @@ class codewriter: def __init__(self, file) -> None: self.file = file ## functions need to be able to grab file. - + @staticmethod def writeArithmetic(command : str) -> None: """ Arguments @@ -16,27 +26,30 @@ def writeArithmetic(command : str) -> None: """ print(command) - def writePushPop(command : str, segment : str, index : int, wtf): + @staticmethod + def writePushPop(command : str, segment : str, index : int): """ Arguments ---- - command (C_PUSH or C_POP) - segment : str - index : int + command : ('C_PUSH' or 'C_POP') + segment : constant, local etc. + index : pointer number in the segment Function ---- Writes to the output file the assembly code that implements the given command, where command is either C_PUSH or C_POP. """ + newline = '\n' + + segmentPointer = dicts.segment[segment] + # Write push and pop commands from push.asm and pop.asm - print(f"command = '{command}', segment = {segment}, index = {index}, wtf = {wtf}") - - def close(): - """ - Function - ---- - Closes the output file. + if command == "C_PUSH": + with open("nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm", 'r') as asm: + lines = f"{asm.read().replace(newline, '')}".format(**locals()) + print(lines) - Likely redundant for my method. - """ + + + \ No newline at end of file From 7a9707b59025135bf822a55a6b553573176f3306 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:05:35 +0200 Subject: [PATCH 10/31] Ignore created asm files --- nand2tetris/projects/7/StackArithmetic/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 nand2tetris/projects/7/StackArithmetic/.gitignore diff --git a/nand2tetris/projects/7/StackArithmetic/.gitignore b/nand2tetris/projects/7/StackArithmetic/.gitignore new file mode 100644 index 0000000..7bdbb1b --- /dev/null +++ b/nand2tetris/projects/7/StackArithmetic/.gitignore @@ -0,0 +1 @@ +*.asm \ No newline at end of file From 08d80b0cb68d3f9ea07992b953478a1d6b06b4bd Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:06:33 +0200 Subject: [PATCH 11/31] Test with constant --- .../projects/7/VMTranslator/src/utils/asm/pushSegment.asm | 6 +++--- nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm index 7caa1a2..a1eda4a 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm @@ -8,9 +8,9 @@ D = A // Not used if segment is 'constant' -@{segmentPointer} -A = D + M -D = M +//@{segmentPointer} +//A = D + M +//D = M // RAM[SP] = RAM[addr] @SP diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py index 6407e95..b9951e5 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py +++ b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py @@ -25,5 +25,5 @@ "argument" : "ARG", "THIS" : "THIS", "THAT" : "THAT", - + "constant" : "CONST", } From e8e44c9800e65b50566fd5c80823232bdbf54405 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:24:15 +0200 Subject: [PATCH 12/31] Create pushConstant.asm --- .../src/utils/asm/pushConstant.asm | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm new file mode 100644 index 0000000..a1eda4a --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushConstant.asm @@ -0,0 +1,22 @@ +// ---- push {segment} {index} ---- + +// addr = segment + i, *SP = *addr, SP++ + + +// addr <- SegmentPointer + i +@{index} +D = A + +// Not used if segment is 'constant' +//@{segmentPointer} +//A = D + M +//D = M + +// RAM[SP] = RAM[addr] +@SP +A = M +M = D + +// SP++ +@SP +M = M + 1 \ No newline at end of file From d33c54dc0a3c92687f3a16c0d00ddabd73909407 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:24:32 +0200 Subject: [PATCH 13/31] Correct pushSegment.asm --- .../projects/7/VMTranslator/src/utils/asm/pushSegment.asm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm index a1eda4a..7caa1a2 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm @@ -8,9 +8,9 @@ D = A // Not used if segment is 'constant' -//@{segmentPointer} -//A = D + M -//D = M +@{segmentPointer} +A = D + M +D = M // RAM[SP] = RAM[addr] @SP From 413199202fd1f28f9a247650993e3800f24211b5 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:25:22 +0200 Subject: [PATCH 14/31] Update segment in dict.py --- .../projects/7/VMTranslator/src/utils/dict/dict.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py index b9951e5..332e804 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py +++ b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py @@ -23,7 +23,14 @@ segment = { "local" : "LCL", "argument" : "ARG", - "THIS" : "THIS", - "THAT" : "THAT", - "constant" : "CONST", + "this" : "THIS", + "that" : "THAT", + + "temp" : 5, } + +""" + "R13" : 13, + "R14" : 14, + "constant" : "CONST", +""" \ No newline at end of file From e9fc652f35c37a38aaf8f4c4a2a0b3403838aeb4 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:26:12 +0200 Subject: [PATCH 15/31] Move class call inside `main` --- .../projects/7/VMTranslator/VMTranslator.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index aff37c4..da78fbd 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -11,12 +11,10 @@ ## Import parser ## We have to use import_module since the path contains an illegal directory name (7). parser_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.parser.parser") -importlib.reload(parser_module) -Parser = parser_module.parser + writer_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.codewriter.codewriter") -importlib.reload(writer_module) -codewriter = writer_module.codewriter + #### ---- main ---- @@ -33,13 +31,16 @@ def main(filename): filename_write = re.sub(regex, r"\1\2.asm", filename) + Parser = parser_module.parser + codewriter = writer_module.codewriter + with open(filename, 'r') as file, open(filename_write, "w") as file_write: parser = Parser(file) writer = codewriter(file_write) while parser.hasMoreCommands(): ## As long as file has more lines, do: parser.advance() ## Go to the next line in the file. - parser.getinstruction() ## sets parser.instruction to current instruction + parser.getVMinstruction() ## sets parser.instruction to current instruction if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. continue print(f"---- Line {parser.lineNo} ----") @@ -63,6 +64,8 @@ def main(filename): +importlib.reload(parser_module) +importlib.reload(writer_module) ## Testing filename = '/nand2tetris/projects/7/StackArithmetic/SimpleAdd/SimpleAdd.vm' @@ -87,6 +90,5 @@ def main(filename): - From 2d67dda9b0315513fc2c2ce4c59dec9a3d0fd7dc Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:26:57 +0200 Subject: [PATCH 16/31] Update codewriter.writePushPop --- .../VMTranslator/src/codewriter/codewriter.py | 32 ++++++++++++++++--- .../7/VMTranslator/src/parser/parser.py | 22 ++++++++++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index 7a0d9fb..2eee5b3 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -41,15 +41,39 @@ def writePushPop(command : str, segment : str, index : int): """ newline = '\n' + Parser = parser_module.parser + + ## Used in some of the .asm templates. + ## Contains Hack name convention for segments, e.g. local is "LCL" segmentPointer = dicts.segment[segment] # Write push and pop commands from push.asm and pop.asm + + ## First handle 'pointer' logic translation to THIS/THAT + if segment == "pointer": + segment = ["THIS", "THAT"][index] if command == "C_PUSH": - with open("nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm", 'r') as asm: - lines = f"{asm.read().replace(newline, '')}".format(**locals()) - print(lines) - + if segment == "constant": + asm_location = "pushConstant.asm" + elif segment in ["local", "argument", "this", "that"]: + asm_location = "pushSegment.asm" + elif segment == "static": + asm_location = "pushStatic.asm" + elif segment == "temp": + ... + elif segment == "pointer": + ... + with open("nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm", 'r') as asm: + parser = Parser(asm) + + while parser.hasMoreCommands(): + parser.advance() + parser.getinstruction() + if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. + continue + return lines + \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py index 53ed6f7..d80cd9d 100644 --- a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py +++ b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py @@ -16,10 +16,11 @@ class parser: """ def __init__(self, file) -> None: - self.line = None ## Initialize line. - self.lineNo = 0 ## Initialize line number. - self.instruction = None ## Initialize instruction. - self.file = file ## functions need to be able to grab file. + self.line = None ## Initialize line. + self.lineNo = 0 ## Initialize line number. + self.instruction = None ## Initialize instruction. + self.VMinstruction = None ## Initialize VM instruction (list) + self.file = file ## functions need to be able to grab file. def peek(self) -> str: @@ -143,7 +144,18 @@ def arg2(self) -> int: return ValueError(f"arg2() called on invalid command type: '{self.commandType()}'") def getinstruction(self): - self.instruction = self.line.split("//")[0].strip().split() + """ + Remove everything after the comment token (//) + """ + self.instruction = self.line.split("//")[0].strip() + + def getVMinstruction(self): + """ + Splits the instruction into a list of objects + """ + self.instruction = self.getinstruction() + print(self.instruction) + self.VMinstruction = self.instruction.split() From 40ed9bc17cd58fdb2311972c1b85712773dc290a Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 10:48:27 +0200 Subject: [PATCH 17/31] Segment handling --- .../7/VMTranslator/src/codewriter/codewriter.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index 2eee5b3..9c856ca 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -51,19 +51,20 @@ def writePushPop(command : str, segment : str, index : int): ## First handle 'pointer' logic translation to THIS/THAT if segment == "pointer": - segment = ["THIS", "THAT"][index] + segment = ["this", "that"][index] ## e.g. 'push pointer 0' means 'push this' + index = 0 ## Silently 'push THIS' means 'push THIS 0' if command == "C_PUSH": if segment == "constant": asm_location = "pushConstant.asm" - elif segment in ["local", "argument", "this", "that"]: + elif segment in ["local", "argument", "this", "that", "temp"]: asm_location = "pushSegment.asm" elif segment == "static": asm_location = "pushStatic.asm" - elif segment == "temp": - ... - elif segment == "pointer": - ... + # elif segment == "temp": + # ... + # elif segment == "pointer": ## Handled above + # ... with open("nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm", 'r') as asm: parser = Parser(asm) From 195655bde2b9eddd79787c19a4953702a0f75781 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 11:57:36 +0200 Subject: [PATCH 18/31] VMinstruction correction. --- .../projects/7/VMTranslator/src/parser/parser.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py index d80cd9d..65fd7bf 100644 --- a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py +++ b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py @@ -92,7 +92,7 @@ def commandType(self) -> str: """ try: - return dicts.commandType[self.instruction[0]] + return dicts.commandType[self.VMinstruction[0]] except: raise KeyError(f"Current command invalid: Cannot parse '{self.line.strip()}' on line {self.lineNo}.") @@ -114,11 +114,11 @@ def arg1(self) -> str: Should not be called if the current command is C_RETURN. """ if self.commandType() == "C_ARITHMETIC": - out = self.instruction[0] + out = self.VMinstruction[0] elif self.commandType() == "C_RETURN": return ValueError(f"arg1() called on invalid command type: '{self.commandType()}'") else: - out = self.instruction[1] + out = self.VMinstruction[1] return out @@ -139,7 +139,7 @@ def arg2(self) -> int: C_PUSH, C_POP, C_FUNCTION or C_CALL. """ if self.commandType() in ["C_PUSH", "C_POP", "C_FUNCTION", "C_CALL"]: - return int(self.instruction[2]) + return int(self.VMinstruction[2]) else: return ValueError(f"arg2() called on invalid command type: '{self.commandType()}'") @@ -153,8 +153,9 @@ def getVMinstruction(self): """ Splits the instruction into a list of objects """ - self.instruction = self.getinstruction() - print(self.instruction) + + # Call getinstruction to ensure instruction has been retrieved. + self.getinstruction() self.VMinstruction = self.instruction.split() From 10ed3142775c6524204c4a0c3d1e321f061d1cc0 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 11:58:15 +0200 Subject: [PATCH 19/31] VMinstruction correction --- nand2tetris/projects/7/VMTranslator/VMTranslator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index da78fbd..fc525c2 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -40,9 +40,11 @@ def main(filename): while parser.hasMoreCommands(): ## As long as file has more lines, do: parser.advance() ## Go to the next line in the file. - parser.getVMinstruction() ## sets parser.instruction to current instruction + parser.getinstruction() if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. continue + parser.getVMinstruction() ## sets parser.VMinstruction to current instruction + print(f"---- Line {parser.lineNo} ----") # print(f"instruction = {parser.instruction}") # print(f"commandType() = {parser.commandType()}, type = {type(parser.commandType())}") From 5a5d3160a685a75f1e8d91880fca8bca03c894a3 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:04:42 +0200 Subject: [PATCH 20/31] Update writePushPop --- .../VMTranslator/src/codewriter/codewriter.py | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index 9c856ca..ef420aa 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -15,19 +15,30 @@ class codewriter: def __init__(self, file) -> None: self.file = file ## functions need to be able to grab file. + self.newline = '\n' + + self.Parser = parser_module.parser @staticmethod - def writeArithmetic(command : str) -> None: + def writeArithmetic(command : str, ) -> None: """ Arguments command (string) Function Writes to the output file the assembly code that implements the given arithmetic command. """ - print(command) - @staticmethod - def writePushPop(command : str, segment : str, index : int): + ## Unary or binary operation: + arity = dicts.arithmetic[command] + + with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_{arity}", 'r') as asm: + ... + + + + + + def writePushPop(self, command : str, segment : str, index : int): """ Arguments ---- @@ -39,15 +50,6 @@ def writePushPop(command : str, segment : str, index : int): Writes to the output file the assembly code that implements the given command, where command is either C_PUSH or C_POP. """ - newline = '\n' - - Parser = parser_module.parser - - ## Used in some of the .asm templates. - ## Contains Hack name convention for segments, e.g. local is "LCL" - segmentPointer = dicts.segment[segment] - - # Write push and pop commands from push.asm and pop.asm ## First handle 'pointer' logic translation to THIS/THAT if segment == "pointer": @@ -58,6 +60,10 @@ def writePushPop(command : str, segment : str, index : int): if segment == "constant": asm_location = "pushConstant.asm" elif segment in ["local", "argument", "this", "that", "temp"]: + ## Used in some of the .asm templates. + ## Contains Hack name convention for segments, e.g. local is "LCL" + segmentPointer = dicts.segment[segment] + asm_location = "pushSegment.asm" elif segment == "static": asm_location = "pushStatic.asm" @@ -66,15 +72,24 @@ def writePushPop(command : str, segment : str, index : int): # elif segment == "pointer": ## Handled above # ... - with open("nand2tetris/projects/7/VMTranslator/src/utils/asm/pushSegment.asm", 'r') as asm: - parser = Parser(asm) + lines = [] ## Initialize lines. + + + with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/{asm_location}", 'r') as asm: + parser = self.Parser(asm) while parser.hasMoreCommands(): parser.advance() parser.getinstruction() if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. continue + + line = parser.instruction.format(**locals()) + lines.append(line) + # if not parser.hasMoreCommands(): + # lines.append(self.newline) return lines + \ No newline at end of file From e43f12e6b434ba4f74bb054839999d5f4a939f85 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:43:30 +0200 Subject: [PATCH 21/31] Create arithmetic asm files --- .../src/utils/asm/arithmetic_1.asm | 8 ++++++ .../src/utils/asm/arithmetic_2.asm | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm create mode 100644 nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm new file mode 100644 index 0000000..e05404c --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm @@ -0,0 +1,8 @@ +// ---- unary action ---- +// *SP = {unary}*SP + +@SP +A = M + +M = {unary}M + diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm new file mode 100644 index 0000000..b2a9751 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm @@ -0,0 +1,28 @@ +// ---- x {action} y ---- +// D = *SP +// SP-- +// *SP = *SP {action} D +// SP++ + + + + +// D = *SP +@SP +A = M +D = M + +// SP-- +@SP +M = M - 1 + +// Arithmetic operation +// E.g. add: *SP = *SP + D +// E.g. eq: D = *SP - D, D; JEQ +A = M +{action} + +// SP++ +@SP +M = M + 1 + From bfe12df3b5b784ab5ea27cbf45cf63fded87abd0 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:44:00 +0200 Subject: [PATCH 22/31] Update VMTranslator --- .../projects/7/VMTranslator/VMTranslator.py | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index fc525c2..d6b0503 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -45,32 +45,42 @@ def main(filename): continue parser.getVMinstruction() ## sets parser.VMinstruction to current instruction - print(f"---- Line {parser.lineNo} ----") + # print(f"---- Line {parser.lineNo} ----") # print(f"instruction = {parser.instruction}") # print(f"commandType() = {parser.commandType()}, type = {type(parser.commandType())}") # print(f"arg1() = {parser.arg1()}") # print(f"arg2() = {parser.arg2()}") + commandType = parser.commandType() if parser.commandType() == "C_ARITHMETIC": # Write arithmetic from arithmetic.asm - ... + arg1 = parser.arg1() + lines = writer.writeArithmetic(commandType, arg1) + elif parser.commandType() in ["C_PUSH", "C_POP"]: - commandType = parser.commandType() arg1 = parser.arg1() arg2 = parser.arg2() - print(writer.writePushPop(commandType, arg1, arg2)) - ... + lines = writer.writePushPop(commandType, arg1, arg2) else: ... + + ## lines is now the full .asm script. Write to output asm file. + file_write.write(f'// {parser.instruction}\n') + for line in lines: + file_write.write(f'{line}\n') + + -importlib.reload(parser_module) -importlib.reload(writer_module) ## Testing filename = '/nand2tetris/projects/7/StackArithmetic/SimpleAdd/SimpleAdd.vm' + +importlib.reload(parser_module) +importlib.reload(writer_module) + main(filename[1:]) From 3a484e7edd9125bc34744c32362b8b8a450bd70f Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:46:13 +0200 Subject: [PATCH 23/31] Update VMTranslator --- nand2tetris/projects/7/VMTranslator/VMTranslator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index d6b0503..74543d8 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -56,7 +56,7 @@ def main(filename): if parser.commandType() == "C_ARITHMETIC": # Write arithmetic from arithmetic.asm arg1 = parser.arg1() - lines = writer.writeArithmetic(commandType, arg1) + lines = writer.writeArithmetic(arg1) elif parser.commandType() in ["C_PUSH", "C_POP"]: arg1 = parser.arg1() From 9377149073234ef5bd16f1abc3e71c3e864b49e1 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:46:42 +0200 Subject: [PATCH 24/31] Update codewriter, create processCommands --- .../VMTranslator/src/codewriter/codewriter.py | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index ef420aa..c019d68 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -19,8 +19,11 @@ def __init__(self, file) -> None: self.Parser = parser_module.parser - @staticmethod - def writeArithmetic(command : str, ) -> None: + ## Used in some of the .asm templates. + self.action = None + self.segmentPointer = None + + def writeArithmetic(self, command : str) -> None: """ Arguments command (string) @@ -30,9 +33,17 @@ def writeArithmetic(command : str, ) -> None: ## Unary or binary operation: arity = dicts.arithmetic[command] + print(arity) + + ## action is used in some of the .asm templates. + ## Contains Hack code for the arithmetic operations + self.action = dicts.arithmetic_action[command] - with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_{arity}", 'r') as asm: - ... + with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_{arity}.asm", 'r') as asm: + parser = self.Parser(asm) + + lines = self.processCommands(parser) + return lines @@ -62,7 +73,7 @@ def writePushPop(self, command : str, segment : str, index : int): elif segment in ["local", "argument", "this", "that", "temp"]: ## Used in some of the .asm templates. ## Contains Hack name convention for segments, e.g. local is "LCL" - segmentPointer = dicts.segment[segment] + self.segmentPointer = dicts.segment[segment] asm_location = "pushSegment.asm" elif segment == "static": @@ -78,18 +89,32 @@ def writePushPop(self, command : str, segment : str, index : int): with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/{asm_location}", 'r') as asm: parser = self.Parser(asm) - while parser.hasMoreCommands(): - parser.advance() - parser.getinstruction() - if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. - continue - - line = parser.instruction.format(**locals()) - lines.append(line) - # if not parser.hasMoreCommands(): - # lines.append(self.newline) + lines = self.processCommands(parser) return lines + def processCommands(self, parser): + """ + Arguments + ---- + parser : parser object + Function + ---- + Process commands using the provided parser object until there are no more commands. + """ + lines = [] + while parser.hasMoreCommands(): + parser.advance() + parser.getinstruction() + if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. + continue + + print(parser.instruction) + + line = parser.instruction.format(**locals()) + lines.append(line) + + return lines + \ No newline at end of file From ff10599ba12605e1540d7282d59014a35fa019ae Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:46:53 +0200 Subject: [PATCH 25/31] Update dict.py --- .../7/VMTranslator/src/utils/dict/dict.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py index 332e804..8bb6128 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py +++ b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py @@ -29,6 +29,33 @@ "temp" : 5, } +arithmetic = { + "neg" : 1, + "not" : 1, + + "add" : 2, + "sub" : 2, + "eq" : 2, + "gt" : 2, + "lt" : 2, + "and" : 2, + "or" : 2, +} + +arithmetic_action = { + "neg" : "M = -M", + "not" : "M = !M", + + "add" : "M = M + D", + "sub" : "M = M - D", + "eq" : "D = M - D \\n D; JEQ", + "gt" : "D = M - D \\n D; JGT", + "lt" : "D = M - D \\n D; JLT", + "and" : "M = M & D", + "or" : "M = M | D", +} + + """ "R13" : 13, "R14" : 14, From c239eec5936ad4cf91e5d521a77858c61609e621 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:47:15 +0200 Subject: [PATCH 26/31] Create test_arithmetic.py --- .../7/VMTranslator/tests/test_arithmetic.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py diff --git a/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py b/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py new file mode 100644 index 0000000..b88eef3 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py @@ -0,0 +1,15 @@ + + +import importlib + + + +writer_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.codewriter.codewriter") + +importlib.reload(writer_module) + + +testwriter = writer_module.codewriter("") + + +testwriter.writeArithmetic("add") From 250356d6f0e713f8ce61e15fa4e58afaf4378b07 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Thu, 16 May 2024 13:47:29 +0200 Subject: [PATCH 27/31] Update test_arithmetic.py --- nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py b/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py index b88eef3..b0708c9 100644 --- a/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py +++ b/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py @@ -13,3 +13,7 @@ testwriter.writeArithmetic("add") + +testwriter.writePushPop("push", "constant", 7) + + From bea7c019eac77affcf6e0e43b3654442466be19a Mon Sep 17 00:00:00 2001 From: ATherkel Date: Fri, 17 May 2024 22:15:29 +0200 Subject: [PATCH 28/31] Change for Python debugger --- .../projects/7/VMTranslator/VMTranslator.py | 21 ++++++++++--------- .../projects/7/VMTranslator/__init__.py | 1 + .../VMTranslator/src/codewriter/codewriter.py | 16 ++++++++------ .../7/VMTranslator/src/parser/parser.py | 8 +++---- 4 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 nand2tetris/projects/7/VMTranslator/__init__.py diff --git a/nand2tetris/projects/7/VMTranslator/VMTranslator.py b/nand2tetris/projects/7/VMTranslator/VMTranslator.py index 74543d8..4ec9a24 100644 --- a/nand2tetris/projects/7/VMTranslator/VMTranslator.py +++ b/nand2tetris/projects/7/VMTranslator/VMTranslator.py @@ -5,16 +5,15 @@ #### ---- import ---- # https://stackoverflow.com/a/37867717/3560695 -import importlib import re ## Import parser ## We have to use import_module since the path contains an illegal directory name (7). -parser_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.parser.parser") - - -writer_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.codewriter.codewriter") +# parser_module = importlib.import_module("src.parser.parser") +import src.parser.parser as p +# writer_module = importlib.import_module("src.codewriter.codewriter") +import src.codewriter.codewriter as cw #### ---- main ---- @@ -31,8 +30,8 @@ def main(filename): filename_write = re.sub(regex, r"\1\2.asm", filename) - Parser = parser_module.parser - codewriter = writer_module.codewriter + Parser = p.parser + codewriter = cw.codewriter with open(filename, 'r') as file, open(filename_write, "w") as file_write: parser = Parser(file) @@ -74,12 +73,14 @@ def main(filename): +import importlib ## Testing -filename = '/nand2tetris/projects/7/StackArithmetic/SimpleAdd/SimpleAdd.vm' +filename = '.../StackArithmetic/SimpleAdd/SimpleAdd.vm' +filename = '.../StackArithmetic/Stacktest/Stacktest.vm' -importlib.reload(parser_module) -importlib.reload(writer_module) +importlib.reload(p) +importlib.reload(cw) main(filename[1:]) diff --git a/nand2tetris/projects/7/VMTranslator/__init__.py b/nand2tetris/projects/7/VMTranslator/__init__.py new file mode 100644 index 0000000..d65e1a9 --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/__init__.py @@ -0,0 +1 @@ +__package__ = '' \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index c019d68..39577b7 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -1,13 +1,17 @@ -import importlib +import sys +# import importlib -parser_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.parser.parser") -importlib.reload(parser_module) +# sys.path.append("C:/Users/Bruger/OneDrive/Dokumenter/GitHub/BuildComputer/nand2tetris/projects/7/VMTranslator") -dicts_filepath = "nand2tetris/projects/7/VMTranslator/src/utils/dict/dict" -dicts = importlib.import_module(dicts_filepath.replace("/", ".")) +# parser_module = importlib.import_module("src.parser.parser") +import src.parser.parser as parser_module +# importlib.reload(parser_module) +# dicts_filepath = "nand2tetris/projects/7/VMTranslator/src/utils/dict/dict" +# dicts = importlib.import_module(dicts_filepath.replace("/", ".")) +import src.utils.dict.dict as dicts class codewriter: """ writes the assembly code that implements the parsed command. """ @@ -86,7 +90,7 @@ def writePushPop(self, command : str, segment : str, index : int): lines = [] ## Initialize lines. - with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/{asm_location}", 'r') as asm: + with open(f"src/utils/asm/{asm_location}", 'r') as asm: parser = self.Parser(asm) lines = self.processCommands(parser) diff --git a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py index 65fd7bf..5ef8266 100644 --- a/nand2tetris/projects/7/VMTranslator/src/parser/parser.py +++ b/nand2tetris/projects/7/VMTranslator/src/parser/parser.py @@ -1,9 +1,9 @@ -import importlib - -dicts_filepath = "nand2tetris/projects/7/VMTranslator/src/utils/dict/dict" -dicts = importlib.import_module(dicts_filepath.replace("/", ".")) +# import importlib +# dicts_filepath = "src/utils/dict/dict" +#dicts = importlib.import_module(dicts_filepath.replace("/", ".")) +import src.utils.dict.dict as dicts class parser: """ From 4ae24d8176705ce869644e11e598f9cf26d134bf Mon Sep 17 00:00:00 2001 From: ATherkel Date: Fri, 17 May 2024 22:15:48 +0200 Subject: [PATCH 29/31] Python debugger --- .vscode/launch.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5a3b1fe --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}\\nand2tetris\\projects\\7\\VMTranslator", + "env": { + "PYTHONPATH": "${workspaceFolder}\\nand2tetris\\projects\\7\\VMTranslator" + } + }, + { + "name": "Python Debugger: Python File", + "type": "debugpy", + "request": "launch", + "program": "${file}" + } + ] +} \ No newline at end of file From d3a9feb60938f69a2d5009a53d79dfa0ff975916 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Fri, 17 May 2024 22:16:52 +0200 Subject: [PATCH 30/31] Fix vwriteArithmetic --- .../VMTranslator/src/codewriter/codewriter.py | 42 +++++++++++++------ .../src/utils/asm/arithmetic_1.asm | 12 ++++-- .../src/utils/asm/arithmetic_2.asm | 6 ++- .../7/VMTranslator/src/utils/dict/dict.py | 29 ++++++++++--- 4 files changed, 65 insertions(+), 24 deletions(-) diff --git a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py index 39577b7..0d983fb 100644 --- a/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py +++ b/nand2tetris/projects/7/VMTranslator/src/codewriter/codewriter.py @@ -22,10 +22,13 @@ def __init__(self, file) -> None: self.newline = '\n' self.Parser = parser_module.parser + + ## Initialize number of times arithmetic has been called + self.arithmeticNo = 0 ## Used in some of the .asm templates. - self.action = None - self.segmentPointer = None + self.segment = None + self.index = None def writeArithmetic(self, command : str) -> None: """ @@ -37,16 +40,20 @@ def writeArithmetic(self, command : str) -> None: ## Unary or binary operation: arity = dicts.arithmetic[command] - print(arity) + ## action is used in some of the .asm templates. ## Contains Hack code for the arithmetic operations - self.action = dicts.arithmetic_action[command] + action = dicts.arithmetic_action[command] + if command in ["eq", "lt", "gt"]: + action = dicts.compare_action.format(**locals()) - with open(f"nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_{arity}.asm", 'r') as asm: + with open(f"src/utils/asm/arithmetic_{arity}.asm", 'r') as asm: parser = self.Parser(asm) - lines = self.processCommands(parser) + lines = self.processCommands(parser, action = action) + + self.arithmeticNo += 1 return lines @@ -66,6 +73,8 @@ def writePushPop(self, command : str, segment : str, index : int): where command is either C_PUSH or C_POP. """ + segmentPointer = None ## Initialize - passed to self.processCommands but not always used. + ## First handle 'pointer' logic translation to THIS/THAT if segment == "pointer": segment = ["this", "that"][index] ## e.g. 'push pointer 0' means 'push this' @@ -77,8 +86,7 @@ def writePushPop(self, command : str, segment : str, index : int): elif segment in ["local", "argument", "this", "that", "temp"]: ## Used in some of the .asm templates. ## Contains Hack name convention for segments, e.g. local is "LCL" - self.segmentPointer = dicts.segment[segment] - + segmentPointer = dicts.segment[segment] asm_location = "pushSegment.asm" elif segment == "static": asm_location = "pushStatic.asm" @@ -86,6 +94,10 @@ def writePushPop(self, command : str, segment : str, index : int): # ... # elif segment == "pointer": ## Handled above # ... + # elif command == "C_POP": + # ... + else: + raise KeyError(f"Unexpected command '{command}' in writePushPop (should be 'C_PUSH' or 'C_POP')") lines = [] ## Initialize lines. @@ -93,10 +105,10 @@ def writePushPop(self, command : str, segment : str, index : int): with open(f"src/utils/asm/{asm_location}", 'r') as asm: parser = self.Parser(asm) - lines = self.processCommands(parser) + lines = self.processCommands(parser, segment = segment, segmentPointer = segmentPointer, index = index) return lines - def processCommands(self, parser): + def processCommands(self, parser, **kwargs): """ Arguments ---- @@ -112,9 +124,13 @@ def processCommands(self, parser): if not parser.instruction: ## If instruction is blank, skip. Line consisted only of a comment. continue - print(parser.instruction) - - line = parser.instruction.format(**locals()) + ## Replace any {} in the input file with its value, sent to this function through **kwargs. + ## Important that the arguments are named. E.g. + ## segment = 'local' + ## processCommands(..., segment = segment) + ## processCommands(..., segment = 'local') + line = parser.instruction.format(**kwargs) + lines.append(line) return lines diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm index e05404c..7704f7e 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_1.asm @@ -1,8 +1,12 @@ // ---- unary action ---- -// *SP = {unary}*SP - +// SP-- +// *SP = {action}*SP +// SP++ @SP -A = M +M = M - 1 -M = {unary}M +A = M +M = {action}M +@SP +M = M + 1 \ No newline at end of file diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm index b2a9751..9c2cdbf 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm +++ b/nand2tetris/projects/7/VMTranslator/src/utils/asm/arithmetic_2.asm @@ -1,14 +1,16 @@ // ---- x {action} y ---- +// SP-- // D = *SP // SP-- // *SP = *SP {action} D // SP++ - +// SP-- +@SP +M = M - 1 // D = *SP -@SP A = M D = M diff --git a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py index 8bb6128..930f176 100644 --- a/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py +++ b/nand2tetris/projects/7/VMTranslator/src/utils/dict/dict.py @@ -43,18 +43,37 @@ } arithmetic_action = { - "neg" : "M = -M", - "not" : "M = !M", + "neg" : "-", # M = -M + "not" : "!", # M = !M "add" : "M = M + D", "sub" : "M = M - D", - "eq" : "D = M - D \\n D; JEQ", - "gt" : "D = M - D \\n D; JGT", - "lt" : "D = M - D \\n D; JLT", + "eq" : "JEQ", + "gt" : "JGT", + "lt" : "JLT", "and" : "M = M & D", "or" : "M = M | D", } +compare_action = """ +D = M - D +@TRUE{self.arithmeticNo} +D; {action} +D = 0 +@SP +A = M +M = D +@CONTINUE{self.arithmeticNo} +0; JMP +(TRUE{self.arithmeticNo}) +D = -1 +@SP +A = M +M = D +(CONTINUE{self.arithmeticNo}) +""".strip() + + """ "R13" : 13, From 582e054fd1897fb0e82816ea1384348f95179f91 Mon Sep 17 00:00:00 2001 From: ATherkel Date: Fri, 17 May 2024 22:17:12 +0200 Subject: [PATCH 31/31] Create test scripts --- .../projects/7/VMTranslator/tests/conftest.py | 0 .../7/VMTranslator/tests/test_arithmetic.py | 18 ++++++++++-------- .../7/VMTranslator/tests/test_writePushPop.py | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 nand2tetris/projects/7/VMTranslator/tests/conftest.py create mode 100644 nand2tetris/projects/7/VMTranslator/tests/test_writePushPop.py diff --git a/nand2tetris/projects/7/VMTranslator/tests/conftest.py b/nand2tetris/projects/7/VMTranslator/tests/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py b/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py index b0708c9..5c690e7 100644 --- a/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py +++ b/nand2tetris/projects/7/VMTranslator/tests/test_arithmetic.py @@ -1,19 +1,21 @@ -import importlib +# import importlib -writer_module = importlib.import_module("nand2tetris.projects.7.VMTranslator.src.codewriter.codewriter") +# writer_module = importlib.import_module("src.codewriter.codewriter") +from src.codewriter import codewriter as cw +# importlib.reload(cw) -importlib.reload(writer_module) +# importlib.reload(cw) +testwriter = cw.codewriter("") -testwriter = writer_module.codewriter("") +print("---- eq ----") +print(testwriter.writeArithmetic("lt")) - -testwriter.writeArithmetic("add") - -testwriter.writePushPop("push", "constant", 7) +# print("---- push local 7 ----") +# testwriter.writePushPop("C_PUSH", "constant", 7) diff --git a/nand2tetris/projects/7/VMTranslator/tests/test_writePushPop.py b/nand2tetris/projects/7/VMTranslator/tests/test_writePushPop.py new file mode 100644 index 0000000..dd67e7d --- /dev/null +++ b/nand2tetris/projects/7/VMTranslator/tests/test_writePushPop.py @@ -0,0 +1,17 @@ + + + + +# import importlib + +# writer_module = importlib.import_module("src.codewriter.codewriter") +from src.codewriter import codewriter as cw +# importlib.reload(cw) + + +testwriter = cw.codewriter("") + +print("---- push local 7 ----") +print(testwriter.writePushPop("C_PUSH", "static", 7)) + +