PageRenderTime 26ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/Branches/4.0/Scintilla/src/Lexers/LexCOBOL.cxx

#
C++ | 368 lines | 325 code | 28 blank | 15 comment | 136 complexity | f1e7c36266f5bf53282bbe1c41135846 MD5 | raw file
Possible License(s): MIT
  1. // Scintilla source code edit control
  2. /** @file LexCOBOL.cxx
  3. ** Lexer for COBOL
  4. ** Based on LexPascal.cxx
  5. ** Written by Laurent le Tynevez
  6. ** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
  7. ** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
  8. ** Updated by Rod Falck, Aug 2006 Converted to COBOL
  9. **/
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <stdio.h>
  14. #include <stdarg.h>
  15. #include "Platform.h"
  16. #include "PropSet.h"
  17. #include "Accessor.h"
  18. #include "KeyWords.h"
  19. #include "Scintilla.h"
  20. #include "SciLexer.h"
  21. #include "StyleContext.h"
  22. #ifdef SCI_NAMESPACE
  23. using namespace Scintilla;
  24. #endif
  25. #define IN_DIVISION 0x01
  26. #define IN_DECLARATIVES 0x02
  27. #define IN_SECTION 0x04
  28. #define IN_PARAGRAPH 0x08
  29. #define IN_FLAGS 0xF
  30. #define NOT_HEADER 0x10
  31. inline bool isCOBOLoperator(char ch)
  32. {
  33. return isoperator(ch);
  34. }
  35. inline bool isCOBOLwordchar(char ch)
  36. {
  37. return isascii(ch) && (isalnum(ch) || ch == '-');
  38. }
  39. inline bool isCOBOLwordstart(char ch)
  40. {
  41. return isascii(ch) && isalnum(ch);
  42. }
  43. static int CountBits(int nBits)
  44. {
  45. int count = 0;
  46. for (int i = 0; i < 32; ++i)
  47. {
  48. count += nBits & 1;
  49. nBits >>= 1;
  50. }
  51. return count;
  52. }
  53. static void getRange(unsigned int start,
  54. unsigned int end,
  55. Accessor &styler,
  56. char *s,
  57. unsigned int len) {
  58. unsigned int i = 0;
  59. while ((i < end - start + 1) && (i < len-1)) {
  60. s[i] = static_cast<char>(tolower(styler[start + i]));
  61. i++;
  62. }
  63. s[i] = '\0';
  64. }
  65. static void ColourTo(Accessor &styler, unsigned int end, unsigned int attr) {
  66. styler.ColourTo(end, attr);
  67. }
  68. static int classifyWordCOBOL(unsigned int start, unsigned int end, /*WordList &keywords*/WordList *keywordlists[], Accessor &styler, int nContainment, bool *bAarea) {
  69. int ret = 0;
  70. WordList& a_keywords = *keywordlists[0];
  71. WordList& b_keywords = *keywordlists[1];
  72. WordList& c_keywords = *keywordlists[2];
  73. char s[100];
  74. getRange(start, end, styler, s, sizeof(s));
  75. char chAttr = SCE_C_IDENTIFIER;
  76. if (isdigit(s[0]) || (s[0] == '.')) {
  77. chAttr = SCE_C_NUMBER;
  78. char *p = s + 1;
  79. while (*p) {
  80. if (!isdigit(*p) && isCOBOLwordchar(*p)) {
  81. chAttr = SCE_C_IDENTIFIER;
  82. break;
  83. }
  84. ++p;
  85. }
  86. }
  87. else {
  88. if (a_keywords.InList(s)) {
  89. chAttr = SCE_C_WORD;
  90. }
  91. else if (b_keywords.InList(s)) {
  92. chAttr = SCE_C_WORD2;
  93. }
  94. else if (c_keywords.InList(s)) {
  95. chAttr = SCE_C_UUID;
  96. }
  97. }
  98. if (*bAarea) {
  99. if (strcmp(s, "division") == 0) {
  100. ret = IN_DIVISION;
  101. // we've determined the containment, anything else is just ignored for those purposes
  102. *bAarea = false;
  103. } else if (strcmp(s, "declaratives") == 0) {
  104. ret = IN_DIVISION | IN_DECLARATIVES;
  105. if (nContainment & IN_DECLARATIVES)
  106. ret |= NOT_HEADER | IN_SECTION;
  107. // we've determined the containment, anything else is just ignored for those purposes
  108. *bAarea = false;
  109. } else if (strcmp(s, "section") == 0) {
  110. ret = (nContainment &~ IN_PARAGRAPH) | IN_SECTION;
  111. // we've determined the containment, anything else is just ignored for those purposes
  112. *bAarea = false;
  113. } else if (strcmp(s, "end") == 0 && (nContainment & IN_DECLARATIVES)) {
  114. ret = IN_DIVISION | IN_DECLARATIVES | IN_SECTION | NOT_HEADER;
  115. } else {
  116. ret = nContainment | IN_PARAGRAPH;
  117. }
  118. }
  119. ColourTo(styler, end, chAttr);
  120. return ret;
  121. }
  122. static void ColouriseCOBOLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
  123. Accessor &styler) {
  124. styler.StartAt(startPos);
  125. int state = initStyle;
  126. if (state == SCE_C_CHARACTER) // Does not leak onto next line
  127. state = SCE_C_DEFAULT;
  128. char chPrev = ' ';
  129. char chNext = styler[startPos];
  130. unsigned int lengthDoc = startPos + length;
  131. int nContainment;
  132. int currentLine = styler.GetLine(startPos);
  133. if (currentLine > 0) {
  134. styler.SetLineState(currentLine, styler.GetLineState(currentLine-1));
  135. nContainment = styler.GetLineState(currentLine);
  136. nContainment &= ~NOT_HEADER;
  137. } else {
  138. styler.SetLineState(currentLine, 0);
  139. nContainment = 0;
  140. }
  141. styler.StartSegment(startPos);
  142. bool bNewLine = true;
  143. bool bAarea = !isspacechar(chNext);
  144. int column = 0;
  145. for (unsigned int i = startPos; i < lengthDoc; i++) {
  146. char ch = chNext;
  147. chNext = styler.SafeGetCharAt(i + 1);
  148. ++column;
  149. if (bNewLine) {
  150. column = 0;
  151. }
  152. if (column <= 1 && !bAarea) {
  153. bAarea = !isspacechar(ch);
  154. }
  155. bool bSetNewLine = false;
  156. if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
  157. // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
  158. // Avoid triggering two times on Dos/Win
  159. // End of line
  160. if (state == SCE_C_CHARACTER) {
  161. ColourTo(styler, i, state);
  162. state = SCE_C_DEFAULT;
  163. }
  164. styler.SetLineState(currentLine, nContainment);
  165. currentLine++;
  166. bSetNewLine = true;
  167. if (nContainment & NOT_HEADER)
  168. nContainment &= ~(NOT_HEADER | IN_DECLARATIVES | IN_SECTION);
  169. }
  170. if (styler.IsLeadByte(ch)) {
  171. chNext = styler.SafeGetCharAt(i + 2);
  172. chPrev = ' ';
  173. i += 1;
  174. continue;
  175. }
  176. if (state == SCE_C_DEFAULT) {
  177. if (isCOBOLwordstart(ch) || (ch == '$' && isascii(chNext) && isalpha(chNext))) {
  178. ColourTo(styler, i-1, state);
  179. state = SCE_C_IDENTIFIER;
  180. } else if (column == 0 && ch == '*' && chNext != '*') {
  181. ColourTo(styler, i-1, state);
  182. state = SCE_C_COMMENTLINE;
  183. } else if (column == 0 && ch == '/' && chNext != '*') {
  184. ColourTo(styler, i-1, state);
  185. state = SCE_C_COMMENTLINE;
  186. } else if (column == 0 && ch == '*' && chNext == '*') {
  187. ColourTo(styler, i-1, state);
  188. state = SCE_C_COMMENTDOC;
  189. } else if (column == 0 && ch == '/' && chNext == '*') {
  190. ColourTo(styler, i-1, state);
  191. state = SCE_C_COMMENTDOC;
  192. } else if (ch == '"') {
  193. ColourTo(styler, i-1, state);
  194. state = SCE_C_STRING;
  195. } else if (ch == '\'') {
  196. ColourTo(styler, i-1, state);
  197. state = SCE_C_CHARACTER;
  198. } else if (ch == '?' && column == 0) {
  199. ColourTo(styler, i-1, state);
  200. state = SCE_C_PREPROCESSOR;
  201. } else if (isCOBOLoperator(ch)) {
  202. ColourTo(styler, i-1, state);
  203. ColourTo(styler, i, SCE_C_OPERATOR);
  204. }
  205. } else if (state == SCE_C_IDENTIFIER) {
  206. if (!isCOBOLwordchar(ch)) {
  207. int lStateChange = classifyWordCOBOL(styler.GetStartSegment(), i - 1, keywordlists, styler, nContainment, &bAarea);
  208. if(lStateChange != 0) {
  209. styler.SetLineState(currentLine, lStateChange);
  210. nContainment = lStateChange;
  211. }
  212. state = SCE_C_DEFAULT;
  213. chNext = styler.SafeGetCharAt(i + 1);
  214. if (ch == '"') {
  215. state = SCE_C_STRING;
  216. } else if (ch == '\'') {
  217. state = SCE_C_CHARACTER;
  218. } else if (isCOBOLoperator(ch)) {
  219. ColourTo(styler, i, SCE_C_OPERATOR);
  220. }
  221. }
  222. } else {
  223. if (state == SCE_C_PREPROCESSOR) {
  224. if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) {
  225. ColourTo(styler, i-1, state);
  226. state = SCE_C_DEFAULT;
  227. }
  228. } else if (state == SCE_C_COMMENT) {
  229. if (ch == '\r' || ch == '\n') {
  230. ColourTo(styler, i, state);
  231. state = SCE_C_DEFAULT;
  232. }
  233. } else if (state == SCE_C_COMMENTDOC) {
  234. if (ch == '\r' || ch == '\n') {
  235. if (((i > styler.GetStartSegment() + 2) || (
  236. (initStyle == SCE_C_COMMENTDOC) &&
  237. (styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
  238. ColourTo(styler, i, state);
  239. state = SCE_C_DEFAULT;
  240. }
  241. }
  242. } else if (state == SCE_C_COMMENTLINE) {
  243. if (ch == '\r' || ch == '\n') {
  244. ColourTo(styler, i-1, state);
  245. state = SCE_C_DEFAULT;
  246. }
  247. } else if (state == SCE_C_STRING) {
  248. if (ch == '"') {
  249. ColourTo(styler, i, state);
  250. state = SCE_C_DEFAULT;
  251. }
  252. } else if (state == SCE_C_CHARACTER) {
  253. if (ch == '\'') {
  254. ColourTo(styler, i, state);
  255. state = SCE_C_DEFAULT;
  256. }
  257. }
  258. }
  259. chPrev = ch;
  260. bNewLine = bSetNewLine;
  261. if (bNewLine)
  262. {
  263. bAarea = false;
  264. }
  265. }
  266. ColourTo(styler, lengthDoc - 1, state);
  267. }
  268. static void FoldCOBOLDoc(unsigned int startPos, int length, int, WordList *[],
  269. Accessor &styler) {
  270. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  271. unsigned int endPos = startPos + length;
  272. int visibleChars = 0;
  273. int lineCurrent = styler.GetLine(startPos);
  274. int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) & SC_FOLDLEVELNUMBERMASK : 0xFFF;
  275. char chNext = styler[startPos];
  276. bool bNewLine = true;
  277. bool bAarea = !isspacechar(chNext);
  278. int column = 0;
  279. bool bComment = false;
  280. for (unsigned int i = startPos; i < endPos; i++) {
  281. char ch = chNext;
  282. chNext = styler.SafeGetCharAt(i + 1);
  283. ++column;
  284. if (bNewLine) {
  285. column = 0;
  286. bComment = (ch == '*' || ch == '/' || ch == '?');
  287. }
  288. if (column <= 1 && !bAarea) {
  289. bAarea = !isspacechar(ch);
  290. }
  291. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  292. if (atEOL) {
  293. int nContainment = styler.GetLineState(lineCurrent);
  294. int lev = CountBits(nContainment & IN_FLAGS) | SC_FOLDLEVELBASE;
  295. if (bAarea && !bComment)
  296. --lev;
  297. if (visibleChars == 0 && foldCompact)
  298. lev |= SC_FOLDLEVELWHITEFLAG;
  299. if ((bAarea) && (visibleChars > 0) && !(nContainment & NOT_HEADER) && !bComment)
  300. lev |= SC_FOLDLEVELHEADERFLAG;
  301. if (lev != styler.LevelAt(lineCurrent)) {
  302. styler.SetLevel(lineCurrent, lev);
  303. }
  304. if ((lev & SC_FOLDLEVELNUMBERMASK) <= (levelPrev & SC_FOLDLEVELNUMBERMASK)) {
  305. // this level is at the same level or less than the previous line
  306. // therefore these is nothing for the previous header to collapse, so remove the header
  307. styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG);
  308. }
  309. levelPrev = lev;
  310. visibleChars = 0;
  311. bAarea = false;
  312. bNewLine = true;
  313. lineCurrent++;
  314. } else {
  315. bNewLine = false;
  316. }
  317. if (!isspacechar(ch))
  318. visibleChars++;
  319. }
  320. // Fill in the real level of the next line, keeping the current flags as they will be filled in later
  321. int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
  322. styler.SetLevel(lineCurrent, levelPrev | flagsNext);
  323. }
  324. static const char * const COBOLWordListDesc[] = {
  325. "A Keywords",
  326. "B Keywords",
  327. "Extended Keywords",
  328. 0
  329. };
  330. LexerModule lmCOBOL(SCLEX_COBOL, ColouriseCOBOLDoc, "COBOL", FoldCOBOLDoc, COBOLWordListDesc);