private static void DisplayToken(StringBuilder output, AsmToken asmToken)
 {
     if (asmToken.LeadingWhiteSpace != null)
     {
         DisplayToken(output, asmToken.LeadingWhiteSpace);
     }
     output.Append("<span class=\"" + GetClassFromTokenType(asmToken.Type) + "\">");
     output.Append(asmToken.Text);
     output.Append("</span>");
 }
 public AsmToken(string asmLine, AsmToken leadingWhitespaceToken, AsmTokenType type, int startIndex, int endIndex, object value)
 {
     this.asmLine = asmLine;
     this.LeadingWhiteSpace = leadingWhitespaceToken;
     Type = type;
     StartIndex = startIndex;
     EndIndex = endIndex;
     Value = value;
 }
 public AsmToken(string asmLine, AsmToken leadingWhitespaceToken, AsmTokenType type, int startIndex, int endIndex)
     : this(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, null)
 {
 }
        private AsmToken FindNextToken()
        {
            int startIndex = nextIndex;
            char startChar = GetNextChar();
            AsmToken leadingWhitespaceToken = null;
            if (IsWhitespace(startChar))
            {
                AsmTokenType type = AsmTokenType.WHITESPACE;
                for (char c = PeekNextChar(); IsWhitespace(c); c = PeekNextChar())
                {
                    GetNextChar();
                }
                int endIndex = nextIndex;
                leadingWhitespaceToken = new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                // Start next token
                startIndex = nextIndex;
                startChar = GetNextChar();
            }
            switch (startChar)
            {
                case ':':
                    AsmTokenType type = AsmTokenType.COLON;
                    int endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case ',':
                    type = AsmTokenType.COMMA;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case '(':
                    type = AsmTokenType.OPENINGPAR;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case ')':
                    type = AsmTokenType.CLOSINGPAR;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case '+':
                    type = AsmTokenType.PLUS;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case '-':
                    type = AsmTokenType.MINUS;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case '*':
                    type = AsmTokenType.MULTIPLY;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case '[':
                    type = AsmTokenType.OPENINGBRA;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case ']':
                    type = AsmTokenType.CLOSINGBRA;
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                case '$':
                    char nc = PeekNextChar();
                    if(!IsHexaDigit(nc))
                    {
                        type = AsmTokenType.DOLLAR;
                        endIndex = nextIndex;
                        return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                    }
                    else
                    {
                        type = AsmTokenType.NUMBER;
                        int valStartIndex = nextIndex;
                        for (char c = PeekNextChar(); c != (char)0 && IsHexaDigit(c); c = PeekNextChar())
                        {
                            GetNextChar();
                        }
                        endIndex = nextIndex;
                        int intValue = Convert.ToInt32(asmLine.Substring(valStartIndex, endIndex - valStartIndex), 16);
                        return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, intValue);
                    }
                case ';':
                    type = AsmTokenType.COMMENT;
                    while(GetNextChar() != 0) { }
                    endIndex = nextIndex;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, asmLine.Substring(startIndex + 1, endIndex - startIndex - 1).Trim());
                case '"':
                    type = AsmTokenType.STRING;
                    int valueStartIndex = nextIndex;
                    char previousChar = (char)0;
                    StringBuilder sbValue;
                    ReadStringToken('"', startIndex, valueStartIndex, previousChar, out endIndex, out sbValue);
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, sbValue.ToString());
                case '\'':
                    type = AsmTokenType.NUMBER;
                    valueStartIndex = nextIndex;
                    char chr = GetNextChar();
                    if(chr == '\\')
                    {
                        chr = GetNextChar();
                        chr = GetCharValueFromEscapeChar(chr);
                    }
                    if(GetNextChar() != '\'')
                    {
                        // Then switch to string token
                        type = AsmTokenType.STRING;
                        previousChar = chr;
                        ReadStringToken('\'', startIndex, valueStartIndex, previousChar, out endIndex, out sbValue);
                        return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, sbValue.ToString());
                    }
                    endIndex = nextIndex;
                    int asciiValue = (byte)chr;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, asciiValue);
                case '%':
                    type = AsmTokenType.NUMBER;
                    valueStartIndex = nextIndex;
                    for (char c = PeekNextChar(); c != (char)0 && (c == '0' || c == '1'); c = PeekNextChar())
                    {
                        GetNextChar();
                    }
                    endIndex = nextIndex;
                    int binValue = Convert.ToByte(asmLine.Substring(valueStartIndex, endIndex - valueStartIndex), 2);
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, binValue);
                case (char)0:
                    type = AsmTokenType.ENDOFLINE;
                    return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, startIndex);
                default:
                    // Special case 1 : 0-7 char is ambiguous, it can be a BIT or a NUMBER, but it can be a BIT only if previous token is OPCODE = BIT, RES, SET
                    if(startChar >= 48 && startChar <= 55 && currentToken.Type == AsmTokenType.OPCODE &&
                            (String.Compare(currentToken.Text, "BIT", stringComparisonMode) == 0 ||
                             String.Compare(currentToken.Text, "RES", stringComparisonMode) == 0 ||
                             String.Compare(currentToken.Text, "SET", stringComparisonMode) == 0 ))
                    {
                        type = AsmTokenType.BIT;
                        endIndex = nextIndex;
                        return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, startChar - 48);
                    }
                    // Special case 2 : 0-2 char is ambiguous, it can be an INTERRUPTMODE or a NUMBER, but it can be an INTERRUPTMODE only if previous token is OPCODE = IM
                    else if(startChar >= 48 && startChar <= 50 && currentToken.Type == AsmTokenType.OPCODE &&
                             String.Compare(currentToken.Text, "IM", stringComparisonMode) == 0 )
                    {
                        type = AsmTokenType.INTERRUPTMODE;
                        endIndex = nextIndex;
                        return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, startChar - 48);
                    }
                    else if(IsFirstSymbolChar(startChar))
                    {
                        for (char c = PeekNextChar(); c != (char)0 && IsSymbolChar(c); c = PeekNextChar())
                        {
                            GetNextChar();
                        }
                        endIndex = nextIndex;
                        string symbol = asmLine.Substring(startIndex, endIndex - startIndex);
                        // Special case 3 : ' is not a valid symbol char, but AF' is a valid register name
                        if(String.Compare(symbol, "AF", stringComparisonMode) == 0 && PeekNextChar() == '\'')
                        {
                            GetNextChar();
                            endIndex = nextIndex;
                            symbol = "AF'";
                        }
                        // Special case 4 : C symbol is ambiguous, it can be a flag condition or a register, but it can be a flag only if previous token is OPCODE = CALL, JP, JR, RET
                        if(String.Compare(symbol, "C", stringComparisonMode) == 0 && currentToken.Type == AsmTokenType.OPCODE &&
                            (String.Compare(currentToken.Text, "CALL", stringComparisonMode) == 0 ||
                             String.Compare(currentToken.Text, "JP", stringComparisonMode) == 0   ||
                             String.Compare(currentToken.Text, "JR", stringComparisonMode) == 0   ||
                             String.Compare(currentToken.Text, "RET", stringComparisonMode) == 0  ))
                        {
                            type = AsmTokenType.FLAGCONDITION;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        else if(OPCODES.Contains<string>(symbol, stringComparer))
                        {
                            type = AsmTokenType.OPCODE;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        else if (REGISTERS8.Contains<string>(symbol, stringComparer))
                        {
                            type = AsmTokenType.REGISTER;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        else if (REGISTERS16.Contains<string>(symbol, stringComparer))
                        {
                            type = AsmTokenType.REGISTER16;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        else if (FLAGS.Contains<string>(symbol, stringComparer))
                        {
                            type = AsmTokenType.FLAGS;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        else if(FLAGCONDITIONS.Contains<string>(symbol, stringComparer))
                        {
                            type = AsmTokenType.FLAGCONDITION;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        else if(DIRECTIVES.Contains<string>(symbol, stringComparer))
                        {
                            type = AsmTokenType.DIRECTIVE;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                        // Special case 5 : an hexadecimal number is also a valid symbol
                        else if(hexaNumberRegex.IsMatch(symbol))
                        {
                            type = AsmTokenType.NUMBER;
                            Match hexaMatch = hexaNumberRegex.Match(symbol);
                            string numberString = hexaMatch.Groups[1].Value;
                            int intValue = 0;
                            if (numberString.Length <= 2)
                            {
                                intValue = Convert.ToByte(numberString, 16);
                            }
                            else
                            {
                                intValue = Convert.ToUInt16(numberString, 16);
                            }
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex, intValue);
                        }
                        else
                        {
                            type = AsmTokenType.SYMBOL;
                            return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, endIndex);
                        }
                    }
                    else if(IsDigit(startChar))
                    {
                        type = AsmTokenType.NUMBER;
                        for (char c = PeekNextChar(); c != (char)0 && IsHexaDigit(c); c = PeekNextChar())
                        {
                            GetNextChar();
                        }
                        switch (PeekNextChar())
                        {
                            case 'O':
                            case 'Q':
                            case 'H':
                            case 'o':
                            case 'q':
                            case 'h':
                                GetNextChar();
                                break;
                        }
                        int nbEndIndex = nextIndex;
                        string numberString = asmLine.Substring(startIndex, nbEndIndex - startIndex);
                        int intValue = 0;
                        if(hexaNumberRegex.IsMatch(numberString))
                        {
                            Match hexaMatch = hexaNumberRegex.Match(numberString);
                            numberString = hexaMatch.Groups[1].Value;
                            if (numberString.Length <= 2)
                            {
                                intValue = Convert.ToByte(numberString, 16);
                            }
                            else
                            {
                                intValue = Convert.ToUInt16(numberString, 16);
                            }
                        }
                        else if (decimalNumberRegex.IsMatch(numberString))
                        {
                            Match decimalMatch = decimalNumberRegex.Match(numberString);
                            numberString = decimalMatch.Groups[1].Value;
                            intValue = UInt16.Parse(numberString);
                        }
                        else if (binaryNumberRegex.IsMatch(numberString))
                        {
                            Match binMatch = binaryNumberRegex.Match(numberString);
                            numberString = binMatch.Groups[1].Value;
                            if (numberString.Length <= 8)
                            {
                                intValue = Convert.ToByte(numberString, 2);
                            }
                            else
                            {
                                intValue = Convert.ToUInt16(numberString, 2);
                            }
                        }
                        else if (octalNumberRegex.IsMatch(numberString))
                        {
                            Match octalMatch = octalNumberRegex.Match(numberString);
                            numberString = octalMatch.Groups[1].Value;
                            intValue = Convert.ToUInt16(numberString , 8);
                        }
                        else
                        {
                            throw new Exception(String.Format("Line {0} : Invalid number format {1} at column {2}", lineNumber, numberString, startIndex));
                        }
                        return new AsmToken(asmLine, leadingWhitespaceToken, type, startIndex, nbEndIndex, intValue);

                    }
                    else
                    {
                        throw new Exception(String.Format("Line {0} : Unexpected char {1} at column {2}", lineNumber, startChar, startIndex));
                    }
            }
        }
 public AsmToken PeekNextToken()
 {
     if (nextToken == null)
     {
         nextToken = FindNextToken();
     }
     return nextToken;
 }
 public AsmToken GetNextToken()
 {
     if (nextToken != null)
     {
         currentToken = nextToken;
         nextToken = null;
     }
     else
     {
         currentToken = FindNextToken();
     }
     AllTokens.Add(currentToken);
     if(buildTokenList)
     {
         partialTokenList.Add(currentToken);
     }
     return currentToken;
 }