Hack Assembly Language Assembler Implementation

Content is a summary and my notes mainly but not only from:

The Elements of Computing Systems: Building a Modern Computer from First Principles
by Noam Nisan


Hack Assembly Language Assembler

This is my implementation of Hack Assembly Language Assembler. It is not complete. It does not support comments and fixed memory locations such as (R1), (R2) etc.. 
package biz.tugay.hack.assembler;
/* User: koray@tugay.biz Date: 07/03/15 Time: 13:14 */
 
import java.util.HashMap;
import java.util.Map;
 
public class BInstructionsMap {
 
    public static Map<String,String> computationMnemonicMap
            = new HashMap<String,String>();
 
    public static Map<String,String> jumpMnemonnicMap
            = new HashMap<String, String>();
 
    public static Map<String,String> destinationMnemonnicMap
            = new HashMap<String, String>();
 
    static {
        computationMnemonicMap.put("0"  ,"0101010");
        computationMnemonicMap.put("1"  ,"0111111");
        computationMnemonicMap.put("-1" ,"0111010");
        computationMnemonicMap.put("D"  ,"0001100");
        computationMnemonicMap.put("A"  ,"0110000");
        computationMnemonicMap.put("!D" ,"0001101");
        computationMnemonicMap.put("!A" ,"0110001");
        computationMnemonicMap.put("-D" ,"0001111");
        computationMnemonicMap.put("-A" ,"0110011");
        computationMnemonicMap.put("D+1","0011111");
        computationMnemonicMap.put("A+1","0110111");
        computationMnemonicMap.put("D-1","0001110");
        computationMnemonicMap.put("A-1","0110010");
        computationMnemonicMap.put("D+A","0000010");
        computationMnemonicMap.put("D-A","0010011");
        computationMnemonicMap.put("A-D","0000111");
        computationMnemonicMap.put("D&A","0000000");
        computationMnemonicMap.put("D|A","0010101");
 
        computationMnemonicMap.put("M"  ,"1110000");
        computationMnemonicMap.put("!M" ,"1110001");
        computationMnemonicMap.put("-M" ,"1110011");
        computationMnemonicMap.put("M+1","1110111");
        computationMnemonicMap.put("M-1","1110010");
        computationMnemonicMap.put("D+M","1000010");
        computationMnemonicMap.put("D-M","1010011");
        computationMnemonicMap.put("M-D","1000111");
        computationMnemonicMap.put("D&M","1000000");
        computationMnemonicMap.put("D|M","1010101");
    }
 
    static {
        jumpMnemonnicMap.put("null","000");
        jumpMnemonnicMap.put("JGT" ,"001");
        jumpMnemonnicMap.put("JEQ" ,"010");
        jumpMnemonnicMap.put("JGE" ,"011");
        jumpMnemonnicMap.put("JLT" ,"100");
        jumpMnemonnicMap.put("JNE" ,"101");
        jumpMnemonnicMap.put("JLE" ,"110");
        jumpMnemonnicMap.put("JMP" ,"111");
    }
 
    static {
        destinationMnemonnicMap.put("null","000");
        destinationMnemonnicMap.put("M"   ,"001");
        destinationMnemonnicMap.put("D"   ,"010");
        destinationMnemonnicMap.put("MD"  ,"011");
        destinationMnemonnicMap.put("A"   ,"100");
        destinationMnemonnicMap.put("AM"  ,"101");
        destinationMnemonnicMap.put("AD"  ,"110");
        destinationMnemonnicMap.put("AMD" ,"111");
    }
}
package biz.tugay.hack.assembler;
/* User: koray.asm@tugay.biz Date: 07/03/15 Time: 10:47 */
 
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
 
public class HackAssembler {
 
    private static File machineLanguageFile;
    private static File assembled;
    private static FileWriter fileWriter;
    private static int variableAddressCounter = 16;
    private static Map<String,Integer> variableAddressMap = new HashMap<String,Integer>();
    private static Map<String,Integer> labelAddressMap = new HashMap<String, Integer>();
 
    public static void main(String[] args) throws IOException {
        doChecksForSourceFile(args);
        checkLabelsAndPopulateLoopAddressMap(machineLanguageFile);
        Scanner machineLanguageFileScanner = new Scanner(machineLanguageFile);
        fileWriter = new FileWriter(assembled);
        while(machineLanguageFileScanner.hasNextLine()){
            String nextAssemblyLine = machineLanguageFileScanner.nextLine();
            assemble(nextAssemblyLine);
        }
        fileWriter.flush();
        fileWriter.close();
    }
 
    private static void assemble(String lineToBeAssembled) throws IOException {
        if(lineToBeAssembled.startsWith("(")) {
 
        }
        else if(lineToBeAssembled.startsWith("@")) {
            assemble_A_Instruction(lineToBeAssembled);
            fileWriter.write(System.lineSeparator());
        }
        else {
            assemble_C_Instruction(lineToBeAssembled);
            fileWriter.write(System.lineSeparator());
        }
    }
 
    private static void assemble_C_Instruction(String lineToBeAssembled) throws IOException {
        String compMnemonnic;
        String destinationMnemonnic = "null";
        String jumpMnemonnic = "null";
 
        String compBinaryRepresentation;
        String jumpBinaryRepresentation;
        String destinationBinaryRepresentation;
 
        String[] split = lineToBeAssembled.split("=");
        String s = split[split.length - 1];
        String[] split1 = s.split(";");
        compMnemonnic = split1[0];
        compBinaryRepresentation = BInstructionsMap.computationMnemonicMap.get(compMnemonnic);
 
        if(lineToBeAssembled.contains("=")) {
            destinationMnemonnic = lineToBeAssembled.split("=")[0];
        }
        destinationBinaryRepresentation = BInstructionsMap.destinationMnemonnicMap.get(destinationMnemonnic);
 
        if(lineToBeAssembled.contains(";")) {
            String[] x = lineToBeAssembled.split(";");
            jumpMnemonnic = x[x.length-1];
        }
        jumpBinaryRepresentation = BInstructionsMap.jumpMnemonnicMap.get(jumpMnemonnic);
 
        fileWriter.write("111" + compBinaryRepresentation + destinationBinaryRepresentation + jumpBinaryRepresentation);
 
    }
 
    private static void assemble_A_Instruction(String lineToBeAssembled) throws IOException {
        String subString = lineToBeAssembled.substring(1);
        try {
            Integer.parseInt(subString);
            assemble_A_InstructionWithDirectAddress(subString);
        } catch (NumberFormatException e) {
            assemble_A_InstructionWithVariableOrLabel(subString);
        }
    }
 
    private static void assemble_A_InstructionWithVariableOrLabel(String subString) throws IOException {
        int assignedAddress = variableAddressCounter;
        if(labelAddressMap.containsKey(subString)) {
            assignedAddress = labelAddressMap.get(subString);
        }
        else if(variableAddressMap.containsKey(subString)) {
            assignedAddress = variableAddressMap.get(subString);
        }
        else if(!variableAddressMap.containsKey(subString)) {
            variableAddressMap.put(subString,variableAddressCounter);
            variableAddressCounter++;
        }
        fileWriter.write(appendZerosToString(Integer.toBinaryString(assignedAddress)));
    }
 
    private static void assemble_A_InstructionWithDirectAddress(String lineToBeAssembled) throws IOException {
        fileWriter.write(appendZerosToString(Integer.toBinaryString(Integer.parseInt(lineToBeAssembled))));
    }
 
 
 
    public static void doChecksForSourceFile(String[] args) throws IOException {
        // Check if filename has been passed to the program.
        if(args.length == 0) {
            System.out.println("Please pass the filename as parameter without the file extension.");
            System.exit(0);
        }
        // Check if the passed file exists.
        machineLanguageFile = new File(args[0]+".asm");
        if(!machineLanguageFile.exists()) {
            System.out.println("File does not exist..");
            System.exit(0);
        }
        // Create the new file which will contain the machine instructions in binary format.
        assembled = new File(args[0]+".hack");
        boolean delete = true;
        if(assembled.exists()) {
            delete = assembled.delete();
        }
        boolean newFile = assembled.createNewFile();
        if(!delete ||!newFile) {
            System.out.println("Can not create new file..");
            System.exit(0);
        }
    }
 
    private static void checkLabelsAndPopulateLoopAddressMap(File machineLanguageFile)
            throws FileNotFoundException {
        Scanner machineLanguageFileScanner = new Scanner(machineLanguageFile);
        int counter = 0;
        while(machineLanguageFileScanner.hasNextLine()){
            String nextAssemblyLine = machineLanguageFileScanner.nextLine();
            if(nextAssemblyLine.startsWith("(")) {
                String loopLabel = nextAssemblyLine.substring(1,nextAssemblyLine.length()-1);
                labelAddressMap.put(loopLabel, counter);
                counter--;
            }
            counter++;
        }
    }
 
    private static String appendZerosToString(String stringToBeAppended) {
        char[] chars = stringToBeAppended.toCharArray();
        int zerosToAppend = 16 - chars.length;
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0;i<zerosToAppend;i++) {
            stringBuilder.append("0");
        }
        stringBuilder.append(stringToBeAppended);
        return stringBuilder.toString();
    }
 
}