feat: class clean up. mneumonics for diff commands. comp, jmp, dest. symbol table start.
This commit is contained in:
@@ -1,32 +1,86 @@
|
||||
from pathlib import Path
|
||||
|
||||
from .parser import Parser
|
||||
from assembler.parser import Parser
|
||||
|
||||
from .symbol_table import SymbolTable
|
||||
|
||||
|
||||
def assemble(input_file: Path, output_file: Path):
|
||||
class Assembler:
|
||||
"""
|
||||
Assemble a Hack assembly file into machine code.
|
||||
Main assembler that coordinates the two-pass assembly process.
|
||||
|
||||
Args:
|
||||
input_file: Path to the .asm file
|
||||
output_file: Path where the .hack file will be written
|
||||
Attributes:
|
||||
input_file: Path to the .asm input file
|
||||
output_file: Path to the .hack output file
|
||||
parser: Parser instance for reading commands
|
||||
symbol_table: SymbolTable instance for managing symbols
|
||||
binary_instructions: List of translated binary instructions
|
||||
"""
|
||||
# Read input file
|
||||
with open(input_file, "r") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# Parser
|
||||
parser = Parser(lines)
|
||||
# while parser.has_more_commands(): # Will raise NotImplementedError
|
||||
parser.advance() # Does nothing
|
||||
# cmd_type = parser.command_type()
|
||||
def __init__(self, input_file: Path, output_file: Path):
|
||||
"""Initialize assembler with input/output paths."""
|
||||
# File paths
|
||||
self.input_file: Path = input_file
|
||||
self.output_file: Path = output_file
|
||||
|
||||
# For now, just write a placeholder
|
||||
# Later we'll implement:
|
||||
# 1. First pass: build symbol table
|
||||
# 2. Second pass: generate machine code
|
||||
# Components (create now)
|
||||
self.symbol_table: SymbolTable = SymbolTable()
|
||||
|
||||
# Output
|
||||
with open(output_file, "w") as f:
|
||||
f.write(f"// Assembled from {input_file.name}\n")
|
||||
f.write(f"// {len(lines)} lines processed\n")
|
||||
# Data structures (empty, will fill later)
|
||||
self.binary_instructions: list[str] = []
|
||||
|
||||
# Counters
|
||||
self.next_variable_address = 16
|
||||
|
||||
# Will be created later
|
||||
self.parser: Parser
|
||||
self.lines: list[str] = []
|
||||
|
||||
with open(input_file, "r") as f:
|
||||
self.lines = f.readlines()
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
def assemble(self) -> None:
|
||||
"""
|
||||
Main assembly process - coordinates first and second pass.
|
||||
Public API method that CLI will call.
|
||||
"""
|
||||
|
||||
def _first_pass(self) -> None:
|
||||
"""
|
||||
First pass: Build symbol table with label addresses.
|
||||
Scans through code to find all (LABEL) declarations.
|
||||
"""
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
def _second_pass(self) -> None:
|
||||
"""
|
||||
Second pass: Translate instructions to binary.
|
||||
Handles A-commands, C-commands, and resolves symbols.
|
||||
"""
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
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")
|
||||
|
||||
def _translate_c_command(self) -> str:
|
||||
"""
|
||||
Translate C-command to 16-bit binary.
|
||||
Format: 111 a c1c2c3c4c5c6 d1d2d3 j1j2j3
|
||||
"""
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
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.lines)} lines processed\n")
|
||||
raise NotImplementedError("Not implemented")
|
||||
|
||||
def _assembled_success(self) -> None:
|
||||
"""Success Message"""
|
||||
print(f"Successfully assembled {self.input_file} -> {self.output_file}")
|
||||
|
||||
@@ -2,7 +2,7 @@ import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from .assembler import assemble
|
||||
from .assembler import Assembler
|
||||
|
||||
|
||||
def main():
|
||||
@@ -26,8 +26,9 @@ def main():
|
||||
|
||||
# Assemble
|
||||
try:
|
||||
assemble(input_path, output_path)
|
||||
print(f"Successfully assembled {input_path} -> {output_path}")
|
||||
# Assemble
|
||||
assembler = Assembler(input_path, output_path)
|
||||
assembler.assemble()
|
||||
except Exception as e:
|
||||
print(f"Error during assembly: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
from .code_tables import DEST_TABLE, COMP_TABLE, JUMP_TABLE
|
||||
|
||||
|
||||
class Code:
|
||||
"""Translates Hack assembly mnemonics into binary codes."""
|
||||
|
||||
@staticmethod
|
||||
def dest(mnemonic: str) -> str:
|
||||
"""
|
||||
Returns the 3-bit binary code for the dest mnemonic.
|
||||
|
||||
Args:
|
||||
mnemonic: Destination mnemonic (e.g., "M", "D", "MD", "AMD")
|
||||
|
||||
Returns:
|
||||
3-bit binary string (e.g., "010", "111")
|
||||
|
||||
Raises:
|
||||
KeyError: If mnemonic is invalid
|
||||
"""
|
||||
# Use dictionary lookup table
|
||||
print(mnemonic)
|
||||
raise NotImplementedError("not implemented")
|
||||
|
||||
@staticmethod
|
||||
def comp(mnemonic: str) -> str:
|
||||
"""
|
||||
Returns the 7-bit binary code for the comp mnemonic.
|
||||
|
||||
Args:
|
||||
mnemonic: Computation mnemonic (e.g., "D+1", "M-1", "D&A")
|
||||
|
||||
Returns:
|
||||
7-bit binary string (e.g., "0001111", "1110000")
|
||||
|
||||
Raises:
|
||||
KeyError: If mnemonic is invalid
|
||||
"""
|
||||
print(mnemonic)
|
||||
raise NotImplementedError("not implemented")
|
||||
# Use dictionary lookup table
|
||||
|
||||
@staticmethod
|
||||
def jump(mnemonic: str) -> str:
|
||||
"""
|
||||
Returns the 3-bit binary code for the jump mnemonic.
|
||||
|
||||
Args:
|
||||
mnemonic: Jump mnemonic (e.g., "JGT", "JEQ", "JMP", or "" for no jump)
|
||||
|
||||
Returns:
|
||||
3-bit binary string (e.g., "001", "111")
|
||||
|
||||
Raises:
|
||||
KeyError: If mnemonic is invalid
|
||||
"""
|
||||
print(mnemonic)
|
||||
raise NotImplementedError("not implemented")
|
||||
# Use dictionary lookup table
|
||||
|
||||
52
project-6-assembler/assembler/src/assembler/code_tables.py
Normal file
52
project-6-assembler/assembler/src/assembler/code_tables.py
Normal file
@@ -0,0 +1,52 @@
|
||||
DEST_TABLE = {
|
||||
"": "000",
|
||||
"M": "001",
|
||||
"D": "010",
|
||||
"MD": "011",
|
||||
"A": "100",
|
||||
"AM": "101",
|
||||
"AD": "110",
|
||||
"AMD": "111",
|
||||
}
|
||||
JUMP_TABLE = {
|
||||
"": "000",
|
||||
"JGT": "001",
|
||||
"JEQ": "010",
|
||||
"JGE": "011",
|
||||
"JLT": "100",
|
||||
"JNE": "101",
|
||||
"JLE": "110",
|
||||
"JMP": "111",
|
||||
}
|
||||
COMP_TABLE = {
|
||||
# Constant and register operations (a=0)
|
||||
"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",
|
||||
# Memory-based operations (a=1)
|
||||
"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",
|
||||
}
|
||||
@@ -41,7 +41,7 @@ class Parser:
|
||||
Raises:
|
||||
NotImplementedError: Not yet implemented
|
||||
"""
|
||||
raise NotImplementedError("commandType not yet implemented")
|
||||
raise NotImplementedError("command_type not yet implemented")
|
||||
|
||||
def symbol(self) -> str:
|
||||
"""
|
||||
@@ -63,7 +63,7 @@ class Parser:
|
||||
"""
|
||||
Returns the dest mnemonic in the current C-command.
|
||||
|
||||
Should only be called when commandType() is C_COMMAND.
|
||||
Should only be called when command_type () is C_COMMAND.
|
||||
|
||||
Returns:
|
||||
str: The dest mnemonic (e.g., "M", "MD", "AMD")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
class SymbolTable:
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize dictionary with predefined Hack platform symbols
|
||||
"""
|
||||
self.symbols = {
|
||||
"SP": 0,
|
||||
"LCL": 1,
|
||||
"ARG": 2,
|
||||
"THIS": 3,
|
||||
"THAT": 4,
|
||||
"R0": 0,
|
||||
"R1": 1,
|
||||
"R2": 2,
|
||||
"R3": 3,
|
||||
"R4": 4,
|
||||
"R5": 5,
|
||||
"R6": 6,
|
||||
"R7": 7,
|
||||
"R8": 8,
|
||||
"R9": 9,
|
||||
"R10": 10,
|
||||
"R11": 11,
|
||||
"R12": 12,
|
||||
"R13": 13,
|
||||
"R14": 14,
|
||||
"R15": 15,
|
||||
"SCREEN": 16384,
|
||||
"KBD": 24576,
|
||||
}
|
||||
|
||||
def add_entry(self, symbol: str, address: int) -> None:
|
||||
print(symbol)
|
||||
print(address)
|
||||
# Add symbol-address pair to dictionary
|
||||
raise NotImplementedError("add_entru not yet implemented")
|
||||
|
||||
def contains(self, symbol: str) -> bool:
|
||||
print(symbol)
|
||||
raise NotImplementedError("contains not yet implemented")
|
||||
# Check if symbol exists in dictionary
|
||||
|
||||
def get_address(self, symbol: str) -> int:
|
||||
print(symbol)
|
||||
raise NotImplementedError("get_address not yet implemented")
|
||||
# Return address for symbol (raises KeyError if not found)
|
||||
|
||||
Reference in New Issue
Block a user