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 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:
|
Attributes:
|
||||||
input_file: Path to the .asm file
|
input_file: Path to the .asm input file
|
||||||
output_file: Path where the .hack file will be written
|
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
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Components (create now)
|
||||||
|
self.symbol_table: SymbolTable = SymbolTable()
|
||||||
|
|
||||||
|
# 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:
|
with open(input_file, "r") as f:
|
||||||
lines = f.readlines()
|
self.lines = f.readlines()
|
||||||
|
raise NotImplementedError("Not implemented")
|
||||||
|
|
||||||
# Parser
|
def assemble(self) -> None:
|
||||||
parser = Parser(lines)
|
"""
|
||||||
# while parser.has_more_commands(): # Will raise NotImplementedError
|
Main assembly process - coordinates first and second pass.
|
||||||
parser.advance() # Does nothing
|
Public API method that CLI will call.
|
||||||
# cmd_type = parser.command_type()
|
"""
|
||||||
|
|
||||||
# For now, just write a placeholder
|
def _first_pass(self) -> None:
|
||||||
# Later we'll implement:
|
"""
|
||||||
# 1. First pass: build symbol table
|
First pass: Build symbol table with label addresses.
|
||||||
# 2. Second pass: generate machine code
|
Scans through code to find all (LABEL) declarations.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError("Not implemented")
|
||||||
|
|
||||||
# Output
|
def _second_pass(self) -> None:
|
||||||
with open(output_file, "w") as f:
|
"""
|
||||||
f.write(f"// Assembled from {input_file.name}\n")
|
Second pass: Translate instructions to binary.
|
||||||
f.write(f"// {len(lines)} lines processed\n")
|
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
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .assembler import assemble
|
from .assembler import Assembler
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -26,8 +26,9 @@ def main():
|
|||||||
|
|
||||||
# Assemble
|
# Assemble
|
||||||
try:
|
try:
|
||||||
assemble(input_path, output_path)
|
# Assemble
|
||||||
print(f"Successfully assembled {input_path} -> {output_path}")
|
assembler = Assembler(input_path, output_path)
|
||||||
|
assembler.assemble()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during assembly: {e}", file=sys.stderr)
|
print(f"Error during assembly: {e}", file=sys.stderr)
|
||||||
sys.exit(1)
|
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:
|
Raises:
|
||||||
NotImplementedError: Not yet implemented
|
NotImplementedError: Not yet implemented
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError("commandType not yet implemented")
|
raise NotImplementedError("command_type not yet implemented")
|
||||||
|
|
||||||
def symbol(self) -> str:
|
def symbol(self) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -63,7 +63,7 @@ class Parser:
|
|||||||
"""
|
"""
|
||||||
Returns the dest mnemonic in the current C-command.
|
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:
|
Returns:
|
||||||
str: The dest mnemonic (e.g., "M", "MD", "AMD")
|
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