LexCPP.cpp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641
  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. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <stdarg.h>
  12. #include <assert.h>
  13. #include <ctype.h>
  14. #include <string>
  15. #include <vector>
  16. #include <map>
  17. #include <algorithm>
  18. #include "ILexer.h"
  19. #include "Scintilla.h"
  20. #include "SciLexer.h"
  21. #include "WordList.h"
  22. #include "LexAccessor.h"
  23. #include "Accessor.h"
  24. #include "StyleContext.h"
  25. #include "CharacterSet.h"
  26. #include "LexerModule.h"
  27. #include "OptionSet.h"
  28. #include "SparseState.h"
  29. #include "SubStyles.h"
  30. #ifdef SCI_NAMESPACE
  31. using namespace Scintilla;
  32. #endif
  33. namespace {
  34. // Use an unnamed namespace to protect the functions and classes from name conflicts
  35. bool IsSpaceEquiv(int state) {
  36. return (state <= SCE_C_COMMENTDOC) ||
  37. // including SCE_C_DEFAULT, SCE_C_COMMENT, SCE_C_COMMENTLINE
  38. (state == SCE_C_COMMENTLINEDOC) || (state == SCE_C_COMMENTDOCKEYWORD) ||
  39. (state == SCE_C_COMMENTDOCKEYWORDERROR);
  40. }
  41. // Preconditions: sc.currentPos points to a character after '+' or '-'.
  42. // The test for pos reaching 0 should be redundant,
  43. // and is in only for safety measures.
  44. // Limitation: this code will give the incorrect answer for code like
  45. // a = b+++/ptn/...
  46. // Putting a space between the '++' post-inc operator and the '+' binary op
  47. // fixes this, and is highly recommended for readability anyway.
  48. bool FollowsPostfixOperator(StyleContext &sc, LexAccessor &styler) {
  49. Sci_Position pos = (Sci_Position) sc.currentPos;
  50. while (--pos > 0) {
  51. char ch = styler[pos];
  52. if (ch == '+' || ch == '-') {
  53. return styler[pos - 1] == ch;
  54. }
  55. }
  56. return false;
  57. }
  58. bool followsReturnKeyword(StyleContext &sc, LexAccessor &styler) {
  59. // Don't look at styles, so no need to flush.
  60. Sci_Position pos = (Sci_Position) sc.currentPos;
  61. Sci_Position currentLine = styler.GetLine(pos);
  62. Sci_Position lineStartPos = styler.LineStart(currentLine);
  63. while (--pos > lineStartPos) {
  64. char ch = styler.SafeGetCharAt(pos);
  65. if (ch != ' ' && ch != '\t') {
  66. break;
  67. }
  68. }
  69. const char *retBack = "nruter";
  70. const char *s = retBack;
  71. while (*s
  72. && pos >= lineStartPos
  73. && styler.SafeGetCharAt(pos) == *s) {
  74. s++;
  75. pos--;
  76. }
  77. return !*s;
  78. }
  79. bool IsSpaceOrTab(int ch) {
  80. return ch == ' ' || ch == '\t';
  81. }
  82. bool OnlySpaceOrTab(const std::string &s) {
  83. for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
  84. if (!IsSpaceOrTab(*it))
  85. return false;
  86. }
  87. return true;
  88. }
  89. std::vector<std::string> StringSplit(const std::string &text, int separator) {
  90. std::vector<std::string> vs(text.empty() ? 0 : 1);
  91. for (std::string::const_iterator it = text.begin(); it != text.end(); ++it) {
  92. if (*it == separator) {
  93. vs.push_back(std::string());
  94. } else {
  95. vs.back() += *it;
  96. }
  97. }
  98. return vs;
  99. }
  100. struct BracketPair {
  101. std::vector<std::string>::iterator itBracket;
  102. std::vector<std::string>::iterator itEndBracket;
  103. };
  104. BracketPair FindBracketPair(std::vector<std::string> &tokens) {
  105. BracketPair bp;
  106. std::vector<std::string>::iterator itTok = std::find(tokens.begin(), tokens.end(), "(");
  107. bp.itBracket = tokens.end();
  108. bp.itEndBracket = tokens.end();
  109. if (itTok != tokens.end()) {
  110. bp.itBracket = itTok;
  111. size_t nest = 0;
  112. while (itTok != tokens.end()) {
  113. if (*itTok == "(") {
  114. nest++;
  115. } else if (*itTok == ")") {
  116. nest--;
  117. if (nest == 0) {
  118. bp.itEndBracket = itTok;
  119. return bp;
  120. }
  121. }
  122. ++itTok;
  123. }
  124. }
  125. bp.itBracket = tokens.end();
  126. return bp;
  127. }
  128. void highlightTaskMarker(StyleContext &sc, LexAccessor &styler,
  129. int activity, WordList &markerList, bool caseSensitive){
  130. if ((isoperator(sc.chPrev) || IsASpace(sc.chPrev)) && markerList.Length()) {
  131. const int lengthMarker = 50;
  132. char marker[lengthMarker+1];
  133. Sci_Position currPos = (Sci_Position) sc.currentPos;
  134. int i = 0;
  135. while (i < lengthMarker) {
  136. char ch = styler.SafeGetCharAt(currPos + i);
  137. if (IsASpace(ch) || isoperator(ch)) {
  138. break;
  139. }
  140. if (caseSensitive)
  141. marker[i] = ch;
  142. else
  143. marker[i] = static_cast<char>(tolower(ch));
  144. i++;
  145. }
  146. marker[i] = '\0';
  147. if (markerList.InList(marker)) {
  148. sc.SetState(SCE_C_TASKMARKER|activity);
  149. }
  150. }
  151. }
  152. struct EscapeSequence {
  153. int digitsLeft;
  154. CharacterSet setHexDigits;
  155. CharacterSet setOctDigits;
  156. CharacterSet setNoneNumeric;
  157. CharacterSet *escapeSetValid;
  158. EscapeSequence() {
  159. digitsLeft = 0;
  160. escapeSetValid = 0;
  161. setHexDigits = CharacterSet(CharacterSet::setDigits, "ABCDEFabcdef");
  162. setOctDigits = CharacterSet(CharacterSet::setNone, "01234567");
  163. }
  164. void resetEscapeState(int nextChar) {
  165. digitsLeft = 0;
  166. escapeSetValid = &setNoneNumeric;
  167. if (nextChar == 'U') {
  168. digitsLeft = 9;
  169. escapeSetValid = &setHexDigits;
  170. } else if (nextChar == 'u') {
  171. digitsLeft = 5;
  172. escapeSetValid = &setHexDigits;
  173. } else if (nextChar == 'x') {
  174. digitsLeft = 5;
  175. escapeSetValid = &setHexDigits;
  176. } else if (setOctDigits.Contains(nextChar)) {
  177. digitsLeft = 3;
  178. escapeSetValid = &setOctDigits;
  179. }
  180. }
  181. bool atEscapeEnd(int currChar) const {
  182. return (digitsLeft <= 0) || !escapeSetValid->Contains(currChar);
  183. }
  184. };
  185. std::string GetRestOfLine(LexAccessor &styler, Sci_Position start, bool allowSpace) {
  186. std::string restOfLine;
  187. Sci_Position i =0;
  188. char ch = styler.SafeGetCharAt(start, '\n');
  189. Sci_Position endLine = styler.LineEnd(styler.GetLine(start));
  190. while (((start+i) < endLine) && (ch != '\r')) {
  191. char chNext = styler.SafeGetCharAt(start + i + 1, '\n');
  192. if (ch == '/' && (chNext == '/' || chNext == '*'))
  193. break;
  194. if (allowSpace || (ch != ' '))
  195. restOfLine += ch;
  196. i++;
  197. ch = chNext;
  198. }
  199. return restOfLine;
  200. }
  201. bool IsStreamCommentStyle(int style) {
  202. return style == SCE_C_COMMENT ||
  203. style == SCE_C_COMMENTDOC ||
  204. style == SCE_C_COMMENTDOCKEYWORD ||
  205. style == SCE_C_COMMENTDOCKEYWORDERROR;
  206. }
  207. struct PPDefinition {
  208. Sci_Position line;
  209. std::string key;
  210. std::string value;
  211. bool isUndef;
  212. std::string arguments;
  213. PPDefinition(Sci_Position line_, const std::string &key_, const std::string &value_, bool isUndef_ = false, const std::string &arguments_="") :
  214. line(line_), key(key_), value(value_), isUndef(isUndef_), arguments(arguments_) {
  215. }
  216. };
  217. class LinePPState {
  218. int state;
  219. int ifTaken;
  220. int level;
  221. bool ValidLevel() const {
  222. return level >= 0 && level < 32;
  223. }
  224. int maskLevel() const {
  225. return 1 << level;
  226. }
  227. public:
  228. LinePPState() : state(0), ifTaken(0), level(-1) {
  229. }
  230. bool IsInactive() const {
  231. return state != 0;
  232. }
  233. bool CurrentIfTaken() const {
  234. return (ifTaken & maskLevel()) != 0;
  235. }
  236. void StartSection(bool on) {
  237. level++;
  238. if (ValidLevel()) {
  239. if (on) {
  240. state &= ~maskLevel();
  241. ifTaken |= maskLevel();
  242. } else {
  243. state |= maskLevel();
  244. ifTaken &= ~maskLevel();
  245. }
  246. }
  247. }
  248. void EndSection() {
  249. if (ValidLevel()) {
  250. state &= ~maskLevel();
  251. ifTaken &= ~maskLevel();
  252. }
  253. level--;
  254. }
  255. void InvertCurrentLevel() {
  256. if (ValidLevel()) {
  257. state ^= maskLevel();
  258. ifTaken |= maskLevel();
  259. }
  260. }
  261. };
  262. // Hold the preprocessor state for each line seen.
  263. // Currently one entry per line but could become sparse with just one entry per preprocessor line.
  264. class PPStates {
  265. std::vector<LinePPState> vlls;
  266. public:
  267. LinePPState ForLine(Sci_Position line) const {
  268. if ((line > 0) && (vlls.size() > static_cast<size_t>(line))) {
  269. return vlls[line];
  270. } else {
  271. return LinePPState();
  272. }
  273. }
  274. void Add(Sci_Position line, LinePPState lls) {
  275. vlls.resize(line+1);
  276. vlls[line] = lls;
  277. }
  278. };
  279. // An individual named option for use in an OptionSet
  280. // Options used for LexerCPP
  281. struct OptionsCPP {
  282. bool stylingWithinPreprocessor;
  283. bool identifiersAllowDollars;
  284. bool trackPreprocessor;
  285. bool updatePreprocessor;
  286. bool verbatimStringsAllowEscapes;
  287. bool triplequotedStrings;
  288. bool hashquotedStrings;
  289. bool backQuotedStrings;
  290. bool escapeSequence;
  291. bool fold;
  292. bool foldSyntaxBased;
  293. bool foldComment;
  294. bool foldCommentMultiline;
  295. bool foldCommentExplicit;
  296. std::string foldExplicitStart;
  297. std::string foldExplicitEnd;
  298. bool foldExplicitAnywhere;
  299. bool foldPreprocessor;
  300. bool foldPreprocessorAtElse;
  301. bool foldCompact;
  302. bool foldAtElse;
  303. OptionsCPP() {
  304. stylingWithinPreprocessor = false;
  305. identifiersAllowDollars = true;
  306. trackPreprocessor = true;
  307. updatePreprocessor = true;
  308. verbatimStringsAllowEscapes = false;
  309. triplequotedStrings = false;
  310. hashquotedStrings = false;
  311. backQuotedStrings = false;
  312. escapeSequence = false;
  313. fold = false;
  314. foldSyntaxBased = true;
  315. foldComment = false;
  316. foldCommentMultiline = true;
  317. foldCommentExplicit = true;
  318. foldExplicitStart = "";
  319. foldExplicitEnd = "";
  320. foldExplicitAnywhere = false;
  321. foldPreprocessor = false;
  322. foldPreprocessorAtElse = false;
  323. foldCompact = false;
  324. foldAtElse = false;
  325. }
  326. };
  327. const char *const cppWordLists[] = {
  328. "Primary keywords and identifiers",
  329. "Secondary keywords and identifiers",
  330. "Documentation comment keywords",
  331. "Global classes and typedefs",
  332. "Preprocessor definitions",
  333. "Task marker and error marker keywords",
  334. 0,
  335. };
  336. struct OptionSetCPP : public OptionSet<OptionsCPP> {
  337. OptionSetCPP() {
  338. DefineProperty("styling.within.preprocessor", &OptionsCPP::stylingWithinPreprocessor,
  339. "For C++ code, determines whether all preprocessor code is styled in the "
  340. "preprocessor style (0, the default) or only from the initial # to the end "
  341. "of the command word(1).");
  342. DefineProperty("lexer.cpp.allow.dollars", &OptionsCPP::identifiersAllowDollars,
  343. "Set to 0 to disallow the '$' character in identifiers with the cpp lexer.");
  344. DefineProperty("lexer.cpp.track.preprocessor", &OptionsCPP::trackPreprocessor,
  345. "Set to 1 to interpret #if/#else/#endif to grey out code that is not active.");
  346. DefineProperty("lexer.cpp.update.preprocessor", &OptionsCPP::updatePreprocessor,
  347. "Set to 1 to update preprocessor definitions when #define found.");
  348. DefineProperty("lexer.cpp.verbatim.strings.allow.escapes", &OptionsCPP::verbatimStringsAllowEscapes,
  349. "Set to 1 to allow verbatim strings to contain escape sequences.");
  350. DefineProperty("lexer.cpp.triplequoted.strings", &OptionsCPP::triplequotedStrings,
  351. "Set to 1 to enable highlighting of triple-quoted strings.");
  352. DefineProperty("lexer.cpp.hashquoted.strings", &OptionsCPP::hashquotedStrings,
  353. "Set to 1 to enable highlighting of hash-quoted strings.");
  354. DefineProperty("lexer.cpp.backquoted.strings", &OptionsCPP::backQuotedStrings,
  355. "Set to 1 to enable highlighting of back-quoted raw strings .");
  356. DefineProperty("lexer.cpp.escape.sequence", &OptionsCPP::escapeSequence,
  357. "Set to 1 to enable highlighting of escape sequences in strings");
  358. DefineProperty("fold", &OptionsCPP::fold);
  359. DefineProperty("fold.cpp.syntax.based", &OptionsCPP::foldSyntaxBased,
  360. "Set this property to 0 to disable syntax based folding.");
  361. DefineProperty("fold.comment", &OptionsCPP::foldComment,
  362. "This option enables folding multi-line comments and explicit fold points when using the C++ lexer. "
  363. "Explicit fold points allows adding extra folding by placing a //{ comment at the start and a //} "
  364. "at the end of a section that should fold.");
  365. DefineProperty("fold.cpp.comment.multiline", &OptionsCPP::foldCommentMultiline,
  366. "Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
  367. DefineProperty("fold.cpp.comment.explicit", &OptionsCPP::foldCommentExplicit,
  368. "Set this property to 0 to disable folding explicit fold points when fold.comment=1.");
  369. DefineProperty("fold.cpp.explicit.start", &OptionsCPP::foldExplicitStart,
  370. "The string to use for explicit fold start points, replacing the standard //{.");
  371. DefineProperty("fold.cpp.explicit.end", &OptionsCPP::foldExplicitEnd,
  372. "The string to use for explicit fold end points, replacing the standard //}.");
  373. DefineProperty("fold.cpp.explicit.anywhere", &OptionsCPP::foldExplicitAnywhere,
  374. "Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
  375. DefineProperty("fold.cpp.preprocessor.at.else", &OptionsCPP::foldPreprocessorAtElse,
  376. "This option enables folding on a preprocessor #else or #endif line of an #if statement.");
  377. DefineProperty("fold.preprocessor", &OptionsCPP::foldPreprocessor,
  378. "This option enables folding preprocessor directives when using the C++ lexer. "
  379. "Includes C#'s explicit #region and #endregion folding directives.");
  380. DefineProperty("fold.compact", &OptionsCPP::foldCompact);
  381. DefineProperty("fold.at.else", &OptionsCPP::foldAtElse,
  382. "This option enables C++ folding on a \"} else {\" line of an if statement.");
  383. DefineWordListSets(cppWordLists);
  384. }
  385. };
  386. const char styleSubable[] = {SCE_C_IDENTIFIER, SCE_C_COMMENTDOCKEYWORD, 0};
  387. }
  388. class LexerCPP : public ILexerWithSubStyles {
  389. bool caseSensitive;
  390. CharacterSet setWord;
  391. CharacterSet setNegationOp;
  392. CharacterSet setArithmethicOp;
  393. CharacterSet setRelOp;
  394. CharacterSet setLogicalOp;
  395. CharacterSet setWordStart;
  396. PPStates vlls;
  397. std::vector<PPDefinition> ppDefineHistory;
  398. WordList keywords;
  399. WordList keywords2;
  400. WordList keywords3;
  401. WordList keywords4;
  402. WordList ppDefinitions;
  403. WordList markerList;
  404. struct SymbolValue {
  405. std::string value;
  406. std::string arguments;
  407. SymbolValue(const std::string &value_="", const std::string &arguments_="") : value(value_), arguments(arguments_) {
  408. }
  409. SymbolValue &operator = (const std::string &value_) {
  410. value = value_;
  411. arguments.clear();
  412. return *this;
  413. }
  414. bool IsMacro() const {
  415. return !arguments.empty();
  416. }
  417. };
  418. typedef std::map<std::string, SymbolValue> SymbolTable;
  419. SymbolTable preprocessorDefinitionsStart;
  420. OptionsCPP options;
  421. OptionSetCPP osCPP;
  422. EscapeSequence escapeSeq;
  423. SparseState<std::string> rawStringTerminators;
  424. enum { activeFlag = 0x40 };
  425. enum { ssIdentifier, ssDocKeyword };
  426. SubStyles subStyles;
  427. public:
  428. explicit LexerCPP(bool caseSensitive_) :
  429. caseSensitive(caseSensitive_),
  430. setWord(CharacterSet::setAlphaNum, "._", 0x80, true),
  431. setNegationOp(CharacterSet::setNone, "!"),
  432. setArithmethicOp(CharacterSet::setNone, "+-/*%"),
  433. setRelOp(CharacterSet::setNone, "=!<>"),
  434. setLogicalOp(CharacterSet::setNone, "|&"),
  435. subStyles(styleSubable, 0x80, 0x40, activeFlag) {
  436. }
  437. virtual ~LexerCPP() {
  438. }
  439. void SCI_METHOD Release() {
  440. delete this;
  441. }
  442. int SCI_METHOD Version() const {
  443. return lvSubStyles;
  444. }
  445. const char * SCI_METHOD PropertyNames() {
  446. return osCPP.PropertyNames();
  447. }
  448. int SCI_METHOD PropertyType(const char *name) {
  449. return osCPP.PropertyType(name);
  450. }
  451. const char * SCI_METHOD DescribeProperty(const char *name) {
  452. return osCPP.DescribeProperty(name);
  453. }
  454. Sci_Position SCI_METHOD PropertySet(const char *key, const char *val);
  455. const char * SCI_METHOD DescribeWordListSets() {
  456. return osCPP.DescribeWordListSets();
  457. }
  458. Sci_Position SCI_METHOD WordListSet(int n, const char *wl);
  459. void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess);
  460. void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess);
  461. void * SCI_METHOD PrivateCall(int, void *) {
  462. return 0;
  463. }
  464. int SCI_METHOD LineEndTypesSupported() {
  465. return SC_LINE_END_TYPE_UNICODE;
  466. }
  467. int SCI_METHOD AllocateSubStyles(int styleBase, int numberStyles) {
  468. return subStyles.Allocate(styleBase, numberStyles);
  469. }
  470. int SCI_METHOD SubStylesStart(int styleBase) {
  471. return subStyles.Start(styleBase);
  472. }
  473. int SCI_METHOD SubStylesLength(int styleBase) {
  474. return subStyles.Length(styleBase);
  475. }
  476. int SCI_METHOD StyleFromSubStyle(int subStyle) {
  477. int styleBase = subStyles.BaseStyle(MaskActive(subStyle));
  478. int active = subStyle & activeFlag;
  479. return styleBase | active;
  480. }
  481. int SCI_METHOD PrimaryStyleFromStyle(int style) {
  482. return MaskActive(style);
  483. }
  484. void SCI_METHOD FreeSubStyles() {
  485. subStyles.Free();
  486. }
  487. void SCI_METHOD SetIdentifiers(int style, const char *identifiers) {
  488. subStyles.SetIdentifiers(style, identifiers);
  489. }
  490. int SCI_METHOD DistanceToSecondaryStyles() {
  491. return activeFlag;
  492. }
  493. const char * SCI_METHOD GetSubStyleBases() {
  494. return styleSubable;
  495. }
  496. static ILexer *LexerFactoryCPP() {
  497. return new LexerCPP(true);
  498. }
  499. static ILexer *LexerFactoryCPPInsensitive() {
  500. return new LexerCPP(false);
  501. }
  502. static int MaskActive(int style) {
  503. return style & ~activeFlag;
  504. }
  505. void EvaluateTokens(std::vector<std::string> &tokens, const SymbolTable &preprocessorDefinitions);
  506. std::vector<std::string> Tokenize(const std::string &expr) const;
  507. bool EvaluateExpression(const std::string &expr, const SymbolTable &preprocessorDefinitions);
  508. };
  509. Sci_Position SCI_METHOD LexerCPP::PropertySet(const char *key, const char *val) {
  510. if (osCPP.PropertySet(&options, key, val)) {
  511. if (strcmp(key, "lexer.cpp.allow.dollars") == 0) {
  512. setWord = CharacterSet(CharacterSet::setAlphaNum, "._", 0x80, true);
  513. if (options.identifiersAllowDollars) {
  514. setWord.Add('$');
  515. }
  516. }
  517. return 0;
  518. }
  519. return -1;
  520. }
  521. Sci_Position SCI_METHOD LexerCPP::WordListSet(int n, const char *wl) {
  522. WordList *wordListN = 0;
  523. switch (n) {
  524. case 0:
  525. wordListN = &keywords;
  526. break;
  527. case 1:
  528. wordListN = &keywords2;
  529. break;
  530. case 2:
  531. wordListN = &keywords3;
  532. break;
  533. case 3:
  534. wordListN = &keywords4;
  535. break;
  536. case 4:
  537. wordListN = &ppDefinitions;
  538. break;
  539. case 5:
  540. wordListN = &markerList;
  541. break;
  542. }
  543. Sci_Position firstModification = -1;
  544. if (wordListN) {
  545. WordList wlNew;
  546. wlNew.Set(wl);
  547. if (*wordListN != wlNew) {
  548. wordListN->Set(wl);
  549. firstModification = 0;
  550. if (n == 4) {
  551. // Rebuild preprocessorDefinitions
  552. preprocessorDefinitionsStart.clear();
  553. for (int nDefinition = 0; nDefinition < ppDefinitions.Length(); nDefinition++) {
  554. const char *cpDefinition = ppDefinitions.WordAt(nDefinition);
  555. const char *cpEquals = strchr(cpDefinition, '=');
  556. if (cpEquals) {
  557. std::string name(cpDefinition, cpEquals - cpDefinition);
  558. std::string val(cpEquals+1);
  559. size_t bracket = name.find('(');
  560. size_t bracketEnd = name.find(')');
  561. if ((bracket != std::string::npos) && (bracketEnd != std::string::npos)) {
  562. // Macro
  563. std::string args = name.substr(bracket + 1, bracketEnd - bracket - 1);
  564. name = name.substr(0, bracket);
  565. preprocessorDefinitionsStart[name] = SymbolValue(val, args);
  566. } else {
  567. preprocessorDefinitionsStart[name] = val;
  568. }
  569. } else {
  570. std::string name(cpDefinition);
  571. std::string val("1");
  572. preprocessorDefinitionsStart[name] = val;
  573. }
  574. }
  575. }
  576. }
  577. }
  578. return firstModification;
  579. }
  580. // Functor used to truncate history
  581. struct After {
  582. Sci_Position line;
  583. explicit After(Sci_Position line_) : line(line_) {}
  584. bool operator()(PPDefinition &p) const {
  585. return p.line > line;
  586. }
  587. };
  588. void SCI_METHOD LexerCPP::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
  589. LexAccessor styler(pAccess);
  590. CharacterSet setOKBeforeRE(CharacterSet::setNone, "([{=,:;!%^&*|?~+-");
  591. CharacterSet setCouldBePostOp(CharacterSet::setNone, "+-");
  592. CharacterSet setDoxygen(CharacterSet::setAlpha, "$@\\&<>#{}[]");
  593. setWordStart = CharacterSet(CharacterSet::setAlpha, "_", 0x80, true);
  594. CharacterSet setInvalidRawFirst(CharacterSet::setNone, " )\\\t\v\f\n");
  595. if (options.identifiersAllowDollars) {
  596. setWordStart.Add('$');
  597. }
  598. int chPrevNonWhite = ' ';
  599. int visibleChars = 0;
  600. bool lastWordWasUUID = false;
  601. int styleBeforeDCKeyword = SCE_C_DEFAULT;
  602. int styleBeforeTaskMarker = SCE_C_DEFAULT;
  603. bool continuationLine = false;
  604. bool isIncludePreprocessor = false;
  605. bool isStringInPreprocessor = false;
  606. bool inRERange = false;
  607. bool seenDocKeyBrace = false;
  608. Sci_Position lineCurrent = styler.GetLine(startPos);
  609. if ((MaskActive(initStyle) == SCE_C_PREPROCESSOR) ||
  610. (MaskActive(initStyle) == SCE_C_COMMENTLINE) ||
  611. (MaskActive(initStyle) == SCE_C_COMMENTLINEDOC)) {
  612. // Set continuationLine if last character of previous line is '\'
  613. if (lineCurrent > 0) {
  614. Sci_Position endLinePrevious = styler.LineEnd(lineCurrent - 1);
  615. if (endLinePrevious > 0) {
  616. continuationLine = styler.SafeGetCharAt(endLinePrevious-1) == '\\';
  617. }
  618. }
  619. }
  620. // look back to set chPrevNonWhite properly for better regex colouring
  621. if (startPos > 0) {
  622. Sci_Position back = startPos;
  623. while (--back && IsSpaceEquiv(MaskActive(styler.StyleAt(back))))
  624. ;
  625. if (MaskActive(styler.StyleAt(back)) == SCE_C_OPERATOR) {
  626. chPrevNonWhite = styler.SafeGetCharAt(back);
  627. }
  628. }
  629. StyleContext sc(startPos, length, initStyle, styler);
  630. LinePPState preproc = vlls.ForLine(lineCurrent);
  631. bool definitionsChanged = false;
  632. // Truncate ppDefineHistory before current line
  633. if (!options.updatePreprocessor)
  634. ppDefineHistory.clear();
  635. std::vector<PPDefinition>::iterator itInvalid = std::find_if(ppDefineHistory.begin(), ppDefineHistory.end(), After(lineCurrent-1));
  636. if (itInvalid != ppDefineHistory.end()) {
  637. ppDefineHistory.erase(itInvalid, ppDefineHistory.end());
  638. definitionsChanged = true;
  639. }
  640. SymbolTable preprocessorDefinitions = preprocessorDefinitionsStart;
  641. for (std::vector<PPDefinition>::iterator itDef = ppDefineHistory.begin(); itDef != ppDefineHistory.end(); ++itDef) {
  642. if (itDef->isUndef)
  643. preprocessorDefinitions.erase(itDef->key);
  644. else
  645. preprocessorDefinitions[itDef->key] = SymbolValue(itDef->value, itDef->arguments);
  646. }
  647. std::string rawStringTerminator = rawStringTerminators.ValueAt(lineCurrent-1);
  648. SparseState<std::string> rawSTNew(lineCurrent);
  649. int activitySet = preproc.IsInactive() ? activeFlag : 0;
  650. const WordClassifier &classifierIdentifiers = subStyles.Classifier(SCE_C_IDENTIFIER);
  651. const WordClassifier &classifierDocKeyWords = subStyles.Classifier(SCE_C_COMMENTDOCKEYWORD);
  652. Sci_Position lineEndNext = styler.LineEnd(lineCurrent);
  653. for (; sc.More();) {
  654. if (sc.atLineStart) {
  655. // Using MaskActive() is not needed in the following statement.
  656. // Inside inactive preprocessor declaration, state will be reset anyway at the end of this block.
  657. if ((sc.state == SCE_C_STRING) || (sc.state == SCE_C_CHARACTER)) {
  658. // Prevent SCE_C_STRINGEOL from leaking back to previous line which
  659. // ends with a line continuation by locking in the state up to this position.
  660. sc.SetState(sc.state);
  661. }
  662. if ((MaskActive(sc.state) == SCE_C_PREPROCESSOR) && (!continuationLine)) {
  663. sc.SetState(SCE_C_DEFAULT|activitySet);
  664. }
  665. // Reset states to beginning of colourise so no surprises
  666. // if different sets of lines lexed.
  667. visibleChars = 0;
  668. lastWordWasUUID = false;
  669. isIncludePreprocessor = false;
  670. inRERange = false;
  671. if (preproc.IsInactive()) {
  672. activitySet = activeFlag;
  673. sc.SetState(sc.state | activitySet);
  674. }
  675. }
  676. if (sc.atLineEnd) {
  677. lineCurrent++;
  678. lineEndNext = styler.LineEnd(lineCurrent);
  679. vlls.Add(lineCurrent, preproc);
  680. if (rawStringTerminator != "") {
  681. rawSTNew.Set(lineCurrent-1, rawStringTerminator);
  682. }
  683. }
  684. // Handle line continuation generically.
  685. if (sc.ch == '\\') {
  686. if (static_cast<Sci_Position>((sc.currentPos+1)) >= lineEndNext) {
  687. lineCurrent++;
  688. lineEndNext = styler.LineEnd(lineCurrent);
  689. vlls.Add(lineCurrent, preproc);
  690. if (rawStringTerminator != "") {
  691. rawSTNew.Set(lineCurrent-1, rawStringTerminator);
  692. }
  693. sc.Forward();
  694. if (sc.ch == '\r' && sc.chNext == '\n') {
  695. // Even in UTF-8, \r and \n are separate
  696. sc.Forward();
  697. }
  698. continuationLine = true;
  699. sc.Forward();
  700. continue;
  701. }
  702. }
  703. const bool atLineEndBeforeSwitch = sc.atLineEnd;
  704. // Determine if the current state should terminate.
  705. switch (MaskActive(sc.state)) {
  706. case SCE_C_OPERATOR:
  707. sc.SetState(SCE_C_DEFAULT|activitySet);
  708. break;
  709. case SCE_C_NUMBER:
  710. // We accept almost anything because of hex. and number suffixes
  711. if (sc.ch == '_') {
  712. sc.ChangeState(SCE_C_USERLITERAL|activitySet);
  713. } else if (!(setWord.Contains(sc.ch)
  714. || (sc.ch == '\'')
  715. || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E' ||
  716. sc.chPrev == 'p' || sc.chPrev == 'P')))) {
  717. sc.SetState(SCE_C_DEFAULT|activitySet);
  718. }
  719. break;
  720. case SCE_C_USERLITERAL:
  721. if (!(setWord.Contains(sc.ch)))
  722. sc.SetState(SCE_C_DEFAULT|activitySet);
  723. break;
  724. case SCE_C_IDENTIFIER:
  725. if (sc.atLineStart || sc.atLineEnd || !setWord.Contains(sc.ch) || (sc.ch == '.')) {
  726. char s[1000];
  727. if (caseSensitive) {
  728. sc.GetCurrent(s, sizeof(s));
  729. } else {
  730. sc.GetCurrentLowered(s, sizeof(s));
  731. }
  732. if (keywords.InList(s)) {
  733. lastWordWasUUID = strcmp(s, "uuid") == 0;
  734. sc.ChangeState(SCE_C_WORD|activitySet);
  735. } else if (keywords2.InList(s)) {
  736. sc.ChangeState(SCE_C_WORD2|activitySet);
  737. } else if (keywords4.InList(s)) {
  738. sc.ChangeState(SCE_C_GLOBALCLASS|activitySet);
  739. } else {
  740. int subStyle = classifierIdentifiers.ValueFor(s);
  741. if (subStyle >= 0) {
  742. sc.ChangeState(subStyle|activitySet);
  743. }
  744. }
  745. const bool literalString = sc.ch == '\"';
  746. if (literalString || sc.ch == '\'') {
  747. size_t lenS = strlen(s);
  748. const bool raw = literalString && sc.chPrev == 'R' && !setInvalidRawFirst.Contains(sc.chNext);
  749. if (raw)
  750. s[lenS--] = '\0';
  751. bool valid =
  752. (lenS == 0) ||
  753. ((lenS == 1) && ((s[0] == 'L') || (s[0] == 'u') || (s[0] == 'U'))) ||
  754. ((lenS == 2) && literalString && (s[0] == 'u') && (s[1] == '8'));
  755. if (valid) {
  756. if (literalString) {
  757. if (raw) {
  758. // Set the style of the string prefix to SCE_C_STRINGRAW but then change to
  759. // SCE_C_DEFAULT as that allows the raw string start code to run.
  760. sc.ChangeState(SCE_C_STRINGRAW|activitySet);
  761. sc.SetState(SCE_C_DEFAULT|activitySet);
  762. } else {
  763. sc.ChangeState(SCE_C_STRING|activitySet);
  764. }
  765. } else {
  766. sc.ChangeState(SCE_C_CHARACTER|activitySet);
  767. }
  768. } else {
  769. sc.SetState(SCE_C_DEFAULT | activitySet);
  770. }
  771. } else {
  772. sc.SetState(SCE_C_DEFAULT|activitySet);
  773. }
  774. }
  775. break;
  776. case SCE_C_PREPROCESSOR:
  777. if (options.stylingWithinPreprocessor) {
  778. if (IsASpace(sc.ch)) {
  779. sc.SetState(SCE_C_DEFAULT|activitySet);
  780. }
  781. } else if (isStringInPreprocessor && (sc.Match('>') || sc.Match('\"') || sc.atLineEnd)) {
  782. isStringInPreprocessor = false;
  783. } else if (!isStringInPreprocessor) {
  784. if ((isIncludePreprocessor && sc.Match('<')) || sc.Match('\"')) {
  785. isStringInPreprocessor = true;
  786. } else if (sc.Match('/', '*')) {
  787. if (sc.Match("/**") || sc.Match("/*!")) {
  788. sc.SetState(SCE_C_PREPROCESSORCOMMENTDOC|activitySet);
  789. } else {
  790. sc.SetState(SCE_C_PREPROCESSORCOMMENT|activitySet);
  791. }
  792. sc.Forward(); // Eat the *
  793. } else if (sc.Match('/', '/')) {
  794. sc.SetState(SCE_C_DEFAULT|activitySet);
  795. }
  796. }
  797. break;
  798. case SCE_C_PREPROCESSORCOMMENT:
  799. case SCE_C_PREPROCESSORCOMMENTDOC:
  800. if (sc.Match('*', '/')) {
  801. sc.Forward();
  802. sc.ForwardSetState(SCE_C_PREPROCESSOR|activitySet);
  803. continue; // Without advancing in case of '\'.
  804. }
  805. break;
  806. case SCE_C_COMMENT:
  807. if (sc.Match('*', '/')) {
  808. sc.Forward();
  809. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  810. } else {
  811. styleBeforeTaskMarker = SCE_C_COMMENT;
  812. highlightTaskMarker(sc, styler, activitySet, markerList, caseSensitive);
  813. }
  814. break;
  815. case SCE_C_COMMENTDOC:
  816. if (sc.Match('*', '/')) {
  817. sc.Forward();
  818. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  819. } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
  820. // Verify that we have the conditions to mark a comment-doc-keyword
  821. if ((IsASpace(sc.chPrev) || sc.chPrev == '*') && (!IsASpace(sc.chNext))) {
  822. styleBeforeDCKeyword = SCE_C_COMMENTDOC;
  823. sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet);
  824. }
  825. }
  826. break;
  827. case SCE_C_COMMENTLINE:
  828. if (sc.atLineStart && !continuationLine) {
  829. sc.SetState(SCE_C_DEFAULT|activitySet);
  830. } else {
  831. styleBeforeTaskMarker = SCE_C_COMMENTLINE;
  832. highlightTaskMarker(sc, styler, activitySet, markerList, caseSensitive);
  833. }
  834. break;
  835. case SCE_C_COMMENTLINEDOC:
  836. if (sc.atLineStart && !continuationLine) {
  837. sc.SetState(SCE_C_DEFAULT|activitySet);
  838. } else if (sc.ch == '@' || sc.ch == '\\') { // JavaDoc and Doxygen support
  839. // Verify that we have the conditions to mark a comment-doc-keyword
  840. if ((IsASpace(sc.chPrev) || sc.chPrev == '/' || sc.chPrev == '!') && (!IsASpace(sc.chNext))) {
  841. styleBeforeDCKeyword = SCE_C_COMMENTLINEDOC;
  842. sc.SetState(SCE_C_COMMENTDOCKEYWORD|activitySet);
  843. }
  844. }
  845. break;
  846. case SCE_C_COMMENTDOCKEYWORD:
  847. if ((styleBeforeDCKeyword == SCE_C_COMMENTDOC) && sc.Match('*', '/')) {
  848. sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
  849. sc.Forward();
  850. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  851. seenDocKeyBrace = false;
  852. } else if (sc.ch == '[' || sc.ch == '{') {
  853. seenDocKeyBrace = true;
  854. } else if (!setDoxygen.Contains(sc.ch)
  855. && !(seenDocKeyBrace && (sc.ch == ',' || sc.ch == '.'))) {
  856. char s[100];
  857. if (caseSensitive) {
  858. sc.GetCurrent(s, sizeof(s));
  859. } else {
  860. sc.GetCurrentLowered(s, sizeof(s));
  861. }
  862. if (!(IsASpace(sc.ch) || (sc.ch == 0))) {
  863. sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet);
  864. } else if (!keywords3.InList(s + 1)) {
  865. int subStyleCDKW = classifierDocKeyWords.ValueFor(s+1);
  866. if (subStyleCDKW >= 0) {
  867. sc.ChangeState(subStyleCDKW|activitySet);
  868. } else {
  869. sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR|activitySet);
  870. }
  871. }
  872. sc.SetState(styleBeforeDCKeyword|activitySet);
  873. seenDocKeyBrace = false;
  874. }
  875. break;
  876. case SCE_C_STRING:
  877. if (sc.atLineEnd) {
  878. sc.ChangeState(SCE_C_STRINGEOL|activitySet);
  879. } else if (isIncludePreprocessor) {
  880. if (sc.ch == '>') {
  881. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  882. isIncludePreprocessor = false;
  883. }
  884. } else if (sc.ch == '\\') {
  885. if (options.escapeSequence) {
  886. sc.SetState(SCE_C_ESCAPESEQUENCE|activitySet);
  887. escapeSeq.resetEscapeState(sc.chNext);
  888. }
  889. sc.Forward(); // Skip all characters after the backslash
  890. } else if (sc.ch == '\"') {
  891. if (sc.chNext == '_') {
  892. sc.ChangeState(SCE_C_USERLITERAL|activitySet);
  893. } else {
  894. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  895. }
  896. }
  897. break;
  898. case SCE_C_ESCAPESEQUENCE:
  899. escapeSeq.digitsLeft--;
  900. if (!escapeSeq.atEscapeEnd(sc.ch)) {
  901. break;
  902. }
  903. if (sc.ch == '"') {
  904. sc.SetState(SCE_C_STRING|activitySet);
  905. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  906. } else if (sc.ch == '\\') {
  907. escapeSeq.resetEscapeState(sc.chNext);
  908. sc.Forward();
  909. } else {
  910. sc.SetState(SCE_C_STRING|activitySet);
  911. if (sc.atLineEnd) {
  912. sc.ChangeState(SCE_C_STRINGEOL|activitySet);
  913. }
  914. }
  915. break;
  916. case SCE_C_HASHQUOTEDSTRING:
  917. if (sc.ch == '\\') {
  918. if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
  919. sc.Forward();
  920. }
  921. } else if (sc.ch == '\"') {
  922. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  923. }
  924. break;
  925. case SCE_C_STRINGRAW:
  926. if (sc.Match(rawStringTerminator.c_str())) {
  927. for (size_t termPos=rawStringTerminator.size(); termPos; termPos--)
  928. sc.Forward();
  929. sc.SetState(SCE_C_DEFAULT|activitySet);
  930. rawStringTerminator = "";
  931. }
  932. break;
  933. case SCE_C_CHARACTER:
  934. if (sc.atLineEnd) {
  935. sc.ChangeState(SCE_C_STRINGEOL|activitySet);
  936. } else if (sc.ch == '\\') {
  937. if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
  938. sc.Forward();
  939. }
  940. } else if (sc.ch == '\'') {
  941. if (sc.chNext == '_') {
  942. sc.ChangeState(SCE_C_USERLITERAL|activitySet);
  943. } else {
  944. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  945. }
  946. }
  947. break;
  948. case SCE_C_REGEX:
  949. if (sc.atLineStart) {
  950. sc.SetState(SCE_C_DEFAULT|activitySet);
  951. } else if (! inRERange && sc.ch == '/') {
  952. sc.Forward();
  953. while ((sc.ch < 0x80) && islower(sc.ch))
  954. sc.Forward(); // gobble regex flags
  955. sc.SetState(SCE_C_DEFAULT|activitySet);
  956. } else if (sc.ch == '\\' && (static_cast<Sci_Position>(sc.currentPos+1) < lineEndNext)) {
  957. // Gobble up the escaped character
  958. sc.Forward();
  959. } else if (sc.ch == '[') {
  960. inRERange = true;
  961. } else if (sc.ch == ']') {
  962. inRERange = false;
  963. }
  964. break;
  965. case SCE_C_STRINGEOL:
  966. if (sc.atLineStart) {
  967. sc.SetState(SCE_C_DEFAULT|activitySet);
  968. }
  969. break;
  970. case SCE_C_VERBATIM:
  971. if (options.verbatimStringsAllowEscapes && (sc.ch == '\\')) {
  972. sc.Forward(); // Skip all characters after the backslash
  973. } else if (sc.ch == '\"') {
  974. if (sc.chNext == '\"') {
  975. sc.Forward();
  976. } else {
  977. sc.ForwardSetState(SCE_C_DEFAULT|activitySet);
  978. }
  979. }
  980. break;
  981. case SCE_C_TRIPLEVERBATIM:
  982. if (sc.Match("\"\"\"")) {
  983. while (sc.Match('"')) {
  984. sc.Forward();
  985. }
  986. sc.SetState(SCE_C_DEFAULT|activitySet);
  987. }
  988. break;
  989. case SCE_C_UUID:
  990. if (sc.atLineEnd || sc.ch == ')') {
  991. sc.SetState(SCE_C_DEFAULT|activitySet);
  992. }
  993. break;
  994. case SCE_C_TASKMARKER:
  995. if (isoperator(sc.ch) || IsASpace(sc.ch)) {
  996. sc.SetState(styleBeforeTaskMarker|activitySet);
  997. styleBeforeTaskMarker = SCE_C_DEFAULT;
  998. }
  999. }
  1000. if (sc.atLineEnd && !atLineEndBeforeSwitch) {
  1001. // State exit processing consumed characters up to end of line.
  1002. lineCurrent++;
  1003. lineEndNext = styler.LineEnd(lineCurrent);
  1004. vlls.Add(lineCurrent, preproc);
  1005. }
  1006. // Determine if a new state should be entered.
  1007. if (MaskActive(sc.state) == SCE_C_DEFAULT) {
  1008. if (sc.Match('@', '\"')) {
  1009. sc.SetState(SCE_C_VERBATIM|activitySet);
  1010. sc.Forward();
  1011. } else if (options.triplequotedStrings && sc.Match("\"\"\"")) {
  1012. sc.SetState(SCE_C_TRIPLEVERBATIM|activitySet);
  1013. sc.Forward(2);
  1014. } else if (options.hashquotedStrings && sc.Match('#', '\"')) {
  1015. sc.SetState(SCE_C_HASHQUOTEDSTRING|activitySet);
  1016. sc.Forward();
  1017. } else if (options.backQuotedStrings && sc.Match('`')) {
  1018. sc.SetState(SCE_C_STRINGRAW|activitySet);
  1019. rawStringTerminator = "`";
  1020. } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
  1021. if (lastWordWasUUID) {
  1022. sc.SetState(SCE_C_UUID|activitySet);
  1023. lastWordWasUUID = false;
  1024. } else {
  1025. sc.SetState(SCE_C_NUMBER|activitySet);
  1026. }
  1027. } else if (!sc.atLineEnd && (setWordStart.Contains(sc.ch) || (sc.ch == '@'))) {
  1028. if (lastWordWasUUID) {
  1029. sc.SetState(SCE_C_UUID|activitySet);
  1030. lastWordWasUUID = false;
  1031. } else {
  1032. sc.SetState(SCE_C_IDENTIFIER|activitySet);
  1033. }
  1034. } else if (sc.Match('/', '*')) {
  1035. if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
  1036. sc.SetState(SCE_C_COMMENTDOC|activitySet);
  1037. } else {
  1038. sc.SetState(SCE_C_COMMENT|activitySet);
  1039. }
  1040. sc.Forward(); // Eat the * so it isn't used for the end of the comment
  1041. } else if (sc.Match('/', '/')) {
  1042. if ((sc.Match("///") && !sc.Match("////")) || sc.Match("//!"))
  1043. // Support of Qt/Doxygen doc. style
  1044. sc.SetState(SCE_C_COMMENTLINEDOC|activitySet);
  1045. else
  1046. sc.SetState(SCE_C_COMMENTLINE|activitySet);
  1047. } else if (sc.ch == '/'
  1048. && (setOKBeforeRE.Contains(chPrevNonWhite)
  1049. || followsReturnKeyword(sc, styler))
  1050. && (!setCouldBePostOp.Contains(chPrevNonWhite)
  1051. || !FollowsPostfixOperator(sc, styler))) {
  1052. sc.SetState(SCE_C_REGEX|activitySet); // JavaScript's RegEx
  1053. inRERange = false;
  1054. } else if (sc.ch == '\"') {
  1055. if (sc.chPrev == 'R') {
  1056. styler.Flush();
  1057. if (MaskActive(styler.StyleAt(sc.currentPos - 1)) == SCE_C_STRINGRAW) {
  1058. sc.SetState(SCE_C_STRINGRAW|activitySet);
  1059. rawStringTerminator = ")";
  1060. for (Sci_Position termPos = sc.currentPos + 1;; termPos++) {
  1061. char chTerminator = styler.SafeGetCharAt(termPos, '(');
  1062. if (chTerminator == '(')
  1063. break;
  1064. rawStringTerminator += chTerminator;
  1065. }
  1066. rawStringTerminator += '\"';
  1067. } else {
  1068. sc.SetState(SCE_C_STRING|activitySet);
  1069. }
  1070. } else {
  1071. sc.SetState(SCE_C_STRING|activitySet);
  1072. }
  1073. isIncludePreprocessor = false; // ensure that '>' won't end the string
  1074. } else if (isIncludePreprocessor && sc.ch == '<') {
  1075. sc.SetState(SCE_C_STRING|activitySet);
  1076. } else if (sc.ch == '\'') {
  1077. sc.SetState(SCE_C_CHARACTER|activitySet);
  1078. } else if (sc.ch == '#' && visibleChars == 0) {
  1079. // Preprocessor commands are alone on their line
  1080. sc.SetState(SCE_C_PREPROCESSOR|activitySet);
  1081. // Skip whitespace between # and preprocessor word
  1082. do {
  1083. sc.Forward();
  1084. } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
  1085. if (sc.atLineEnd) {
  1086. sc.SetState(SCE_C_DEFAULT|activitySet);
  1087. } else if (sc.Match("include")) {
  1088. isIncludePreprocessor = true;
  1089. } else {
  1090. if (options.trackPreprocessor) {
  1091. if (sc.Match("ifdef") || sc.Match("ifndef")) {
  1092. bool isIfDef = sc.Match("ifdef");
  1093. int i = isIfDef ? 5 : 6;
  1094. std::string restOfLine = GetRestOfLine(styler, sc.currentPos + i + 1, false);
  1095. bool foundDef = preprocessorDefinitions.find(restOfLine) != preprocessorDefinitions.end();
  1096. preproc.StartSection(isIfDef == foundDef);
  1097. } else if (sc.Match("if")) {
  1098. std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true);
  1099. bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions);
  1100. preproc.StartSection(ifGood);
  1101. } else if (sc.Match("else")) {
  1102. if (!preproc.CurrentIfTaken()) {
  1103. preproc.InvertCurrentLevel();
  1104. activitySet = preproc.IsInactive() ? activeFlag : 0;
  1105. if (!activitySet)
  1106. sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
  1107. } else if (!preproc.IsInactive()) {
  1108. preproc.InvertCurrentLevel();
  1109. activitySet = preproc.IsInactive() ? activeFlag : 0;
  1110. if (!activitySet)
  1111. sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
  1112. }
  1113. } else if (sc.Match("elif")) {
  1114. // Ensure only one chosen out of #if .. #elif .. #elif .. #else .. #endif
  1115. if (!preproc.CurrentIfTaken()) {
  1116. // Similar to #if
  1117. std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 2, true);
  1118. bool ifGood = EvaluateExpression(restOfLine, preprocessorDefinitions);
  1119. if (ifGood) {
  1120. preproc.InvertCurrentLevel();
  1121. activitySet = preproc.IsInactive() ? activeFlag : 0;
  1122. if (!activitySet)
  1123. sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
  1124. }
  1125. } else if (!preproc.IsInactive()) {
  1126. preproc.InvertCurrentLevel();
  1127. activitySet = preproc.IsInactive() ? activeFlag : 0;
  1128. if (!activitySet)
  1129. sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
  1130. }
  1131. } else if (sc.Match("endif")) {
  1132. preproc.EndSection();
  1133. activitySet = preproc.IsInactive() ? activeFlag : 0;
  1134. sc.ChangeState(SCE_C_PREPROCESSOR|activitySet);
  1135. } else if (sc.Match("define")) {
  1136. if (options.updatePreprocessor && !preproc.IsInactive()) {
  1137. std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 6, true);
  1138. size_t startName = 0;
  1139. while ((startName < restOfLine.length()) && IsSpaceOrTab(restOfLine[startName]))
  1140. startName++;
  1141. size_t endName = startName;
  1142. while ((endName < restOfLine.length()) && setWord.Contains(static_cast<unsigned char>(restOfLine[endName])))
  1143. endName++;
  1144. std::string key = restOfLine.substr(startName, endName-startName);
  1145. if ((endName < restOfLine.length()) && (restOfLine.at(endName) == '(')) {
  1146. // Macro
  1147. size_t endArgs = endName;
  1148. while ((endArgs < restOfLine.length()) && (restOfLine[endArgs] != ')'))
  1149. endArgs++;
  1150. std::string args = restOfLine.substr(endName + 1, endArgs - endName - 1);
  1151. size_t startValue = endArgs+1;
  1152. while ((startValue < restOfLine.length()) && IsSpaceOrTab(restOfLine[startValue]))
  1153. startValue++;
  1154. std::string value;
  1155. if (startValue < restOfLine.length())
  1156. value = restOfLine.substr(startValue);
  1157. preprocessorDefinitions[key] = SymbolValue(value, args);
  1158. ppDefineHistory.push_back(PPDefinition(lineCurrent, key, value, false, args));
  1159. definitionsChanged = true;
  1160. } else {
  1161. // Value
  1162. size_t startValue = endName;
  1163. while ((startValue < restOfLine.length()) && IsSpaceOrTab(restOfLine[startValue]))
  1164. startValue++;
  1165. std::string value = restOfLine.substr(startValue);
  1166. preprocessorDefinitions[key] = value;
  1167. ppDefineHistory.push_back(PPDefinition(lineCurrent, key, value));
  1168. definitionsChanged = true;
  1169. }
  1170. }
  1171. } else if (sc.Match("undef")) {
  1172. if (options.updatePreprocessor && !preproc.IsInactive()) {
  1173. const std::string restOfLine = GetRestOfLine(styler, sc.currentPos + 5, false);
  1174. std::vector<std::string> tokens = Tokenize(restOfLine);
  1175. if (tokens.size() >= 1) {
  1176. const std::string key = tokens[0];
  1177. preprocessorDefinitions.erase(key);
  1178. ppDefineHistory.push_back(PPDefinition(lineCurrent, key, "", true));
  1179. definitionsChanged = true;
  1180. }
  1181. }
  1182. }
  1183. }
  1184. }
  1185. } else if (isoperator(sc.ch)) {
  1186. sc.SetState(SCE_C_OPERATOR|activitySet);
  1187. }
  1188. }
  1189. if (!IsASpace(sc.ch) && !IsSpaceEquiv(MaskActive(sc.state))) {
  1190. chPrevNonWhite = sc.ch;
  1191. visibleChars++;
  1192. }
  1193. continuationLine = false;
  1194. sc.Forward();
  1195. }
  1196. const bool rawStringsChanged = rawStringTerminators.Merge(rawSTNew, lineCurrent);
  1197. if (definitionsChanged || rawStringsChanged)
  1198. styler.ChangeLexerState(startPos, startPos + length);
  1199. sc.Complete();
  1200. }
  1201. // Store both the current line's fold level and the next lines in the
  1202. // level store to make it easy to pick up with each increment
  1203. // and to make it possible to fiddle the current level for "} else {".
  1204. void SCI_METHOD LexerCPP::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
  1205. if (!options.fold)
  1206. return;
  1207. LexAccessor styler(pAccess);
  1208. Sci_PositionU endPos = startPos + length;
  1209. int visibleChars = 0;
  1210. bool inLineComment = false;
  1211. Sci_Position lineCurrent = styler.GetLine(startPos);
  1212. int levelCurrent = SC_FOLDLEVELBASE;
  1213. if (lineCurrent > 0)
  1214. levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
  1215. Sci_PositionU lineStartNext = styler.LineStart(lineCurrent+1);
  1216. int levelMinCurrent = levelCurrent;
  1217. int levelNext = levelCurrent;
  1218. char chNext = styler[startPos];
  1219. int styleNext = MaskActive(styler.StyleAt(startPos));
  1220. int style = MaskActive(initStyle);
  1221. const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
  1222. for (Sci_PositionU i = startPos; i < endPos; i++) {
  1223. char ch = chNext;
  1224. chNext = styler.SafeGetCharAt(i + 1);
  1225. int stylePrev = style;
  1226. style = styleNext;
  1227. styleNext = MaskActive(styler.StyleAt(i + 1));
  1228. bool atEOL = i == (lineStartNext-1);
  1229. if ((style == SCE_C_COMMENTLINE) || (style == SCE_C_COMMENTLINEDOC))
  1230. inLineComment = true;
  1231. if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style) && !inLineComment) {
  1232. if (!IsStreamCommentStyle(stylePrev)) {
  1233. levelNext++;
  1234. } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
  1235. // Comments don't end at end of line and the next character may be unstyled.
  1236. levelNext--;
  1237. }
  1238. }
  1239. if (options.foldComment && options.foldCommentExplicit && ((style == SCE_C_COMMENTLINE) || options.foldExplicitAnywhere)) {
  1240. if (userDefinedFoldMarkers) {
  1241. if (styler.Match(i, options.foldExplicitStart.c_str())) {
  1242. levelNext++;
  1243. } else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
  1244. levelNext--;
  1245. }
  1246. } else {
  1247. if ((ch == '/') && (chNext == '/')) {
  1248. char chNext2 = styler.SafeGetCharAt(i + 2);
  1249. if (chNext2 == '{') {
  1250. levelNext++;
  1251. } else if (chNext2 == '}') {
  1252. levelNext--;
  1253. }
  1254. }
  1255. }
  1256. }
  1257. if (options.foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
  1258. if (ch == '#') {
  1259. Sci_PositionU j = i + 1;
  1260. while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
  1261. j++;
  1262. }
  1263. if (styler.Match(j, "region") || styler.Match(j, "if")) {
  1264. levelNext++;
  1265. } else if (styler.Match(j, "end")) {
  1266. levelNext--;
  1267. }
  1268. if (options.foldPreprocessorAtElse && (styler.Match(j, "else") || styler.Match(j, "elif"))) {
  1269. levelMinCurrent--;
  1270. }
  1271. }
  1272. }
  1273. if (options.foldSyntaxBased && (style == SCE_C_OPERATOR)) {
  1274. if (ch == '{' || ch == '[' || ch == '(') {
  1275. // Measure the minimum before a '{' to allow
  1276. // folding on "} else {"
  1277. if (options.foldAtElse && levelMinCurrent > levelNext) {
  1278. levelMinCurrent = levelNext;
  1279. }
  1280. levelNext++;
  1281. } else if (ch == '}' || ch == ']' || ch == ')') {
  1282. levelNext--;
  1283. }
  1284. }
  1285. if (!IsASpace(ch))
  1286. visibleChars++;
  1287. if (atEOL || (i == endPos-1)) {
  1288. int levelUse = levelCurrent;
  1289. if ((options.foldSyntaxBased && options.foldAtElse) ||
  1290. (options.foldPreprocessor && options.foldPreprocessorAtElse)
  1291. ) {
  1292. levelUse = levelMinCurrent;
  1293. }
  1294. int lev = levelUse | levelNext << 16;
  1295. if (visibleChars == 0 && options.foldCompact)
  1296. lev |= SC_FOLDLEVELWHITEFLAG;
  1297. if (levelUse < levelNext)
  1298. lev |= SC_FOLDLEVELHEADERFLAG;
  1299. if (lev != styler.LevelAt(lineCurrent)) {
  1300. styler.SetLevel(lineCurrent, lev);
  1301. }
  1302. lineCurrent++;
  1303. lineStartNext = styler.LineStart(lineCurrent+1);
  1304. levelCurrent = levelNext;
  1305. levelMinCurrent = levelCurrent;
  1306. if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length()-1))) {
  1307. // There is an empty line at end of file so give it same level and empty
  1308. styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
  1309. }
  1310. visibleChars = 0;
  1311. inLineComment = false;
  1312. }
  1313. }
  1314. }
  1315. void LexerCPP::EvaluateTokens(std::vector<std::string> &tokens, const SymbolTable &preprocessorDefinitions) {
  1316. // Remove whitespace tokens
  1317. tokens.erase(std::remove_if(tokens.begin(), tokens.end(), OnlySpaceOrTab), tokens.end());
  1318. // Evaluate defined statements to either 0 or 1
  1319. for (size_t i=0; (i+1)<tokens.size();) {
  1320. if (tokens[i] == "defined") {
  1321. const char *val = "0";
  1322. if (tokens[i+1] == "(") {
  1323. if (((i + 2)<tokens.size()) && (tokens[i + 2] == ")")) {
  1324. // defined()
  1325. tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 3);
  1326. } else if (((i+3)<tokens.size()) && (tokens[i+3] == ")")) {
  1327. // defined(<identifier>)
  1328. SymbolTable::const_iterator it = preprocessorDefinitions.find(tokens[i+2]);
  1329. if (it != preprocessorDefinitions.end()) {
  1330. val = "1";
  1331. }
  1332. tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 4);
  1333. } else {
  1334. // Spurious '(' so erase as more likely to result in false
  1335. tokens.erase(tokens.begin() + i + 1, tokens.begin() + i + 2);
  1336. }
  1337. } else {
  1338. // defined <identifier>
  1339. SymbolTable::const_iterator it = preprocessorDefinitions.find(tokens[i+1]);
  1340. if (it != preprocessorDefinitions.end()) {
  1341. val = "1";
  1342. }
  1343. }
  1344. tokens[i] = val;
  1345. } else {
  1346. i++;
  1347. }
  1348. }
  1349. // Evaluate identifiers
  1350. const size_t maxIterations = 100;
  1351. size_t iterations = 0; // Limit number of iterations in case there is a recursive macro.
  1352. for (size_t i = 0; (i<tokens.size()) && (iterations < maxIterations);) {
  1353. iterations++;
  1354. if (setWordStart.Contains(static_cast<unsigned char>(tokens[i][0]))) {
  1355. SymbolTable::const_iterator it = preprocessorDefinitions.find(tokens[i]);
  1356. if (it != preprocessorDefinitions.end()) {
  1357. // Tokenize value
  1358. std::vector<std::string> macroTokens = Tokenize(it->second.value);
  1359. if (it->second.IsMacro()) {
  1360. if ((i + 1 < tokens.size()) && (tokens.at(i + 1) == "(")) {
  1361. // Create map of argument name to value
  1362. std::vector<std::string> argumentNames = StringSplit(it->second.arguments, ',');
  1363. std::map<std::string, std::string> arguments;
  1364. size_t arg = 0;
  1365. size_t tok = i+2;
  1366. while ((tok < tokens.size()) && (arg < argumentNames.size()) && (tokens.at(tok) != ")")) {
  1367. if (tokens.at(tok) != ",") {
  1368. arguments[argumentNames.at(arg)] = tokens.at(tok);
  1369. arg++;
  1370. }
  1371. tok++;
  1372. }
  1373. // Remove invocation
  1374. tokens.erase(tokens.begin() + i, tokens.begin() + tok + 1);
  1375. // Substitute values into macro
  1376. macroTokens.erase(std::remove_if(macroTokens.begin(), macroTokens.end(), OnlySpaceOrTab), macroTokens.end());
  1377. for (size_t iMacro = 0; iMacro < macroTokens.size();) {
  1378. if (setWordStart.Contains(static_cast<unsigned char>(macroTokens[iMacro][0]))) {
  1379. std::map<std::string, std::string>::const_iterator itFind = arguments.find(macroTokens[iMacro]);
  1380. if (itFind != arguments.end()) {
  1381. // TODO: Possible that value will be expression so should insert tokenized form
  1382. macroTokens[iMacro] = itFind->second;
  1383. }
  1384. }
  1385. iMacro++;
  1386. }
  1387. // Insert results back into tokens
  1388. tokens.insert(tokens.begin() + i, macroTokens.begin(), macroTokens.end());
  1389. } else {
  1390. i++;
  1391. }
  1392. } else {
  1393. // Remove invocation
  1394. tokens.erase(tokens.begin() + i);
  1395. // Insert results back into tokens
  1396. tokens.insert(tokens.begin() + i, macroTokens.begin(), macroTokens.end());
  1397. }
  1398. } else {
  1399. // Identifier not found
  1400. tokens.erase(tokens.begin() + i);
  1401. }
  1402. } else {
  1403. i++;
  1404. }
  1405. }
  1406. // Find bracketed subexpressions and recurse on them
  1407. BracketPair bracketPair = FindBracketPair(tokens);
  1408. while (bracketPair.itBracket != tokens.end()) {
  1409. std::vector<std::string> inBracket(bracketPair.itBracket + 1, bracketPair.itEndBracket);
  1410. EvaluateTokens(inBracket, preprocessorDefinitions);
  1411. // The insertion is done before the removal because there were failures with the opposite approach
  1412. tokens.insert(bracketPair.itBracket, inBracket.begin(), inBracket.end());
  1413. bracketPair = FindBracketPair(tokens);
  1414. tokens.erase(bracketPair.itBracket, bracketPair.itEndBracket + 1);
  1415. bracketPair = FindBracketPair(tokens);
  1416. }
  1417. // Evaluate logical negations
  1418. for (size_t j=0; (j+1)<tokens.size();) {
  1419. if (setNegationOp.Contains(tokens[j][0])) {
  1420. int isTrue = atoi(tokens[j+1].c_str());
  1421. if (tokens[j] == "!")
  1422. isTrue = !isTrue;
  1423. std::vector<std::string>::iterator itInsert =
  1424. tokens.erase(tokens.begin() + j, tokens.begin() + j + 2);
  1425. tokens.insert(itInsert, isTrue ? "1" : "0");
  1426. } else {
  1427. j++;
  1428. }
  1429. }
  1430. // Evaluate expressions in precedence order
  1431. enum precedence { precArithmetic, precRelative, precLogical };
  1432. for (int prec=precArithmetic; prec <= precLogical; prec++) {
  1433. // Looking at 3 tokens at a time so end at 2 before end
  1434. for (size_t k=0; (k+2)<tokens.size();) {
  1435. char chOp = tokens[k+1][0];
  1436. if (
  1437. ((prec==precArithmetic) && setArithmethicOp.Contains(chOp)) ||
  1438. ((prec==precRelative) && setRelOp.Contains(chOp)) ||
  1439. ((prec==precLogical) && setLogicalOp.Contains(chOp))
  1440. ) {
  1441. int valA = atoi(tokens[k].c_str());
  1442. int valB = atoi(tokens[k+2].c_str());
  1443. int result = 0;
  1444. if (tokens[k+1] == "+")
  1445. result = valA + valB;
  1446. else if (tokens[k+1] == "-")
  1447. result = valA - valB;
  1448. else if (tokens[k+1] == "*")
  1449. result = valA * valB;
  1450. else if (tokens[k+1] == "/")
  1451. result = valA / (valB ? valB : 1);
  1452. else if (tokens[k+1] == "%")
  1453. result = valA % (valB ? valB : 1);
  1454. else if (tokens[k+1] == "<")
  1455. result = valA < valB;
  1456. else if (tokens[k+1] == "<=")
  1457. result = valA <= valB;
  1458. else if (tokens[k+1] == ">")
  1459. result = valA > valB;
  1460. else if (tokens[k+1] == ">=")
  1461. result = valA >= valB;
  1462. else if (tokens[k+1] == "==")
  1463. result = valA == valB;
  1464. else if (tokens[k+1] == "!=")
  1465. result = valA != valB;
  1466. else if (tokens[k+1] == "||")
  1467. result = valA || valB;
  1468. else if (tokens[k+1] == "&&")
  1469. result = valA && valB;
  1470. char sResult[30];
  1471. sprintf(sResult, "%d", result);
  1472. std::vector<std::string>::iterator itInsert =
  1473. tokens.erase(tokens.begin() + k, tokens.begin() + k + 3);
  1474. tokens.insert(itInsert, sResult);
  1475. } else {
  1476. k++;
  1477. }
  1478. }
  1479. }
  1480. }
  1481. std::vector<std::string> LexerCPP::Tokenize(const std::string &expr) const {
  1482. // Break into tokens
  1483. std::vector<std::string> tokens;
  1484. const char *cp = expr.c_str();
  1485. while (*cp) {
  1486. std::string word;
  1487. if (setWord.Contains(static_cast<unsigned char>(*cp))) {
  1488. // Identifiers and numbers
  1489. while (setWord.Contains(static_cast<unsigned char>(*cp))) {
  1490. word += *cp;
  1491. cp++;
  1492. }
  1493. } else if (IsSpaceOrTab(*cp)) {
  1494. while (IsSpaceOrTab(*cp)) {
  1495. word += *cp;
  1496. cp++;
  1497. }
  1498. } else if (setRelOp.Contains(static_cast<unsigned char>(*cp))) {
  1499. word += *cp;
  1500. cp++;
  1501. if (setRelOp.Contains(static_cast<unsigned char>(*cp))) {
  1502. word += *cp;
  1503. cp++;
  1504. }
  1505. } else if (setLogicalOp.Contains(static_cast<unsigned char>(*cp))) {
  1506. word += *cp;
  1507. cp++;
  1508. if (setLogicalOp.Contains(static_cast<unsigned char>(*cp))) {
  1509. word += *cp;
  1510. cp++;
  1511. }
  1512. } else {
  1513. // Should handle strings, characters, and comments here
  1514. word += *cp;
  1515. cp++;
  1516. }
  1517. tokens.push_back(word);
  1518. }
  1519. return tokens;
  1520. }
  1521. bool LexerCPP::EvaluateExpression(const std::string &expr, const SymbolTable &preprocessorDefinitions) {
  1522. std::vector<std::string> tokens = Tokenize(expr);
  1523. EvaluateTokens(tokens, preprocessorDefinitions);
  1524. // "0" or "" -> false else true
  1525. bool isFalse = tokens.empty() ||
  1526. ((tokens.size() == 1) && ((tokens[0] == "") || tokens[0] == "0"));
  1527. return !isFalse;
  1528. }
  1529. LexerModule lmCPP(SCLEX_CPP, LexerCPP::LexerFactoryCPP, "cpp", cppWordLists);
  1530. LexerModule lmCPPNoCase(SCLEX_CPPNOCASE, LexerCPP::LexerFactoryCPPInsensitive, "cppnocase", cppWordLists);