// numexpr := addexpr ((PLUS|MINUS) addexpr)*
        private NumberExpression ParseNumberExpression()
        {
            NumberExpression operand1 = ParseAddExpression();

            AsmToken nextToken = lexer.PeekNextToken();
            while (nextToken.Type == AsmTokenType.PLUS || nextToken.Type == AsmTokenType.MINUS)
            {
                lexer.ConsumeToken();

                NumberExpression operand2 = ParseAddExpression();
                if (nextToken.Type == AsmTokenType.PLUS)
                {
                    operand1 = new NumberOperationExpression(operand1, NumberOperationType.Addition, operand2);
                }
                else if (nextToken.Type == AsmTokenType.MINUS)
                {
                    operand1 = new NumberOperationExpression(operand1, NumberOperationType.Subtraction, operand2);
                }

                nextToken = lexer.PeekNextToken();
            }

            return operand1;
        }
        // Param type   : Address                        | Bit | FlagCondition | Flags | IOPortRegister                 |
        //                Indexed                                               | InterruptMode | Number | Register | Register16 | RegisterIndirect
        // opcodeparam := *OPENINGPAR numexpr CLOSINGPAR  | *BIT | *FLAGCONDITION | *FLAGS | *OPENINGPAR REGISTER CLOSINGPAR |
        //                *OPENINGPAR REGISTER16 (PLUS|MINUS) numexpr CLOSINGPAR | *INTERRUPTMODE | *numexpr | *REGISTER | *REGISTER16 | *OPENINGPAR REGISTER16 CLOSINGPAR
        private void ParseOpcodeParam()
        {
            AsmToken nextToken = lexer.PeekNextToken();
            if (nextToken.Type == AsmTokenType.BIT)
            {
                AsmToken bitToken = lexer.GetNextToken();
                InstructionLineParam bitParam = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.Bit,
                    Bit = AsmLexer.ParseBitToken(bitToken.Text)
                };
                bitParam.Tokens.Add(bitToken);
                prgLine.OpCodeParameters.Add(bitParam);
            }
            else if (nextToken.Type == AsmTokenType.FLAGCONDITION)
            {
                AsmToken flagConditionToken = lexer.GetNextToken();
                InstructionLineParam flagConditionParam = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.FlagCondition,
                    FlagCondition = AsmLexer.ParseFlagConditionToken(flagConditionToken.Text)
                };
                flagConditionParam.Tokens.Add(flagConditionToken);
                prgLine.OpCodeParameters.Add(flagConditionParam);
            }
            else if (nextToken.Type == AsmTokenType.FLAGS)
            {
                AsmToken flagsToken = lexer.GetNextToken();
                InstructionLineParam flagsParam = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.Flags
                };
                flagsParam.Tokens.Add(flagsToken);
                prgLine.OpCodeParameters.Add(flagsParam);
            }
            else if (nextToken.Type == AsmTokenType.INTERRUPTMODE)
            {
                AsmToken interruptModeToken = lexer.GetNextToken();
                InstructionLineParam interruptModeParam = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.InterruptMode,
                    InterruptMode = AsmLexer.ParseInterruptModeToken(interruptModeToken.Text)
                };
                interruptModeParam.Tokens.Add(interruptModeToken);
                prgLine.OpCodeParameters.Add(interruptModeParam);
            }
            else if (nextToken.Type == AsmTokenType.REGISTER)
            {
                AsmToken registerToken = lexer.GetNextToken();
                InstructionLineParam registerParam = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.Register,
                    Register = AsmLexer.ParseRegisterToken(registerToken.Text)
                };
                registerParam.Tokens.Add(registerToken);
                prgLine.OpCodeParameters.Add(registerParam);
            }
            else if (nextToken.Type == AsmTokenType.REGISTER16)
            {
                AsmToken register16Token = lexer.GetNextToken();
                InstructionLineParam register16Param = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.Register16,
                    Register16 = AsmLexer.ParseRegister16Token(register16Token.Text)
                };
                register16Param.Tokens.Add(register16Token);
                prgLine.OpCodeParameters.Add(register16Param);
            }
            else if (nextToken.Type == AsmTokenType.OPENINGPAR)
            {
                lexer.StartTokenList();
                InstructionLineParam resultLineParam = null;

                lexer.ConsumeToken();

                nextToken = lexer.PeekNextToken();
                if (nextToken.Type == AsmTokenType.REGISTER)
                {
                    AsmToken registerToken = lexer.GetNextToken();
                    InstructionLineParam registerParam = new InstructionLineParam()
                    {
                        Type = InstructionLineParamType.IOPortRegister,
                        Register = AsmLexer.ParseRegisterToken(registerToken.Text)
                    };
                    resultLineParam = registerParam;
                    prgLine.OpCodeParameters.Add(registerParam);
                }
                else if (nextToken.Type == AsmTokenType.REGISTER16)
                {
                    AsmToken register16Token = lexer.GetNextToken();
                    Register16 register16 = AsmLexer.ParseRegister16Token(register16Token.Text);

                    nextToken = lexer.PeekNextToken();
                    if (nextToken.Type == AsmTokenType.PLUS || nextToken.Type == AsmTokenType.MINUS)
                    {
                        AsmToken operatorToken = lexer.GetNextToken();
                        NumberExpression numberExpression = ParseNumberExpression();

                        NumberExpression displacementExpression = null;
                        if (operatorToken.Type == AsmTokenType.PLUS)
                        {
                            displacementExpression = numberExpression;
                        }
                        else if (operatorToken.Type == AsmTokenType.MINUS)
                        {
                            displacementExpression = new NumberOperationExpression(
                                new NumberOperand(0),
                                NumberOperationType.Subtraction,
                                numberExpression);
                        }

                        InstructionLineParam indexedParam = new InstructionLineParam()
                        {
                            Type = InstructionLineParamType.Indexed,
                            Register16 = register16,
                            NumberExpression = displacementExpression
                        };
                        resultLineParam = indexedParam;
                        prgLine.OpCodeParameters.Add(indexedParam);
                    }
                    else
                    {
                        InstructionLineParam register16Param = new InstructionLineParam()
                        {
                            Type = InstructionLineParamType.RegisterIndirect,
                            Register16 = register16
                        };
                        resultLineParam = register16Param;
                        prgLine.OpCodeParameters.Add(register16Param);
                    }
                }
                else
                {
                    NumberExpression numberExpression = ParseNumberExpression();
                    InstructionLineParam numberParam = new InstructionLineParam()
                    {
                        Type = InstructionLineParamType.Address,
                        NumberExpression = numberExpression
                    };
                    resultLineParam = numberParam;
                    prgLine.OpCodeParameters.Add(numberParam);
                }

                nextToken = lexer.PeekNextToken();
                if (nextToken.Type == AsmTokenType.CLOSINGPAR)
                {
                    lexer.ConsumeToken();
                }
                else
                {
                    throw new Exception(String.Format("Line {0} : Expecting closing parenthesis ) at column {1} instead of {2} : {3}", lineNumber, nextToken.StartIndex, nextToken.Type.ToString(), nextToken.Text));
                }

                ((List<AsmToken>)resultLineParam.Tokens).AddRange(lexer.EndTokenList());
            }
            else
            {
                lexer.StartTokenList();

                NumberExpression numberExpression = ParseNumberExpression();
                InstructionLineParam numberParam = new InstructionLineParam()
                {
                    Type = InstructionLineParamType.Number,
                    NumberExpression = numberExpression
                };
                prgLine.OpCodeParameters.Add(numberParam);

                ((List<AsmToken>)numberParam.Tokens).AddRange(lexer.EndTokenList());
            }
        }
        // addexpr := operand (MULTIPLY operand)*
        private NumberExpression ParseAddExpression()
        {
            NumberExpression operand1 = ParseOperandExpression();

            AsmToken nextToken = lexer.PeekNextToken();
            while (nextToken.Type == AsmTokenType.MULTIPLY)
            {
                lexer.ConsumeToken();

                NumberExpression operand2 = ParseOperandExpression();
                operand1 = new NumberOperationExpression(operand1, NumberOperationType.Multiplication, operand2);

                nextToken = lexer.PeekNextToken();
            }

            return operand1;
        }