feat: working assembler! second pass implemenation. mnemonic parsing and binary construction and writing

This commit is contained in:
2026-02-24 14:10:09 +01:00
parent b968110397
commit 144179e0b8
8 changed files with 27579 additions and 29 deletions

View File

@@ -1,5 +1,6 @@
from pathlib import Path
from assembler.code import Code
from assembler.constants.command_types import CommandType
from assembler.parser import Parser
@@ -47,13 +48,16 @@ class Assembler:
Main assembly process - coordinates first and second pass.
Public API method that CLI will call.
"""
print("[] - Starting First Pass..")
print("[ ] - Starting First Pass..")
self._first_pass()
print("Symbol Table After First Pass")
print(self.symbol_table.symbols)
print("[x] - First Pass Done..")
print("[] - Starting Second Pass..")
print("[ ] - Starting Second Pass..")
self._second_pass()
print("[x] - Second pass done..")
print("[ ] - Writing output file..")
self._write_output()
print("[x] - Output file written..")
self._assembled_success()
def _trim_comments_and_whitespace(self, lines: list[str]) -> list[str]:
"""
@@ -88,7 +92,6 @@ class Assembler:
while self.parser.has_more_commands():
self.parser.advance() # Move to next command
print(self.parser.command_type())
cmd_type = self.parser.command_type()
if cmd_type == CommandType.L_COMMAND:
label = self.parser.symbol() # Extract label name
@@ -105,43 +108,59 @@ class Assembler:
Second pass: Translate instructions to binary.
Handles A-commands, C-commands, and resolves symbols.
"""
print(self.cleaned_lines)
while self.parser.has_more_commands():
self.parser.advance() # Move to next command
print(self.parser.command_type())
# cmd cmd_type
cmd_type = self.parser.command_type()
if cmd_type == CommandType.L_COMMAND:
continue
elif cmd_type == CommandType.A_COMMAND:
print("....")
binary = self._translate_a_command(self.parser.symbol())
self.binary_instructions.append(binary) # Store resultp
# Do A command things
elif cmd_type == CommandType.C_COMMAND:
print("..")
# Do C command Things
binary = self._translate_c_command()
self.binary_instructions.append(binary) # Store resultp
# Do C command Things
def _translate_a_command(self, symbol: str) -> str:
"""
Translate A-command to 16-bit binary.
Handles: numeric constants, predefined symbols, variables.
"""
raise NotImplementedError("Not implemented")
# Case 1: Check if symbol is a numeric constant (e.g., "2", "100")
if symbol.isdigit():
address = int(symbol)
# Case 2: Check if symbol exists in symbol table (predefined or label)
elif self.symbol_table.contains(symbol):
address = self.symbol_table.get_address(symbol)
# Case 3: It's a new variable - allocate next available address
else:
address = self.next_variable_address
self.symbol_table.add_entry(symbol, address)
self.next_variable_address += 1
# Convert address to 16-bit binary string (format: 0xxxxxxxxxxxxxxx)
return format(address, "016b")
def _translate_c_command(self) -> str:
"""
Translate C-command to 16-bit binary.
Format: 111 a c1c2c3c4c5c6 d1d2d3 j1j2j3
"""
raise NotImplementedError("Not implemented")
comp = Code.comp(self.parser.comp())
dest = Code.dest(self.parser.dest())
jump = Code.jump(self.parser.jump())
binary = f"111{comp}{dest}{jump}"
return binary
def _write_output(self) -> None:
"""Write binary instructions to output file."""
with open(self.output_file, "w") as f:
f.write(f"// Assembled from {self.input_file.name}\n")
f.write(f"// {len(self.cleaned_lines)} lines processed\n")
raise NotImplementedError("Not implemented")
f.write("\n".join(self.binary_instructions))
def _assembled_success(self) -> None:
"""Success Message"""

View File

@@ -28,7 +28,6 @@ def main():
try:
assembler = Assembler(input_path, output_path)
assembler.assemble()
print(f"Successfully assembled {input_path} -> {output_path}")
except ValueError as e:
# Handle validation errors (empty labels, invalid syntax, etc.)
print(f"Assembly Error: {e}", file=sys.stderr)

View File

@@ -1,4 +1,4 @@
from .code_tables import DEST_TABLE, COMP_TABLE, JUMP_TABLE
from .code_tables import COMP_TABLE, DEST_TABLE, JUMP_TABLE
class Code: