|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-11 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- BEGIN_JUCE_NAMESPACE
-
- //==============================================================================
- CPlusPlusCodeTokeniser::CPlusPlusCodeTokeniser() {}
- CPlusPlusCodeTokeniser::~CPlusPlusCodeTokeniser() {}
-
- //==============================================================================
- namespace CppTokeniser
- {
- bool isIdentifierStart (const juce_wchar c) noexcept
- {
- return CharacterFunctions::isLetter (c)
- || c == '_' || c == '@';
- }
-
- bool isIdentifierBody (const juce_wchar c) noexcept
- {
- return CharacterFunctions::isLetterOrDigit (c)
- || c == '_' || c == '@';
- }
-
- bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
- {
- static const char* const keywords2Char[] =
- { "if", "do", "or", "id", 0 };
-
- static const char* const keywords3Char[] =
- { "for", "int", "new", "try", "xor", "and", "asm", "not", 0 };
-
- static const char* const keywords4Char[] =
- { "bool", "void", "this", "true", "long", "else", "char",
- "enum", "case", "goto", "auto", 0 };
-
- static const char* const keywords5Char[] =
- { "while", "bitor", "break", "catch", "class", "compl", "const", "false",
- "float", "short", "throw", "union", "using", "or_eq", 0 };
-
- static const char* const keywords6Char[] =
- { "return", "struct", "and_eq", "bitand", "delete", "double", "extern",
- "friend", "inline", "not_eq", "public", "sizeof", "static", "signed",
- "switch", "typeid", "wchar_t", "xor_eq", 0};
-
- static const char* const keywords7Char[] =
- { "default", "mutable", "private", "typedef", "nullptr", "virtual", 0 };
-
- static const char* const keywordsOther[] =
- { "noexcept", "const_cast", "continue", "explicit", "namespace",
- "operator", "protected", "register", "reinterpret_cast", "static_cast",
- "template", "typename", "unsigned", "volatile", "constexpr",
- "@implementation", "@interface", "@end", "@synthesize", "@dynamic", "@public",
- "@private", "@property", "@protected", "@class", 0 };
-
- const char* const* k;
-
- switch (tokenLength)
- {
- case 2: k = keywords2Char; break;
- case 3: k = keywords3Char; break;
- case 4: k = keywords4Char; break;
- case 5: k = keywords5Char; break;
- case 6: k = keywords6Char; break;
- case 7: k = keywords7Char; break;
-
- default:
- if (tokenLength < 2 || tokenLength > 16)
- return false;
-
- k = keywordsOther;
- break;
- }
-
- int i = 0;
- while (k[i] != 0)
- {
- if (token.compare (CharPointer_ASCII (k[i])) == 0)
- return true;
-
- ++i;
- }
-
- return false;
- }
-
- int parseIdentifier (CodeDocument::Iterator& source) noexcept
- {
- int tokenLength = 0;
- String::CharPointerType::CharType possibleIdentifier [100];
- String::CharPointerType possible (possibleIdentifier);
-
- while (isIdentifierBody (source.peekNextChar()))
- {
- const juce_wchar c = source.nextChar();
-
- if (tokenLength < 20)
- possible.write (c);
-
- ++tokenLength;
- }
-
- if (tokenLength > 1 && tokenLength <= 16)
- {
- possible.writeNull();
-
- if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
- return CPlusPlusCodeTokeniser::tokenType_builtInKeyword;
- }
-
- return CPlusPlusCodeTokeniser::tokenType_identifier;
- }
-
- bool skipNumberSuffix (CodeDocument::Iterator& source)
- {
- const juce_wchar c = source.peekNextChar();
- if (c == 'l' || c == 'L' || c == 'u' || c == 'U')
- source.skip();
-
- if (CharacterFunctions::isLetterOrDigit (source.peekNextChar()))
- return false;
-
- return true;
- }
-
- bool isHexDigit (const juce_wchar c) noexcept
- {
- return (c >= '0' && c <= '9')
- || (c >= 'a' && c <= 'f')
- || (c >= 'A' && c <= 'F');
- }
-
- bool parseHexLiteral (CodeDocument::Iterator& source) noexcept
- {
- if (source.nextChar() != '0')
- return false;
-
- juce_wchar c = source.nextChar();
- if (c != 'x' && c != 'X')
- return false;
-
- int numDigits = 0;
- while (isHexDigit (source.peekNextChar()))
- {
- ++numDigits;
- source.skip();
- }
-
- if (numDigits == 0)
- return false;
-
- return skipNumberSuffix (source);
- }
-
- bool isOctalDigit (const juce_wchar c) noexcept
- {
- return c >= '0' && c <= '7';
- }
-
- bool parseOctalLiteral (CodeDocument::Iterator& source) noexcept
- {
- if (source.nextChar() != '0')
- return false;
-
- if (! isOctalDigit (source.nextChar()))
- return false;
-
- while (isOctalDigit (source.peekNextChar()))
- source.skip();
-
- return skipNumberSuffix (source);
- }
-
- bool isDecimalDigit (const juce_wchar c) noexcept
- {
- return c >= '0' && c <= '9';
- }
-
- bool parseDecimalLiteral (CodeDocument::Iterator& source) noexcept
- {
- int numChars = 0;
- while (isDecimalDigit (source.peekNextChar()))
- {
- ++numChars;
- source.skip();
- }
-
- if (numChars == 0)
- return false;
-
- return skipNumberSuffix (source);
- }
-
- bool parseFloatLiteral (CodeDocument::Iterator& source) noexcept
- {
- int numDigits = 0;
-
- while (isDecimalDigit (source.peekNextChar()))
- {
- source.skip();
- ++numDigits;
- }
-
- const bool hasPoint = (source.peekNextChar() == '.');
-
- if (hasPoint)
- {
- source.skip();
-
- while (isDecimalDigit (source.peekNextChar()))
- {
- source.skip();
- ++numDigits;
- }
- }
-
- if (numDigits == 0)
- return false;
-
- juce_wchar c = source.peekNextChar();
- const bool hasExponent = (c == 'e' || c == 'E');
-
- if (hasExponent)
- {
- source.skip();
-
- c = source.peekNextChar();
- if (c == '+' || c == '-')
- source.skip();
-
- int numExpDigits = 0;
- while (isDecimalDigit (source.peekNextChar()))
- {
- source.skip();
- ++numExpDigits;
- }
-
- if (numExpDigits == 0)
- return false;
- }
-
- c = source.peekNextChar();
- if (c == 'f' || c == 'F')
- source.skip();
- else if (! (hasExponent || hasPoint))
- return false;
-
- return true;
- }
-
- int parseNumber (CodeDocument::Iterator& source)
- {
- const CodeDocument::Iterator original (source);
-
- if (parseFloatLiteral (source))
- return CPlusPlusCodeTokeniser::tokenType_floatLiteral;
-
- source = original;
-
- if (parseHexLiteral (source))
- return CPlusPlusCodeTokeniser::tokenType_integerLiteral;
-
- source = original;
-
- if (parseOctalLiteral (source))
- return CPlusPlusCodeTokeniser::tokenType_integerLiteral;
-
- source = original;
-
- if (parseDecimalLiteral (source))
- return CPlusPlusCodeTokeniser::tokenType_integerLiteral;
-
- source = original;
- source.skip();
-
- return CPlusPlusCodeTokeniser::tokenType_error;
- }
-
- void skipQuotedString (CodeDocument::Iterator& source) noexcept
- {
- const juce_wchar quote = source.nextChar();
-
- for (;;)
- {
- const juce_wchar c = source.nextChar();
-
- if (c == quote || c == 0)
- break;
-
- if (c == '\\')
- source.skip();
- }
- }
-
- void skipComment (CodeDocument::Iterator& source) noexcept
- {
- bool lastWasStar = false;
-
- for (;;)
- {
- const juce_wchar c = source.nextChar();
-
- if (c == 0 || (c == '/' && lastWasStar))
- break;
-
- lastWasStar = (c == '*');
- }
- }
- }
-
- //==============================================================================
- int CPlusPlusCodeTokeniser::readNextToken (CodeDocument::Iterator& source)
- {
- int result = tokenType_error;
- source.skipWhitespace();
-
- juce_wchar firstChar = source.peekNextChar();
-
- switch (firstChar)
- {
- case 0:
- source.skip();
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- result = CppTokeniser::parseNumber (source);
- break;
-
- case '.':
- result = CppTokeniser::parseNumber (source);
-
- if (result == tokenType_error)
- result = tokenType_punctuation;
-
- break;
-
- case ',':
- case ';':
- case ':':
- source.skip();
- result = tokenType_punctuation;
- break;
-
- case '(':
- case ')':
- case '{':
- case '}':
- case '[':
- case ']':
- source.skip();
- result = tokenType_bracket;
- break;
-
- case '"':
- case '\'':
- CppTokeniser::skipQuotedString (source);
- result = tokenType_stringLiteral;
- break;
-
- case '+':
- result = tokenType_operator;
- source.skip();
-
- if (source.peekNextChar() == '+')
- source.skip();
- else if (source.peekNextChar() == '=')
- source.skip();
-
- break;
-
- case '-':
- source.skip();
- result = CppTokeniser::parseNumber (source);
-
- if (result == tokenType_error)
- {
- result = tokenType_operator;
-
- if (source.peekNextChar() == '-')
- source.skip();
- else if (source.peekNextChar() == '=')
- source.skip();
- }
- break;
-
- case '*':
- case '%':
- case '=':
- case '!':
- result = tokenType_operator;
- source.skip();
-
- if (source.peekNextChar() == '=')
- source.skip();
-
- break;
-
- case '/':
- result = tokenType_operator;
- source.skip();
-
- if (source.peekNextChar() == '=')
- {
- source.skip();
- }
- else if (source.peekNextChar() == '/')
- {
- result = tokenType_comment;
- source.skipToEndOfLine();
- }
- else if (source.peekNextChar() == '*')
- {
- source.skip();
- result = tokenType_comment;
- CppTokeniser::skipComment (source);
- }
-
- break;
-
- case '?':
- case '~':
- source.skip();
- result = tokenType_operator;
- break;
-
- case '<':
- source.skip();
- result = tokenType_operator;
-
- if (source.peekNextChar() == '=')
- {
- source.skip();
- }
- else if (source.peekNextChar() == '<')
- {
- source.skip();
-
- if (source.peekNextChar() == '=')
- source.skip();
- }
-
- break;
-
- case '>':
- source.skip();
- result = tokenType_operator;
-
- if (source.peekNextChar() == '=')
- {
- source.skip();
- }
- else if (source.peekNextChar() == '<')
- {
- source.skip();
-
- if (source.peekNextChar() == '=')
- source.skip();
- }
-
- break;
-
- case '|':
- source.skip();
- result = tokenType_operator;
-
- if (source.peekNextChar() == '=')
- {
- source.skip();
- }
- else if (source.peekNextChar() == '|')
- {
- source.skip();
-
- if (source.peekNextChar() == '=')
- source.skip();
- }
-
- break;
-
- case '&':
- source.skip();
- result = tokenType_operator;
-
- if (source.peekNextChar() == '=')
- {
- source.skip();
- }
- else if (source.peekNextChar() == '&')
- {
- source.skip();
-
- if (source.peekNextChar() == '=')
- source.skip();
- }
-
- break;
-
- case '^':
- source.skip();
- result = tokenType_operator;
-
- if (source.peekNextChar() == '=')
- {
- source.skip();
- }
- else if (source.peekNextChar() == '^')
- {
- source.skip();
-
- if (source.peekNextChar() == '=')
- source.skip();
- }
-
- break;
-
- case '#':
- result = tokenType_preprocessor;
- source.skipToEndOfLine();
- break;
-
- default:
- if (CppTokeniser::isIdentifierStart (firstChar))
- result = CppTokeniser::parseIdentifier (source);
- else
- source.skip();
-
- break;
- }
-
- return result;
- }
-
- StringArray CPlusPlusCodeTokeniser::getTokenTypes()
- {
- const char* const types[] =
- {
- "Error",
- "Comment",
- "C++ keyword",
- "Identifier",
- "Integer literal",
- "Float literal",
- "String literal",
- "Operator",
- "Bracket",
- "Punctuation",
- "Preprocessor line",
- 0
- };
-
- return StringArray (types);
- }
-
- Colour CPlusPlusCodeTokeniser::getDefaultColour (const int tokenType)
- {
- const uint32 colours[] =
- {
- 0xffcc0000, // error
- 0xff00aa00, // comment
- 0xff0000cc, // keyword
- 0xff000000, // identifier
- 0xff880000, // int literal
- 0xff885500, // float literal
- 0xff990099, // string literal
- 0xff225500, // operator
- 0xff000055, // bracket
- 0xff004400, // punctuation
- 0xff660000 // preprocessor
- };
-
- if (tokenType >= 0 && tokenType < numElementsInArray (colours))
- return Colour (colours [tokenType]);
-
- return Colours::black;
- }
-
- bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) noexcept
- {
- return CppTokeniser::isReservedKeyword (token.getCharPointer(), token.length());
- }
-
- END_JUCE_NAMESPACE
|