feat: assembler file parsing, parser module beginning
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
// Assembled from Add.asm
|
||||||
|
// 12 lines processed
|
||||||
13
project-6-assembler/assembler/provided-asm-files/Add.js
Normal file
13
project-6-assembler/assembler/provided-asm-files/Add.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// this file is for resting purposes only
|
||||||
|
// This file is part of www.nand2tetris.org
|
||||||
|
// and the book "The Elements of Computing Systems"
|
||||||
|
// by Nisan and Schocken, MIT Press.
|
||||||
|
|
||||||
|
// Computes R0 = 2 + 3 (R0 refers to RAM[0])
|
||||||
|
|
||||||
|
@2
|
||||||
|
D=A
|
||||||
|
@3
|
||||||
|
D=D+A
|
||||||
|
@0
|
||||||
|
M=D
|
||||||
@@ -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")
|
||||||
|
|||||||
@@ -1,2 +1,33 @@
|
|||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .assembler import assemble
|
||||||
|
|
||||||
|
|
||||||
def main():
|
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)
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user