PageRenderTime 25ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/scintilla/lexers/LexAda.cxx

https://gitlab.com/life436/tortoisegit
C++ | 515 lines | 386 code | 87 blank | 42 comment | 136 complexity | c96601c338de5a2a53a21b0f76369be9 MD5 | raw file
  1. // Scintilla source code edit control
  2. /** @file LexAda.cxx
  3. ** Lexer for Ada 95
  4. **/
  5. // Copyright 2002 by Sergey Koshcheyev <sergey.k@seznam.cz>
  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 <string>
  14. #include "ILexer.h"
  15. #include "Scintilla.h"
  16. #include "SciLexer.h"
  17. #include "WordList.h"
  18. #include "LexAccessor.h"
  19. #include "Accessor.h"
  20. #include "StyleContext.h"
  21. #include "CharacterSet.h"
  22. #include "LexerModule.h"
  23. #ifdef SCI_NAMESPACE
  24. using namespace Scintilla;
  25. #endif
  26. /*
  27. * Interface
  28. */
  29. static void ColouriseDocument(
  30. Sci_PositionU startPos,
  31. Sci_Position length,
  32. int initStyle,
  33. WordList *keywordlists[],
  34. Accessor &styler);
  35. static const char * const adaWordListDesc[] = {
  36. "Keywords",
  37. 0
  38. };
  39. LexerModule lmAda(SCLEX_ADA, ColouriseDocument, "ada", NULL, adaWordListDesc);
  40. /*
  41. * Implementation
  42. */
  43. // Functions that have apostropheStartsAttribute as a parameter set it according to whether
  44. // an apostrophe encountered after processing the current token will start an attribute or
  45. // a character literal.
  46. static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute);
  47. static void ColouriseComment(StyleContext& sc, bool& apostropheStartsAttribute);
  48. static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL);
  49. static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute);
  50. static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
  51. static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute);
  52. static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute);
  53. static void ColouriseWhiteSpace(StyleContext& sc, bool& apostropheStartsAttribute);
  54. static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute);
  55. static inline bool IsDelimiterCharacter(int ch);
  56. static inline bool IsSeparatorOrDelimiterCharacter(int ch);
  57. static bool IsValidIdentifier(const std::string& identifier);
  58. static bool IsValidNumber(const std::string& number);
  59. static inline bool IsWordStartCharacter(int ch);
  60. static inline bool IsWordCharacter(int ch);
  61. static void ColouriseCharacter(StyleContext& sc, bool& apostropheStartsAttribute) {
  62. apostropheStartsAttribute = true;
  63. sc.SetState(SCE_ADA_CHARACTER);
  64. // Skip the apostrophe and one more character (so that '' is shown as non-terminated and '''
  65. // is handled correctly)
  66. sc.Forward();
  67. sc.Forward();
  68. ColouriseContext(sc, '\'', SCE_ADA_CHARACTEREOL);
  69. }
  70. static void ColouriseContext(StyleContext& sc, char chEnd, int stateEOL) {
  71. while (!sc.atLineEnd && !sc.Match(chEnd)) {
  72. sc.Forward();
  73. }
  74. if (!sc.atLineEnd) {
  75. sc.ForwardSetState(SCE_ADA_DEFAULT);
  76. } else {
  77. sc.ChangeState(stateEOL);
  78. }
  79. }
  80. static void ColouriseComment(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
  81. // Apostrophe meaning is not changed, but the parameter is present for uniformity
  82. sc.SetState(SCE_ADA_COMMENTLINE);
  83. while (!sc.atLineEnd) {
  84. sc.Forward();
  85. }
  86. }
  87. static void ColouriseDelimiter(StyleContext& sc, bool& apostropheStartsAttribute) {
  88. apostropheStartsAttribute = sc.Match (')');
  89. sc.SetState(SCE_ADA_DELIMITER);
  90. sc.ForwardSetState(SCE_ADA_DEFAULT);
  91. }
  92. static void ColouriseLabel(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
  93. apostropheStartsAttribute = false;
  94. sc.SetState(SCE_ADA_LABEL);
  95. // Skip "<<"
  96. sc.Forward();
  97. sc.Forward();
  98. std::string identifier;
  99. while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
  100. identifier += static_cast<char>(tolower(sc.ch));
  101. sc.Forward();
  102. }
  103. // Skip ">>"
  104. if (sc.Match('>', '>')) {
  105. sc.Forward();
  106. sc.Forward();
  107. } else {
  108. sc.ChangeState(SCE_ADA_ILLEGAL);
  109. }
  110. // If the name is an invalid identifier or a keyword, then make it invalid label
  111. if (!IsValidIdentifier(identifier) || keywords.InList(identifier.c_str())) {
  112. sc.ChangeState(SCE_ADA_ILLEGAL);
  113. }
  114. sc.SetState(SCE_ADA_DEFAULT);
  115. }
  116. static void ColouriseNumber(StyleContext& sc, bool& apostropheStartsAttribute) {
  117. apostropheStartsAttribute = true;
  118. std::string number;
  119. sc.SetState(SCE_ADA_NUMBER);
  120. // Get all characters up to a delimiter or a separator, including points, but excluding
  121. // double points (ranges).
  122. while (!IsSeparatorOrDelimiterCharacter(sc.ch) || (sc.ch == '.' && sc.chNext != '.')) {
  123. number += static_cast<char>(sc.ch);
  124. sc.Forward();
  125. }
  126. // Special case: exponent with sign
  127. if ((sc.chPrev == 'e' || sc.chPrev == 'E') &&
  128. (sc.ch == '+' || sc.ch == '-')) {
  129. number += static_cast<char>(sc.ch);
  130. sc.Forward ();
  131. while (!IsSeparatorOrDelimiterCharacter(sc.ch)) {
  132. number += static_cast<char>(sc.ch);
  133. sc.Forward();
  134. }
  135. }
  136. if (!IsValidNumber(number)) {
  137. sc.ChangeState(SCE_ADA_ILLEGAL);
  138. }
  139. sc.SetState(SCE_ADA_DEFAULT);
  140. }
  141. static void ColouriseString(StyleContext& sc, bool& apostropheStartsAttribute) {
  142. apostropheStartsAttribute = true;
  143. sc.SetState(SCE_ADA_STRING);
  144. sc.Forward();
  145. ColouriseContext(sc, '"', SCE_ADA_STRINGEOL);
  146. }
  147. static void ColouriseWhiteSpace(StyleContext& sc, bool& /*apostropheStartsAttribute*/) {
  148. // Apostrophe meaning is not changed, but the parameter is present for uniformity
  149. sc.SetState(SCE_ADA_DEFAULT);
  150. sc.ForwardSetState(SCE_ADA_DEFAULT);
  151. }
  152. static void ColouriseWord(StyleContext& sc, WordList& keywords, bool& apostropheStartsAttribute) {
  153. apostropheStartsAttribute = true;
  154. sc.SetState(SCE_ADA_IDENTIFIER);
  155. std::string word;
  156. while (!sc.atLineEnd && !IsSeparatorOrDelimiterCharacter(sc.ch)) {
  157. word += static_cast<char>(tolower(sc.ch));
  158. sc.Forward();
  159. }
  160. if (!IsValidIdentifier(word)) {
  161. sc.ChangeState(SCE_ADA_ILLEGAL);
  162. } else if (keywords.InList(word.c_str())) {
  163. sc.ChangeState(SCE_ADA_WORD);
  164. if (word != "all") {
  165. apostropheStartsAttribute = false;
  166. }
  167. }
  168. sc.SetState(SCE_ADA_DEFAULT);
  169. }
  170. //
  171. // ColouriseDocument
  172. //
  173. static void ColouriseDocument(
  174. Sci_PositionU startPos,
  175. Sci_Position length,
  176. int initStyle,
  177. WordList *keywordlists[],
  178. Accessor &styler) {
  179. WordList &keywords = *keywordlists[0];
  180. StyleContext sc(startPos, length, initStyle, styler);
  181. Sci_Position lineCurrent = styler.GetLine(startPos);
  182. bool apostropheStartsAttribute = (styler.GetLineState(lineCurrent) & 1) != 0;
  183. while (sc.More()) {
  184. if (sc.atLineEnd) {
  185. // Go to the next line
  186. sc.Forward();
  187. lineCurrent++;
  188. // Remember the line state for future incremental lexing
  189. styler.SetLineState(lineCurrent, apostropheStartsAttribute);
  190. // Don't continue any styles on the next line
  191. sc.SetState(SCE_ADA_DEFAULT);
  192. }
  193. // Comments
  194. if (sc.Match('-', '-')) {
  195. ColouriseComment(sc, apostropheStartsAttribute);
  196. // Strings
  197. } else if (sc.Match('"')) {
  198. ColouriseString(sc, apostropheStartsAttribute);
  199. // Characters
  200. } else if (sc.Match('\'') && !apostropheStartsAttribute) {
  201. ColouriseCharacter(sc, apostropheStartsAttribute);
  202. // Labels
  203. } else if (sc.Match('<', '<')) {
  204. ColouriseLabel(sc, keywords, apostropheStartsAttribute);
  205. // Whitespace
  206. } else if (IsASpace(sc.ch)) {
  207. ColouriseWhiteSpace(sc, apostropheStartsAttribute);
  208. // Delimiters
  209. } else if (IsDelimiterCharacter(sc.ch)) {
  210. ColouriseDelimiter(sc, apostropheStartsAttribute);
  211. // Numbers
  212. } else if (IsADigit(sc.ch) || sc.ch == '#') {
  213. ColouriseNumber(sc, apostropheStartsAttribute);
  214. // Keywords or identifiers
  215. } else {
  216. ColouriseWord(sc, keywords, apostropheStartsAttribute);
  217. }
  218. }
  219. sc.Complete();
  220. }
  221. static inline bool IsDelimiterCharacter(int ch) {
  222. switch (ch) {
  223. case '&':
  224. case '\'':
  225. case '(':
  226. case ')':
  227. case '*':
  228. case '+':
  229. case ',':
  230. case '-':
  231. case '.':
  232. case '/':
  233. case ':':
  234. case ';':
  235. case '<':
  236. case '=':
  237. case '>':
  238. case '|':
  239. return true;
  240. default:
  241. return false;
  242. }
  243. }
  244. static inline bool IsSeparatorOrDelimiterCharacter(int ch) {
  245. return IsASpace(ch) || IsDelimiterCharacter(ch);
  246. }
  247. static bool IsValidIdentifier(const std::string& identifier) {
  248. // First character can't be '_', so initialize the flag to true
  249. bool lastWasUnderscore = true;
  250. size_t length = identifier.length();
  251. // Zero-length identifiers are not valid (these can occur inside labels)
  252. if (length == 0) {
  253. return false;
  254. }
  255. // Check for valid character at the start
  256. if (!IsWordStartCharacter(identifier[0])) {
  257. return false;
  258. }
  259. // Check for only valid characters and no double underscores
  260. for (size_t i = 0; i < length; i++) {
  261. if (!IsWordCharacter(identifier[i]) ||
  262. (identifier[i] == '_' && lastWasUnderscore)) {
  263. return false;
  264. }
  265. lastWasUnderscore = identifier[i] == '_';
  266. }
  267. // Check for underscore at the end
  268. if (lastWasUnderscore == true) {
  269. return false;
  270. }
  271. // All checks passed
  272. return true;
  273. }
  274. static bool IsValidNumber(const std::string& number) {
  275. size_t hashPos = number.find("#");
  276. bool seenDot = false;
  277. size_t i = 0;
  278. size_t length = number.length();
  279. if (length == 0)
  280. return false; // Just in case
  281. // Decimal number
  282. if (hashPos == std::string::npos) {
  283. bool canBeSpecial = false;
  284. for (; i < length; i++) {
  285. if (number[i] == '_') {
  286. if (!canBeSpecial) {
  287. return false;
  288. }
  289. canBeSpecial = false;
  290. } else if (number[i] == '.') {
  291. if (!canBeSpecial || seenDot) {
  292. return false;
  293. }
  294. canBeSpecial = false;
  295. seenDot = true;
  296. } else if (IsADigit(number[i])) {
  297. canBeSpecial = true;
  298. } else {
  299. break;
  300. }
  301. }
  302. if (!canBeSpecial)
  303. return false;
  304. } else {
  305. // Based number
  306. bool canBeSpecial = false;
  307. int base = 0;
  308. // Parse base
  309. for (; i < length; i++) {
  310. int ch = number[i];
  311. if (ch == '_') {
  312. if (!canBeSpecial)
  313. return false;
  314. canBeSpecial = false;
  315. } else if (IsADigit(ch)) {
  316. base = base * 10 + (ch - '0');
  317. if (base > 16)
  318. return false;
  319. canBeSpecial = true;
  320. } else if (ch == '#' && canBeSpecial) {
  321. break;
  322. } else {
  323. return false;
  324. }
  325. }
  326. if (base < 2)
  327. return false;
  328. if (i == length)
  329. return false;
  330. i++; // Skip over '#'
  331. // Parse number
  332. canBeSpecial = false;
  333. for (; i < length; i++) {
  334. int ch = tolower(number[i]);
  335. if (ch == '_') {
  336. if (!canBeSpecial) {
  337. return false;
  338. }
  339. canBeSpecial = false;
  340. } else if (ch == '.') {
  341. if (!canBeSpecial || seenDot) {
  342. return false;
  343. }
  344. canBeSpecial = false;
  345. seenDot = true;
  346. } else if (IsADigit(ch)) {
  347. if (ch - '0' >= base) {
  348. return false;
  349. }
  350. canBeSpecial = true;
  351. } else if (ch >= 'a' && ch <= 'f') {
  352. if (ch - 'a' + 10 >= base) {
  353. return false;
  354. }
  355. canBeSpecial = true;
  356. } else if (ch == '#' && canBeSpecial) {
  357. break;
  358. } else {
  359. return false;
  360. }
  361. }
  362. if (i == length) {
  363. return false;
  364. }
  365. i++;
  366. }
  367. // Exponent (optional)
  368. if (i < length) {
  369. if (number[i] != 'e' && number[i] != 'E')
  370. return false;
  371. i++; // Move past 'E'
  372. if (i == length) {
  373. return false;
  374. }
  375. if (number[i] == '+')
  376. i++;
  377. else if (number[i] == '-') {
  378. if (seenDot) {
  379. i++;
  380. } else {
  381. return false; // Integer literals should not have negative exponents
  382. }
  383. }
  384. if (i == length) {
  385. return false;
  386. }
  387. bool canBeSpecial = false;
  388. for (; i < length; i++) {
  389. if (number[i] == '_') {
  390. if (!canBeSpecial) {
  391. return false;
  392. }
  393. canBeSpecial = false;
  394. } else if (IsADigit(number[i])) {
  395. canBeSpecial = true;
  396. } else {
  397. return false;
  398. }
  399. }
  400. if (!canBeSpecial)
  401. return false;
  402. }
  403. // if i == length, number was parsed successfully.
  404. return i == length;
  405. }
  406. static inline bool IsWordCharacter(int ch) {
  407. return IsWordStartCharacter(ch) || IsADigit(ch);
  408. }
  409. static inline bool IsWordStartCharacter(int ch) {
  410. return (IsASCII(ch) && isalpha(ch)) || ch == '_';
  411. }