Пример #1
0
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
}
Пример #2
0
func pushStatements(statements *parser.Node, table *SymbolTable) string {
	result := ""

	for _, statement := range statements.Children {
		switch statement.Name {
		case "letStatement":
			identifier, _ := statement.Find(&parser.Node{Name: "identifier"})
			symbol := table.Get(identifier.Value)
			if symbol == nil {
				panic(fmt.Sprintf("variable `%v` is not defined: %v\n%v", identifier.Value, table.String(), statements.ToXML()))
			}

			bracket, _ := statement.Find(&parser.Node{Name: "symbol", Value: "["})
			if bracket != nil {
				expressions := statement.FindAll(&parser.Node{Name: "expression"})
				result += pushExpression(expressions[0], table)
				result += pushSymbol(symbol)
				result += "add\n"
				result += pushExpression(expressions[1], table)
				result += "pop temp 0\n"
				result += "pop pointer 1\n"
				result += "push temp 0\n"
				result += "pop that 0\n"
			} else {
				expression, _ := statement.Find(&parser.Node{Name: "expression"})
				result += pushExpression(expression, table)

				result += popSymbol(symbol)
			}

		case "doStatement":
			subroutineCall := &parser.Node{Name: "subroutineCall", Children: statement.Children[1 : len(statement.Children)-1]}
			result += compileSubroutineCall(subroutineCall, table)
			result += "pop temp 0\n"

		case "returnStatement":
			expression, _ := statement.Find(&parser.Node{Name: "expression"})

			if expression != nil {
				result += pushExpression(expression, table)
			} else {
				result += "push constant 0\n"
			}

			result += "return\n"
		case "ifStatement":
			ifExpression, _ := statement.Find(&parser.Node{Name: "expression"})
			ifStatementsList := statement.FindAll(&parser.Node{Name: "statements"})

			trueLabel := uniqueLabel("IF_TRUE")
			falseLabel := uniqueLabel("IF_FALSE")
			endLabel := uniqueLabel("IF_END")

			if len(ifStatementsList) > 1 {
				ifStatements, elseStatements := ifStatementsList[0], ifStatementsList[1]

				result += pushExpression(ifExpression, table)
				result += "if-goto " + trueLabel + "\n"
				result += "goto " + falseLabel + "\n"
				result += "label " + trueLabel + "\n"
				result += pushStatements(ifStatements, table)
				result += "goto " + endLabel + "\n"
				result += "label " + falseLabel + "\n"
				result += pushStatements(elseStatements, table)
				result += "label " + endLabel + "\n"
			} else {
				ifStatements := ifStatementsList[0]

				result += pushExpression(ifExpression, table)
				result += "if-goto " + trueLabel + "\n"
				result += "goto " + falseLabel + "\n"
				result += "label " + trueLabel + "\n"
				result += pushStatements(ifStatements, table)
				result += "label " + falseLabel + "\n"
			}

		case "whileStatement":
			expLabel := uniqueLabel("WHILE_EXP")
			endLabel := uniqueLabel("WHILE_END")

			result += "label " + expLabel + "\n"
			whileExpression, _ := statement.Find(&parser.Node{Name: "expression"})
			result += pushExpression(whileExpression, table)
			result += "not\n"
			result += "if-goto " + endLabel + "\n"

			whileBody, _ := statement.Find(&parser.Node{Name: "statements"})
			result += pushStatements(whileBody, table)
			result += "goto " + expLabel + "\n"
			result += "label " + endLabel + "\n"
		}
	}

	return result
}