RedPanda-CPP/RedPandaIDE/qsynedit/highlighter/cpp.cpp

1648 lines
42 KiB
C++
Raw Normal View History

2021-12-26 23:18:28 +08:00
/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2021-05-14 23:56:43 +08:00
#include "cpp.h"
#include "../Constants.h"
#include <QFont>
static const QSet<QString> CppStatementKeyWords {
2021-10-28 23:46:54 +08:00
"if",
"for",
"try",
"catch",
"else",
"while",
"do"
2021-10-28 23:46:54 +08:00
};
2021-05-14 23:56:43 +08:00
const QSet<QString> SynEditCppHighlighter::Keywords {
"and",
"and_eq",
"bitand",
"bitor",
"break",
"compl",
"constexpr",
"const_cast",
"continue",
"dynamic_cast",
"else",
"explicit",
"export",
"extern",
"false",
"for",
"mutable",
"noexcept",
"not",
"not_eq",
"nullptr",
"or",
"or_eq",
"register",
"reinterpret_cast",
"static_assert",
"static_cast",
"template",
"this",
"thread_local",
"true",
"typename",
"virtual",
"volatile",
"xor",
"xor_eq",
"delete",
"delete[]",
"goto",
"new",
"return",
"throw",
"using",
"case",
"default",
"alignas",
"alignof",
"decltype",
"if",
"sizeof",
"switch",
"typeid",
"while",
"asm",
"catch",
"do",
"namespace",
"try",
"atomic_cancel",
"atomic_commit",
"atomic_noexcept",
"concept",
"consteval",
"constinit",
"co_wait",
"co_return",
"co_yield",
"reflexpr",
"requires",
"auto",
"bool",
"char",
"char8_t",
"char16_t",
"char32_t",
"double",
"float",
"int",
"long",
"short",
"signed",
"unsigned",
"void",
"wchar_t",
"const",
"inline",
"class",
"enum",
"friend",
"operator",
"private",
"protected",
"public",
"static",
"struct",
"typedef",
"union",
"nullptr",
};
2021-05-26 00:04:20 +08:00
SynEditCppHighlighter::SynEditCppHighlighter(): SynHighlighter()
2021-05-14 23:56:43 +08:00
{
mAsmAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrAssembler);
addAttribute(mAsmAttribute);
mCharAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrCharacter);
addAttribute(mCharAttribute);
mCommentAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrComment);
addAttribute(mCommentAttribute);
mClassAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrClass);
addAttribute(mClassAttribute);
mFloatAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrFloat);
addAttribute(mFloatAttribute);
mFunctionAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrFunction);
addAttribute(mFunctionAttribute);
mGlobalVarAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrGlobalVariable);
addAttribute(mGlobalVarAttribute);
mHexAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrHexadecimal);
addAttribute(mHexAttribute);
mIdentifierAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrIdentifier);
addAttribute(mIdentifierAttribute);
mInvalidAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrIllegalChar);
addAttribute(mInvalidAttribute);
mLocalVarAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrLocalVariable);
addAttribute(mLocalVarAttribute);
mNumberAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrNumber);
addAttribute(mNumberAttribute);
mOctAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrOctal);
addAttribute(mOctAttribute);
mPreprocessorAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrPreprocessor);
addAttribute(mPreprocessorAttribute);
2021-07-02 10:32:29 +08:00
mKeywordAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrReservedWord);
addAttribute(mKeywordAttribute);
2021-05-14 23:56:43 +08:00
mWhitespaceAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrSpace);
addAttribute(mWhitespaceAttribute);
mStringAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrString);
addAttribute(mStringAttribute);
mStringEscapeSequenceAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrStringEscapeSequences);
addAttribute(mStringEscapeSequenceAttribute);
mSymbolAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrSymbol);
addAttribute(mSymbolAttribute);
mVariableAttribute = std::make_shared<SynHighlighterAttribute>(SYNS_AttrVariable);
addAttribute(mVariableAttribute);
2021-10-28 08:56:13 +08:00
resetState();
2021-05-14 23:56:43 +08:00
}
PSynHighlighterAttribute SynEditCppHighlighter::asmAttribute() const
{
return mAsmAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::preprocessorAttribute() const
2021-05-14 23:56:43 +08:00
{
return mPreprocessorAttribute;
2021-05-14 23:56:43 +08:00
}
PSynHighlighterAttribute SynEditCppHighlighter::invalidAttribute() const
{
return mInvalidAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::numberAttribute() const
{
return mNumberAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::floatAttribute() const
{
return mFloatAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::hexAttribute() const
{
return mHexAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::octAttribute() const
{
return mOctAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::stringEscapeSequenceAttribute() const
{
return mStringEscapeSequenceAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::charAttribute() const
{
return mCharAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::variableAttribute() const
{
return mVariableAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::functionAttribute() const
{
return mFunctionAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::classAttribute() const
{
return mClassAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::globalVarAttribute() const
{
return mGlobalVarAttribute;
}
PSynHighlighterAttribute SynEditCppHighlighter::localVarAttribute() const
{
return mLocalVarAttribute;
}
SynEditCppHighlighter::ExtTokenKind SynEditCppHighlighter::getExtTokenId()
{
return mExtTokenId;
}
SynTokenKind SynEditCppHighlighter::getTokenId()
{
if ((mRange.state == RangeState::rsAsm || mRange.state == RangeState::rsAsmBlock)
&& !mAsmStart && !(mTokenId == TokenKind::Comment || mTokenId == TokenKind::Space
|| mTokenId == TokenKind::Null)) {
return TokenKind::Asm;
} else {
return mTokenId;
}
}
void SynEditCppHighlighter::andSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch (mLine[mRun+1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::AndAssign;
break;
case '&':
mRun+=2;
mExtTokenId = ExtTokenKind::LogAnd;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::And;
}
}
void SynEditCppHighlighter::ansiCppProc()
{
mTokenId = TokenKind::Comment;
if (mLine[mRun]==0) {
nullProc();
if ( (mRun<1) || (mLine[mRun-1]!='\\')) {
mRange.state = RangeState::rsUnknown;
return;
}
}
while (mLine[mRun]!=0) {
mRun+=1;
}
mRange.state = RangeState::rsCppCommentEnded;
2021-05-14 23:56:43 +08:00
if (mLine[mRun-1] == '\\' && mLine[mRun]==0) { // continues on next line
mRange.state = RangeState::rsCppComment;
}
}
void SynEditCppHighlighter::ansiCProc()
{
bool finishProcess = false;
mTokenId = TokenKind::Comment;
if (mLine[mRun].unicode() == 0) {
nullProc();
return;
}
while (mLine[mRun]!=0) {
switch(mLine[mRun].unicode()) {
case '*':
if (mLine[mRun+1] == '/') {
mRun += 2;
if (mRange.state == RangeState::rsAnsiCAsm) {
mRange.state = RangeState::rsAsm;
} else if (mRange.state == RangeState::rsAnsiCAsmBlock){
mRange.state = RangeState::rsAsmBlock;
} else if (mRange.state == RangeState::rsDirectiveComment &&
2021-08-16 23:17:48 +08:00
mLine[mRun] != 0 && mLine[mRun]!='\r' && mLine[mRun]!='\n') {
2021-05-14 23:56:43 +08:00
mRange.state = RangeState::rsMultiLineDirective;
} else {
mRange.state = RangeState::rsUnknown;
}
finishProcess = true;
2021-05-14 23:56:43 +08:00
} else
mRun+=1;
2021-05-26 18:32:17 +08:00
break;
2021-05-14 23:56:43 +08:00
default:
mRun+=1;
}
if (finishProcess)
break;
}
}
void SynEditCppHighlighter::asciiCharProc()
{
mTokenId = TokenKind::Char;
do {
if (mLine[mRun] == '\\') {
if (mLine[mRun+1] == '\'' || mLine[mRun+1] == '\\') {
mRun+=1;
}
}
mRun+=1;
} while (mLine[mRun]!=0 && mLine[mRun]!='\'');
if (mLine[mRun] == '\'')
mRun+=1;
mRange.state = RangeState::rsUnknown;
}
void SynEditCppHighlighter::atSymbolProc()
{
mTokenId = TokenKind::Unknown;
mRun+=1;
}
void SynEditCppHighlighter::braceCloseProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::BraceClose;
if (mRange.state == RangeState::rsAsmBlock) {
mRange.state = rsUnknown;
}
mRange.braceLevel -= 1;
if (mRange.braceLevel<0)
mRange.braceLevel = 0;
2021-10-28 08:56:13 +08:00
if (mRange.leftBraces>0) {
mRange.leftBraces--;
2021-09-23 14:07:47 +08:00
} else {
2021-10-28 08:56:13 +08:00
mRange.rightBraces++ ;
}
popIndents(sitBrace);
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::braceOpenProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::BraceOpen;
if (mRange.state == RangeState::rsAsm) {
mRange.state = RangeState::rsAsmBlock;
mAsmStart = true;
}
mRange.braceLevel += 1;
2021-10-28 08:56:13 +08:00
mRange.leftBraces++;
if (mRange.getLastIndent() == sitStatement) {
2021-10-28 23:46:54 +08:00
// if last indent is started by 'if' 'for' etc
// just replace it
while (mRange.getLastIndent() == sitStatement)
popIndents(sitStatement);
pushIndents(sitBrace);
// int idx = mRange.indents.length()-1;
// if (idx < mRange.firstIndentThisLine) {
// mRange.firstIndentThisLine = idx;
// }
// mRange.indents.replace(idx,1,BraceIndentType);
2021-10-28 23:46:54 +08:00
} else {
pushIndents(sitBrace);
2021-10-28 23:46:54 +08:00
}
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::colonProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1]==':') {
mRun+=2;
mExtTokenId = ExtTokenKind::ScopeResolution;
} else {
mRun+=1;
mExtTokenId = ExtTokenKind::Colon;
}
}
void SynEditCppHighlighter::commaProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::Comma;
}
void SynEditCppHighlighter::directiveProc()
{
QString preContents = mLineString.left(mRun).trimmed();
if (!preContents.isEmpty()) { // '#' is not first non-space char on the line, treat it as an invalid char
2021-05-14 23:56:43 +08:00
mTokenId = TokenKind::Unknown;
mRun+=1;
return;
}
mTokenId = TokenKind::Directive;
mRun+=1;
//skip spaces
while (mLine[mRun]!=0 && isSpaceChar(mLine[mRun])) {
2021-05-14 23:56:43 +08:00
mRun+=1;
}
while (mLine[mRun]!=0 && isIdentChar(mLine[mRun])) {
mRun+=1;
}
mRange.state = RangeState::rsUnknown;
// do {
// switch(mLine[mRun].unicode()) {
// case '/': //comment?
// switch (mLine[mRun+1].unicode()) {
// case '/': // is end of directive as well
// mRange.state = RangeState::rsUnknown;
// return;
// case '*': // might be embeded only
// mRange.state = RangeState::rsDirectiveComment;
// return;
// }
// break;
// case '\\': // yet another line?
// if (mLine[mRun+1] == 0) {
// mRun+=1;
// mRange.state = RangeState::rsMultiLineDirective;
// return;
// }
// break;
// }
// mRun+=1;
// } while (mLine[mRun]!=0);
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::directiveEndProc()
{
mTokenId = TokenKind::Directive;
if (mLine[mRun] == 0) {
nullProc();
return;
}
mRange.state = RangeState::rsUnknown;
do {
switch(mLine[mRun].unicode()) {
case '/': //comment?
switch (mLine[mRun+1].unicode()) {
case '/': // is end of directive as well
mRange.state = RangeState::rsUnknown;
return;
case '*': // might be embeded only
mRange.state = RangeState::rsDirectiveComment;
return;
}
break;
case '\\': // yet another line?
if (mLine[mRun+1] == 0) {
mRun+=1;
mRange.state = RangeState::rsMultiLineDirective;
return;
}
break;
}
mRun+=1;
} while (mLine[mRun]!=0);
}
void SynEditCppHighlighter::equalProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1] == '=') {
mRun += 2;
mExtTokenId = ExtTokenKind::LogEqual;
} else {
mRun += 1;
mExtTokenId = ExtTokenKind::Assign;
}
}
void SynEditCppHighlighter::greaterProc()
{
mTokenId = TokenKind::Symbol;
switch (mLine[mRun + 1].unicode()) {
case '=':
mRun += 2;
mExtTokenId = ExtTokenKind::GreaterThanEqual;
break;
case '>':
if (mLine[mRun+2] == '=') {
mRun+=3;
mExtTokenId = ExtTokenKind::ShiftRightAssign;
} else {
mRun += 2;
mExtTokenId = ExtTokenKind::ShiftRight;
}
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::GreaterThan;
}
}
void SynEditCppHighlighter::identProc()
{
int wordEnd = mRun;
while (isIdentChar(mLine[wordEnd])) {
wordEnd+=1;
}
QString word = mLineString.mid(mRun,wordEnd-mRun);
mRun=wordEnd;
if (isKeyword(word)) {
mTokenId = TokenKind::Key;
if (CppStatementKeyWords.contains(word)) {
pushIndents(sitStatement);
2021-10-28 23:46:54 +08:00
}
2021-05-14 23:56:43 +08:00
} else {
mTokenId = TokenKind::Identifier;
}
}
void SynEditCppHighlighter::lowerProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun+1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::LessThanEqual;
break;
case '<':
if (mLine[mRun+2] == '=') {
mRun+=3;
mExtTokenId = ExtTokenKind::ShiftLeftAssign;
} else {
mRun+=2;
mExtTokenId = ExtTokenKind::ShiftLeft;
}
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::LessThan;
}
}
void SynEditCppHighlighter::minusProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun+1].unicode()) {
case '=':
mRun += 2;
mExtTokenId = ExtTokenKind::SubtractAssign;
break;
case '-':
mRun += 2;
mExtTokenId = ExtTokenKind::Decrement;
break;
case '>':
2021-12-03 11:40:05 +08:00
if (mLine[mRun+2]=='*') {
mRun += 3;
mExtTokenId = ExtTokenKind::PointerToMemberOfPointer;
} else {
mRun += 2;
mExtTokenId = ExtTokenKind::Arrow;
}
2021-05-14 23:56:43 +08:00
break;
default:
mRun += 1;
mExtTokenId = ExtTokenKind::Subtract;
}
}
void SynEditCppHighlighter::modSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun + 1].unicode()) {
case '=':
mRun += 2;
mExtTokenId = ExtTokenKind::ModAssign;
break;
default:
mRun += 1;
mExtTokenId = ExtTokenKind::Mod;
}
}
void SynEditCppHighlighter::notSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun + 1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::NotEqual;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::LogComplement;
}
}
void SynEditCppHighlighter::nullProc()
{
if ((mRun-1>=0) && isSpaceChar(mLine[mRun-1]) &&
(mRange.state == RangeState::rsCppComment
|| mRange.state == RangeState::rsDirective
|| mRange.state == RangeState::rsString
|| mRange.state == RangeState::rsMultiLineString
|| mRange.state == RangeState::rsMultiLineDirective) ) {
mRange.state = RangeState::rsUnknown;
} else
mTokenId = TokenKind::Null;
}
void SynEditCppHighlighter::numberProc()
{
int idx1; // token[1]
idx1 = mRun;
mRun+=1;
mTokenId = TokenKind::Number;
bool shouldExit = false;
while (mLine[mRun]!=0) {
switch(mLine[mRun].unicode()) {
case '\'':
if (mTokenId != TokenKind::Number) {
mTokenId = TokenKind::Symbol;
return;
}
break;
case '.':
if (mLine[mRun+1] == '.') {
mRun+=2;
mTokenId = TokenKind::Unknown;
return;
} else if (mTokenId != TokenKind::Hex) {
mTokenId = TokenKind::Float;
} else {
mTokenId = TokenKind::Unknown;
return;
}
break;
case '-':
case '+':
if (mTokenId != TokenKind::Float) // number <> float. an arithmetic operator
return;
if (mLine[mRun-1]!= 'e' && mLine[mRun-1]!='E') // number = float, but no exponent. an arithmetic operator
return;
if (mLine[mRun+1]<'0' || mLine[mRun+1]>'9') {// invalid
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if ((mRun == idx1+1) && (mLine[idx1] == '0')) { // octal number
mTokenId = TokenKind::Octal;
}
break;
case '8':
case '9':
if ( (mLine[idx1]=='0') && (mTokenId != TokenKind::Hex) && (mTokenId != TokenKind::Float) ) // invalid octal char
mTokenId = TokenKind::Unknown; // we must continue parse, it may be an float number
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'A':
case 'B':
case 'C':
case 'D':
if (mTokenId!=TokenKind::Hex) { //invalid
mTokenId = TokenKind::Unknown;
return;
}
break;
case 'e':
case 'E':
if (mTokenId!=TokenKind::Hex) {
2021-08-16 23:17:48 +08:00
if (mLine[mRun-1]>='0' || mLine[mRun-1]<='9' ) {//exponent
2021-05-14 23:56:43 +08:00
for (int i=idx1;i<mRun;i++) {
if (mLine[i] == 'e' || mLine[i]=='E') { // too many exponents
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
}
if (mLine[mRun+1]!='+' && mLine[mRun+1]!='-' && !(mLine[mRun+1]>='0' && mLine[mRun+1]<='9')) {
return;
} else {
mTokenId = TokenKind::Float;
}
} else {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
}
break;
case 'f':
case 'F':
if (mTokenId!=TokenKind::Hex) {
for (int i=idx1;i<mRun;i++) {
if (mLine[i] == 'f' || mLine[i]=='F') {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
}
if (mTokenId == TokenKind::Float) {
if (mLine[mRun-1]=='l' || mLine[mRun-1]=='L') {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
} else {
mTokenId = TokenKind::Float;
}
}
break;
case 'l':
case 'L':
for (int i=idx1;i<=mRun-2;i++) {
if (mLine[i] == 'l' && mLine[i]=='L') {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
}
if (mTokenId == TokenKind::Float && (mLine[mRun-1]=='f' || mLine[mRun-1]=='F')) {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
break;
case 'u':
case 'U':
if (mTokenId == TokenKind::Float) {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
} else {
for (int i=idx1;i<mRun;i++) {
if (mLine[i] == 'u' || mLine[i]=='U') {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
}
}
break;
case 'x':
case 'X':
if ((mRun == idx1+1) && (mLine[idx1]=='0') &&
((mLine[mRun+1]>='0' && mLine[mRun+1]<='9')
|| (mLine[mRun+1]>='a' && mLine[mRun+1]<='f')
|| (mLine[mRun+1]>='A' && mLine[mRun+1]<='F')) ) {
mTokenId = TokenKind::Hex;
} else {
mRun+=1;
mTokenId = TokenKind::Unknown;
return;
}
break;
2021-05-26 00:04:20 +08:00
default:
shouldExit=true;
2021-05-14 23:56:43 +08:00
}
2021-05-26 00:04:20 +08:00
if (shouldExit) {
break;
}
mRun+=1;
2021-05-14 23:56:43 +08:00
}
if (mLine[mRun-1] == '\'') {
mTokenId = TokenKind::Unknown;
}
}
void SynEditCppHighlighter::orSymbolProc()
{
mTokenId = TokenKind::Symbol;
switch ( mLine[mRun+1].unicode()) {
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::IncOrAssign;
break;
case '|':
mRun+=2;
mExtTokenId = ExtTokenKind::LogOr;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::IncOr;
}
}
void SynEditCppHighlighter::plusProc()
{
mTokenId = TokenKind::Symbol;
switch(mLine[mRun+1].unicode()){
case '=':
mRun+=2;
mExtTokenId = ExtTokenKind::AddAssign;
break;
case '+':
mRun+=2;
mExtTokenId = ExtTokenKind::Increment;
break;
default:
mRun+=1;
mExtTokenId = ExtTokenKind::Add;
}
}
void SynEditCppHighlighter::pointProc()
{
mTokenId = TokenKind::Symbol;
2021-12-03 11:40:05 +08:00
if (mLine[mRun+1] == '*' ) {
mRun+=2;
mExtTokenId = ExtTokenKind::PointerToMemberOfObject;
} else if (mLine[mRun+1] == '.' && mLine[mRun+2] == '.') {
2021-05-14 23:56:43 +08:00
mRun+=3;
mExtTokenId = ExtTokenKind::Ellipse;
2021-08-26 20:18:20 +08:00
} else if (mLine[mRun+1]>='0' && mLine[mRun+1]<='9') {
2021-05-14 23:56:43 +08:00
numberProc();
} else {
mRun+=1;
mExtTokenId = ExtTokenKind::Point;
}
}
void SynEditCppHighlighter::questionProc()
{
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::Question;
mRun+=1;
}
void SynEditCppHighlighter::rawStringProc()
{
bool noEscaping = false;
if (mRange.state == RangeState::rsRawStringNotEscaping)
noEscaping = true;
mTokenId = TokenKind::RawString;
mRange.state = RangeState::rsRawString;
while (mLine[mRun]!=0) {
if ((!noEscaping) && (mLine[mRun]=='"')) {
mRun+=1;
break;
}
switch (mLine[mRun].unicode()) {
case '(':
noEscaping = true;
break;
case ')':
noEscaping = false;
break;
}
mRun+=1;
}
mRange.state = RangeState::rsUnknown;
}
void SynEditCppHighlighter::roundCloseProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::RoundClose;
mRange.parenthesisLevel--;
if (mRange.parenthesisLevel<0)
mRange.parenthesisLevel=0;
popIndents(sitParenthesis);
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::roundOpenProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::RoundOpen;
mRange.parenthesisLevel++;
pushIndents(sitParenthesis);
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::semiColonProc()
{
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SemiColon;
if (mRange.state == RangeState::rsAsm)
mRange.state = RangeState::rsUnknown;
while (mRange.getLastIndent() == sitStatement) {
popIndents(sitStatement);
2021-10-28 23:46:54 +08:00
}
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::slashProc()
{
switch(mLine[mRun+1].unicode()) {
case '/': // Cpp style comment
mTokenId = TokenKind::Comment;
mRun+=2;
mRange.state = RangeState::rsCppComment;
return;
case '*': // C style comment
mTokenId = TokenKind::Comment;
if (mRange.state == RangeState::rsAsm) {
mRange.state = RangeState::rsAnsiCAsm;
} else if (mRange.state == RangeState::rsAsmBlock) {
mRange.state = RangeState::rsAnsiCAsmBlock;
} else if (mRange.state == RangeState::rsDirective) {
mRange.state = RangeState::rsDirectiveComment;
} else {
mRange.state = RangeState::rsAnsiC;
}
mRun += 2;
if (mLine[mRun]!=0)
ansiCProc();
break;
case '=':
mRun+=2;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::DivideAssign;
break;
default:
mRun += 1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::Divide;
}
}
void SynEditCppHighlighter::spaceProc()
{
mRun += 1;
mTokenId = TokenKind::Space;
while (mLine[mRun]>=1 && mLine[mRun]<=32)
mRun+=1;
mRange.state = RangeState::rsUnknown;
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::squareCloseProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SquareClose;
mRange.bracketLevel--;
if (mRange.bracketLevel<0)
mRange.bracketLevel=0;
popIndents(sitBracket);
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::squareOpenProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SquareOpen;
mRange.bracketLevel++;
pushIndents(sitBracket);
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::starProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1] == '=') {
mRun += 2;
mExtTokenId = ExtTokenKind::MultiplyAssign;
} else {
mRun += 1;
mExtTokenId = ExtTokenKind::Star;
}
}
void SynEditCppHighlighter::stringEndProc()
{
mTokenId = TokenKind::String;
if (mLine[mRun]==0) {
nullProc();
return;
}
mRange.state = RangeState::rsUnknown;
while (mLine[mRun]!=0) {
if (mLine[mRun]=='"') {
mRun += 1;
break;
}
if (mLine[mRun].unicode()=='\\') {
switch(mLine[mRun+1].unicode()) {
case '\'':
case '"':
case '\\':
case '?':
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'x':
case 'u':
case 'U':
mRange.state = RangeState::rsMultiLineStringEscapeSeq;
return;
case 0:
mRun+=1;
mRange.state = RangeState::rsMultiLineString;
return;
}
}
mRun += 1;
}
}
void SynEditCppHighlighter::stringEscapeSeqProc()
{
mTokenId = TokenKind::StringEscapeSeq;
mRun+=1;
switch(mLine[mRun].unicode()) {
case '\'':
case '"':
case '?':
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '\\':
mRun+=1;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
for (int i=0;i<3;i++) {
if (mLine[mRun]<'0' || mLine[mRun]>'7')
break;
mRun+=1;
}
break;
case '8':
case '9':
mTokenId = TokenKind::Unknown;
mRun+=1;
break;
case 'x':
mRun+=1;
if ( !(
(mLine[mRun]>='0' && mLine[mRun]<='9')
|| (mLine[mRun]>='a' && mLine[mRun]<='f')
|| (mLine[mRun]>='A' && mLine[mRun]<='F')
)) {
mTokenId = TokenKind::Unknown;
} else {
while (
(mLine[mRun]>='0' && mLine[mRun]<='9')
|| (mLine[mRun]>='a' && mLine[mRun]<='f')
|| (mLine[mRun]>='A' && mLine[mRun]<='F')
) {
mRun+=1;
}
}
break;
case 'u':
mRun+=1;
for (int i=0;i<4;i++) {
if (mLine[mRun]<'0' || mLine[mRun]>'7') {
mTokenId = TokenKind::Unknown;
return;
}
mRun+=1;
}
break;
case 'U':
mRun+=1;
for (int i=0;i<8;i++) {
if (mLine[mRun]<'0' || mLine[mRun]>'7') {
mTokenId = TokenKind::Unknown;
return;
}
mRun+=1;
}
break;
}
if (mRange.state == RangeState::rsMultiLineStringEscapeSeq)
mRange.state = RangeState::rsMultiLineString;
else
mRange.state = RangeState::rsString;
}
void SynEditCppHighlighter::stringProc()
{
if (mLine[mRun] == 0) {
mRange.state = RangeState::rsUnknown;
return;
}
mTokenId = TokenKind::String;
mRange.state = RangeState::rsString;
while (mLine[mRun]!=0) {
if (mLine[mRun]=='"') {
mRun+=1;
break;
}
if (mLine[mRun].unicode()=='\\') {
switch(mLine[mRun+1].unicode()) {
case '\'':
case '"':
case '\\':
case '?':
case 'a':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'x':
case 'u':
case 'U':
mRange.state = RangeState::rsStringEscapeSeq;
return;
case 0:
mRun+=1;
mRange.state = RangeState::rsMultiLineString;
return;
}
}
2021-05-26 00:04:20 +08:00
mRun+=1;
2021-05-14 23:56:43 +08:00
}
mRange.state = RangeState::rsUnknown;
}
void SynEditCppHighlighter::stringStartProc()
{
mTokenId = TokenKind::String;
mRun += 1;
if (mLine[mRun]==0) {
mRange.state = RangeState::rsUnknown;
return;
}
stringProc();
}
void SynEditCppHighlighter::tildeProc()
{
mRun+=1;
mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::BitComplement;
}
void SynEditCppHighlighter::unknownProc()
{
mRun+=1;
mTokenId = TokenKind::Unknown;
}
void SynEditCppHighlighter::xorSymbolProc()
{
mTokenId = TokenKind::Symbol;
if (mLine[mRun+1]=='=') {
mRun+=2;
mExtTokenId = ExtTokenKind::XorAssign;
} else {
mRun+=1;
mExtTokenId = ExtTokenKind::Xor;
}
}
void SynEditCppHighlighter::processChar()
{
switch(mLine[mRun].unicode()) {
case '&':
andSymbolProc();
break;
case '\'':
asciiCharProc();
break;
case '@':
atSymbolProc();
break;
case '}':
braceCloseProc();
break;
case '{':
braceOpenProc();
break;
case '\r':
case '\n':
spaceProc();
break;
case ':':
colonProc();
break;
case ',':
commaProc();
break;
case '#':
directiveProc();
break;
case '=':
equalProc();
break;
case '>':
greaterProc();
break;
case '?':
questionProc();
break;
case '<':
lowerProc();
break;
case '-':
minusProc();
break;
case '%':
modSymbolProc();
break;
case '!':
notSymbolProc();
break;
case 0:
nullProc();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
numberProc();
break;
case '|':
orSymbolProc();
break;
case '+':
plusProc();
break;
case '.':
pointProc();
break;
case ')':
roundCloseProc();
break;
case '(':
roundOpenProc();
break;
case ';':
semiColonProc();
break;
case '/':
slashProc();
break;
case ']':
squareCloseProc();
break;
case '[':
squareOpenProc();
break;
case '*':
starProc();
break;
case '"':
stringStartProc();
break;
case '~':
tildeProc();
break;
case '^':
xorSymbolProc();
break;
default:
if (isIdentChar(mLine[mRun])) {
identProc();
} else if (isSpaceChar(mLine[mRun])) {
spaceProc();
} else {
unknownProc();
}
}
}
void SynEditCppHighlighter::popIndents(int indentType)
2021-10-28 23:46:54 +08:00
{
while (!mRange.indents.isEmpty() && mRange.indents.back()!=indentType) {
mRange.indents.pop_back();
2021-10-28 23:46:54 +08:00
}
if (!mRange.indents.isEmpty()) {
int idx = mRange.indents.length()-1;
if (idx < mRange.firstIndentThisLine) {
mRange.matchingIndents.append(mRange.indents[idx]);
}
mRange.indents.pop_back();
}
}
void SynEditCppHighlighter::pushIndents(int indentType)
{
int idx = mRange.indents.length();
if (idx<mRange.firstIndentThisLine)
mRange.firstIndentThisLine = idx;
mRange.indents.push_back(indentType);
2021-10-28 23:46:54 +08:00
}
2021-05-14 23:56:43 +08:00
bool SynEditCppHighlighter::getTokenFinished() const
{
if (mTokenId == TokenKind::Comment
|| mTokenId == TokenKind::String
|| mTokenId == TokenKind::RawString) {
return mRange.state == RangeState::rsUnknown;
}
return true;
}
bool SynEditCppHighlighter::isLastLineCommentNotFinished(int state) const
{
return (state == RangeState::rsAnsiC ||
state == RangeState::rsAnsiCAsm ||
state == RangeState::rsAnsiCAsmBlock ||
state == RangeState::rsDirectiveComment||
state == RangeState::rsCppComment);
}
bool SynEditCppHighlighter::isLastLineStringNotFinished(int state) const
{
return state == RangeState::rsMultiLineString;
}
bool SynEditCppHighlighter::eol() const
{
return mTokenId == TokenKind::Null;
}
QString SynEditCppHighlighter::getToken() const
{
return mLineString.mid(mTokenPos,mRun-mTokenPos);
}
PSynHighlighterAttribute SynEditCppHighlighter::getTokenAttribute() const
{
switch (mTokenId) {
case TokenKind::Asm:
return mAsmAttribute;
case TokenKind::Comment:
return mCommentAttribute;
case TokenKind::Directive:
return mPreprocessorAttribute;
2021-05-14 23:56:43 +08:00
case TokenKind::Identifier:
return mIdentifierAttribute;
case TokenKind::Key:
2021-07-02 10:32:29 +08:00
return mKeywordAttribute;
2021-05-14 23:56:43 +08:00
case TokenKind::Number:
return mNumberAttribute;
case TokenKind::Float:
case TokenKind::HexFloat:
return mFloatAttribute;
case TokenKind::Hex:
return mHexAttribute;
case TokenKind::Octal:
return mOctAttribute;
case TokenKind::Space:
return mWhitespaceAttribute;
case TokenKind::String:
return mStringAttribute;
case TokenKind::StringEscapeSeq:
return mStringEscapeSequenceAttribute;
case TokenKind::RawString:
return mStringAttribute;
case TokenKind::Char:
return mCharAttribute;
case TokenKind::Symbol:
return mSymbolAttribute;
case TokenKind::Unknown:
return mInvalidAttribute;
default:
return mInvalidAttribute;
}
}
SynTokenKind SynEditCppHighlighter::getTokenKind()
{
return mTokenId;
}
int SynEditCppHighlighter::getTokenPos()
{
return mTokenPos;
}
void SynEditCppHighlighter::next()
{
mAsmStart = false;
mTokenPos = mRun;
do {
switch (mRange.state) {
case RangeState::rsAnsiC:
case RangeState::rsAnsiCAsm:
case RangeState::rsAnsiCAsmBlock:
case RangeState::rsDirectiveComment:
ansiCProc();
break;
case RangeState::rsString:
stringProc();
break;
case RangeState::rsCppComment:
ansiCppProc();
break;
case RangeState::rsMultiLineDirective:
directiveEndProc();
break;
case RangeState::rsMultiLineString:
stringEndProc();
break;
case RangeState::rsRawStringEscaping:
case RangeState::rsRawStringNotEscaping:
rawStringProc();
break;
case RangeState::rsStringEscapeSeq:
case RangeState::rsMultiLineStringEscapeSeq:
stringEscapeSeqProc();
break;
case RangeState::rsChar:
if (mLine[mRun]=='\'') {
mRange.state = rsUnknown;
mTokenId = TokenKind::Char;
mRun+=1;
} else {
asciiCharProc();
}
break;
default:
mRange.state = RangeState::rsUnknown;
if (mLine[mRun] == 'R' && mLine[mRun+1] == '"') {
mRun+=2;
rawStringProc();
} else if ((mLine[mRun] == 'L' || mLine[mRun] == 'u' || mLine[mRun]=='U') && mLine[mRun+1]=='\"') {
mRun+=1;
stringStartProc();
} else if (mLine[mRun] == 'u' && mLine[mRun+1] == '8' && mLine[mRun+2]=='\"') {
mRun+=2;
stringStartProc();
} else
processChar();
}
} while (mTokenId!=TokenKind::Null && mRun<=mTokenPos);
}
void SynEditCppHighlighter::setLine(const QString &newLine, int lineNumber)
{
mLineString = newLine;
mLine = mLineString.data();
mLineNumber = lineNumber;
mRun = 0;
2021-10-28 09:20:58 +08:00
mRange.leftBraces = 0;
mRange.rightBraces = 0;
mRange.firstIndentThisLine = mRange.indents.length();
mRange.matchingIndents.clear();
2021-05-14 23:56:43 +08:00
next();
}
bool SynEditCppHighlighter::isKeyword(const QString &word)
{
return Keywords.contains(word);
}
SynHighlighterTokenType SynEditCppHighlighter::getTokenType()
{
switch(mTokenId) {
case TokenKind::Comment:
return SynHighlighterTokenType::Comment;
case TokenKind::Directive:
return SynHighlighterTokenType::PreprocessDirective;
case TokenKind::Identifier:
return SynHighlighterTokenType::Identifier;
case TokenKind::Key:
return SynHighlighterTokenType::Keyword;
case TokenKind::Space:
switch (mRange.state) {
case RangeState::rsAnsiC:
case RangeState::rsAnsiCAsm:
case RangeState::rsAnsiCAsmBlock:
case RangeState::rsAsm:
case RangeState::rsAsmBlock:
case RangeState::rsDirectiveComment:
case RangeState::rsCppComment:
return SynHighlighterTokenType::Comment;
case RangeState::rsDirective:
case RangeState::rsMultiLineDirective:
return SynHighlighterTokenType::PreprocessDirective;
case RangeState::rsString:
case RangeState::rsMultiLineString:
case RangeState::rsStringEscapeSeq:
case RangeState::rsMultiLineStringEscapeSeq:
case RangeState::rsRawString:
return SynHighlighterTokenType::String;
case RangeState::rsChar :
return SynHighlighterTokenType::Character;
default:
return SynHighlighterTokenType::Space;
}
case TokenKind::String:
return SynHighlighterTokenType::String;
case TokenKind::StringEscapeSeq:
return SynHighlighterTokenType::StringEscapeSequence;
case TokenKind::RawString:
return SynHighlighterTokenType::String;
case TokenKind::Char:
return SynHighlighterTokenType::Character;
case TokenKind::Symbol:
return SynHighlighterTokenType::Symbol;
2021-08-26 20:18:20 +08:00
case TokenKind::Number:
return SynHighlighterTokenType::Number;
2021-05-14 23:56:43 +08:00
default:
return SynHighlighterTokenType::Default;
}
}
void SynEditCppHighlighter::setState(const SynRangeState& rangeState)
2021-05-14 23:56:43 +08:00
{
mRange = rangeState;
2021-10-28 08:56:13 +08:00
// current line's left / right parenthesis count should be reset before parsing each line
mRange.leftBraces = 0;
mRange.rightBraces = 0;
mRange.firstIndentThisLine = mRange.indents.length();
mRange.matchingIndents.clear();
2021-05-14 23:56:43 +08:00
}
void SynEditCppHighlighter::resetState()
{
mRange.state = RangeState::rsUnknown;
mRange.braceLevel = 0;
mRange.bracketLevel = 0;
mRange.parenthesisLevel = 0;
2021-10-28 08:56:13 +08:00
mRange.leftBraces = 0;
mRange.rightBraces = 0;
mRange.indents.clear();
mRange.firstIndentThisLine = 0;
mRange.matchingIndents.clear();
2021-10-28 08:56:13 +08:00
mAsmStart = false;
2021-05-14 23:56:43 +08:00
}
SynHighlighterClass SynEditCppHighlighter::getClass() const
{
return SynHighlighterClass::CppHighlighter;
}
QString SynEditCppHighlighter::getName() const
{
return SYN_HIGHLIGHTER_CPP;
2021-05-14 23:56:43 +08:00
}
2021-05-26 00:04:20 +08:00
QString SynEditCppHighlighter::languageName()
{
return "cpp";
}
SynHighlighterLanguage SynEditCppHighlighter::language()
{
return SynHighlighterLanguage::Cpp;
}
2021-05-26 18:32:17 +08:00
SynRangeState SynEditCppHighlighter::getRangeState() const
{
return mRange;
}
2021-10-02 14:54:49 +08:00
bool SynEditCppHighlighter::isIdentChar(const QChar &ch) const
{
return ch=='_' || ch.isDigit() || ch.isLetter();
}
QSet<QString> SynEditCppHighlighter::keywords() const
{
return Keywords;
}