diff options
Diffstat (limited to 'lexers/LexCPP.cxx')
-rw-r--r-- | lexers/LexCPP.cxx | 96 |
1 files changed, 63 insertions, 33 deletions
diff --git a/lexers/LexCPP.cxx b/lexers/LexCPP.cxx index 1581b6826..6d3f55684 100644 --- a/lexers/LexCPP.cxx +++ b/lexers/LexCPP.cxx @@ -245,12 +245,24 @@ struct PPDefinition { } }; +const int inactiveFlag = 0x40; + class LinePPState { - int state; - int ifTaken; - int level; + // Track the state of preprocessor conditionals to allow showing active and inactive + // code in different styles. + // Only works up to 31 levels of conditional nesting. + + // state is a bit mask with 1 bit per level + // bit is 1 for level if section inactive, so any bits set = inactive style + int state = 0; + // ifTaken is a bit mask with 1 bit per level + // bit is 1 for level if some branch at this level has been taken + int ifTaken = 0; + // level is the nesting level of #if constructs + int level = -1; + static const int maximumNestingLevel = 31; bool ValidLevel() const noexcept { - return level >= 0 && level < 32; + return level >= 0 && level < maximumNestingLevel; } int maskLevel() const noexcept { if (level >= 0) { @@ -260,11 +272,17 @@ class LinePPState { } } public: - LinePPState() noexcept : state(0), ifTaken(0), level(-1) { + LinePPState() noexcept { + } + bool IsActive() const noexcept { + return state == 0; } bool IsInactive() const noexcept { return state != 0; } + int ActiveState() const noexcept { + return state ? inactiveFlag : 0; + } bool CurrentIfTaken() const noexcept { return (ifTaken & maskLevel()) != 0; } @@ -521,7 +539,6 @@ class LexerCPP : public ILexer4 { OptionSetCPP osCPP; EscapeSequence escapeSeq; SparseState<std::string> rawStringTerminators; - enum { activeFlag = 0x40 }; enum { ssIdentifier, ssDocKeyword }; SubStyles subStyles; std::string returnBuffer; @@ -534,7 +551,7 @@ public: setMultOp(CharacterSet::setNone, "*/%"), setRelOp(CharacterSet::setNone, "=!<>"), setLogicalOp(CharacterSet::setNone, "|&"), - subStyles(styleSubable, 0x80, 0x40, activeFlag) { + subStyles(styleSubable, 0x80, 0x40, inactiveFlag) { } // Deleted so LexerCPP objects can not be copied. LexerCPP(const LexerCPP &) = delete; @@ -585,8 +602,8 @@ public: } int SCI_METHOD StyleFromSubStyle(int subStyle) override { const int styleBase = subStyles.BaseStyle(MaskActive(subStyle)); - const int active = subStyle & activeFlag; - return styleBase | active; + const int inactive = subStyle & inactiveFlag; + return styleBase | inactive; } int SCI_METHOD PrimaryStyleFromStyle(int style) noexcept override { return MaskActive(style); @@ -598,7 +615,7 @@ public: subStyles.SetIdentifiers(style, identifiers); } int SCI_METHOD DistanceToSecondaryStyles() noexcept override { - return activeFlag; + return inactiveFlag; } const char * SCI_METHOD GetSubStyleBases() noexcept override { return styleSubable; @@ -606,7 +623,7 @@ public: int SCI_METHOD NamedStyles() override { return std::max(subStyles.LastAllocated() + 1, sizeLexicalClasses) + - activeFlag; + inactiveFlag; } const char * SCI_METHOD NameOfStyle(int style) override { if (style >= NamedStyles()) @@ -624,11 +641,11 @@ public: if (firstSubStyle >= 0) { const int lastSubStyle = subStyles.LastAllocated(); if (((style >= firstSubStyle) && (style <= (lastSubStyle))) || - ((style >= firstSubStyle + activeFlag) && (style <= (lastSubStyle + activeFlag)))) { + ((style >= firstSubStyle + inactiveFlag) && (style <= (lastSubStyle + inactiveFlag)))) { int styleActive = style; if (style > lastSubStyle) { returnBuffer = "inactive "; - styleActive -= activeFlag; + styleActive -= inactiveFlag; } const int styleMain = StyleFromSubStyle(styleActive); returnBuffer += lexicalClasses[styleMain].tags; @@ -637,9 +654,9 @@ public: } if (style < sizeLexicalClasses) return lexicalClasses[style].tags; - if (style >= activeFlag) { + if (style >= inactiveFlag) { returnBuffer = "inactive "; - const int styleActive = style - activeFlag; + const int styleActive = style - inactiveFlag; if (styleActive < sizeLexicalClasses) returnBuffer += lexicalClasses[styleActive].tags; else @@ -664,7 +681,7 @@ public: return new LexerCPP(false); } constexpr static int MaskActive(int style) noexcept { - return style & ~activeFlag; + return style & ~inactiveFlag; } void EvaluateTokens(std::vector<std::string> &tokens, const SymbolTable &preprocessorDefinitions); std::vector<std::string> Tokenize(const std::string &expr) const; @@ -822,7 +839,7 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1); SparseState<std::string> rawSTNew(lineCurrent); - int activitySet = preproc.IsInactive() ? activeFlag : 0; + int activitySet = preproc.ActiveState(); const WordClassifier &classifierIdentifiers = subStyles.Classifier(SCE_C_IDENTIFIER); const WordClassifier &classifierDocKeyWords = subStyles.Classifier(SCE_C_COMMENTDOCKEYWORD); @@ -849,7 +866,7 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i isIncludePreprocessor = false; inRERange = false; if (preproc.IsInactive()) { - activitySet = activeFlag; + activitySet = inactiveFlag; sc.SetState(sc.state | activitySet); } } @@ -1274,6 +1291,8 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i isIncludePreprocessor = true; } else { if (options.trackPreprocessor) { + // If #if is nested too deeply (>31 levels) the active/inactive appearance + // will stop reflecting the code. if (sc.Match("ifdef") || sc.Match("ifndef")) { const bool isIfDef = sc.Match("ifdef"); const int startRest = isIfDef ? 5 : 6; @@ -1285,41 +1304,52 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i const bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions); preproc.StartSection(ifGood); } else if (sc.Match("else")) { + // #else is shown as active if either preceding or following section is active + // as that means that it contributed to the result. if (!preproc.CurrentIfTaken()) { + // Inactive, may become active if parent scope active + assert(sc.state == (SCE_C_PREPROCESSOR|inactiveFlag)); preproc.InvertCurrentLevel(); - activitySet = preproc.IsInactive() ? activeFlag : 0; + activitySet = preproc.ActiveState(); + // If following is active then show "else" as active if (!activitySet) - sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); - } else if (!preproc.IsInactive()) { + sc.ChangeState(SCE_C_PREPROCESSOR); + } else if (preproc.IsActive()) { + // Active -> inactive + assert(sc.state == SCE_C_PREPROCESSOR); preproc.InvertCurrentLevel(); - activitySet = preproc.IsInactive() ? activeFlag : 0; - if (!activitySet) - sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + activitySet = preproc.ActiveState(); + // Continue to show "else" as active as it ends active section. } } else if (sc.Match("elif")) { // Ensure only one chosen out of #if .. #elif .. #elif .. #else .. #endif + // #elif is shown as active if either preceding or following section is active + // as that means that it contributed to the result. if (!preproc.CurrentIfTaken()) { + // Inactive, if expression true then may become active if parent scope active + assert(sc.state == (SCE_C_PREPROCESSOR|inactiveFlag)); // Similar to #if std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 4, true); const bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions); if (ifGood) { preproc.InvertCurrentLevel(); - activitySet = preproc.IsInactive() ? activeFlag : 0; + activitySet = preproc.ActiveState(); if (!activitySet) - sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + sc.ChangeState(SCE_C_PREPROCESSOR); } - } else if (!preproc.IsInactive()) { + } else if (preproc.IsActive()) { + // Active -> inactive + assert(sc.state == SCE_C_PREPROCESSOR); preproc.InvertCurrentLevel(); - activitySet = preproc.IsInactive() ? activeFlag : 0; - if (!activitySet) - sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); + activitySet = preproc.ActiveState(); + // Continue to show "elif" as active as it ends active section. } } else if (sc.Match("endif")) { preproc.EndSection(); - activitySet = preproc.IsInactive() ? activeFlag : 0; + activitySet = preproc.ActiveState(); sc.ChangeState(SCE_C_PREPROCESSOR|activitySet); } else if (sc.Match("define")) { - if (options.updatePreprocessor && !preproc.IsInactive()) { + if (options.updatePreprocessor && preproc.IsActive()) { std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true); size_t startName = 0; while ((startName < restOfLine.length()) && IsSpaceOrTab(restOfLine[startName])) @@ -1357,7 +1387,7 @@ void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int i } } } else if (sc.Match("undef")) { - if (options.updatePreprocessor && !preproc.IsInactive()) { + if (options.updatePreprocessor && preproc.IsActive()) { const std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 5, false); std::vector<std::string> tokens = Tokenize(restOfLine); if (tokens.size() >= 1) { |