コード例 #1
0
        /// <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();
        }