protected string[] generatePushToStackFromSymbolImmediate(string symbol, InstructionData currentVMinstruction)
        {
            var output = new List <string>();

            output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
            output.Add(symbol);
            output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
            output.Add(stackPointer_symbol);
            output.AddRange(generateIncrement(stackPointer_symbol));
            return(output.ToArray());
        }
        protected string[] generatePopFromStackToSymbol(string symbol, InstructionData currentVMinstruction)
        {
            var output = new List <string>();

            output.AddRange(generateDecrement(stackPointer_symbol));
            output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
            output.Add(stackPointer_symbol);
            //TODO...treat symbol as pointer as argument to this func?
            output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
            output.Add(symbol);
            return(output.ToArray());
        }
        public void handleCommand(InstructionData instructionData)
        {
            switch (instructionData.CommandType)
            {
            case vmILParser.vmCommandType.ARITHMETIC:
                handleArithmeticCommand(instructionData);
                break;

            case vmILParser.vmCommandType.PUSH:
                handlePushPop(instructionData);
                break;

            case vmILParser.vmCommandType.POP:
                handlePushPop(instructionData);
                break;

            case vmILParser.vmCommandType.LABEL:
            {
                handleControlFlow(instructionData);
                break;
            }

            case vmILParser.vmCommandType.IF:
            {
                handleControlFlow(instructionData);
                break;
            }

            case vmILParser.vmCommandType.GOTO:
            {
                handleControlFlow(instructionData);
                break;
            }

            case vmILParser.vmCommandType.CALL:
                handleFunctionCallingCommand(instructionData);
                break;

            case vmILParser.vmCommandType.RETURN:
                handleFunctionCallingCommand(instructionData);
                break;

            case vmILParser.vmCommandType.FUNCTION:
                handleFunctionCallingCommand(instructionData);
                break;

            default:
                throw new Exception($"unkown command:{instructionData.CommandType}");
            }
        }
        private void handleControlFlow(InstructionData instructionData)
        {
            if (instructionData.CommandType == vmCommandType.LABEL)
            {
                this.Output.Add("//handle VM LABEL");
                var labelString = instructionData.Operands.FirstOrDefault();
                this.Output.Add($"({labelString})");
            }
            if (instructionData.CommandType == vmCommandType.GOTO)
            {
                this.Output.Add("//handle GOTO");
                var labelToJumpTo = instructionData.Operands.FirstOrDefault();
                this.Output.Add(assembler.CommandType.JUMP.ToString());
                this.Output.Add(labelToJumpTo);
            }
            if (instructionData.CommandType == vmCommandType.IF)
            {
                this.Output.Add("//handle IF GOTO");
                var blockID = Guid.NewGuid().ToString("N");

                var labelToJumpTo = instructionData.Operands.FirstOrDefault();
                // we only do the jump if whatever is at the top of the stack is not equal to 0.
                // so load a with stack value, load b with 0, then do a jumpIfNotEqual
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.Add(assembler.CommandType.LOADBIMMEDIATE.ToString());
                this.Output.Add("0");
                this.Output.Add(assembler.CommandType.UPDATEFLAGS.ToString());

                this.Output.Add(assembler.CommandType.JUMPIFEQUAL.ToString());
                this.Output.Add($"FALSE{blockID}");

                this.Output.Add(assembler.CommandType.JUMP.ToString());
                this.Output.Add(labelToJumpTo);
                this.Output.Add($"(FALSE{blockID})");
            }
        }
        protected void handleFunctionCallingCommand(InstructionData instructionData)
        {
            //function funcName 5 //number of arguments to get from stack.
            if (instructionData.CommandType == vmCommandType.FUNCTION)
            {
                this.Output.Add("//handle FUNCTION DEF");
                var funcName = instructionData.Operands[0];
                var argNum   = instructionData.Operands[1];

                //label
                Output.Add($"({funcName})");
                //allocate some memory for local arguments
                for (var i = 0; i < int.Parse(argNum); i++)
                {
                    this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                    this.Output.Add("0");
                    this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                    this.Output.Add(stackPointer_symbol);
                    this.Output.AddRange(generateIncrement(stackPointer_symbol));
                }
            }

            if (instructionData.CommandType == vmCommandType.CALL)
            {
                this.Output.Add($"//handle CALL {instructionData.Operands[0]}");
                var funcName      = instructionData.Operands[0];
                var argNum        = instructionData.Operands[1];
                var returnaddress = "RETURN" + Guid.NewGuid().ToString("N");

                //push return address
                Output.AddRange(generatePushToStackFromSymbolImmediate(returnaddress, instructionData));
                //push LCL
                Output.AddRange(generatePushToStackFromSymbol(local_symbol, instructionData));
                //push ARG
                Output.AddRange(generatePushToStackFromSymbol(arg_symbol, instructionData));
                //push THIS
                Output.AddRange(generatePushToStackFromSymbol(this_symbol, instructionData));
                //push THAT
                Output.AddRange(generatePushToStackFromSymbol(that_symbol, instructionData));

                //set ARG to SP-n-5
                //first calculate the new address and store in A.
                Output.AddRange(generateDecrement(stackPointer_symbol, (int.Parse(argNum) + 5).ToString(), false));
                //then store it in ARG.
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(arg_symbol);

                //set LCL to new SP.
                Output.Add(assembler.CommandType.LOADA.ToString());
                Output.Add(stackPointer_symbol);
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(local_symbol);
                //execute function.
                Output.Add(assembler.CommandType.JUMP.ToString());
                Output.Add(funcName);
                //return label
                Output.Add($"({returnaddress})");
            }

            if (instructionData.CommandType == vmCommandType.RETURN)
            {
                Output.Add("//handle RETURN");

                Output.Add(assembler.CommandType.LOADA.ToString());
                Output.Add(local_symbol);
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add("FRAME");


                //frame currently points to somewhere on the stack -
                //lets get the real value at the frame pointer and save to ret.
                Output.AddRange(generateDecrement("FRAME", "5", false));
                Output.AddRange(generateMoveAtoTemp());
                Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                Output.Add(temp_symbol);
                //A should now contain a real return address.
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add("RET");

                Output.AddRange(generatePopFromStackToSymbol(arg_symbol, instructionData));

                Output.AddRange(generateIncrement(arg_symbol, "1", false));
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(stackPointer_symbol);

                Output.AddRange(generateDecrement("FRAME", (1).ToString(), false));
                Output.AddRange(generateMoveAtoTemp());
                Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                Output.Add(temp_symbol);
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(that_symbol);

                Output.AddRange(generateDecrement("FRAME", (2).ToString(), false));
                Output.AddRange(generateMoveAtoTemp());
                Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                Output.Add(temp_symbol);
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(this_symbol);

                Output.AddRange(generateDecrement("FRAME", (3).ToString(), false));
                Output.AddRange(generateMoveAtoTemp());
                Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                Output.Add(temp_symbol);
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(arg_symbol);

                Output.AddRange(generateDecrement("FRAME", (4).ToString(), false));
                Output.AddRange(generateMoveAtoTemp());
                Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                Output.Add(temp_symbol);
                Output.Add(assembler.CommandType.STOREA.ToString());
                Output.Add(local_symbol);


                Output.Add(assembler.CommandType.JUMPTOPOINTER.ToString());
                Output.Add("RET");
            }
        }
        private void handlePushPop(InstructionData instructionData)
        {
            ////////////////////////////////////////////////////////////////////////////////////
            /////PUSH - write to stack
            /// ///////////////////////////////////////////////////////////////////////////////

            if (instructionData.CommandType == vmILParser.vmCommandType.PUSH)
            {
                this.Output.Add("//handle PUSH");
                //memory instructions look like
                //pop segment index
                var segment      = parseVmSegment(instructionData.Operands.FirstOrDefault());
                var indexORValue = instructionData.Operands.Skip(1).FirstOrDefault();
                if (segment == vmILParser.vmMemSegments.constant)
                {
                    this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                    this.Output.Add(indexORValue);
                    this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                    this.Output.Add(stackPointer_symbol);
                    this.Output.AddRange(generateIncrement(stackPointer_symbol));
                }
                //segments
                else if (segment == vmILParser.vmMemSegments.local)
                {
                    this.Output.AddRange(generatePushToStackFromSegment(vmMemSegments.local, indexORValue, instructionData));
                }

                else if (segment == vmILParser.vmMemSegments.argument)
                {
                    this.Output.AddRange(generatePushToStackFromSegment(vmMemSegments.argument, indexORValue, instructionData));
                }

                else if (segment == vmILParser.vmMemSegments.pointer)
                {
                    this.Output.AddRange(generatePushToStackFromSegment(vmMemSegments.pointer, indexORValue, instructionData));
                }

                else if (segment == vmILParser.vmMemSegments._this)
                {
                    this.Output.AddRange(generatePushToStackFromSegment(vmMemSegments._this, indexORValue, instructionData));
                }

                else if (segment == vmILParser.vmMemSegments.that)
                {
                    this.Output.AddRange(generatePushToStackFromSegment(vmMemSegments.that, indexORValue, instructionData));
                }
                else if (segment == vmILParser.vmMemSegments._static)
                {
                    this.Output.AddRange(generatePushToStackFromSegment(vmMemSegments._static, indexORValue, instructionData));
                }


                ////////////////////////////////////////////////////////////////////////////////////
                /////POP - write to memory
                /// ///////////////////////////////////////////////////////////////////////////////
            }

            else if (instructionData.CommandType == vmILParser.vmCommandType.POP)
            {
                this.Output.Add("//handle POP");
                var segment      = parseVmSegment(instructionData.Operands.FirstOrDefault());
                var indexORValue = instructionData.Operands.Skip(1).FirstOrDefault();

                if (segment == vmILParser.vmMemSegments.constant)
                {
                    throw new Exception("cannot write to constant segment ");
                }
                else if (segment == vmILParser.vmMemSegments.local)
                {
                    this.Output.AddRange(generatePopFromStackToSegment(vmMemSegments.local, indexORValue, instructionData));
                }
                else if (segment == vmILParser.vmMemSegments.argument)
                {
                    this.Output.AddRange(generatePopFromStackToSegment(vmMemSegments.argument, indexORValue, instructionData));
                }
                else if (segment == vmILParser.vmMemSegments.pointer)
                {
                    this.Output.AddRange(generatePopFromStackToSegment(vmMemSegments.pointer, indexORValue, instructionData));
                }
                else if (segment == vmILParser.vmMemSegments._this)
                {
                    this.Output.AddRange(generatePopFromStackToSegment(vmMemSegments._this, indexORValue, instructionData));
                }
                else if (segment == vmILParser.vmMemSegments.that)
                {
                    this.Output.AddRange(generatePopFromStackToSegment(vmMemSegments.that, indexORValue, instructionData));
                }
                else if (segment == vmILParser.vmMemSegments._static)
                {
                    this.Output.AddRange(generatePopFromStackToSegment(vmMemSegments._static, indexORValue, instructionData));
                }
            }
        }
        private void handleArithmeticCommand(InstructionData instructionData)
        {
            //depending on the specific ALU command we need to generate the appropriate ASM command
            //there will be no operands for these commands -
            //instead we will need to include pop twice to get the operands from the stack...
            //the stack lies from location 256 -2047 - we will need to reconcile this with our bootloader...
            // and assembler offsets..

            //For now - lets just try offsetting everything by 256 - to make room for the bootloader...
            // so 256  - 256+15 = virtual registers
            // 256+16 - 256+255  = static variables
            // 256 + 256 - 256 + 2047 = THE STACK

            //we'll assume there is always a symbol called "stackpointer" which points to the last item in the stack.


            vmILParser.vmArithmetic_Logic_Instructions subCommand = (vmILParser.vmArithmetic_Logic_Instructions)instructionData.CommmandObject;
            //ADD
            this.Output.Add("//handleArithmeticCommand");
            if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.add)
            {
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());
                this.Output.AddRange(generateDecrement(stackPointer_symbol));

                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.Add(assembler.CommandType.ADD.ToString());
                this.Output.Add(temp_symbol);
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.sub)
            {
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.Add(assembler.CommandType.SUBTRACT.ToString());
                this.Output.Add(temp_symbol);
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.neg)
            {
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());

                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("-1");

                this.Output.Add(assembler.CommandType.MULTIPLY.ToString());
                this.Output.Add(temp_symbol);
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.eq)
            {
                var blockID = Guid.NewGuid().ToString("N");

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //load temp into B somehow
                this.Output.Add(assembler.CommandType.LOADB.ToString());
                this.Output.Add(temp_symbol);

                // update flags
                this.Output.Add(assembler.CommandType.UPDATEFLAGS.ToString());
                // we need to return different results to the stack depending on
                // if equal is true or not - can do this using jumps.
                this.Output.Add(assembler.CommandType.JUMPIFEQUAL.ToString());
                this.Output.Add($"EQ_TRUE_{blockID}");

                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("0");
                this.Output.Add(assembler.CommandType.JUMP.ToString());
                this.Output.Add($"EQ_STORE_STACK_{blockID}");

                this.Output.Add($"(EQ_TRUE_{blockID})");
                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("1");

                this.Output.Add($"(EQ_STORE_STACK_{blockID})");
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.gt)
            {
                var blockID = Guid.NewGuid().ToString("N");

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //load temp into B somehow
                this.Output.Add(assembler.CommandType.LOADB.ToString());
                this.Output.Add(temp_symbol);

                // update flags
                this.Output.Add(assembler.CommandType.UPDATEFLAGS.ToString());
                // we need to return different results to the stack depending on
                // if A>B or not - can do this using jumps.
                this.Output.Add(assembler.CommandType.JUMPIFGREATER.ToString());
                this.Output.Add($"GT_TRUE_{blockID}");

                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("0");
                this.Output.Add(assembler.CommandType.JUMP.ToString());
                this.Output.Add($"GT_STORE_STACK_{blockID}");

                this.Output.Add($"(GT_TRUE_{blockID})");
                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("1");

                this.Output.Add($"(GT_STORE_STACK_{blockID})");
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.lt)
            {
                var blockID = Guid.NewGuid().ToString("N");

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());

                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //load temp into B somehow
                this.Output.Add(assembler.CommandType.LOADB.ToString());
                this.Output.Add(temp_symbol);

                // update flags
                this.Output.Add(assembler.CommandType.UPDATEFLAGS.ToString());
                // we need to return different results to the stack depending on
                // if A>B or not - can do this using jumps.
                this.Output.Add(assembler.CommandType.JUMPIFLESS.ToString());
                this.Output.Add($"LT_TRUE_{blockID}");

                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("0");
                this.Output.Add(assembler.CommandType.JUMP.ToString());
                this.Output.Add($"LT_STORE_STACK_{blockID}");

                this.Output.Add($"(LT_TRUE_{blockID})");
                this.Output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                this.Output.Add("1");

                this.Output.Add($"(LT_STORE_STACK_{blockID})");
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.and)
            {
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());
                this.Output.AddRange(generateDecrement(stackPointer_symbol));

                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.Add(assembler.CommandType.AND.ToString());
                this.Output.Add(temp_symbol);
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }
            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.or)
            {
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.AddRange(generateMoveAtoTemp());
                this.Output.AddRange(generateDecrement(stackPointer_symbol));

                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                this.Output.Add(assembler.CommandType.OR.ToString());
                this.Output.Add(temp_symbol);
                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }

            else if (subCommand == vmILParser.vmArithmetic_Logic_Instructions.not)
            {
                this.Output.AddRange(generateDecrement(stackPointer_symbol));
                this.Output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);

                this.Output.Add(assembler.CommandType.NOT.ToString());

                //now store the result in SP
                this.Output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                this.Output.Add(stackPointer_symbol);
                //and increment
                this.Output.AddRange(generateIncrement(stackPointer_symbol));
            }
        }
        protected string[] generatePushToStackFromSegment(vmILParser.vmMemSegments segment, string index, InstructionData currentVMinstruction)
        {
            //if we are writing from local to stack - we need to read from memory at the base address
            //pointed to by the local symbol which is stored at LCL
            //flow is LoadAFromPointer LCL - lets assume LCL holds the number 100 - which is the base address for the LCL segment
            //then increment A by index
            //store this in temp
            var output = new List <String>();

            //add LCL and index and store in A

            //static is different from other segments
            //we need to read a value from the symbol VMFILE.VMFUNCTION.INDEX
            if (segment == vmMemSegments._static)
            {
                output.Add(assembler.CommandType.LOADA.ToString());
                output.Add($"STATIC{currentVMinstruction.VMFilePath}.{currentVMinstruction.VMFunction}.{index}");
            }
            //if constant, then just load the constant specified into A.
            else if (segment == vmMemSegments.constant)
            {
                output.Add(assembler.CommandType.LOADAIMMEDIATE.ToString());
                output.Add(index);
            }
            else
            {
                output.AddRange(generateIncrement(vmSegmentToSymbolName[segment], index, updateSymbol: false));
                output.Add(assembler.CommandType.STOREA.ToString());
                output.Add(temp_symbol + " + 2");

                output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                output.Add(temp_symbol + " + 2");
            }
            //store it on the stack, and increment SP
            output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
            output.Add(stackPointer_symbol);
            output.AddRange(generateIncrement(stackPointer_symbol));
            return(output.ToArray());
        }
        protected string[] generatePopFromStackToSegment(vmILParser.vmMemSegments segment, string IndexOperand, InstructionData currentVMinstruction)
        {
            var output = new List <String>();

            if (segment == vmMemSegments._static)
            {
                output.AddRange(generateDecrement(stackPointer_symbol));
                output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                output.Add(stackPointer_symbol);
                output.Add(assembler.CommandType.STOREA.ToString());
                output.Add($"STATIC{currentVMinstruction.VMFilePath}.{currentVMinstruction.VMFunction}.{IndexOperand}");
            }
            else
            {
                //offset the base address of the symbol by the index
                output.AddRange(generateIncrement(this.vmSegmentToSymbolName[segment], IndexOperand, updateSymbol: false));
                output.AddRange(generateMoveAtoTemp());

                output.AddRange(generateDecrement(stackPointer_symbol));
                output.Add(assembler.CommandType.LOADAATPOINTER.ToString());
                output.Add(stackPointer_symbol);

                output.Add(assembler.CommandType.STOREAATPOINTER.ToString());
                output.Add(temp_symbol);
            }
            return(output.ToArray());
        }