Skip to content

Instantly share code, notes, and snippets.

@hiepph
Created July 5, 2020 17:18
Show Gist options
  • Save hiepph/789d78e90a6d3d380e2dc6c36f6fd28a to your computer and use it in GitHub Desktop.
Save hiepph/789d78e90a6d3d380e2dc6c36f6fd28a to your computer and use it in GitHub Desktop.
Hack Assembler
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