~ubuntu-branches/ubuntu/utopic/geany/utopic

« back to all changes in this revision

Viewing changes to scintilla/lexers/LexCPP.cxx

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Scintilla source code edit control
 
2
/** @file LexCPP.cxx
 
3
 ** Lexer for C++, C, Java, and JavaScript.
 
4
 ** Further folding features and configuration properties added by "Udo Lechner" <dlchnr(at)gmx(dot)net>
 
5
 **/
 
6
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
 
7
// The License.txt file describes the conditions under which this software may be distributed.
 
8
 
 
9
#include <stdlib.h>
 
10
#include <string.h>
 
11
#include <ctype.h>
 
12
#include <stdio.h>
 
13
#include <stdarg.h>
 
14
#include <assert.h>
 
15
 
 
16
#ifdef _MSC_VER
 
17
#pragma warning(disable: 4786)
 
18
#endif
 
19
 
 
20
#include <string>
 
21
#include <vector>
 
22
#include <map>
 
23
#include <algorithm>
 
24
 
 
25
#include "ILexer.h"
 
26
#include "Scintilla.h"
 
27
#include "SciLexer.h"
 
28
 
 
29
#include "WordList.h"
 
30
#include "LexAccessor.h"
 
31
#include "Accessor.h"
 
32
#include "StyleContext.h"
 
33
#include "CharacterSet.h"
 
34
#include "LexerModule.h"
 
35
#include "OptionSet.h"
 
36
#include "SparseState.h"
 
37
 
 
38
#ifdef SCI_NAMESPACE
 
39
using namespace Scintilla;
 
40
#endif
 
41
 
 
42
static bool IsSpaceEquiv(int state) {
 
43
        return (state <= SCE_C_COMMENTDOC) ||
 
44
                // including SCE_C_DEFAULT, SCE_C_COMMENT, SCE_C_COMMENTLINE
 
45
                (state == SCE_C_COMMENTLINEDOC) || (state == SCE_C_COMMENTDOCKEYWORD) ||
 
46
                (state == SCE_C_COMMENTDOCKEYWORDERROR);
 
47
}
 
48
 
 
49
// Preconditions: sc.currentPos points to a character after '+' or '-'.
 
50
// The test for pos reaching 0 should be redundant,
 
51
// and is in only for safety measures.
 
52
// Limitation: this code will give the incorrect answer for code like
 
53
// a = b+++/ptn/...
 
54
// Putting a space between the '++' post-inc operator and the '+' binary op
 
55
// fixes this, and is highly recommended for readability anyway.
 
56
static bool FollowsPostfixOperator(StyleContext &sc, LexAccessor &styler) {
 
57
        int pos = (int) sc.currentPos;
 
58
        while (--pos > 0) {
 
59
                char ch = styler[pos];
 
60
                if (ch == '+' || ch == '-') {
 
61
                        return styler[pos - 1] == ch;
 
62
                }
 
63
        }
 
64
        return false;
 
65
}
 
66
 
 
67
static bool followsReturnKeyword(StyleContext &sc, LexAccessor &styler) {
 
68
        // Don't look at styles, so no need to flush.
 
69
        int pos = (int) sc.currentPos;
 
70
        int currentLine = styler.GetLine(pos);
 
71
        int lineStartPos = styler.LineStart(currentLine);
 
72
        char ch;
 
73
        while (--pos > lineStartPos) {
 
74
                ch = styler.SafeGetCharAt(pos);
 
75
                if (ch != ' ' && ch != '\t') {
 
76
                        break;
 
77
                }
 
78
        }
 
79
        const char *retBack = "nruter";
 
80
        const char *s = retBack;
 
81
        while (*s
 
82
                && pos >= lineStartPos
 
83
                && styler.SafeGetCharAt(pos) == *s) {
 
84
                s++;
 
85
                pos--;
 
86
        }
 
87
        return !*s;
 
88
}
 
89
 
 
90
static std::string GetRestOfLine(LexAccessor &styler, int start, bool allowSpace) {
 
91
        std::string restOfLine;
 
92
        int i =0;
 
93
        char ch = styler.SafeGetCharAt(start + i, '\n');
 
94
        while ((ch != '\r') && (ch != '\n')) {
 
95
                if (allowSpace || (ch != ' '))
 
96
                        restOfLine += ch;
 
97
                i++;
 
98
                ch = styler.SafeGetCharAt(start + i, '\n');
 
99
        }
 
100
        return restOfLine;
 
101
}
 
102
 
 
103
static bool IsStreamCommentStyle(int style) {
 
104
        return style == SCE_C_COMMENT ||
 
105
                style == SCE_C_COMMENTDOC ||
 
106
                style == SCE_C_COMMENTDOCKEYWORD ||
 
107
                style == SCE_C_COMMENTDOCKEYWORDERROR;
 
108
}
 
109
 
 
110
static std::vector<std::string> Tokenize(const std::string &s) {
 
111
        // Break into space separated tokens
 
112
        std::string word;
 
113
        std::vector<std::string> tokens;
 
114
        for (const char *cp = s.c_str(); *cp; cp++) {
 
115
                if ((*cp == ' ') || (*cp == '\t')) {
 
116
                        if (!word.empty()) {
 
117
                                tokens.push_back(word);
 
118
                                word = "";
 
119
                        }
 
120
                } else {
 
121
                        word += *cp;
 
122
                }
 
123
        }
 
124
        if (!word.empty()) {
 
125
                tokens.push_back(word);
 
126
        }
 
127
        return tokens;
 
128
}
 
129
 
 
130
struct PPDefinition {
 
131
        int line;
 
132
        std::string key;
 
133
        std::string value;
 
134
        PPDefinition(int line_, const std::string &key_, const std::string &value_) :
 
135
                line(line_), key(key_), value(value_) {
 
136
        }
 
137
};
 
138
 
 
139
class LinePPState {
 
140
        int state;
 
141
        int ifTaken;
 
142
        int level;
 
143
        bool ValidLevel() const {
 
144
                return level >= 0 && level < 32;
 
145
        }
 
146
        int maskLevel() const {
 
147
                return 1 << level;
 
148
        }
 
149
public:
 
150
        LinePPState() : state(0), ifTaken(0), level(-1) {
 
151
        }
 
152
        bool IsInactive() const {
 
153
                return state != 0;
 
154
        }
 
155
        bool CurrentIfTaken() {
 
156
                return (ifTaken & maskLevel()) != 0;
 
157
        }
 
158
        void StartSection(bool on) {
 
159
                level++;
 
160
                if (ValidLevel()) {
 
161
                        if (on) {
 
162
                                state &= ~maskLevel();
 
163
                                ifTaken |= maskLevel();
 
164
                        } else {
 
165
                                state |= maskLevel();
 
166
                                ifTaken &= ~maskLevel();
 
167
                        }
 
168
                }
 
169
        }
 
170
        void EndSection() {
 
171
                if (ValidLevel()) {
 
172
                        state &= ~maskLevel();
 
173
                        ifTaken &= ~maskLevel();
 
174
                }
 
175
                level--;
 
176
        }
 
177
        void InvertCurrentLevel() {
 
178
                if (ValidLevel()) {
 
179
                        state ^= maskLevel();
 
180
                        ifTaken |= maskLevel();
 
181
                }
 
182
        }
 
183
};
 
184
 
 
185
// Hold the preprocessor state for each line seen.
 
186
// Currently one entry per line but could become sparse with just one entry per preprocessor line.
 
187
class PPStates {
 
188
        std::vector<LinePPState> vlls;
 
189
public:
 
190
        LinePPState ForLine(int line) {
 
191
                if ((line > 0) && (vlls.size() > static_cast<size_t>(line))) {
 
192
                        return vlls[line];
 
193
                } else {
 
194
                        return LinePPState();
 
195
                }
 
196
        }
 
197
        void Add(int line, LinePPState lls) {
 
198
                vlls.resize(line+1);
 
199
                vlls[line] = lls;
 
200
        }
 
201
};
 
202
 
 
203
// An individual named option for use in an OptionSet
 
204
 
 
205
// Options used for LexerCPP
 
206
struct OptionsCPP {
 
207
        bool stylingWithinPreprocessor;
 
208
        bool identifiersAllowDollars;
 
209
        bool trackPreprocessor;
 
210
        bool updatePreprocessor;
 
211
        bool triplequotedStrings;
 
212
        bool fold;
 
213
        bool foldSyntaxBased;
 
214
        bool foldComment;
 
215
        bool foldCommentMultiline;
 
216
        bool foldCommentExplicit;
 
217
        std::string foldExplicitStart;
 
218
        std::string foldExplicitEnd;
 
219
        bool foldExplicitAnywhere;
 
220
        bool foldPreprocessor;
 
221
        bool foldCompact;
 
222
        bool foldAtElse;
 
223
        OptionsCPP() {
 
224
                stylingWithinPreprocessor = false;
 
225
                identifiersAllowDollars = true;
 
226
                trackPreprocessor = true;
 
227
                updatePreprocessor = true;
 
228
                triplequotedStrings = false;
 
229
                fold = false;
 
230
                foldSyntaxBased = true;
 
231
                foldComment = false;
 
232
                foldCommentMultiline = true;
 
233
                foldCommentExplicit = true;
 
234
                foldExplicitStart = "";
 
235
                foldExplicitEnd = "";
 
236
                foldExplicitAnywhere = false;
 
237
                foldPreprocessor = false;
 
238
                foldCompact = false;
 
239
                foldAtElse = false;
 
240
        }
 
241
};
 
242
 
 
243
static const char *const cppWordLists[] = {
 
244
            "Primary keywords and identifiers",
 
245
            "Secondary keywords and identifiers",
 
246
            "Documentation comment keywords",
 
247
            "Global classes and typedefs",
 
248
            "Preprocessor definitions",
 
249
            0,
 
250
};
 
251
 
 
252
struct OptionSetCPP : public OptionSet<OptionsCPP> {
 
253
        OptionSetCPP() {
 
254
                DefineProperty("styling.within.preprocessor", &OptionsCPP::stylingWithinPreprocessor,
 
255
                        "For C++ code, determines whether all preprocessor code is styled in the "
 
256
                        "preprocessor style (0, the default) or only from the initial # to the end "
 
257
                        "of the command word(1).");
 
258
 
 
259
                DefineProperty("lexer.cpp.allow.dollars", &OptionsCPP::identifiersAllowDollars,
 
260
                        "Set to 0 to disallow the '$' character in identifiers with the cpp lexer.");
 
261
 
 
262
                DefineProperty("lexer.cpp.track.preprocessor", &OptionsCPP::trackPreprocessor,
 
263
                        "Set to 1 to interpret #if/#else/#endif to grey out code that is not active.");
 
264
 
 
265
                DefineProperty("lexer.cpp.update.preprocessor", &OptionsCPP::updatePreprocessor,
 
266
                        "Set to 1 to update preprocessor definitions when #define found.");
 
267
 
 
268
                DefineProperty("lexer.cpp.triplequoted.strings", &OptionsCPP::triplequotedStrings,
 
269
                        "Set to 1 to enable highlighting of triple-quoted strings.");
 
270
 
 
271
                DefineProperty("fold", &OptionsCPP::fold);
 
272
 
 
273
                DefineProperty("fold.cpp.syntax.based", &OptionsCPP::foldSyntaxBased,
 
274
                        "Set this property to 0 to disable syntax based folding.");
 
275
 
 
276
                DefineProperty("fold.comment", &OptionsCPP::foldComment,
 
277
                        "This option enables folding multi-line comments and explicit fold points when using the C++ lexer. "
 
278
                        "Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //} "
 
279
                        "at the end of a section that should fold.");
 
280
 
 
281
                DefineProperty("fold.cpp.comment.multiline", &OptionsCPP::foldCommentMultiline,
 
282
                        "Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
 
283
 
 
284
                DefineProperty("fold.cpp.comment.explicit", &OptionsCPP::foldCommentExplicit,
 
285
                        "Set this property to 0 to disable folding explicit fold points when fold.comment=1.");
 
286
 
 
287
                DefineProperty("fold.cpp.explicit.start", &OptionsCPP::foldExplicitStart,
 
288
                        "The string to use for explicit fold start points, replacing the standard //{.");
 
289
 
 
290
                DefineProperty("fold.cpp.explicit.end", &OptionsCPP::foldExplicitEnd,
 
291
                        "The string to use for explicit fold end points, replacing the standard //}.");
 
292
 
 
293
                DefineProperty("fold.cpp.explicit.anywhere", &OptionsCPP::foldExplicitAnywhere,
 
294
                        "Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
 
295
 
 
296
                DefineProperty("fold.preprocessor", &OptionsCPP::foldPreprocessor,
 
297
                        "This option enables folding preprocessor directives when using the C++ lexer. "
 
298
                        "Includes C#'s explicit #region and #endregion folding directives.");
 
299
 
 
300
                DefineProperty("fold.compact", &OptionsCPP::foldCompact);
 
301
 
 
302
                DefineProperty("fold.at.else", &OptionsCPP::foldAtElse,
 
303
                        "This option enables C++ folding on a \"} else {\" line of an if statement.");
 
304
 
 
305
                DefineWordListSets(cppWordLists);
 
306
        }
 
307
};
 
308
 
 
309
class LexerCPP : public ILexer {
 
310
        bool caseSensitive;
 
311
        CharacterSet setWord;
 
312
        CharacterSet setNegationOp;
 
313
        CharacterSet setArithmethicOp;
 
314
        CharacterSet setRelOp;
 
315
        CharacterSet setLogicalOp;
 
316
        PPStates vlls;
 
317
        std::vector<PPDefinition> ppDefineHistory;
 
318
        WordList keywords;
 
319
        WordList keywords2;
 
320
        WordList keywords3;
 
321
        WordList keywords4;
 
322
        WordList ppDefinitions;
 
323
        std::map<std::string, std::string> preprocessorDefinitionsStart;
 
324
        OptionsCPP options;
 
325
        OptionSetCPP osCPP;
 
326
        SparseState<std::string> rawStringTerminators;
 
327
public:
 
328
        LexerCPP(bool caseSensitive_) :
 
329
                caseSensitive(caseSensitive_),
 
330
                setWord(CharacterSet::setAlphaNum, "._", 0x80, true),
 
331
                setNegationOp(CharacterSet::setNone, "!"),
 
332
                setArithmethicOp(CharacterSet::setNone, "+-/*%"),
 
333
                setRelOp(CharacterSet::setNone, "=!<>"),
 
334
                setLogicalOp(CharacterSet::setNone, "|&") {
 
335
        }
 
336
        ~LexerCPP() {
 
337
        }
 
338
        void SCI_METHOD Release() {
 
339
                delete this;
 
340
        }
 
341
        int SCI_METHOD Version() const {
 
342
                return lvOriginal;
 
343
        }
 
344
        const char * SCI_METHOD PropertyNames() {
 
345
                return osCPP.PropertyNames();
 
346
        }
 
347
        int SCI_METHOD PropertyType(const char *name) {
 
348
                return osCPP.PropertyType(name);
 
349
        }
 
350
        const char * SCI_METHOD DescribeProperty(const char *name) {
 
351
                return osCPP.DescribeProperty(name);
 
352
        }
 
353
        int SCI_METHOD PropertySet(const char *key, const char *val);
 
354
        const char * SCI_METHOD DescribeWordListSets() {
 
355
                return osCPP.DescribeWordListSets();
 
356
        }
 
357
        int SCI_METHOD WordListSet(int n, const char *wl);
 
358
        void SCI_METHOD Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess);
 
359
        void SCI_METHOD Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess);
 
360
 
 
361
        void * SCI_METHOD PrivateCall(int, void *) {
 
362
                return 0;
 
363
        }
 
364
 
 
365
        static ILexer *LexerFactoryCPP() {
 
366
                return new LexerCPP(true);
 
367
        }
 
368
        static ILexer *LexerFactoryCPPInsensitive() {
 
369
                return new LexerCPP(false);
 
370
        }
 
371
 
 
372
        void EvaluateTokens(std::vector<std::string> &tokens);
 
373
        bool EvaluateExpression(const std::string &expr, const std::map<std::string, std::string> &preprocessorDefinitions);
 
374
};
 
375
 
 
376
int SCI_METHOD LexerCPP::PropertySet(const char *key, const char *val) {
 
377
        if (osCPP.PropertySet(&options, key, val)) {
 
378
                return 0;
 
379
        }
 
380
        return -1;
 
381
}
 
382
 
 
383
int SCI_METHOD LexerCPP::WordListSet(int n, const char *wl) {
 
384
        WordList *wordListN = 0;
 
385
        switch (n) {
 
386
        case 0:
 
387
                wordListN = &keywords;
 
388
                break;
 
389
        case 1:
 
390
                wordListN = &keywords2;
 
391
                break;
 
392
        case 2:
 
393
                wordListN = &keywords3;
 
394
                break;
 
395
        case 3:
 
396
                wordListN = &keywords4;
 
397
                break;
 
398
        case 4:
 
399
                wordListN = &ppDefinitions;
 
400
                break;
 
401
        }
 
402
        int firstModification = -1;
 
403
        if (wordListN) {
 
404
                WordList wlNew;
 
405
                wlNew.Set(wl);
 
406
                if (*wordListN != wlNew) {
 
407
                        wordListN->Set(wl);
 
408
                        firstModification = 0;
 
409
                        if (n == 4) {
 
410
                                // Rebuild preprocessorDefinitions
 
411
                                preprocessorDefinitionsStart.clear();
 
412
                                for (int nDefinition = 0; nDefinition < ppDefinitions.len; nDefinition++) {
 
413
                                        char *cpDefinition = ppDefinitions.words[nDefinition];
 
414
                                        char *cpEquals = strchr(cpDefinition, '=');
 
415
                                        if (cpEquals) {
 
416
                                                std::string name(cpDefinition, cpEquals - cpDefinition);
 
417
                                                std::string val(cpEquals+1);
 
418
                                                preprocessorDefinitionsStart[name] = val;
 
419
                                        } else {
 
420
                                                std::string name(cpDefinition);
 
421
                                                std::string val("1");
 
422
                                                preprocessorDefinitionsStart[name] = val;
 
423
                                        }
 
424
                                }
 
425
                        }
 
426
                }
 
427
        }
 
428
        return firstModification;
 
429
}
 
430
 
 
431
// Functor used to truncate history
 
432
struct After {
 
433
        int line;
 
434
        After(int line_) : line(line_) {}
 
435
        bool operator() (PPDefinition &p) const {
 
436
                return p.line > line;
 
437
        }
 
438
};
 
439
 
 
440
void SCI_METHOD LexerCPP::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
 
441
        LexAccessor styler(pAccess);
 
442
 
 
443
        CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-");
 
444
        CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
 
445
 
 
446
        CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]");
 
447
 
 
448
        CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
 
449
 
 
450
        if (options.identifiersAllowDollars) {
 
451
                setWordStart.Add('$');
 
452
                setWord.Add('$');
 
453
        }
 
454
 
 
455
        int chPrevNonWhite = ' ';
 
456
        int visibleChars = 0;
 
457
        bool lastWordWasUUID = false;
 
458
        int styleBeforeDCKeyword = SCE_C_DEFAULT;
 
459
        bool continuationLine = false;
 
460
        bool isIncludePreprocessor = false;
 
461
 
 
462
        int lineCurrent = styler.GetLine(startPos);
 
463
        if ((initStyle == SCE_C_PREPROCESSOR) ||
 
464
      (initStyle == SCE_C_COMMENTLINE) ||
 
465
      (initStyle == SCE_C_COMMENTLINEDOC)) {
 
466
                // Set continuationLine if last character of previous line is '\'
 
467
                if (lineCurrent > 0) {
 
468
                        int chBack = styler.SafeGetCharAt(startPos-1, 0);
 
469
                        int chBack2 = styler.SafeGetCharAt(startPos-2, 0);
 
470
                        int lineEndChar = '!';
 
471
                        if (chBack2 == '\r' && chBack == '\n') {
 
472
                                lineEndChar = styler.SafeGetCharAt(startPos-3, 0);
 
473
                        } else if (chBack == '\n' || chBack == '\r') {
 
474
                                lineEndChar = chBack2;
 
475
                        }
 
476
                        continuationLine = lineEndChar == '\\';
 
477
                }
 
478
        }
 
479
 
 
480
        // look back to set chPrevNonWhite properly for better regex colouring
 
481
        if (startPos > 0) {
 
482
                int back = startPos;
 
483
                while (--back && IsSpaceEquiv(styler.StyleAt(back)))
 
484
                        ;
 
485
                if (styler.StyleAt(back) == SCE_C_OPERATOR) {
 
486
                        chPrevNonWhite = styler.SafeGetCharAt(back);
 
487
                }
 
488
        }
 
489
 
 
490
        StyleContext sc(startPos, length, initStyle, styler, 0x7f);
 
491
        LinePPState preproc = vlls.ForLine(lineCurrent);
 
492
 
 
493
        bool definitionsChanged = false;
 
494
 
 
495
        // Truncate ppDefineHistory before current line
 
496
 
 
497
        if (!options.updatePreprocessor)
 
498
                ppDefineHistory.clear();
 
499
 
 
500
        std::vector<PPDefinition>::iterator itInvalid = std::find_if(ppDefineHistory.begin(), ppDefineHistory.end(), After(lineCurrent-1));
 
501
        if (itInvalid != ppDefineHistory.end()) {
 
502
                ppDefineHistory.erase(itInvalid, ppDefineHistory.end());
 
503
                definitionsChanged = true;
 
504
        }
 
505
 
 
506
        std::map<std::string, std::string> preprocessorDefinitions = preprocessorDefinitionsStart;
 
507
        for (std::vector<PPDefinition>::iterator itDef = ppDefineHistory.begin(); itDef != ppDefineHistory.end(); ++itDef) {
 
508
                preprocessorDefinitions[itDef->key] = itDef->value;
 
509
        }
 
510
 
 
511
        const int maskActivity = 0x3F;
 
512
        std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1);
 
513
        SparseState<std::string> rawSTNew(lineCurrent);
 
514
 
 
515
        int activitySet = preproc.IsInactive() ? 0x40 : 0;
 
516
 
 
517
        for (; sc.More(); sc.Forward()) {
 
518
 
 
519
                if (sc.atLineStart) {
 
520
                        if ((sc.state == SCE_C_STRING) || (sc.state == SCE_C_CHARACTER)) {
 
521
                                // Prevent SCE_C_STRINGEOL from leaking back to previous line which
 
522
                                // ends with a line continuation by locking in the state upto this position.
 
523
                                sc.SetState(sc.state);
 
524
                        }
 
525
                        // Reset states to begining of colourise so no surprises
 
526
                        // if different sets of lines lexed.
 
527
                        visibleChars = 0;
 
528
                        lastWordWasUUID = false;
 
529
                        isIncludePreprocessor = false;
 
530
                        if (preproc.IsInactive()) {
 
531
                                activitySet = 0x40;
 
532
                                sc.SetState(sc.state | activitySet);
 
533
                        }
 
534
                        if (activitySet) {
 
535
                                if (sc.ch == '#') {
 
536
                                        if (sc.Match("#else") || sc.Match("#end") || sc.Match("#if")) {
 
537
                                                //activitySet = 0;
 
538
                                        }
 
539
                                }
 
540
                        }
 
541
                }
 
542
 
 
543
                if (sc.atLineEnd) {
 
544
                        lineCurrent++;
 
545
                        vlls.Add(lineCurrent, preproc);
 
546
                        if (rawStringTerminator != "") {
 
547
                                rawSTNew.Set(lineCurrent-1, rawStringTerminator);
 
548
                        }
 
549
                }
 
550
 
 
551
                // Handle line continuation generically.
 
552
                if (sc.ch == '\\') {
 
553
                        if (sc.chNext == '\n' || sc.chNext == '\r') {
 
554
                                sc.Forward();
 
555
                                if (sc.ch == '\r' && sc.chNext == '\n') {
 
556
                                        sc.Forward();
 
557
                                }
 
558
                                continuationLine = true;
 
559
                                continue;
 
560
                        }
 
561
                }
 
562
 
 
563
                const bool atLineEndBeforeSwitch = sc.atLineEnd;
 
564
 
 
565
                // Determine if the current state should terminate.
 
566
                switch (sc.state & maskActivity) {
 
567
                        case SCE_C_OPERATOR:
 
568
                                sc.SetState(SCE_C_DEFAULT|activitySet);
 
569
                                break;
 
570
                        case SCE_C_NUMBER:
 
571
                                // We accept almost anything because of hex. and number suffixes
 
572
                                if (!(setWord.Contains(sc.ch) || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) {
 
573
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
574
                                }
 
575
                                break;
 
576
                        case SCE_C_IDENTIFIER:
 
577
                                if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
 
578
                                        char s[1000];
 
579
                                        if (caseSensitive) {
 
580
                                                sc.GetCurrent(s, sizeof(s));
 
581
                                        } else {
 
582
                                                sc.GetCurrentLowered(s, sizeof(s));
 
583
                                        }
 
584
                                        if (keywords.InList(s)) {
 
585
                                                lastWordWasUUID = strcmp(s, "uuid") == 0;
 
586
                                                sc.ChangeState(SCE_C_WORD|activitySet);
 
587
                                        } else if (keywords2.InList(s)) {
 
588
                                                sc.ChangeState(SCE_C_WORD2|activitySet);
 
589
                                        } else if (keywords4.InList(s)) {
 
590
                                                sc.ChangeState(SCE_C_GLOBALCLASS|activitySet);
 
591
                                        }
 
592
                                        const bool literalString = sc.ch == '\"';
 
593
                                        if (literalString || sc.ch == '\'') {
 
594
                                                size_t lenS = strlen(s);
 
595
                                                const bool raw = literalString && sc.chPrev == 'R';
 
596
                                                if (raw)
 
597
                                                        s[lenS--] = '\0';
 
598
                                                bool valid =
 
599
                                                        (lenS == 0) ||
 
600
                                                        ((lenS == 1) && ((s[0] == 'L') || (s[0] == 'u') || (s[0] == 'U'))) ||
 
601
                                                        ((lenS == 2) && literalString && (s[0] == 'u') && (s[1] == '8'));
 
602
                                                if (valid) {
 
603
                                                        if (literalString)
 
604
                                                                sc.ChangeState((raw ? SCE_C_STRINGRAW : SCE_C_STRING)|activitySet);
 
605
                                                        else
 
606
                                                                sc.ChangeState(SCE_C_CHARACTER|activitySet);
 
607
                                                }
 
608
                                        }
 
609
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
610
                                }
 
611
                                break;
 
612
                        case SCE_C_PREPROCESSOR:
 
613
                                if (sc.atLineStart && !continuationLine) {
 
614
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
615
                                } else if (options.stylingWithinPreprocessor) {
 
616
                                        if (IsASpace(sc.ch)) {
 
617
                                                sc.SetState(SCE_C_DEFAULT|activitySet);
 
618
                                        }
 
619
                                } else {
 
620
                                        if (sc.Match('/', '*') || sc.Match('/', '/')) {
 
621
                                                sc.SetState(SCE_C_DEFAULT|activitySet);
 
622
                                        }
 
623
                                }
 
624
                                break;
 
625
                        case SCE_C_COMMENT:
 
626
                                if (sc.Match('*', '/')) {
 
627
                                        sc.Forward();
 
628
                                        sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
629
                                }
 
630
                                break;
 
631
                        case SCE_C_COMMENTDOC:
 
632
                                if (sc.Match('*', '/')) {
 
633
                                        sc.Forward();
 
634
                                        sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
635
                                } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
 
636
                                        // Verify that we have the conditions to mark a comment-doc-keyword
 
637
                                        if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
 
638
                                                styleBeforeDCKeyword = SCE_C_COMMENTDOC;
 
639
                                                sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet);
 
640
                                        }
 
641
                                }
 
642
                                break;
 
643
                        case SCE_C_COMMENTLINE:
 
644
                                if (sc.atLineStart && !continuationLine) {
 
645
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
646
                                }
 
647
                                break;
 
648
                        case SCE_C_COMMENTLINEDOC:
 
649
                                if (sc.atLineStart && !continuationLine) {
 
650
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
651
                                } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
 
652
                                        // Verify that we have the conditions to mark a comment-doc-keyword
 
653
                                        if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
 
654
                                                styleBeforeDCKeyword = SCE_C_COMMENTLINEDOC;
 
655
                                                sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet);
 
656
                                        }
 
657
                                }
 
658
                                break;
 
659
                        case SCE_C_COMMENTDOCKEYWORD:
 
660
                                if ((styleBeforeDCKeyword == SCE_C_COMMENTDOC) && sc.Match('*', '/')) {
 
661
                                        sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
 
662
                                        sc.Forward();
 
663
                                        sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
664
                                } else if (!setDoxygen.Contains(sc.ch)) {
 
665
                                        char s[100];
 
666
                                        if (caseSensitive) {
 
667
                                                sc.GetCurrent(s, sizeof(s));
 
668
                                        } else {
 
669
                                                sc.GetCurrentLowered(s, sizeof(s));
 
670
                                        }
 
671
                                        if (!IsASpace(sc.ch) || !keywords3.InList(s + 1)) {
 
672
                                                sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet);
 
673
                                        }
 
674
                                        sc.SetState(styleBeforeDCKeyword);
 
675
                                }
 
676
                                break;
 
677
                        case SCE_C_STRING:
 
678
                                if (sc.atLineEnd) {
 
679
                                        sc.ChangeState(SCE_C_STRINGEOL|activitySet);
 
680
                                } else if (isIncludePreprocessor) {
 
681
                                        if (sc.ch == '>') {
 
682
                                                sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
683
                                                isIncludePreprocessor = false;
 
684
                                        }
 
685
                                } else if (sc.ch == '\\') {
 
686
                                        if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
 
687
                                                sc.Forward();
 
688
                                        }
 
689
                                } else if (sc.ch == '\"') {
 
690
                                        sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
691
                                }
 
692
                                break;
 
693
                        case SCE_C_STRINGRAW:
 
694
                                if (sc.Match(rawStringTerminator.c_str())) {
 
695
                                        for (size_t termPos=rawStringTerminator.size(); termPos; termPos--)
 
696
                                                sc.Forward();
 
697
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
698
                                        rawStringTerminator = "";
 
699
                                }
 
700
                                break;
 
701
                        case SCE_C_CHARACTER:
 
702
                                if (sc.atLineEnd) {
 
703
                                        sc.ChangeState(SCE_C_STRINGEOL|activitySet);
 
704
                                } else if (sc.ch == '\\') {
 
705
                                        if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
 
706
                                                sc.Forward();
 
707
                                        }
 
708
                                } else if (sc.ch == '\'') {
 
709
                                        sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
710
                                }
 
711
                                break;
 
712
                        case SCE_C_REGEX:
 
713
                                if (sc.atLineStart) {
 
714
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
715
                                } else if (sc.ch == '/') {
 
716
                                        sc.Forward();
 
717
                                        while ((sc.ch < 0x80) && islower(sc.ch))
 
718
                                                sc.Forward();    // gobble regex flags
 
719
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
720
                                } else if (sc.ch == '\\') {
 
721
                                        // Gobble up the quoted character
 
722
                                        if (sc.chNext == '\\' || sc.chNext == '/') {
 
723
                                                sc.Forward();
 
724
                                        }
 
725
                                }
 
726
                                break;
 
727
                        case SCE_C_STRINGEOL:
 
728
                                if (sc.atLineStart) {
 
729
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
730
                                }
 
731
                                break;
 
732
                        case SCE_C_VERBATIM:
 
733
                                if (sc.ch == '\"') {
 
734
                                        if (sc.chNext == '\"') {
 
735
                                                sc.Forward();
 
736
                                        } else {
 
737
                                                sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
 
738
                                        }
 
739
                                }
 
740
                                break;
 
741
                        case SCE_C_TRIPLEVERBATIM:
 
742
                                if (sc.Match ("\"\"\"")) {
 
743
                                        while (sc.Match('"')) {
 
744
                                                sc.Forward();
 
745
                                        }
 
746
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
747
                                }
 
748
                                break;
 
749
                        case SCE_C_UUID:
 
750
                                if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
 
751
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
752
                                }
 
753
                }
 
754
 
 
755
                if (sc.atLineEnd && !atLineEndBeforeSwitch) {
 
756
                        // State exit processing consumed characters up to end of line.
 
757
                        lineCurrent++;
 
758
                        vlls.Add(lineCurrent, preproc);
 
759
                }
 
760
 
 
761
                // Determine if a new state should be entered.
 
762
                if ((sc.state & maskActivity) == SCE_C_DEFAULT) {
 
763
                        if (sc.Match('@', '\"')) {
 
764
                                sc.SetState(SCE_C_VERBATIM|activitySet);
 
765
                                sc.Forward();
 
766
                        } else if (options.triplequotedStrings && sc.Match("\"\"\"")) {
 
767
                                sc.SetState(SCE_C_TRIPLEVERBATIM|activitySet);
 
768
                                sc.Forward(2);
 
769
                        } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
 
770
                                if (lastWordWasUUID) {
 
771
                                        sc.SetState(SCE_C_UUID|activitySet);
 
772
                                        lastWordWasUUID = false;
 
773
                                } else {
 
774
                                        sc.SetState(SCE_C_NUMBER|activitySet);
 
775
                                }
 
776
                        } else if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) {
 
777
                                if (lastWordWasUUID) {
 
778
                                        sc.SetState(SCE_C_UUID|activitySet);
 
779
                                        lastWordWasUUID = false;
 
780
                                } else {
 
781
                                        sc.SetState(SCE_C_IDENTIFIER|activitySet);
 
782
                                }
 
783
                        } else if (sc.Match('/', '*')) {
 
784
                                if (sc.Match("/**") || sc.Match("/*!")) {       // Support of Qt/Doxygen doc. style
 
785
                                        sc.SetState(SCE_C_COMMENTDOC|activitySet);
 
786
                                } else {
 
787
                                        sc.SetState(SCE_C_COMMENT|activitySet);
 
788
                                }
 
789
                                sc.Forward();   // Eat the * so it isn't used for the end of the comment
 
790
                        } else if (sc.Match('/', '/')) {
 
791
                                if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!"))
 
792
                                        // Support of Qt/Doxygen doc. style
 
793
                                        sc.SetState(SCE_C_COMMENTLINEDOC|activitySet);
 
794
                                else
 
795
                                        sc.SetState(SCE_C_COMMENTLINE|activitySet);
 
796
                        } else if (sc.ch == '/'
 
797
                                   && (setOKBeforeRE.Contains(chPrevNonWhite)
 
798
                                       || followsReturnKeyword(sc, styler))
 
799
                                   && (!setCouldBePostOp.Contains(chPrevNonWhite)
 
800
                                       || !FollowsPostfixOperator(sc, styler))) {
 
801
                                sc.SetState(SCE_C_REGEX|activitySet);   // JavaScript's RegEx
 
802
                        } else if (sc.ch == '\"') {
 
803
                                if (sc.chPrev == 'R') {
 
804
                                        sc.SetState(SCE_C_STRINGRAW|activitySet);
 
805
                                        rawStringTerminator = ")";
 
806
                                        for (int termPos = sc.currentPos + 1;;termPos++) {
 
807
                                                char chTerminator = styler.SafeGetCharAt(termPos, '(');
 
808
                                                if (chTerminator == '(')
 
809
                                                        break;
 
810
                                                rawStringTerminator += chTerminator;
 
811
                                        }
 
812
                                        rawStringTerminator += '\"';
 
813
                                } else {
 
814
                                        sc.SetState(SCE_C_STRING|activitySet);
 
815
                                }
 
816
                                isIncludePreprocessor = false;  // ensure that '>' won't end the string
 
817
                        } else if (isIncludePreprocessor && sc.ch == '<') {
 
818
                                sc.SetState(SCE_C_STRING|activitySet);
 
819
                        } else if (sc.ch == '\'') {
 
820
                                sc.SetState(SCE_C_CHARACTER|activitySet);
 
821
                        } else if (sc.ch == '#' && visibleChars == 0) {
 
822
                                // Preprocessor commands are alone on their line
 
823
                                sc.SetState(SCE_C_PREPROCESSOR|activitySet);
 
824
                                // Skip whitespace between # and preprocessor word
 
825
                                do {
 
826
                                        sc.Forward();
 
827
                                } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
 
828
                                if (sc.atLineEnd) {
 
829
                                        sc.SetState(SCE_C_DEFAULT|activitySet);
 
830
                                } else if (sc.Match("include")) {
 
831
                                        isIncludePreprocessor = true;
 
832
                                } else {
 
833
                                        if (options.trackPreprocessor) {
 
834
                                                if (sc.Match("ifdef") || sc.Match("ifndef")) {
 
835
                                                        bool isIfDef = sc.Match("ifdef");
 
836
                                                        int i = isIfDef ? 5 : 6;
 
837
                                                        std::string restOfLine = GetRestOfLine(styler, sc.currentPos + i + 1, false);
 
838
                                                        bool foundDef = preprocessorDefinitions.find(restOfLine) != preprocessorDefinitions.end();
 
839
                                                        preproc.StartSection(isIfDef == foundDef);
 
840
                                                } else if (sc.Match("if")) {
 
841
                                                        std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true);
 
842
                                                        bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions);
 
843
                                                        preproc.StartSection(ifGood);
 
844
                                                } else if (sc.Match("else")) {
 
845
                                                        if (!preproc.CurrentIfTaken()) {
 
846
                                                                preproc.InvertCurrentLevel();
 
847
                                                                activitySet = preproc.IsInactive() ? 0x40 : 0;
 
848
                                                                if (!activitySet)
 
849
                                                                        sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
 
850
                                                        } else if (!preproc.IsInactive()) {
 
851
                                                                preproc.InvertCurrentLevel();
 
852
                                                                activitySet = preproc.IsInactive() ? 0x40 : 0;
 
853
                                                                if (!activitySet)
 
854
                                                                        sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
 
855
                                                        }
 
856
                                                } else if (sc.Match("elif")) {
 
857
                                                        // Ensure only one chosen out of #if .. #elif .. #elif .. #else .. #endif
 
858
                                                        if (!preproc.CurrentIfTaken()) {
 
859
                                                                // Similar to #if
 
860
                                                                std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true);
 
861
                                                                bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions);
 
862
                                                                if (ifGood) {
 
863
                                                                        preproc.InvertCurrentLevel();
 
864
                                                                        activitySet = preproc.IsInactive() ? 0x40 : 0;
 
865
                                                                        if (!activitySet)
 
866
                                                                                sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
 
867
                                                                }
 
868
                                                        } else if (!preproc.IsInactive()) {
 
869
                                                                preproc.InvertCurrentLevel();
 
870
                                                                activitySet = preproc.IsInactive() ? 0x40 : 0;
 
871
                                                                if (!activitySet)
 
872
                                                                        sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
 
873
                                                        }
 
874
                                                } else if (sc.Match("endif")) {
 
875
                                                        preproc.EndSection();
 
876
                                                        activitySet = preproc.IsInactive() ? 0x40 : 0;
 
877
                                                        sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
 
878
                                                } else if (sc.Match("define")) {
 
879
                                                        if (options.updatePreprocessor && !preproc.IsInactive()) {
 
880
                                                                std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true);
 
881
                                                                if (restOfLine.find(")") == std::string::npos) {        // Don't handle macros with arguments
 
882
                                                                        std::vector<std::string> tokens = Tokenize(restOfLine);
 
883
                                                                        std::string key;
 
884
                                                                        std::string value("1");
 
885
                                                                        if (tokens.size() >= 1) {
 
886
                                                                                key = tokens[0];
 
887
                                                                                if (tokens.size() >= 2) {
 
888
                                                                                        value = tokens[1];
 
889
                                                                                }
 
890
                                                                                preprocessorDefinitions[key] = value;
 
891
                                                                                ppDefineHistory.push_back(PPDefinition(lineCurrent, key, value));
 
892
                                                                                definitionsChanged = true;
 
893
                                                                        }
 
894
                                                                }
 
895
                                                        }
 
896
                                                }
 
897
                                        }
 
898
                                }
 
899
                        } else if (isoperator(static_cast<char>(sc.ch))) {
 
900
                                sc.SetState(SCE_C_OPERATOR|activitySet);
 
901
                        }
 
902
                }
 
903
 
 
904
                if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) {
 
905
                        chPrevNonWhite = sc.ch;
 
906
                        visibleChars++;
 
907
                }
 
908
                continuationLine = false;
 
909
        }
 
910
        const bool rawStringsChanged = rawStringTerminators.Merge(rawSTNew, lineCurrent);
 
911
        if (definitionsChanged || rawStringsChanged)
 
912
                styler.ChangeLexerState(startPos, startPos + length);
 
913
        sc.Complete();
 
914
}
 
915
 
 
916
// Store both the current line's fold level and the next lines in the
 
917
// level store to make it easy to pick up with each increment
 
918
// and to make it possible to fiddle the current level for "} else {".
 
919
 
 
920
void SCI_METHOD LexerCPP::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
 
921
 
 
922
        if (!options.fold)
 
923
                return;
 
924
 
 
925
        LexAccessor styler(pAccess);
 
926
 
 
927
        unsigned int endPos = startPos + length;
 
928
        int visibleChars = 0;
 
929
        int lineCurrent = styler.GetLine(startPos);
 
930
        int levelCurrent = SC_FOLDLEVELBASE;
 
931
        if (lineCurrent > 0)
 
932
                levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
 
933
        int levelMinCurrent = levelCurrent;
 
934
        int levelNext = levelCurrent;
 
935
        char chNext = styler[startPos];
 
936
        int styleNext = styler.StyleAt(startPos);
 
937
        int style = initStyle;
 
938
        const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
 
939
        for (unsigned int i = startPos; i < endPos; i++) {
 
940
                char ch = chNext;
 
941
                chNext = styler.SafeGetCharAt(i + 1);
 
942
                int stylePrev = style;
 
943
                style = styleNext;
 
944
                styleNext = styler.StyleAt(i + 1);
 
945
                bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
 
946
                if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) {
 
947
                        if (!IsStreamCommentStyle(stylePrev) && (stylePrev != SCE_C_COMMENTLINEDOC)) {
 
948
                                levelNext++;
 
949
                        } else if (!IsStreamCommentStyle(styleNext) && (styleNext != SCE_C_COMMENTLINEDOC) && !atEOL) {
 
950
                                // Comments don't end at end of line and the next character may be unstyled.
 
951
                                levelNext--;
 
952
                        }
 
953
                }
 
954
                if (options.foldComment && options.foldCommentExplicit && ((style == SCE_C_COMMENTLINE) || options.foldExplicitAnywhere)) {
 
955
                        if (userDefinedFoldMarkers) {
 
956
                                if (styler.Match(i, options.foldExplicitStart.c_str())) {
 
957
                                        levelNext++;
 
958
                                } else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
 
959
                                        levelNext--;
 
960
                                }
 
961
                        } else {
 
962
                                if ((ch == '/') && (chNext == '/')) {
 
963
                                        char chNext2 = styler.SafeGetCharAt(i + 2);
 
964
                                        if (chNext2 == '{') {
 
965
                                                levelNext++;
 
966
                                        } else if (chNext2 == '}') {
 
967
                                                levelNext--;
 
968
                                        }
 
969
                                }
 
970
                        }
 
971
                }
 
972
                if (options.foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
 
973
                        if (ch == '#') {
 
974
                                unsigned int j = i + 1;
 
975
                                while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
 
976
                                        j++;
 
977
                                }
 
978
                                if (styler.Match(j, "region") || styler.Match(j, "if")) {
 
979
                                        levelNext++;
 
980
                                } else if (styler.Match(j, "end")) {
 
981
                                        levelNext--;
 
982
                                }
 
983
                        }
 
984
                }
 
985
                if (options.foldSyntaxBased && (style == SCE_C_OPERATOR)) {
 
986
                        if (ch == '{') {
 
987
                                // Measure the minimum before a '{' to allow
 
988
                                // folding on "} else {"
 
989
                                if (levelMinCurrent > levelNext) {
 
990
                                        levelMinCurrent = levelNext;
 
991
                                }
 
992
                                levelNext++;
 
993
                        } else if (ch == '}') {
 
994
                                levelNext--;
 
995
                        }
 
996
                }
 
997
                if (!IsASpace(ch))
 
998
                        visibleChars++;
 
999
                if (atEOL || (i == endPos-1)) {
 
1000
                        int levelUse = levelCurrent;
 
1001
                        if (options.foldSyntaxBased && options.foldAtElse) {
 
1002
                                levelUse = levelMinCurrent;
 
1003
                        }
 
1004
                        int lev = levelUse | levelNext << 16;
 
1005
                        if (visibleChars == 0 && options.foldCompact)
 
1006
                                lev |= SC_FOLDLEVELWHITEFLAG;
 
1007
                        if (levelUse < levelNext)
 
1008
                                lev |= SC_FOLDLEVELHEADERFLAG;
 
1009
                        if (lev != styler.LevelAt(lineCurrent)) {
 
1010
                                styler.SetLevel(lineCurrent, lev);
 
1011
                        }
 
1012
                        lineCurrent++;
 
1013
                        levelCurrent = levelNext;
 
1014
                        levelMinCurrent = levelCurrent;
 
1015
                        if (atEOL && (i == static_cast<unsigned int>(styler.Length()-1))) {
 
1016
                                // There is an empty line at end of file so give it same level and empty
 
1017
                                styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
 
1018
                        }
 
1019
                        visibleChars = 0;
 
1020
                }
 
1021
        }
 
1022
}
 
1023
 
 
1024
void LexerCPP::EvaluateTokens(std::vector<std::string> &tokens) {
 
1025
 
 
1026
        // Evaluate defined() statements to either 0 or 1
 
1027
        for (size_t i=0; (i+2)<tokens.size();) {
 
1028
                if ((tokens[i] == "defined") && (tokens[i+1] == "(")) {
 
1029
                        const char *val = "0";
 
1030
                        if (tokens[i+2] == ")") {
 
1031
                                // defined()
 
1032
                                tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 3);
 
1033
                        } else if (((i+2)<tokens.size()) && (tokens[i+3] == ")")) {
 
1034
                                // defined(<int>)
 
1035
                                tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 4);
 
1036
                                val = "1";
 
1037
                        }
 
1038
                        tokens[i] = val;
 
1039
                } else {
 
1040
                        i++;
 
1041
                }
 
1042
        }
 
1043
 
 
1044
        // Find bracketed subexpressions and recurse on them
 
1045
        std::vector<std::string>::iterator itBracket = std::find(tokens.begin(), tokens.end(), "(");
 
1046
        std::vector<std::string>::iterator itEndBracket = std::find(tokens.begin(), tokens.end(), ")");
 
1047
        while ((itBracket != tokens.end()) && (itEndBracket != tokens.end()) && (itEndBracket > itBracket)) {
 
1048
                std::vector<std::string> inBracket(itBracket + 1, itEndBracket);
 
1049
                EvaluateTokens(inBracket);
 
1050
 
 
1051
                // The insertion is done before the removal because there were failures with the opposite approach
 
1052
                tokens.insert(itBracket, inBracket.begin(), inBracket.end());
 
1053
                itBracket = std::find(tokens.begin(), tokens.end(), "(");
 
1054
                itEndBracket = std::find(tokens.begin(), tokens.end(), ")");
 
1055
                tokens.erase(itBracket, itEndBracket + 1);
 
1056
 
 
1057
                itBracket = std::find(tokens.begin(), tokens.end(), "(");
 
1058
                itEndBracket = std::find(tokens.begin(), tokens.end(), ")");
 
1059
        }
 
1060
 
 
1061
        // Evaluate logical negations
 
1062
        for (size_t j=0; (j+1)<tokens.size();) {
 
1063
                if (setNegationOp.Contains(tokens[j][0])) {
 
1064
                        int isTrue = atoi(tokens[j+1].c_str());
 
1065
                        if (tokens[j] == "!")
 
1066
                                isTrue = !isTrue;
 
1067
                        std::vector<std::string>::iterator itInsert =
 
1068
                                tokens.erase(tokens.begin() + j, tokens.begin() + j + 2);
 
1069
                        tokens.insert(itInsert, isTrue ? "1" : "0");
 
1070
                } else {
 
1071
                        j++;
 
1072
                }
 
1073
        }
 
1074
 
 
1075
        // Evaluate expressions in precedence order
 
1076
        enum precedence { precArithmetic, precRelative, precLogical };
 
1077
        for (int prec=precArithmetic; prec <= precLogical; prec++) {
 
1078
                // Looking at 3 tokens at a time so end at 2 before end
 
1079
                for (size_t k=0; (k+2)<tokens.size();) {
 
1080
                        char chOp = tokens[k+1][0];
 
1081
                        if (
 
1082
                                ((prec==precArithmetic) && setArithmethicOp.Contains(chOp)) ||
 
1083
                                ((prec==precRelative) && setRelOp.Contains(chOp)) ||
 
1084
                                ((prec==precLogical) && setLogicalOp.Contains(chOp))
 
1085
                                ) {
 
1086
                                int valA = atoi(tokens[k].c_str());
 
1087
                                int valB = atoi(tokens[k+2].c_str());
 
1088
                                int result = 0;
 
1089
                                if (tokens[k+1] == "+")
 
1090
                                        result = valA + valB;
 
1091
                                else if (tokens[k+1] == "-")
 
1092
                                        result = valA - valB;
 
1093
                                else if (tokens[k+1] == "*")
 
1094
                                        result = valA * valB;
 
1095
                                else if (tokens[k+1] == "/")
 
1096
                                        result = valA / (valB ? valB : 1);
 
1097
                                else if (tokens[k+1] == "%")
 
1098
                                        result = valA % (valB ? valB : 1);
 
1099
                                else if (tokens[k+1] == "<")
 
1100
                                        result = valA < valB;
 
1101
                                else if (tokens[k+1] == "<=")
 
1102
                                        result = valA <= valB;
 
1103
                                else if (tokens[k+1] == ">")
 
1104
                                        result = valA > valB;
 
1105
                                else if (tokens[k+1] == ">=")
 
1106
                                        result = valA >= valB;
 
1107
                                else if (tokens[k+1] == "==")
 
1108
                                        result = valA == valB;
 
1109
                                else if (tokens[k+1] == "!=")
 
1110
                                        result = valA != valB;
 
1111
                                else if (tokens[k+1] == "||")
 
1112
                                        result = valA || valB;
 
1113
                                else if (tokens[k+1] == "&&")
 
1114
                                        result = valA && valB;
 
1115
                                char sResult[30];
 
1116
                                sprintf(sResult, "%d", result);
 
1117
                                std::vector<std::string>::iterator itInsert =
 
1118
                                        tokens.erase(tokens.begin() + k, tokens.begin() + k + 3);
 
1119
                                tokens.insert(itInsert, sResult);
 
1120
                        } else {
 
1121
                                k++;
 
1122
                        }
 
1123
                }
 
1124
        }
 
1125
}
 
1126
 
 
1127
bool LexerCPP::EvaluateExpression(const std::string &expr, const std::map<std::string, std::string> &preprocessorDefinitions) {
 
1128
        // Break into tokens, replacing with definitions
 
1129
        std::string word;
 
1130
        std::vector<std::string> tokens;
 
1131
        const char *cp = expr.c_str();
 
1132
        for (;;) {
 
1133
                if (setWord.Contains(*cp)) {
 
1134
                        word += *cp;
 
1135
                } else {
 
1136
                        std::map<std::string, std::string>::const_iterator it = preprocessorDefinitions.find(word);
 
1137
                        if (it != preprocessorDefinitions.end()) {
 
1138
                                tokens.push_back(it->second);
 
1139
                        } else if (!word.empty() && ((word[0] >= '0' && word[0] <= '9') || (word == "defined"))) {
 
1140
                                tokens.push_back(word);
 
1141
                        }
 
1142
                        word = "";
 
1143
                        if (!*cp) {
 
1144
                                break;
 
1145
                        }
 
1146
                        if ((*cp != ' ') && (*cp != '\t')) {
 
1147
                                std::string op(cp, 1);
 
1148
                                if (setRelOp.Contains(*cp)) {
 
1149
                                        if (setRelOp.Contains(cp[1])) {
 
1150
                                                op += cp[1];
 
1151
                                                cp++;
 
1152
                                        }
 
1153
                                } else if (setLogicalOp.Contains(*cp)) {
 
1154
                                        if (setLogicalOp.Contains(cp[1])) {
 
1155
                                                op += cp[1];
 
1156
                                                cp++;
 
1157
                                        }
 
1158
                                }
 
1159
                                tokens.push_back(op);
 
1160
                        }
 
1161
                }
 
1162
                cp++;
 
1163
        }
 
1164
 
 
1165
        EvaluateTokens(tokens);
 
1166
 
 
1167
        // "0" or "" -> false else true
 
1168
        bool isFalse = tokens.empty() ||
 
1169
                ((tokens.size() == 1) && ((tokens[0] == "") || tokens[0] == "0"));
 
1170
        return !isFalse;
 
1171
}
 
1172
 
 
1173
LexerModule lmCPP(SCLEX_CPP, LexerCPP::LexerFactoryCPP, "cpp", cppWordLists);
 
1174
LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, LexerCPP::LexerFactoryCPPInsensitive, "cppnocase", cppWordLists);