/// <summary> /// Compiles the sub routine. /// </summary> /// <param name="parentElement">The parent element.</param> private void CompileSubRoutine(XElement parentElement) { // seems that labels only need to be unique inside functions / methods this.whileStatementCount = -1; this.ifStatementCount = -1; string subroutineName = string.Empty; this.symbolTable.StartNewSubroutine(); XElement subRoutineElement = new XElement("subroutineDec"); parentElement.Add(subRoutineElement); bool isConstructor = false; bool isMethod = false; // while not the opening bracked of the method/constructor/function params while (this.classTokens.Peek().Value2 != "(") { Pair <string, string> token = this.classTokens.Pop(); if (isConstructor == false) { isConstructor = token.Value2 == "constructor"; } if (isMethod == false) { isMethod = token.Value2 == "method"; } // finds method name i.e. if the next token is an opening bracket // we must be on the method name if (this.classTokens.Peek().Value2 == "(") { subroutineName = token.Value2; // see page 238 - don't bother adding method or class names to symbol table subRoutineElement.Add(new XElement(token.Value1, token.Value2, new XAttribute("category", "Subroutine"))); } else { subRoutineElement.Add(new XElement(token.Value1, token.Value2)); } } // add the opening braket of param list this.CompileTerminal(); // add the param list this.CompileParameterList(isMethod); // add closing bracket of params this.CompileTerminal(); // add opening curley of methodBody this.CompileTerminal(); // compile sub routine var declarations (they're always first); this.CompileSubRoutineVariableDeclarations(); int numberOfLocals = symbolTable.VarCount(Kind.Var); this.vmWriter.WriteFunction(this.className + "." + subroutineName, symbolTable.VarCount(Kind.Var)); if (isConstructor) { this.vmWriter.WritePush(Segment.Constant, this.symbolTable.VarCount(Kind.Field)); this.vmWriter.WriteCall("Memory.alloc", 1); this.vmWriter.WritePop(Segment.Pointer, 0); } else if (isMethod) { this.vmWriter.WritePush(Segment.Argument, 0); this.vmWriter.WritePop(Segment.Pointer, 0); } this.CompileSubroutineStatments(); // compile closing curley this.CompileTerminal(); }