feat: assembler file parsing, parser module beginning

This commit is contained in:
2026-02-17 14:35:21 +01:00
parent 8063df4760
commit 7bd67b402b
5 changed files with 181 additions and 1 deletions

View File

@@ -0,0 +1,32 @@
from pathlib import Path
from .parser import Parser
def assemble(input_file: Path, output_file: Path):
"""
Assemble a Hack assembly file into machine code.
Args:
input_file: Path to the .asm file
output_file: Path where the .hack file will be written
"""
# 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()
# For now, just write a placeholder
# Later we'll implement:
# 1. First pass: build symbol table
# 2. Second pass: generate machine code
# 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")

View File

@@ -1,2 +1,33 @@
import argparse
import sys
from pathlib import Path
from .assembler import assemble
def main():
print("HELLO CAMPIONI")
parser = argparse.ArgumentParser(description="Hack Assembly Language Assembler")
parser.add_argument("input_file", help="Path to .asm file to assemble")
args = parser.parse_args()
input_path = Path(args.input_file)
# Validation
if not input_path.exists():
print(f"Error: File '{input_path}' does not exist", file=sys.stderr)
sys.exit(1)
if input_path.suffix != ".asm":
print("Error: File must have .asm extension", file=sys.stderr)
sys.exit(1)
# Generate output path
output_path = input_path.with_suffix(".hack")
# Assemble
try:
assemble(input_path, output_path)
print(f"Successfully assembled {input_path} -> {output_path}")
except Exception as e:
print(f"Error during assembly: {e}", file=sys.stderr)
sys.exit(1)

View File

@@ -0,0 +1,102 @@
class Parser:
def __init__(self, file_lines):
"""
Constructor that takes loaded file content.
Args:
file_lines: List of strings (lines from the .asm file)
"""
self.lines = file_lines
# Store the file lines
# Initialize current_command index to -1 (before first command)
# No processing happens in constructor for now
def has_more_commands(self) -> bool:
"""
Check if there are more commands in the input.
Returns:
bool: True if more commands exist, False otherwise
"""
raise NotImplementedError("hasMoreCommands not yet implemented")
def advance(self):
"""
Reads the next command and makes it the current command.
Should only be called if hasMoreCommands() is true.
For now: does nothing (stub)
Later: will skip whitespace/comments and advance to next valid command
"""
print(self.lines)
pass # Does nothing for now
def command_type(self) -> str:
"""
Returns the type of the current command.
Returns:
str: "A_COMMAND", "C_COMMAND", or "L_COMMAND"
Raises:
NotImplementedError: Not yet implemented
"""
raise NotImplementedError("commandType not yet implemented")
def symbol(self) -> str:
"""
Returns the symbol or decimal value of the current command.
Should only be called when commandType() is A_COMMAND or L_COMMAND.
- For @Xxx, returns "Xxx"
- For (Xxx), returns "Xxx"
Returns:
str: The symbol/decimal value
Raises:
NotImplementedError: Not yet implemented
"""
raise NotImplementedError("symbol not yet implemented")
def dest(self) -> str:
"""
Returns the dest mnemonic in the current C-command.
Should only be called when commandType() is C_COMMAND.
Returns:
str: The dest mnemonic (e.g., "M", "MD", "AMD")
Raises:
NotImplementedError: Not yet implemented
"""
raise NotImplementedError("dest not yet implemented")
def comp(self) -> str:
"""
Returns the comp mnemonic in the current C-command.
Should only be called when commandType() is C_COMMAND.
Returns:
str: The comp mnemonic (e.g., "D+1", "M-1", "D&A")
Raises:
NotImplementedError: Not yet implemented
"""
raise NotImplementedError("comp not yet implemented")
def jump(self) -> str:
"""
Returns the jump mnemonic in the current C-command.
Should only be called when commandType() is C_COMMAND.
Returns:
str: The jump mnemonic (e.g., "JGT", "JEQ", "JMP") or empty string
Raises:
NotImplementedError: Not yet implemented
"""
raise NotImplementedError("jump not yet implemented")