func compileTerm(term *parser.Node, table *SymbolTable) string { firstChild := term.Children[0] lastChild := term.Children[len(term.Children)-1] isSubroutineCall := !(firstChild.Name == "symbol" && firstChild.Value == "(") && (lastChild.Name == "symbol" && lastChild.Value == ")") if isSubroutineCall { return compileSubroutineCall(term, table) } switch firstChild.Name { case "integerConstant": return fmt.Sprintf("push constant %s\n", firstChild.Value) case "stringConstant": return pushString(firstChild.Value) case "keyword": switch firstChild.Value { case "true": return "push constant 0\nnot\n" case "false", "null": return "push constant 0\n" case "this": return "push pointer 0\n" } case "identifier": symbol := table.Get(firstChild.Value) bracket, _ := term.Find(&parser.Node{Name: "symbol", Value: "["}) if bracket != nil { result := "" expression, _ := term.Find(&parser.Node{Name: "expression"}) result += pushExpression(expression, table) result += pushSymbol(symbol) result += "add\n" result += "pop pointer 1\n" result += "push that 0\n" return result } return pushSymbol(symbol) case "symbol": switch firstChild.Value { case "(": expression, _ := term.Find(&parser.Node{Name: "expression"}) return pushExpression(expression, table) case "-", "~": childTerm, _ := term.Find(&parser.Node{Name: "term"}) return compileTerm(childTerm, table) + compileUnaryOperator(firstChild.Value) } } return "" }
func compileSubroutineCall(node *parser.Node, table *SymbolTable) string { result := "" argSize := 0 _, i := node.Find(&parser.Node{Name: "symbol", Value: "("}) var functionName string if i == 1 { subroutineName := node.Children[0].Value thisClassName := table.Find(&Symbol{Kind: "class"}).SymbolType functionName = fmt.Sprintf("%s.%s", thisClassName, subroutineName) result += "push pointer 0\n" argSize++ } else if i == 3 { classOrVarName := node.Children[0].Value var className string if symbol := table.Get(classOrVarName); symbol != nil && symbol.Kind != "class" { className = symbol.SymbolType argSize++ result += pushSymbol(symbol) } else { className = classOrVarName } subroutineName := node.Children[2].Value functionName = fmt.Sprintf("%s.%s", className, subroutineName) } expressionList, _ := node.Find(&parser.Node{Name: "expressionList"}) expressions := expressionList.FindAll(&parser.Node{Name: "expression"}) for _, expression := range expressions { result += pushExpression(expression, table) } argSize += len(expressions) result += fmt.Sprintf("call %s %d\n", functionName, argSize) return result }
func compileSubroutineDec(node *parser.Node, classTable *SymbolTable, className string) string { labelCount = map[string]int{} result := "" table := buildSymbolTable(node, classTable) name := node.Children[2].Value localVarCount := 0 for _, symbol := range table.Scopes[0] { if symbol.Kind == "local" { localVarCount++ } } result += fmt.Sprintf("function %s.%s %d\n", className, name, localVarCount) subroutineType := node.Children[0].Value switch subroutineType { case "constructor": fieldCount := 0 for _, symbol := range classTable.Scopes[0] { if symbol.Kind == "field" { fieldCount++ } } result += fmt.Sprintf("push constant %d\n", fieldCount) result += "call Memory.alloc 1\n" result += "pop pointer 0\n" case "method": result += "push argument 0\n" result += "pop pointer 0\n" } subroutineBody, _ := node.Find(&parser.Node{Name: "subroutineBody"}) statements, _ := subroutineBody.Find(&parser.Node{Name: "statements"}) result += pushStatements(statements, table) return result }
func pushExpression(expression *parser.Node, table *SymbolTable) string { if expression == nil { panic("argument must not be nil") } if expression.Name != "expression" { panic(fmt.Sprintf("argument must be `expression`, but actual: %v", expression.ToXML())) } leftTerm, _ := expression.Find(&parser.Node{Name: "term"}) result := compileTerm(leftTerm, table) if len(expression.Children) > 1 { operator := expression.Children[1] expression.Children = expression.Children[2:] result += pushExpression(expression, table) result += compileOperator(operator.Value) } return result }
func buildSymbolTable(node *parser.Node, base *SymbolTable) *SymbolTable { if base == nil { base = &SymbolTable{} } table := &SymbolTable{} currentScope := map[string]*Symbol{} baseScopes := make([]map[string]*Symbol, len(base.Scopes)) copy(baseScopes, base.Scopes) table.Scopes = append([]map[string]*Symbol{currentScope}, baseScopes...) switch node.Name { case "class": identifier, _ := node.Find(&parser.Node{Name: "identifier"}) className := identifier.Value table.Set(className, &Symbol{Kind: "class", SymbolType: className}) for _, node := range node.Children { if node.Name == "classVarDec" { kind := node.Children[0].Value symbolType := node.Children[1].Value names := []string{} for _, node := range node.Children[2:] { if node.Name == "identifier" { names = append(names, node.Value) } } for _, name := range names { table.Set(name, &Symbol{SymbolType: symbolType, Kind: kind}) } } } case "subroutineDec": if node.Children[0].Value == "method" { table.Set("this", &Symbol{SymbolType: "this", Kind: "argument"}) } var parameterList *parser.Node for _, node := range node.Children { if node.Name == "parameterList" { parameterList = node break } } for i := 0; i < len(parameterList.Children); i += 3 { typeNode := parameterList.Children[i] identifier := parameterList.Children[i+1] name := identifier.Value table.Set(name, &Symbol{SymbolType: typeNode.Value, Kind: "argument"}) } subroutineBody, _ := node.Find(&parser.Node{Name: "subroutineBody"}) for _, node := range subroutineBody.Children { if node.Name == "varDec" { symbolType := node.Children[1].Value names := []string{} for _, node := range node.Children[2:] { if node.Name == "identifier" { names = append(names, node.Value) } } for _, name := range names { table.Set(name, &Symbol{ SymbolType: symbolType, Kind: "local", }) } } } } return table }