Created
July 5, 2020 17:18
-
-
Save hiepph/789d78e90a6d3d380e2dc6c36f6fd28a to your computer and use it in GitHub Desktop.
Hack Assembler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"io" | |
"os" | |
"strconv" | |
"strings" | |
) | |
func cdest(s string) string { | |
switch s { | |
case "null": | |
return "000" | |
case "M": | |
return "001" | |
case "D": | |
return "010" | |
case "MD": | |
return "011" | |
case "A": | |
return "100" | |
case "AM": | |
return "101" | |
case "AD": | |
return "110" | |
case "AMD": | |
return "111" | |
} | |
return "" | |
} | |
func ccomp(s string) string { | |
switch s { | |
// a = 0 | |
case "0": | |
return "0101010" | |
case "1": | |
return "0111111" | |
case "-1": | |
return "0111010" | |
case "D": | |
return "0001100" | |
case "A": | |
return "0110000" | |
case "!D": | |
return "0001101" | |
case "!A": | |
return "0110001" | |
case "-D": | |
return "0001111" | |
case "-A": | |
return "0110011" | |
case "D+1": | |
return "0011111" | |
case "A+1": | |
return "0110111" | |
case "D-1": | |
return "0001110" | |
case "A-1": | |
return "0110010" | |
case "D+A": | |
return "0000010" | |
case "D-A": | |
return "0010011" | |
case "A-D": | |
return "0000111" | |
case "D&A": | |
return "0000000" | |
case "D|A": | |
return "0010101" | |
// a = 1 | |
case "M": | |
return "1110000" | |
case "!M": | |
return "1110001" | |
case "-M": | |
return "1110011" | |
case "M+1": | |
return "1110111" | |
case "M-1": | |
return "1110010" | |
case "D+M": | |
return "1000010" | |
case "D-M": | |
return "1010011" | |
case "M-D": | |
return "1000111" | |
case "D&M": | |
return "1000000" | |
case "D|M": | |
return "1010101" | |
} | |
return "" | |
} | |
func cjump(s string) string { | |
switch s { | |
case "JGT": | |
return "001" | |
case "JEQ": | |
return "010" | |
case "JGE": | |
return "011" | |
case "JLT": | |
return "110" | |
case "JNE": | |
return "101" | |
case "JLE": | |
return "110" | |
case "JMP": | |
return "111" | |
} | |
return "" | |
} | |
func predefined(label string) (int64, bool) { | |
symbols := map[string]int64{ | |
"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, | |
} | |
v, found := symbols[label] | |
return v, found | |
} | |
func main() { | |
file, _ := os.Open(os.Args[1]) | |
defer file.Close() | |
// table for storing labels | |
d := make(map[string]int64) | |
scanner := bufio.NewScanner(file) | |
var i int64 = 0 | |
// first pass | |
for scanner.Scan() { | |
line := scanner.Text() | |
// trim comments | |
commentIndex := strings.Index(line, "//") | |
if commentIndex != -1 { | |
line = line[:commentIndex] | |
} | |
// trim leading spaces | |
line = strings.TrimSpace(line) | |
if len(line) == 0 { | |
continue | |
} | |
if strings.HasPrefix(line, "(") { | |
symbol := line[1 : len(line)-1] | |
d[symbol] = i | |
i-- // don't count this line | |
} | |
i++ | |
} | |
// v, _ := d["RET_ADDRESS_CALLO"] | |
// fmt.Println(v) | |
// second pass | |
file.Seek(0, io.SeekStart) | |
scanner = bufio.NewScanner(file) | |
i = 0 | |
var k int64 = 0 // keep count of new variables | |
for scanner.Scan() { | |
line := scanner.Text() | |
// trim comments | |
commentIndex := strings.Index(line, "//") | |
if commentIndex != -1 { | |
line = line[:commentIndex] | |
} | |
// trim leading spaces | |
line = strings.TrimSpace(line) | |
if len(line) == 0 { | |
continue | |
} | |
// fmt.Println(line) | |
if line[0] == '@' { | |
// A | |
content := line[1:] | |
// check if in predefined label | |
if v, found := predefined(content); found { | |
fmt.Println(fmt.Sprintf("0%015s", strconv.FormatInt(v, 2))) | |
} else if v, err := strconv.Atoi(content); err == nil { | |
// number | |
fmt.Println(fmt.Sprintf("0%015s", strconv.FormatInt(int64(v), 2))) | |
} else { | |
// not found in table -> new variable | |
if _, found := d[content]; !found { | |
d[content] = 16 + k | |
k++ | |
} | |
v, _ := d[content] | |
fmt.Println(fmt.Sprintf("0%015s", strconv.FormatInt(v, 2))) | |
} | |
} else if strings.HasPrefix(line, "(") { | |
// L -> do nothing | |
} else { | |
// C | |
delimiters := func(c rune) bool { | |
return c == '=' || c == ';' | |
} | |
elements := strings.FieldsFunc(line, delimiters) | |
if len(elements) == 3 { | |
fmt.Println(fmt.Sprintf("111%s%s%s", | |
ccomp(elements[1]), | |
cdest(elements[0]), | |
cjump(elements[2]))) | |
} else { | |
if strings.Contains(line, "=") { | |
// dest=comp | |
fmt.Println(fmt.Sprintf("111%s%s000", | |
ccomp(elements[1]), | |
cdest(elements[0]))) | |
} else { | |
// comp;jump | |
fmt.Println(fmt.Sprintf("111%s000%s", | |
ccomp(elements[0]), | |
cjump(elements[1]))) | |
} | |
} | |
} | |
i++ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment