LexSTTXT.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Scintilla source code edit control
  2. /** @file LexSTTXT.cxx
  3. ** Lexer for Structured Text language.
  4. ** Written by Pavel Bulochkin
  5. **/
  6. // The License.txt file describes the conditions under which this software may be distributed.
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <assert.h>
  12. #include <ctype.h>
  13. #include "ILexer.h"
  14. #include "Scintilla.h"
  15. #include "SciLexer.h"
  16. #include "WordList.h"
  17. #include "LexAccessor.h"
  18. #include "Accessor.h"
  19. #include "StyleContext.h"
  20. #include "CharacterSet.h"
  21. #include "LexerModule.h"
  22. #ifdef SCI_NAMESPACE
  23. using namespace Scintilla;
  24. #endif
  25. static void ClassifySTTXTWord(WordList *keywordlists[], StyleContext &sc)
  26. {
  27. char s[256] = { 0 };
  28. sc.GetCurrentLowered(s, sizeof(s));
  29. if ((*keywordlists[0]).InList(s)) {
  30. sc.ChangeState(SCE_STTXT_KEYWORD);
  31. }
  32. else if ((*keywordlists[1]).InList(s)) {
  33. sc.ChangeState(SCE_STTXT_TYPE);
  34. }
  35. else if ((*keywordlists[2]).InList(s)) {
  36. sc.ChangeState(SCE_STTXT_FUNCTION);
  37. }
  38. else if ((*keywordlists[3]).InList(s)) {
  39. sc.ChangeState(SCE_STTXT_FB);
  40. }
  41. else if ((*keywordlists[4]).InList(s)) {
  42. sc.ChangeState(SCE_STTXT_VARS);
  43. }
  44. else if ((*keywordlists[5]).InList(s)) {
  45. sc.ChangeState(SCE_STTXT_PRAGMAS);
  46. }
  47. sc.SetState(SCE_STTXT_DEFAULT);
  48. }
  49. static void ColouriseSTTXTDoc (Sci_PositionU startPos, Sci_Position length, int initStyle,
  50. WordList *keywordlists[], Accessor &styler)
  51. {
  52. StyleContext sc(startPos, length, initStyle, styler);
  53. CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
  54. CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
  55. CharacterSet setNumber(CharacterSet::setDigits, "_.eE");
  56. CharacterSet setHexNumber(CharacterSet::setDigits, "_abcdefABCDEF");
  57. CharacterSet setOperator(CharacterSet::setNone,",.+-*/:;<=>[]()%&");
  58. CharacterSet setDataTime(CharacterSet::setDigits,"_.-:dmshDMSH");
  59. for ( ; sc.More() ; sc.Forward())
  60. {
  61. if(sc.atLineStart && sc.state != SCE_STTXT_COMMENT)
  62. sc.SetState(SCE_STTXT_DEFAULT);
  63. switch(sc.state)
  64. {
  65. case SCE_STTXT_NUMBER: {
  66. if(!setNumber.Contains(sc.ch))
  67. sc.SetState(SCE_STTXT_DEFAULT);
  68. break;
  69. }
  70. case SCE_STTXT_HEXNUMBER: {
  71. if (setHexNumber.Contains(sc.ch))
  72. continue;
  73. else if(setDataTime.Contains(sc.ch))
  74. sc.ChangeState(SCE_STTXT_DATETIME);
  75. else if(setWord.Contains(sc.ch))
  76. sc.ChangeState(SCE_STTXT_DEFAULT);
  77. else
  78. sc.SetState(SCE_STTXT_DEFAULT);
  79. break;
  80. }
  81. case SCE_STTXT_DATETIME: {
  82. if (setDataTime.Contains(sc.ch))
  83. continue;
  84. else if(setWord.Contains(sc.ch))
  85. sc.ChangeState(SCE_STTXT_DEFAULT);
  86. else
  87. sc.SetState(SCE_STTXT_DEFAULT);
  88. break;
  89. }
  90. case SCE_STTXT_OPERATOR: {
  91. sc.SetState(SCE_STTXT_DEFAULT);
  92. break;
  93. }
  94. case SCE_STTXT_PRAGMA: {
  95. if (sc.ch == '}')
  96. sc.ForwardSetState(SCE_STTXT_DEFAULT);
  97. break;
  98. }
  99. case SCE_STTXT_COMMENTLINE: {
  100. if (sc.atLineStart)
  101. sc.SetState(SCE_STTXT_DEFAULT);
  102. break;
  103. }
  104. case SCE_STTXT_COMMENT: {
  105. if(sc.Match('*',')'))
  106. {
  107. sc.Forward();
  108. sc.ForwardSetState(SCE_STTXT_DEFAULT);
  109. }
  110. break;
  111. }
  112. case SCE_STTXT_STRING1: {
  113. if(sc.atLineEnd)
  114. sc.SetState(SCE_STTXT_STRINGEOL);
  115. else if(sc.ch == '\'' && sc.chPrev != '$')
  116. sc.ForwardSetState(SCE_STTXT_DEFAULT);
  117. break;
  118. }
  119. case SCE_STTXT_STRING2: {
  120. if (sc.atLineEnd)
  121. sc.SetState(SCE_STTXT_STRINGEOL);
  122. else if(sc.ch == '\"' && sc.chPrev != '$')
  123. sc.ForwardSetState(SCE_STTXT_DEFAULT);
  124. break;
  125. }
  126. case SCE_STTXT_STRINGEOL: {
  127. if(sc.atLineStart)
  128. sc.SetState(SCE_STTXT_DEFAULT);
  129. break;
  130. }
  131. case SCE_STTXT_CHARACTER: {
  132. if(setHexNumber.Contains(sc.ch))
  133. sc.SetState(SCE_STTXT_HEXNUMBER);
  134. else if(setDataTime.Contains(sc.ch))
  135. sc.SetState(SCE_STTXT_DATETIME);
  136. else sc.SetState(SCE_STTXT_DEFAULT);
  137. break;
  138. }
  139. case SCE_STTXT_IDENTIFIER: {
  140. if(!setWord.Contains(sc.ch))
  141. ClassifySTTXTWord(keywordlists, sc);
  142. break;
  143. }
  144. }
  145. if(sc.state == SCE_STTXT_DEFAULT)
  146. {
  147. if(IsADigit(sc.ch))
  148. sc.SetState(SCE_STTXT_NUMBER);
  149. else if (setWordStart.Contains(sc.ch))
  150. sc.SetState(SCE_STTXT_IDENTIFIER);
  151. else if (sc.Match('/', '/'))
  152. sc.SetState(SCE_STTXT_COMMENTLINE);
  153. else if(sc.Match('(', '*'))
  154. sc.SetState(SCE_STTXT_COMMENT);
  155. else if (sc.ch == '{')
  156. sc.SetState(SCE_STTXT_PRAGMA);
  157. else if (sc.ch == '\'')
  158. sc.SetState(SCE_STTXT_STRING1);
  159. else if (sc.ch == '\"')
  160. sc.SetState(SCE_STTXT_STRING2);
  161. else if(sc.ch == '#')
  162. sc.SetState(SCE_STTXT_CHARACTER);
  163. else if (setOperator.Contains(sc.ch))
  164. sc.SetState(SCE_STTXT_OPERATOR);
  165. }
  166. }
  167. if (sc.state == SCE_STTXT_IDENTIFIER && setWord.Contains(sc.chPrev))
  168. ClassifySTTXTWord(keywordlists, sc);
  169. sc.Complete();
  170. }
  171. static const char * const STTXTWordListDesc[] = {
  172. "Keywords",
  173. "Types",
  174. "Functions",
  175. "FB",
  176. "Local_Var",
  177. "Local_Pragma",
  178. 0
  179. };
  180. static bool IsCommentLine(Sci_Position line, Accessor &styler, bool type)
  181. {
  182. Sci_Position pos = styler.LineStart(line);
  183. Sci_Position eolPos = styler.LineStart(line + 1) - 1;
  184. for (Sci_Position i = pos; i < eolPos; i++)
  185. {
  186. char ch = styler[i];
  187. char chNext = styler.SafeGetCharAt(i + 1);
  188. int style = styler.StyleAt(i);
  189. if(type) {
  190. if (ch == '/' && chNext == '/' && style == SCE_STTXT_COMMENTLINE)
  191. return true;
  192. }
  193. else if (ch == '(' && chNext == '*' && style == SCE_STTXT_COMMENT)
  194. break;
  195. if (!IsASpaceOrTab(ch))
  196. return false;
  197. }
  198. for (Sci_Position i = eolPos-2; i>pos; i--)
  199. {
  200. char ch = styler[i];
  201. char chPrev = styler.SafeGetCharAt(i-1);
  202. int style = styler.StyleAt(i);
  203. if(ch == ')' && chPrev == '*' && style == SCE_STTXT_COMMENT)
  204. return true;
  205. if(!IsASpaceOrTab(ch))
  206. return false;
  207. }
  208. return false;
  209. }
  210. static bool IsPragmaLine(Sci_Position line, Accessor &styler)
  211. {
  212. Sci_Position pos = styler.LineStart(line);
  213. Sci_Position eolPos = styler.LineStart(line+1) - 1;
  214. for (Sci_Position i = pos ; i < eolPos ; i++)
  215. {
  216. char ch = styler[i];
  217. int style = styler.StyleAt(i);
  218. if(ch == '{' && style == SCE_STTXT_PRAGMA)
  219. return true;
  220. else if (!IsASpaceOrTab(ch))
  221. return false;
  222. }
  223. return false;
  224. }
  225. static void GetRangeUpper(Sci_PositionU start,Sci_PositionU end,Accessor &styler,char *s,Sci_PositionU len)
  226. {
  227. Sci_PositionU i = 0;
  228. while ((i < end - start + 1) && (i < len-1)) {
  229. s[i] = static_cast<char>(toupper(styler[start + i]));
  230. i++;
  231. }
  232. s[i] = '\0';
  233. }
  234. static void ClassifySTTXTWordFoldPoint(int &levelCurrent,Sci_PositionU lastStart,
  235. Sci_PositionU currentPos, Accessor &styler)
  236. {
  237. char s[256];
  238. GetRangeUpper(lastStart, currentPos, styler, s, sizeof(s));
  239. // See Table C.2 - Keywords
  240. if (!strcmp(s, "ACTION") ||
  241. !strcmp(s, "CASE") ||
  242. !strcmp(s, "CONFIGURATION") ||
  243. !strcmp(s, "FOR") ||
  244. !strcmp(s, "FUNCTION") ||
  245. !strcmp(s, "FUNCTION_BLOCK") ||
  246. !strcmp(s, "IF") ||
  247. !strcmp(s, "INITIAL_STEP") ||
  248. !strcmp(s, "REPEAT") ||
  249. !strcmp(s, "RESOURCE") ||
  250. !strcmp(s, "STEP") ||
  251. !strcmp(s, "STRUCT") ||
  252. !strcmp(s, "TRANSITION") ||
  253. !strcmp(s, "TYPE") ||
  254. !strcmp(s, "VAR") ||
  255. !strcmp(s, "VAR_INPUT") ||
  256. !strcmp(s, "VAR_OUTPUT") ||
  257. !strcmp(s, "VAR_IN_OUT") ||
  258. !strcmp(s, "VAR_TEMP") ||
  259. !strcmp(s, "VAR_EXTERNAL") ||
  260. !strcmp(s, "VAR_ACCESS") ||
  261. !strcmp(s, "VAR_CONFIG") ||
  262. !strcmp(s, "VAR_GLOBAL") ||
  263. !strcmp(s, "WHILE"))
  264. {
  265. levelCurrent++;
  266. }
  267. else if (!strcmp(s, "END_ACTION") ||
  268. !strcmp(s, "END_CASE") ||
  269. !strcmp(s, "END_CONFIGURATION") ||
  270. !strcmp(s, "END_FOR") ||
  271. !strcmp(s, "END_FUNCTION") ||
  272. !strcmp(s, "END_FUNCTION_BLOCK") ||
  273. !strcmp(s, "END_IF") ||
  274. !strcmp(s, "END_REPEAT") ||
  275. !strcmp(s, "END_RESOURCE") ||
  276. !strcmp(s, "END_STEP") ||
  277. !strcmp(s, "END_STRUCT") ||
  278. !strcmp(s, "END_TRANSITION") ||
  279. !strcmp(s, "END_TYPE") ||
  280. !strcmp(s, "END_VAR") ||
  281. !strcmp(s, "END_WHILE"))
  282. {
  283. levelCurrent--;
  284. if (levelCurrent < SC_FOLDLEVELBASE) {
  285. levelCurrent = SC_FOLDLEVELBASE;
  286. }
  287. }
  288. }
  289. static void FoldSTTXTDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[],Accessor &styler)
  290. {
  291. bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
  292. bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
  293. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  294. Sci_PositionU endPos = startPos + length;
  295. int visibleChars = 0;
  296. Sci_Position lineCurrent = styler.GetLine(startPos);
  297. int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
  298. int levelCurrent = levelPrev;
  299. char chNext = styler[startPos];
  300. int styleNext = styler.StyleAt(startPos);
  301. int style = initStyle;
  302. Sci_Position lastStart = 0;
  303. CharacterSet setWord(CharacterSet::setAlphaNum, "_", 0x80, true);
  304. for (Sci_PositionU i = startPos; i < endPos; i++)
  305. {
  306. char ch = chNext;
  307. chNext = styler.SafeGetCharAt(i + 1);
  308. int stylePrev = style;
  309. style = styleNext;
  310. styleNext = styler.StyleAt(i + 1);
  311. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  312. if (foldComment && style == SCE_STTXT_COMMENT) {
  313. if(stylePrev != SCE_STTXT_COMMENT)
  314. levelCurrent++;
  315. else if(styleNext != SCE_STTXT_COMMENT && !atEOL)
  316. levelCurrent--;
  317. }
  318. if ( foldComment && atEOL && ( IsCommentLine(lineCurrent, styler,false)
  319. || IsCommentLine(lineCurrent,styler,true))) {
  320. if(!IsCommentLine(lineCurrent-1, styler,true) && IsCommentLine(lineCurrent+1, styler,true))
  321. levelCurrent++;
  322. if (IsCommentLine(lineCurrent-1, styler,true) && !IsCommentLine(lineCurrent+1, styler,true))
  323. levelCurrent--;
  324. if (!IsCommentLine(lineCurrent-1, styler,false) && IsCommentLine(lineCurrent+1, styler,false))
  325. levelCurrent++;
  326. if (IsCommentLine(lineCurrent-1, styler,false) && !IsCommentLine(lineCurrent+1, styler,false))
  327. levelCurrent--;
  328. }
  329. if(foldPreprocessor && atEOL && IsPragmaLine(lineCurrent, styler)) {
  330. if(!IsPragmaLine(lineCurrent-1, styler) && IsPragmaLine(lineCurrent+1, styler ))
  331. levelCurrent++;
  332. else if(IsPragmaLine(lineCurrent-1, styler) && !IsPragmaLine(lineCurrent+1, styler))
  333. levelCurrent--;
  334. }
  335. if (stylePrev != SCE_STTXT_KEYWORD && style == SCE_STTXT_KEYWORD) {
  336. lastStart = i;
  337. }
  338. if(stylePrev == SCE_STTXT_KEYWORD) {
  339. if(setWord.Contains(ch) && !setWord.Contains(chNext))
  340. ClassifySTTXTWordFoldPoint(levelCurrent,lastStart, i, styler);
  341. }
  342. if (!IsASpace(ch)) {
  343. visibleChars++;
  344. }
  345. if (atEOL) {
  346. int lev = levelPrev;
  347. if (visibleChars == 0 && foldCompact)
  348. lev |= SC_FOLDLEVELWHITEFLAG;
  349. if ((levelCurrent > levelPrev) && (visibleChars > 0))
  350. lev |= SC_FOLDLEVELHEADERFLAG;
  351. if (lev != styler.LevelAt(lineCurrent))
  352. styler.SetLevel(lineCurrent, lev);
  353. lineCurrent++;
  354. levelPrev = levelCurrent;
  355. visibleChars = 0;
  356. }
  357. // If we didn't reach the EOL in previous loop, store line level and whitespace information.
  358. // The rest will be filled in later...
  359. int lev = levelPrev;
  360. if (visibleChars == 0 && foldCompact)
  361. lev |= SC_FOLDLEVELWHITEFLAG;
  362. styler.SetLevel(lineCurrent, lev);
  363. }
  364. }
  365. LexerModule lmSTTXT(SCLEX_STTXT, ColouriseSTTXTDoc, "fcST", FoldSTTXTDoc, STTXTWordListDesc);