LexProgress.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // Scintilla source code edit control
  2. /** @file LexProgress.cxx
  3. ** Lexer for Progress 4GL.
  4. ** Based on LexCPP.cxx of Neil Hodgson <neilh@scintilla.org>
  5. **/
  6. // Copyright 2006-2016 by Yuval Papish <Yuval@YuvCom.com>
  7. // The License.txt file describes the conditions under which this software may be distributed.
  8. /** TODO:
  9. SpeedScript support in html lexer
  10. Differentiate between labels and variables
  11. Option 1: By symbols table
  12. Option 2: As a single unidentified symbol in a sytactical line
  13. **/
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <stdarg.h>
  18. #include <assert.h>
  19. #include <ctype.h>
  20. #include <string>
  21. #include <vector>
  22. #include <map>
  23. #include "ILexer.h"
  24. #include "Scintilla.h"
  25. #include "SciLexer.h"
  26. #include "WordList.h"
  27. #include "LexAccessor.h"
  28. #include "StyleContext.h"
  29. #include "CharacterSet.h"
  30. #include "LexerModule.h"
  31. #include "OptionSet.h"
  32. #include "SparseState.h"
  33. #ifdef SCI_NAMESPACE
  34. using namespace Scintilla;
  35. #endif
  36. namespace {
  37. // Use an unnamed namespace to protect the functions and classes from name conflicts
  38. bool IsSpaceEquiv(int state) {
  39. return (state == SCE_ABL_COMMENT ||
  40. state == SCE_ABL_LINECOMMENT ||
  41. state == SCE_ABL_DEFAULT);
  42. }
  43. void highlightTaskMarker(StyleContext &sc, LexAccessor &styler, WordList &markerList){
  44. if ((isoperator(sc.chPrev) || IsASpace(sc.chPrev)) && markerList.Length()) {
  45. const int lengthMarker = 50;
  46. char marker[lengthMarker+1];
  47. Sci_Position currPos = (Sci_Position) sc.currentPos;
  48. Sci_Position i = 0;
  49. while (i < lengthMarker) {
  50. char ch = styler.SafeGetCharAt(currPos + i);
  51. if (IsASpace(ch) || isoperator(ch)) {
  52. break;
  53. }
  54. marker[i] = ch;
  55. i++;
  56. }
  57. marker[i] = '\0';
  58. if (markerList.InListAbbreviated (marker,'(')) {
  59. sc.SetState(SCE_ABL_TASKMARKER);
  60. }
  61. }
  62. }
  63. bool IsStreamCommentStyle(int style) {
  64. return style == SCE_ABL_COMMENT;
  65. // style == SCE_ABL_LINECOMMENT; Only block comments are used for folding
  66. }
  67. // Options used for LexerABL
  68. struct OptionsABL {
  69. bool fold;
  70. bool foldSyntaxBased;
  71. bool foldComment;
  72. bool foldCommentMultiline;
  73. bool foldCompact;
  74. OptionsABL() {
  75. fold = false;
  76. foldSyntaxBased = true;
  77. foldComment = true;
  78. foldCommentMultiline = true;
  79. foldCompact = false;
  80. }
  81. };
  82. const char *const ablWordLists[] = {
  83. "Primary keywords and identifiers",
  84. "Keywords that opens a block, only when used to begin a syntactic line",
  85. "Keywords that opens a block anywhere in a syntactic line",
  86. "Task Marker", /* "END MODIFY START TODO" */
  87. 0,
  88. };
  89. struct OptionSetABL : public OptionSet<OptionsABL> {
  90. OptionSetABL() {
  91. DefineProperty("fold", &OptionsABL::fold);
  92. DefineProperty("fold.abl.syntax.based", &OptionsABL::foldSyntaxBased,
  93. "Set this property to 0 to disable syntax based folding.");
  94. DefineProperty("fold.comment", &OptionsABL::foldComment,
  95. "This option enables folding multi-line comments and explicit fold points when using the ABL lexer. ");
  96. DefineProperty("fold.abl.comment.multiline", &OptionsABL::foldCommentMultiline,
  97. "Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
  98. DefineProperty("fold.compact", &OptionsABL::foldCompact);
  99. DefineWordListSets(ablWordLists);
  100. }
  101. };
  102. }
  103. class LexerABL : public ILexer {
  104. CharacterSet setWord;
  105. CharacterSet setNegationOp;
  106. CharacterSet setArithmethicOp;
  107. CharacterSet setRelOp;
  108. CharacterSet setLogicalOp;
  109. CharacterSet setWordStart;
  110. WordList keywords1; // regular keywords
  111. WordList keywords2; // block opening keywords, only when isSentenceStart
  112. WordList keywords3; // block opening keywords
  113. WordList keywords4; // Task Marker
  114. OptionsABL options;
  115. OptionSetABL osABL;
  116. public:
  117. LexerABL() :
  118. setWord(CharacterSet::setAlphaNum, "_", 0x80, true),
  119. setNegationOp(CharacterSet::setNone, "!"),
  120. setArithmethicOp(CharacterSet::setNone, "+-/*%"),
  121. setRelOp(CharacterSet::setNone, "=!<>"),
  122. setLogicalOp(CharacterSet::setNone, "|&"){
  123. }
  124. virtual ~LexerABL() {
  125. }
  126. void SCI_METHOD Release() {
  127. delete this;
  128. }
  129. int SCI_METHOD Version() const {
  130. return lvOriginal;
  131. }
  132. const char * SCI_METHOD PropertyNames() {
  133. return osABL.PropertyNames();
  134. }
  135. int SCI_METHOD PropertyType(const char *name) {
  136. return osABL.PropertyType(name);
  137. }
  138. const char * SCI_METHOD DescribeProperty(const char *name) {
  139. return osABL.DescribeProperty(name);
  140. }
  141. Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) ;
  142. const char * SCI_METHOD DescribeWordListSets() {
  143. return osABL.DescribeWordListSets();
  144. }
  145. Sci_Position SCI_METHOD WordListSet(int n, const char *wl);
  146. void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess);
  147. void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess);
  148. void * SCI_METHOD PrivateCall(int, void *) {
  149. return 0;
  150. }
  151. int SCI_METHOD LineEndTypesSupported() {
  152. return SC_LINE_END_TYPE_DEFAULT;
  153. }
  154. static ILexer *LexerFactoryABL() {
  155. return new LexerABL();
  156. }
  157. };
  158. Sci_Position SCI_METHOD LexerABL::PropertySet(const char *key, const char *val) {
  159. if (osABL.PropertySet(&options, key, val)) {
  160. return 0;
  161. }
  162. return -1;
  163. }
  164. Sci_Position SCI_METHOD LexerABL::WordListSet(int n, const char *wl) {
  165. WordList *wordListN = 0;
  166. switch (n) {
  167. case 0:
  168. wordListN = &keywords1;
  169. break;
  170. case 1:
  171. wordListN = &keywords2;
  172. break;
  173. case 2:
  174. wordListN = &keywords3;
  175. break;
  176. case 3:
  177. wordListN = &keywords4;
  178. break;
  179. }
  180. Sci_Position firstModification = -1;
  181. if (wordListN) {
  182. WordList wlNew;
  183. wlNew.Set(wl);
  184. if (*wordListN != wlNew) {
  185. wordListN->Set(wl);
  186. firstModification = 0;
  187. }
  188. }
  189. return firstModification;
  190. }
  191. void SCI_METHOD LexerABL::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
  192. LexAccessor styler(pAccess);
  193. setWordStart = CharacterSet(CharacterSet::setAlpha, "_", 0x80, true);
  194. int visibleChars = 0;
  195. int visibleChars1 = 0;
  196. int styleBeforeTaskMarker = SCE_ABL_DEFAULT;
  197. bool continuationLine = false;
  198. int commentNestingLevel = 0;
  199. bool isSentenceStart = true;
  200. bool possibleOOLChange = false;
  201. Sci_Position lineCurrent = styler.GetLine(startPos);
  202. if (initStyle == SCE_ABL_PREPROCESSOR) {
  203. // Set continuationLine if last character of previous line is '~'
  204. if (lineCurrent > 0) {
  205. Sci_Position endLinePrevious = styler.LineEnd(lineCurrent-1);
  206. if (endLinePrevious > 0) {
  207. continuationLine = styler.SafeGetCharAt(endLinePrevious-1) == '~';
  208. }
  209. }
  210. }
  211. // Look back to set variables that are actually invisible secondary states. The reason to avoid formal states is to cut down on state's bits
  212. if (startPos > 0) {
  213. Sci_Position back = startPos;
  214. bool checkCommentNestingLevel = (initStyle == SCE_ABL_COMMENT);
  215. bool checkIsSentenceStart = (initStyle == SCE_ABL_DEFAULT || initStyle == SCE_ABL_IDENTIFIER);
  216. char ch;
  217. char st;
  218. char chPrev;
  219. char chPrev_1;
  220. char chPrev_2;
  221. char chPrev_3;
  222. while (back >= 0 && (checkCommentNestingLevel || checkIsSentenceStart)) {
  223. ch = styler.SafeGetCharAt(back);
  224. styler.Flush(); // looking at styles so need to flush
  225. st = styler.StyleAt(back);
  226. chPrev = styler.SafeGetCharAt(back-1);
  227. // isSentenceStart is a non-visible state, used to identify where statements and preprocessor declerations can start
  228. if (checkIsSentenceStart && st != SCE_ABL_COMMENT && st != SCE_ABL_LINECOMMENT && st != SCE_ABL_CHARACTER && st != SCE_ABL_STRING ) {
  229. chPrev_1 = styler.SafeGetCharAt(back-2);
  230. chPrev_2 = styler.SafeGetCharAt(back-3);
  231. chPrev_3 = styler.SafeGetCharAt(back-4);
  232. if ((chPrev == '.' || chPrev == ':' || chPrev == '}' ||
  233. (chPrev_3 == 'e' && chPrev_2 == 'l' && chPrev_1 == 's' && chPrev == 'e') ||
  234. (chPrev_3 == 't' && chPrev_2 == 'h' && chPrev_1 == 'e' && chPrev == 'n')) &&
  235. (IsASpace(ch) || (ch == '/' && styler.SafeGetCharAt(back+1) == '*'))
  236. ) {
  237. checkIsSentenceStart = false;
  238. isSentenceStart = true;
  239. }
  240. else if (IsASpace(chPrev) && ch == '{') {
  241. checkIsSentenceStart = false;
  242. isSentenceStart = false;
  243. }
  244. }
  245. // commentNestingLevel is a non-visible state, used to identify the nesting level of a comment
  246. if (checkCommentNestingLevel) {
  247. if (chPrev == '/' && ch == '*')
  248. commentNestingLevel++;
  249. if (chPrev == '*' && ch == '/') {
  250. commentNestingLevel--;
  251. }
  252. }
  253. --back;
  254. }
  255. }
  256. StyleContext sc(startPos, length, initStyle, styler, static_cast<unsigned char>(0xff));
  257. Sci_Position lineEndNext = styler.LineEnd(lineCurrent);
  258. for (; sc.More();) {
  259. if (sc.atLineStart) {
  260. visibleChars = 0;
  261. visibleChars1 = 0;
  262. }
  263. if (sc.atLineEnd) {
  264. lineCurrent++;
  265. lineEndNext = styler.LineEnd(lineCurrent);
  266. }
  267. // Handle line continuation generically.
  268. if (sc.ch == '~') {
  269. if (static_cast<Sci_Position>((sc.currentPos+1)) >= lineEndNext) {
  270. lineCurrent++;
  271. lineEndNext = styler.LineEnd(lineCurrent);
  272. sc.Forward();
  273. if (sc.ch == '\r' && sc.chNext == '\n') {
  274. sc.Forward();
  275. }
  276. continuationLine = true;
  277. sc.Forward();
  278. continue;
  279. }
  280. }
  281. const bool atLineEndBeforeSwitch = sc.atLineEnd;
  282. // Determine if the current state should terminate.
  283. switch (sc.state) {
  284. case SCE_ABL_OPERATOR:
  285. sc.SetState(SCE_ABL_DEFAULT);
  286. break;
  287. case SCE_ABL_NUMBER:
  288. // We accept almost anything because of hex. and maybe number suffixes and scientific notations in the future
  289. if (!(setWord.Contains(sc.ch)
  290. || ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E' ||
  291. sc.chPrev == 'p' || sc.chPrev == 'P')))) {
  292. sc.SetState(SCE_ABL_DEFAULT);
  293. }
  294. break;
  295. case SCE_ABL_IDENTIFIER:
  296. if (sc.atLineStart || sc.atLineEnd || (!setWord.Contains(sc.ch) && sc.ch != '-')) {
  297. char s[1000];
  298. sc.GetCurrentLowered(s, sizeof(s));
  299. bool isLastWordEnd = (s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !IsAlphaNumeric(s[3]) && s[3] != '-'); // helps to identify "end trigger" phrase
  300. if ((isSentenceStart && keywords2.InListAbbreviated (s,'(')) || (!isLastWordEnd && keywords3.InListAbbreviated (s,'('))) {
  301. sc.ChangeState(SCE_ABL_BLOCK);
  302. isSentenceStart = false;
  303. }
  304. else if (keywords1.InListAbbreviated (s,'(')) {
  305. if (isLastWordEnd ||
  306. (s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !IsAlphaNumeric(s[7]))) {
  307. sc.ChangeState(SCE_ABL_END);
  308. isSentenceStart = false;
  309. }
  310. else if ((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') ||
  311. (s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) {
  312. sc.ChangeState(SCE_ABL_WORD);
  313. isSentenceStart = true;
  314. }
  315. else {
  316. sc.ChangeState(SCE_ABL_WORD);
  317. isSentenceStart = false;
  318. }
  319. }
  320. sc.SetState(SCE_ABL_DEFAULT);
  321. }
  322. break;
  323. case SCE_ABL_PREPROCESSOR:
  324. if (sc.atLineStart && !continuationLine) {
  325. sc.SetState(SCE_ABL_DEFAULT);
  326. // Force Scintilla to acknowledge changed stated even though this change might happen outside of the current line
  327. possibleOOLChange = true;
  328. isSentenceStart = true;
  329. }
  330. break;
  331. case SCE_ABL_LINECOMMENT:
  332. if (sc.atLineStart && !continuationLine) {
  333. sc.SetState(SCE_ABL_DEFAULT);
  334. isSentenceStart = true;
  335. } else {
  336. styleBeforeTaskMarker = SCE_ABL_LINECOMMENT;
  337. highlightTaskMarker(sc, styler, keywords4);
  338. }
  339. break;
  340. case SCE_ABL_TASKMARKER:
  341. if (isoperator(sc.ch) || IsASpace(sc.ch)) {
  342. sc.SetState(styleBeforeTaskMarker);
  343. styleBeforeTaskMarker = SCE_ABL_DEFAULT;
  344. }
  345. // fall through
  346. case SCE_ABL_COMMENT:
  347. if (sc.Match('*', '/')) {
  348. sc.Forward();
  349. commentNestingLevel--;
  350. if (commentNestingLevel == 0) {
  351. sc.ForwardSetState(SCE_ABL_DEFAULT);
  352. possibleOOLChange = true;
  353. }
  354. } else if (sc.Match('/', '*')) {
  355. commentNestingLevel++;
  356. sc.Forward();
  357. }
  358. if (commentNestingLevel > 0) {
  359. styleBeforeTaskMarker = SCE_ABL_COMMENT;
  360. possibleOOLChange = true;
  361. highlightTaskMarker(sc, styler, keywords4);
  362. }
  363. break;
  364. case SCE_ABL_STRING:
  365. if (sc.ch == '~') {
  366. sc.Forward(); // Skip a character after a tilde
  367. } else if (sc.ch == '\"') {
  368. sc.ForwardSetState(SCE_ABL_DEFAULT);
  369. }
  370. break;
  371. case SCE_ABL_CHARACTER:
  372. if (sc.ch == '~') {
  373. sc.Forward(); // Skip a character after a tilde
  374. } else if (sc.ch == '\'') {
  375. sc.ForwardSetState(SCE_ABL_DEFAULT);
  376. }
  377. break;
  378. }
  379. if (sc.atLineEnd && !atLineEndBeforeSwitch) {
  380. // State exit processing consumed characters up to end of line.
  381. lineCurrent++;
  382. lineEndNext = styler.LineEnd(lineCurrent);
  383. }
  384. // Determine if a new state should be entered.
  385. if (sc.state == SCE_ABL_DEFAULT) {
  386. if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
  387. sc.SetState(SCE_ABL_NUMBER);
  388. isSentenceStart = false;
  389. } else if (!sc.atLineEnd && (setWordStart.Contains(sc.ch)) && sc.chPrev != '&') {
  390. sc.SetState(SCE_ABL_IDENTIFIER);
  391. } else if (sc.Match('/', '*')) {
  392. if (sc.chPrev == '.' || sc.chPrev == ':' || sc.chPrev == '}') {
  393. isSentenceStart = true;
  394. }
  395. sc.SetState(SCE_ABL_COMMENT);
  396. possibleOOLChange = true;
  397. commentNestingLevel++;
  398. sc.Forward(); // Eat the * so it isn't used for the end of the comment
  399. } else if (sc.ch == '\"') {
  400. sc.SetState(SCE_ABL_STRING);
  401. isSentenceStart = false;
  402. } else if (sc.ch == '\'') {
  403. sc.SetState(SCE_ABL_CHARACTER);
  404. isSentenceStart = false;
  405. } else if (sc.ch == '&' && visibleChars1 == 0 && isSentenceStart) {
  406. // Preprocessor commands are alone on their line
  407. sc.SetState(SCE_ABL_PREPROCESSOR);
  408. // Force Scintilla to acknowledge changed stated even though this change might happen outside of the current line
  409. possibleOOLChange = true;
  410. // Skip whitespace between & and preprocessor word
  411. do {
  412. sc.Forward();
  413. } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
  414. if (sc.atLineEnd) {
  415. sc.SetState(SCE_ABL_DEFAULT);
  416. }
  417. } else if (sc.Match('/','/') && (IsASpace(sc.chPrev) || isSentenceStart)) {
  418. // Line comments are valid after a white space or EOL
  419. sc.SetState(SCE_ABL_LINECOMMENT);
  420. // Skip whitespace between // and preprocessor word
  421. do {
  422. sc.Forward();
  423. } while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
  424. if (sc.atLineEnd) {
  425. sc.SetState(SCE_ABL_DEFAULT);
  426. }
  427. } else if (isoperator(sc.ch)) {
  428. sc.SetState(SCE_ABL_OPERATOR);
  429. /* This code allows highlight of handles. Alas, it would cause the phrase "last-event:function"
  430. to be recognized as a BlockBegin */
  431. isSentenceStart = false;
  432. }
  433. else if ((sc.chPrev == '.' || sc.chPrev == ':' || sc.chPrev == '}') && (IsASpace(sc.ch))) {
  434. isSentenceStart = true;
  435. }
  436. }
  437. if (!IsASpace(sc.ch)) {
  438. visibleChars1++;
  439. }
  440. if (!IsASpace(sc.ch) && !IsSpaceEquiv(sc.state)) {
  441. visibleChars++;
  442. }
  443. continuationLine = false;
  444. sc.Forward();
  445. }
  446. if (possibleOOLChange)
  447. styler.ChangeLexerState(startPos, startPos + length);
  448. sc.Complete();
  449. }
  450. // Store both the current line's fold level and the next lines in the
  451. // level store to make it easy to pick up with each increment
  452. // and to make it possible to fiddle the current level for "} else {".
  453. void SCI_METHOD LexerABL::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
  454. if (!options.fold)
  455. return;
  456. LexAccessor styler(pAccess);
  457. Sci_PositionU endPos = startPos + length;
  458. int visibleChars = 0;
  459. Sci_Position lineCurrent = styler.GetLine(startPos);
  460. int levelCurrent = SC_FOLDLEVELBASE;
  461. if (lineCurrent > 0)
  462. levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
  463. Sci_PositionU lineStartNext = styler.LineStart(lineCurrent+1);
  464. int levelNext = levelCurrent;
  465. char chNext = styler[startPos];
  466. int styleNext = styler.StyleAt(startPos);
  467. int style = initStyle;
  468. for (Sci_PositionU i = startPos; i < endPos; i++) {
  469. chNext = static_cast<char>(tolower(chNext)); // check tolower
  470. char ch = chNext;
  471. chNext = styler.SafeGetCharAt(i+1);
  472. int stylePrev = style;
  473. style = styleNext;
  474. styleNext = styler.StyleAt(i+1);
  475. bool atEOL = i == (lineStartNext-1);
  476. if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style)) {
  477. if (!IsStreamCommentStyle(stylePrev)) {
  478. levelNext++;
  479. } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
  480. // Comments don't end at end of line and the next character may be unstyled.
  481. levelNext--;
  482. }
  483. }
  484. if (options.foldSyntaxBased) {
  485. if (style == SCE_ABL_BLOCK && !IsAlphaNumeric(chNext)) {
  486. levelNext++;
  487. }
  488. else if (style == SCE_ABL_END && (ch == 'e' || ch == 'f')) {
  489. levelNext--;
  490. }
  491. }
  492. if (!IsASpace(ch))
  493. visibleChars++;
  494. if (atEOL || (i == endPos-1)) {
  495. int lev = levelCurrent | levelNext << 16;
  496. if (visibleChars == 0 && options.foldCompact)
  497. lev |= SC_FOLDLEVELWHITEFLAG;
  498. if (levelCurrent < levelNext)
  499. lev |= SC_FOLDLEVELHEADERFLAG;
  500. if (lev != styler.LevelAt(lineCurrent)) {
  501. styler.SetLevel(lineCurrent, lev);
  502. }
  503. lineCurrent++;
  504. lineStartNext = styler.LineStart(lineCurrent+1);
  505. levelCurrent = levelNext;
  506. if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length()-1))) {
  507. // There is an empty line at end of file so give it same level and empty
  508. styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
  509. }
  510. visibleChars = 0;
  511. }
  512. }
  513. }
  514. LexerModule lmProgress(SCLEX_PROGRESS, LexerABL::LexerFactoryABL, "abl", ablWordLists);