From 51c5a3efbac0b195f619b821b9dd68be1fb9d918 Mon Sep 17 00:00:00 2001 From: Daniel Cujba Date: Fri, 2 Apr 2021 21:06:06 +0300 Subject: [PATCH] General Improvements --- Main.py | 64 ++++++++++++++++++++++++++++----------------------- TestFile.asm | 23 ++++++++++++++++++ TestFile.hack | 20 ++++++++++++++++ ToDoList | 10 ++++---- 4 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 TestFile.hack diff --git a/Main.py b/Main.py index 5ee2c03..5c9b137 100644 --- a/Main.py +++ b/Main.py @@ -1,35 +1,35 @@ class ParserModule: def parse_file(self,file_name): + #Reads the content of a file, deletes the comments and white space, + #labels each line base on the command type and separates it into usefull chunks assembly_file=open(file_name,"r") segmented_file=[] for line in assembly_file: - if len(line)>1: - command=[None,None] - if "//" in line: - line=line[:line.find("//")] - if line =="": - continue - line = line.strip() - if "(" in line: - command[0]="L" - command[1]=line.strip("()") - elif "@" in line: - command[0]="A" - command[1]=line.strip("@") - else: - command[0]="C" - c_command=[None,None,None] - start=0 - end=len(line) - if "=" in line: - c_command[0]=line.split("=")[0] - start=line.index("=")+1 - if ";" in line: - c_command[2]=line.split(";")[1] - end = line.index(";") - c_command[1]=line[start:end] - command[1]=c_command - segmented_file.append(command) + command=[None,None] + line=line[:line.find("//")] + if line =="": + continue + line = line.strip() + if "(" in line: + command[0]="L" + command[1]=line.strip("()") + elif "@" in line: + command[0]="A" + command[1]=line.strip("@") + else: + command[0]="C" + c_command=[None,None,None] + start=0 + end=len(line) + if "=" in line: + c_command[0]=line.split("=")[0] + start=line.index("=")+1 + if ";" in line: + c_command[2]=line.split(";")[1] + end = line.index(";") + c_command[1]=line[start:end] + command[1]=c_command + segmented_file.append(command) assembly_file.close() return segmented_file @@ -37,8 +37,9 @@ class SymbolTableModule: def __init__(self): self.c_commands=[{None:"000","M":"001","D":"010","MD":"011","A":"100","AM":"101","AD":"110","AMD":"111"},{"0":"0101010","1":"0111111","-1":"0111010","D":"0001100","A":"0110000","!D":"0001101","!A":"0110001","-D":"0001111","-A":"0110011","D+1":"0011111","A+1":"0110111","D-1":"0001110","A-1":"0110010","D+A":"0000010","D-A":"0010011","A-D":"0000111","D&A":"0000000","D|A":"0010101","M":"1110000","!M":"1110001","-M":"1110011","M+1":"1110111","M-1":"1110010","D+M":"1000010","D-M":"1010011","M-D":"1000111","D&M":"1000000","D|M":"1010101"},{None:"000","JGT":"001","JEG":"010","JGE":"011","JLT":"100","JNE":"101","JLE":"110","JMP":"111"}] self.a_commands={"SP":"0000000000000000","LCL":"0000000000000001","ARG":"0000000000000010","THIS":"0000000000000011","THAT":"0000000000000100","R0":"0000000000000000","R1":"0000000000000001","R2":"0000000000000010","R3":"0000000000000011","R4":"0000000000000100","R5":"0000000000000101","R6":"0000000000000110","R7":"0000000000000111","R8":"0000000000001000","R9":"0000000000001001","R10":"0000000000001010","R11":"0000000000001011","R12":"0000000000001100","R13":"0000000000001101","R14":"0000000000001110","R15":"0000000000001111","SCREEN":"0100000000000000","KBD":"0110000000000000"} - self.counter=1024 + self.counter=16 def translate_l_commands(self,assembly_array): + #Maps each symbol label to a certain place in ROM line_idx=0 for command in assembly_array: if not command[0] == "L": @@ -47,6 +48,7 @@ class SymbolTableModule: self.a_commands[command[1]]=self.decimal_to_binary(line_idx) def translate_a_commands(self,assembly_array): + #Maps each symbol label to a certain place in RAM for command in assembly_array: if command[0] == "A" and not self.a_commands.get(command[1]): if not command[1].isdecimal(): @@ -57,6 +59,7 @@ class SymbolTableModule: def check_command(self,command_array): + #Returns the equivalent machine code for the assembly command command_type,command=command_array if command_type == "A": return self.a_commands.get(command) @@ -65,6 +68,7 @@ class SymbolTableModule: return None def decimal_to_binary(self,value): + #Transforms a decimal value into a 16-bit binary number binary_power=16 binary_array=["0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"] while value > 0: @@ -79,6 +83,8 @@ class Assembler: self.parser=ParserModule() self.symbol_table=SymbolTableModule() def assemble_file(self,file_name): + #Uses the ParserModule and SymbolTableModule to create a machine code file + #in the same directory as the assembly file. assembly_array=self.parser.parse_file(file_name) self.symbol_table.translate_l_commands(assembly_array) self.symbol_table.translate_a_commands(assembly_array) @@ -88,7 +94,7 @@ class Assembler: if machine_code_line != None: machine_code_array.append(machine_code_line) file_content="\n".join(machine_code_array) - machine_code_file=open(file_name[:-3]+"hack","x") + machine_code_file=open(file_name[:file_name.find(".")]+".hack","x") machine_code_file.write(file_content) machine_code_file.close() diff --git a/TestFile.asm b/TestFile.asm index e69de29..332cb5c 100644 --- a/TestFile.asm +++ b/TestFile.asm @@ -0,0 +1,23 @@ +// Adds 1 + ... + 100 +@i +M=1 // i=1 +@sum +M=0 // sum=0 +(LOOP) +@i +D=M // D=i +@100 +D=D-A // D=i-100 +@END +D;JGT // if (i-100)>0 goto END +@i +D=M // D=i +@sum +M=D+M // sum=sum+i +@i +M=M+1 // i=i+1 +@LOOP +0;JMP // goto LOOP +(END) +@END +0;JMP // infinite loop \ No newline at end of file diff --git a/TestFile.hack b/TestFile.hack new file mode 100644 index 0000000..7857323 --- /dev/null +++ b/TestFile.hack @@ -0,0 +1,20 @@ +0000000000010000 +1110111111001000 +0000000000010001 +1110101010001000 +0000000000010000 +1111110000010000 +0000000001100100 +1110010011010000 +0000000000010010 +1110001100000001 +0000000000010000 +1111110000010000 +0000000000010001 +1111000010001000 +0000000000010000 +1111110111001000 +0000000000000100 +1110101010000111 +0000000000010010 +1110101010000111 \ No newline at end of file diff --git a/ToDoList b/ToDoList index 875ff2d..5e8c561 100644 --- a/ToDoList +++ b/ToDoList @@ -1,20 +1,20 @@ -*Nand2Tetris - Chapter 4 Project* +*Nand2Tetris - Chapter 6 Project* Main Goal: Build a fully fuctional Assembler that takes the Assembly writen code and transforms it into machine code for the Hack Computer To Do: -1.Build the Parser Module - Complete - no comments added +1.Build the Parser Module - Complete - Comments added Description: Will break each assembly command into is components to be later process by the other modules. -2.Build the Code Module - Incomplete +2.Build the Code Module - Replace by the Assembler Class Description: Will take the data from the parser module and translate it into machine code. -3.Build the Symbol Table Module - Complete - no comments added +3.Build the Symbol Table Module - Complete - Comments added Description: Will take data from the parser module and transform symbols into acutal addresses which will be store into a python dictionary. -4.Connect the 3 modules together - Incomplete +4.Connect the 3 modules together - Replace by the Assembler Class Description: The workflow of the Assembler Program will involve importing the assembly text from a ".asm" file. Afterward, the parser module will break the code into smaller chunks. This chunks will be than fed to the symbol table module which will build a dictionary for the user generated symbol. The dictionary will be initialize with a series of predefined symbols. Lastly, the code module translates each chunk fed from the parser module into machine code. In case of symbol, the code module will use the symbol table to translate it. The translated program will than be store in a ".hack" file. For more information: https://www.nand2tetris.org/ \ No newline at end of file