/// <summary>
        /// Creates a new instance of a ZInstruction. Check the complete table of opcodes for valid values.
        /// </summary>
        /// <param name="name">The Inform name for the used opcode. It is used for debugging purposes only, so you COULD leave this empty or null.</param>
        /// <param name="opcodeNumer">The opcode number.</param>
        /// <param name="opcodeType">The opcode type.</param>
        /// <param name="operands">The operands to use.</param>
        public ZInstruction(string name, byte opcodeNumber, OpcodeTypeKind opcodeType, params ZOperand[] operands)
        {
            var result = OpcodeHelper.GetFormAndCount(opcodeNumber, opcodeType, operands);
            _opcode = new ZOpcode(name, opcodeNumber, result.Item1, result.Item2, operands.Select(o => o.OperandType).ToArray());
            _subComponents.Add(_opcode);

            _operands = operands;
            _subComponents.AddRange(operands);
        }
 /// <summary>
 /// Creates a new instance of a ZInstructionSt. Check the complete table of opcodes for valid values.
 /// </summary>
 /// <param name="name">The Inform name for the used opcode. It is used for debugging purposes only, so you COULD leave this empty or null.</param>
 /// <param name="opcodeNumer">The opcode number.</param>
 /// <param name="opcodeType">The opcode type.</param>
 /// <param name="store">The store variable.</param>
 /// <param name="operands">The operands to use.</param>
 public ZInstructionSt(string name, byte opcodeNumber, OpcodeTypeKind opcodeType, ZVariable store, params ZOperand[] operands)
     : base(name, opcodeNumber, opcodeType, operands)
 {
     _store = store;
     _subComponents.Add(store);
 }
        /// <summary>
        /// Takes several opcode information and returns the best match of InstructionFormKind and InstructionOperandCountKind.
        /// </summary>
        /// <param name="opcodeNumber">The opcode number.</param>
        /// <param name="opcodeType">The opcode type as written in the table of opcodes.</param>
        /// <param name="operands">The operands to use.</param>
        /// <returns>A tuple of InstructionFormKind and InstructionOperandCountKind.</returns>
        /// <exception cref="ArgumentOutOfRangeException"> If <paramref name="opcodeNumber"/> has an invalid value or <paramref name="operands"/> an invalid count of operands.</exception>
        /// <exception cref="ArgumentException"> If <paramref name="operands"/> contains an unknown enum value.</exception>
        public static Tuple<InstructionFormKind, InstructionOperandCountKind> GetFormAndCount(byte opcodeNumber, OpcodeTypeKind opcodeType, ZOperand[] operands)
        {
            InstructionFormKind instructionForm;
            InstructionOperandCountKind operandCount;

            if (opcodeType == OpcodeTypeKind.ZeroOP)
            {
                if (opcodeNumber > 0xF)
                    throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.ZeroOP must be in range of 0x0 - 0xF.");

                if (operands.Count() > 0)
                    throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.ZeroOP no operands must be given.");

                instructionForm = InstructionFormKind.Short;
                operandCount = InstructionOperandCountKind.ZeroOP;
            }
            else if (opcodeType == OpcodeTypeKind.OneOP)
            {
                if (opcodeNumber > 0xF)
                    throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.OneOP must be in range of 0x0 - 0xF.");

                if (operands.Count() != 1)
                    throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.OneOP excactly operands must be given.");

                instructionForm = InstructionFormKind.Short;
                operandCount = InstructionOperandCountKind.OneOP;
            }
            else if (opcodeType == OpcodeTypeKind.TwoOP)
            {
                if (opcodeNumber > 0x1F)
                    throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.TwoOP must be in range of 0x00 - 0x1F.");

                if (operands.Count() != 2)
                    throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.TwoOP exactly two operands must be given.");

                // Could be in long form for two small constants or variables
                // But let's keep this logic dumb
                // We could save 1 byte per OpcodeTypeKind.TwoOP at best
                instructionForm = InstructionFormKind.Variable;
                operandCount = InstructionOperandCountKind.TwoOP;
            }
            else if (opcodeType == OpcodeTypeKind.Var)
            {
                if (opcodeNumber > 0x1F)
                    throw new ArgumentOutOfRangeException("opcodeNumber", opcodeNumber, "The opcode number of an OpcodeTypeKind.Var must be in range of 0x00-0x1F.");

                if (operands.Count() > 4)
                {
                    if (operands.Count() <= 8)
                        throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.Var only 0 to 4 operands can be given. Up to 8 operands are not supported yet (only call_vs2 and call_vn2 make use of this).");
                    else
                        throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.Var only 0 to 4 operands can be given.");
                }

                instructionForm = InstructionFormKind.Variable;
                operandCount = InstructionOperandCountKind.Var;
            }
            else if (opcodeType == OpcodeTypeKind.Ext)
            {
                if (operands.Count() > 4)
                    throw new ArgumentOutOfRangeException("operands", operands.Count(), "With OpcodeTypeKind.Ext only 0 to 4 operands can be given.");

                instructionForm = InstructionFormKind.Extended;
                operandCount = InstructionOperandCountKind.Var;
            }
            else
                throw new ArgumentException(String.Format("Unknown OpcodeTypeKind '{0}'", opcodeType.ToString()), "opcodeType");

            return new Tuple<InstructionFormKind, InstructionOperandCountKind>(instructionForm, operandCount);
        }
 /// <summary>
 /// Creates a new instance of a ZInstructionBr. Check the complete table of opcodes for valid values.
 /// </summary>
 /// <param name="name">The Inform name for the used opcode. It is used for debugging purposes only, so you COULD leave this empty or null.</param>
 /// <param name="opcodeNumer">The opcode number.</param>
 /// <param name="opcodeType">The opcode type.</param>
 /// <param name="branch">The branch label.</param>
 /// <param name="operands">The operands to use.</param>
 public ZInstructionBr(string name, byte opcodeNumber, OpcodeTypeKind opcodeType, ZLabel branch, params ZOperand[] operands)
     : base(name, opcodeNumber, opcodeType, operands)
 {
     _branch = branch;
     _subComponents.Add(branch);
 }