public static void ReplaceAddressWithSymbolInProgramLine(ProgramLine instructionLine, int addressParameterIndexToReplace, bool addressIsRelative, string symbolName)
        {
            if (addressParameterIndexToReplace == 0 || addressParameterIndexToReplace == 1)
            {
                if (instructionLine.OpCodeParameters != null && instructionLine.OpCodeParameters.Count > 0)
                {
                    InstructionLineParam paramToReplace = instructionLine.OpCodeParameters[addressParameterIndexToReplace];

                    // Find token to replace
                    AsmToken tokenToReplace = paramToReplace.Tokens.FirstOrDefault <AsmToken>(t => t.Type == AsmTokenType.NUMBER);
                    if (tokenToReplace != null)
                    {
                        // Generate new text for the line, replacing only the address token
                        StringBuilder lineText = new StringBuilder();
                        foreach (AsmToken token in instructionLine.AllTokens)
                        {
                            if ((!addressIsRelative && token != tokenToReplace) || !paramToReplace.Tokens.Contains(token))
                            {
                                lineText.Append(token.TextWithLeadingWhiteSpace);
                            }
                            else if (token == tokenToReplace)
                            {
                                if (tokenToReplace.LeadingWhiteSpace != null)
                                {
                                    lineText.Append(tokenToReplace.LeadingWhiteSpace.Text);
                                }
                                else if (addressIsRelative && (paramToReplace.Tokens[0] != tokenToReplace))
                                {
                                    if (paramToReplace.Tokens[0].LeadingWhiteSpace != null)
                                    {
                                        lineText.Append(paramToReplace.Tokens[0].LeadingWhiteSpace.Text);
                                    }
                                }
                                lineText.Append(symbolName);
                            }
                        }

                        // Parse new line from text
                        ProgramLine newTextLine = Assembler.ParseProgramLine(lineText.ToString());

                        // Copy textual representation to the original program Line
                        instructionLine.CopyTextualRepresentationFrom(newTextLine);
                    }
                }
            }
        }
        // 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());
            }
        }
 private static void AddOperandForLineParam(ref int address, IList<Operand> operands, ProgramLine programLine, AddressingMode? paramType, InstructionLineParam lineParam)
 {
     Operand operand = null;
     switch (paramType.Value)
     {
         // 8 bit unsigned operand
         case AddressingMode.Immediate:
         case AddressingMode.IOPortImmediate:
             operand = new Operand() { Type = OperandType.Unsigned8, Address = address, Expression = lineParam.NumberExpression, Line = programLine};
             address += 1;
             break;
         // 8 bit signed operand
         case AddressingMode.Indexed:
         case AddressingMode.Relative:
             operand = new Operand() { Type = OperandType.Signed8, Address = address, Expression = lineParam.NumberExpression, Line = programLine };
             address += 1;
             if (paramType.Value == AddressingMode.Relative && operand.Expression is SymbolOperand)
             {
                 // If a label address is used where a relative address is expected,
                 // we have to compute the relative displacement from the current addres to the label address
                 operand.Expression = new RelativeDisplacementFromLabelAddressExpression((SymbolOperand)operand.Expression, NumberOperationType.Subtraction, new NumberOperand(address));
             }
             else if (paramType.Value == AddressingMode.Relative && operand.Expression is NumberOperand)
             {
                 // Relative adressing mode definition (DJNZ and JR instructions) :
                 // The jump is measured from the address of the instruction OpCode and has a range of -126 to +129 bytes.
                 // The assembler automatically adjusts for the twice incremented PC.
                 operand.Expression = new NumberOperationExpression(operand.Expression, NumberOperationType.Subtraction, new NumberOperand(2));
             }
             break;
         // 16 bit unsigned operand
         case AddressingMode.Immediate16:
         case AddressingMode.Extended:
             operand = new Operand() { Type = OperandType.Unsigned16, Address = address, Expression = lineParam.NumberExpression, Line = programLine};
             address += 2;
             break;
     }
     if (operand != null)
     {
         operands.Add(operand);
     }
 }