LexPS.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. // Scintilla source code edit control
  2. /** @file LexPS.cxx
  3. ** Lexer for PostScript
  4. **
  5. ** Written by Nigel Hathaway <nigel@bprj.co.uk>.
  6. ** The License.txt file describes the conditions under which this software may be distributed.
  7. **/
  8. // Previous releases of this lexer included support for marking token starts with
  9. // a style byte indicator. This was used by the wxGhostscript IDE/debugger.
  10. // Style byte indicators were removed in version 3.4.3.
  11. // Anyone wanting to restore this functionality for wxGhostscript using 'modern'
  12. // indicators can examine the earlier source in the Mercurial repository.
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <stdarg.h>
  17. #include <assert.h>
  18. #include <ctype.h>
  19. #include "ILexer.h"
  20. #include "Scintilla.h"
  21. #include "SciLexer.h"
  22. #include "WordList.h"
  23. #include "LexAccessor.h"
  24. #include "Accessor.h"
  25. #include "StyleContext.h"
  26. #include "CharacterSet.h"
  27. #include "LexerModule.h"
  28. #ifdef SCI_NAMESPACE
  29. using namespace Scintilla;
  30. #endif
  31. static inline bool IsASelfDelimitingChar(const int ch) {
  32. return (ch == '[' || ch == ']' || ch == '{' || ch == '}' ||
  33. ch == '/' || ch == '<' || ch == '>' ||
  34. ch == '(' || ch == ')' || ch == '%');
  35. }
  36. static inline bool IsAWhitespaceChar(const int ch) {
  37. return (ch == ' ' || ch == '\t' || ch == '\r' ||
  38. ch == '\n' || ch == '\f' || ch == '\0');
  39. }
  40. static bool IsABaseNDigit(const int ch, const int base) {
  41. int maxdig = '9';
  42. int letterext = -1;
  43. if (base <= 10)
  44. maxdig = '0' + base - 1;
  45. else
  46. letterext = base - 11;
  47. return ((ch >= '0' && ch <= maxdig) ||
  48. (ch >= 'A' && ch <= ('A' + letterext)) ||
  49. (ch >= 'a' && ch <= ('a' + letterext)));
  50. }
  51. static inline bool IsABase85Char(const int ch) {
  52. return ((ch >= '!' && ch <= 'u') || ch == 'z');
  53. }
  54. static void ColourisePSDoc(
  55. Sci_PositionU startPos,
  56. Sci_Position length,
  57. int initStyle,
  58. WordList *keywordlists[],
  59. Accessor &styler) {
  60. WordList &keywords1 = *keywordlists[0];
  61. WordList &keywords2 = *keywordlists[1];
  62. WordList &keywords3 = *keywordlists[2];
  63. WordList &keywords4 = *keywordlists[3];
  64. WordList &keywords5 = *keywordlists[4];
  65. StyleContext sc(startPos, length, initStyle, styler);
  66. int pslevel = styler.GetPropertyInt("ps.level", 3);
  67. Sci_Position lineCurrent = styler.GetLine(startPos);
  68. int nestTextCurrent = 0;
  69. if (lineCurrent > 0 && initStyle == SCE_PS_TEXT)
  70. nestTextCurrent = styler.GetLineState(lineCurrent - 1);
  71. int numRadix = 0;
  72. bool numHasPoint = false;
  73. bool numHasExponent = false;
  74. bool numHasSign = false;
  75. for (; sc.More(); sc.Forward()) {
  76. if (sc.atLineStart)
  77. lineCurrent = styler.GetLine(sc.currentPos);
  78. // Determine if the current state should terminate.
  79. if (sc.state == SCE_PS_COMMENT || sc.state == SCE_PS_DSC_VALUE) {
  80. if (sc.atLineEnd) {
  81. sc.SetState(SCE_C_DEFAULT);
  82. }
  83. } else if (sc.state == SCE_PS_DSC_COMMENT) {
  84. if (sc.ch == ':') {
  85. sc.Forward();
  86. if (!sc.atLineEnd)
  87. sc.SetState(SCE_PS_DSC_VALUE);
  88. else
  89. sc.SetState(SCE_C_DEFAULT);
  90. } else if (sc.atLineEnd) {
  91. sc.SetState(SCE_C_DEFAULT);
  92. } else if (IsAWhitespaceChar(sc.ch) && sc.ch != '\r') {
  93. sc.ChangeState(SCE_PS_COMMENT);
  94. }
  95. } else if (sc.state == SCE_PS_NUMBER) {
  96. if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch)) {
  97. if ((sc.chPrev == '+' || sc.chPrev == '-' ||
  98. sc.chPrev == 'E' || sc.chPrev == 'e') && numRadix == 0)
  99. sc.ChangeState(SCE_PS_NAME);
  100. sc.SetState(SCE_C_DEFAULT);
  101. } else if (sc.ch == '#') {
  102. if (numHasPoint || numHasExponent || numHasSign || numRadix != 0) {
  103. sc.ChangeState(SCE_PS_NAME);
  104. } else {
  105. char szradix[5];
  106. sc.GetCurrent(szradix, 4);
  107. numRadix = atoi(szradix);
  108. if (numRadix < 2 || numRadix > 36)
  109. sc.ChangeState(SCE_PS_NAME);
  110. }
  111. } else if ((sc.ch == 'E' || sc.ch == 'e') && numRadix == 0) {
  112. if (numHasExponent) {
  113. sc.ChangeState(SCE_PS_NAME);
  114. } else {
  115. numHasExponent = true;
  116. if (sc.chNext == '+' || sc.chNext == '-')
  117. sc.Forward();
  118. }
  119. } else if (sc.ch == '.') {
  120. if (numHasPoint || numHasExponent || numRadix != 0) {
  121. sc.ChangeState(SCE_PS_NAME);
  122. } else {
  123. numHasPoint = true;
  124. }
  125. } else if (numRadix == 0) {
  126. if (!IsABaseNDigit(sc.ch, 10))
  127. sc.ChangeState(SCE_PS_NAME);
  128. } else {
  129. if (!IsABaseNDigit(sc.ch, numRadix))
  130. sc.ChangeState(SCE_PS_NAME);
  131. }
  132. } else if (sc.state == SCE_PS_NAME || sc.state == SCE_PS_KEYWORD) {
  133. if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch)) {
  134. char s[100];
  135. sc.GetCurrent(s, sizeof(s));
  136. if ((pslevel >= 1 && keywords1.InList(s)) ||
  137. (pslevel >= 2 && keywords2.InList(s)) ||
  138. (pslevel >= 3 && keywords3.InList(s)) ||
  139. keywords4.InList(s) || keywords5.InList(s)) {
  140. sc.ChangeState(SCE_PS_KEYWORD);
  141. }
  142. sc.SetState(SCE_C_DEFAULT);
  143. }
  144. } else if (sc.state == SCE_PS_LITERAL || sc.state == SCE_PS_IMMEVAL) {
  145. if (IsASelfDelimitingChar(sc.ch) || IsAWhitespaceChar(sc.ch))
  146. sc.SetState(SCE_C_DEFAULT);
  147. } else if (sc.state == SCE_PS_PAREN_ARRAY || sc.state == SCE_PS_PAREN_DICT ||
  148. sc.state == SCE_PS_PAREN_PROC) {
  149. sc.SetState(SCE_C_DEFAULT);
  150. } else if (sc.state == SCE_PS_TEXT) {
  151. if (sc.ch == '(') {
  152. nestTextCurrent++;
  153. } else if (sc.ch == ')') {
  154. if (--nestTextCurrent == 0)
  155. sc.ForwardSetState(SCE_PS_DEFAULT);
  156. } else if (sc.ch == '\\') {
  157. sc.Forward();
  158. }
  159. } else if (sc.state == SCE_PS_HEXSTRING) {
  160. if (sc.ch == '>') {
  161. sc.ForwardSetState(SCE_PS_DEFAULT);
  162. } else if (!IsABaseNDigit(sc.ch, 16) && !IsAWhitespaceChar(sc.ch)) {
  163. sc.SetState(SCE_PS_HEXSTRING);
  164. styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
  165. }
  166. } else if (sc.state == SCE_PS_BASE85STRING) {
  167. if (sc.Match('~', '>')) {
  168. sc.Forward();
  169. sc.ForwardSetState(SCE_PS_DEFAULT);
  170. } else if (!IsABase85Char(sc.ch) && !IsAWhitespaceChar(sc.ch)) {
  171. sc.SetState(SCE_PS_BASE85STRING);
  172. styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
  173. }
  174. }
  175. // Determine if a new state should be entered.
  176. if (sc.state == SCE_C_DEFAULT) {
  177. if (sc.ch == '[' || sc.ch == ']') {
  178. sc.SetState(SCE_PS_PAREN_ARRAY);
  179. } else if (sc.ch == '{' || sc.ch == '}') {
  180. sc.SetState(SCE_PS_PAREN_PROC);
  181. } else if (sc.ch == '/') {
  182. if (sc.chNext == '/') {
  183. sc.SetState(SCE_PS_IMMEVAL);
  184. sc.Forward();
  185. } else {
  186. sc.SetState(SCE_PS_LITERAL);
  187. }
  188. } else if (sc.ch == '<') {
  189. if (sc.chNext == '<') {
  190. sc.SetState(SCE_PS_PAREN_DICT);
  191. sc.Forward();
  192. } else if (sc.chNext == '~') {
  193. sc.SetState(SCE_PS_BASE85STRING);
  194. sc.Forward();
  195. } else {
  196. sc.SetState(SCE_PS_HEXSTRING);
  197. }
  198. } else if (sc.ch == '>' && sc.chNext == '>') {
  199. sc.SetState(SCE_PS_PAREN_DICT);
  200. sc.Forward();
  201. } else if (sc.ch == '>' || sc.ch == ')') {
  202. sc.SetState(SCE_C_DEFAULT);
  203. styler.ColourTo(sc.currentPos, SCE_PS_BADSTRINGCHAR);
  204. } else if (sc.ch == '(') {
  205. sc.SetState(SCE_PS_TEXT);
  206. nestTextCurrent = 1;
  207. } else if (sc.ch == '%') {
  208. if (sc.chNext == '%' && sc.atLineStart) {
  209. sc.SetState(SCE_PS_DSC_COMMENT);
  210. sc.Forward();
  211. if (sc.chNext == '+') {
  212. sc.Forward();
  213. sc.ForwardSetState(SCE_PS_DSC_VALUE);
  214. }
  215. } else {
  216. sc.SetState(SCE_PS_COMMENT);
  217. }
  218. } else if ((sc.ch == '+' || sc.ch == '-' || sc.ch == '.') &&
  219. IsABaseNDigit(sc.chNext, 10)) {
  220. sc.SetState(SCE_PS_NUMBER);
  221. numRadix = 0;
  222. numHasPoint = (sc.ch == '.');
  223. numHasExponent = false;
  224. numHasSign = (sc.ch == '+' || sc.ch == '-');
  225. } else if ((sc.ch == '+' || sc.ch == '-') && sc.chNext == '.' &&
  226. IsABaseNDigit(sc.GetRelative(2), 10)) {
  227. sc.SetState(SCE_PS_NUMBER);
  228. numRadix = 0;
  229. numHasPoint = false;
  230. numHasExponent = false;
  231. numHasSign = true;
  232. } else if (IsABaseNDigit(sc.ch, 10)) {
  233. sc.SetState(SCE_PS_NUMBER);
  234. numRadix = 0;
  235. numHasPoint = false;
  236. numHasExponent = false;
  237. numHasSign = false;
  238. } else if (!IsAWhitespaceChar(sc.ch)) {
  239. sc.SetState(SCE_PS_NAME);
  240. }
  241. }
  242. if (sc.atLineEnd)
  243. styler.SetLineState(lineCurrent, nestTextCurrent);
  244. }
  245. sc.Complete();
  246. }
  247. static void FoldPSDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
  248. Accessor &styler) {
  249. bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
  250. bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
  251. Sci_PositionU endPos = startPos + length;
  252. int visibleChars = 0;
  253. Sci_Position lineCurrent = styler.GetLine(startPos);
  254. int levelCurrent = SC_FOLDLEVELBASE;
  255. if (lineCurrent > 0)
  256. levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
  257. int levelMinCurrent = levelCurrent;
  258. int levelNext = levelCurrent;
  259. char chNext = styler[startPos];
  260. int styleNext = styler.StyleAt(startPos);
  261. for (Sci_PositionU i = startPos; i < endPos; i++) {
  262. char ch = chNext;
  263. chNext = styler.SafeGetCharAt(i + 1);
  264. int style = styleNext;
  265. styleNext = styler.StyleAt(i + 1);
  266. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); //mac??
  267. if ((style & 31) == SCE_PS_PAREN_PROC) {
  268. if (ch == '{') {
  269. // Measure the minimum before a '{' to allow
  270. // folding on "} {"
  271. if (levelMinCurrent > levelNext) {
  272. levelMinCurrent = levelNext;
  273. }
  274. levelNext++;
  275. } else if (ch == '}') {
  276. levelNext--;
  277. }
  278. }
  279. if (atEOL) {
  280. int levelUse = levelCurrent;
  281. if (foldAtElse) {
  282. levelUse = levelMinCurrent;
  283. }
  284. int lev = levelUse | levelNext << 16;
  285. if (visibleChars == 0 && foldCompact)
  286. lev |= SC_FOLDLEVELWHITEFLAG;
  287. if (levelUse < levelNext)
  288. lev |= SC_FOLDLEVELHEADERFLAG;
  289. if (lev != styler.LevelAt(lineCurrent)) {
  290. styler.SetLevel(lineCurrent, lev);
  291. }
  292. lineCurrent++;
  293. levelCurrent = levelNext;
  294. levelMinCurrent = levelCurrent;
  295. visibleChars = 0;
  296. }
  297. if (!isspacechar(ch))
  298. visibleChars++;
  299. }
  300. }
  301. static const char * const psWordListDesc[] = {
  302. "PS Level 1 operators",
  303. "PS Level 2 operators",
  304. "PS Level 3 operators",
  305. "RIP-specific operators",
  306. "User-defined operators",
  307. 0
  308. };
  309. LexerModule lmPS(SCLEX_PS, ColourisePSDoc, "ps", FoldPSDoc, psWordListDesc);