sh_pas.pp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. {
  2. "SHEdit" - Text editor with syntax highlighting
  3. Copyright (C) 1999-2000 by Sebastian Guenther ([email protected])
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. }
  10. // Syntax highlighting class for Pascal sources
  11. // !!! Slightly modified version for fpDoc !!!
  12. {$MODE objfpc}
  13. {$H+}
  14. {$IFDEF Debug}
  15. {$ASSERTIONS On}
  16. {$ENDIF}
  17. unit sh_pas;
  18. interface
  19. const
  20. LF_SH_Valid = $01;
  21. LF_SH_Multiline1 = $02;
  22. LF_SH_Multiline2 = $04;
  23. LF_SH_Multiline3 = $08;
  24. LF_SH_Multiline4 = $10;
  25. LF_SH_Multiline5 = $20;
  26. LF_SH_Multiline6 = $40;
  27. LF_SH_Multiline7 = $80;
  28. LF_Escape = #10;
  29. shDefault = 1;
  30. shInvalid = 2;
  31. shSymbol = 3;
  32. shKeyword = 4;
  33. shComment = 5;
  34. shDirective = 6;
  35. shNumbers = 7;
  36. shCharacters = 8;
  37. shStrings = 9;
  38. shAssembler = 10;
  39. procedure DoPascalHighlighting(var flags: Byte; source, dest: PChar);
  40. implementation
  41. uses Strings;
  42. const
  43. LF_SH_Comment1 = LF_SH_Multiline1; { Normal braced Comments}
  44. LF_SH_Comment2 = LF_SH_Multiline2; { (* *) Comments}
  45. LF_SH_Asm = LF_SH_Multiline3;
  46. MaxKeywordLength = 15;
  47. MaxKeyword = 60;
  48. KeywordTable: array[0..MaxKeyword] of String =
  49. ('AND', 'ARRAY', 'ASM', 'ASSEMBLER',
  50. 'BEGIN', 'BREAK',
  51. 'CASE', 'CONST', 'CONSTRUCTOR', 'CLASS',
  52. 'DEFAULT', 'DESTRUCTOR', 'DIV', 'DO', 'DOWNTO',
  53. 'ELSE', 'END', 'EXCEPT', 'EXIT',
  54. 'FINALIZATION', 'FINALLY', 'FOR', 'FUNCTION',
  55. 'GOTO',
  56. 'IF', 'IMPLEMENTATION', 'IN', 'INHERITED', 'INITIALIZATION', 'INTERFACE',
  57. 'NIL', 'NOT',
  58. 'OBJECT', 'OF', 'ON', 'OR', 'OVERRIDE',
  59. 'PACKED', 'PRIVATE', 'PROCEDURE', 'PROGRAM', 'PROPERTY', 'PROTECTED',
  60. 'PUBLIC', 'PUBLISHED',
  61. 'RAISE', 'RECORD', 'REPEAT', 'RESOURCESTRING',
  62. 'SET',
  63. 'THEN', 'TRY', 'TYPE',
  64. 'UNIT', 'UNTIL', 'USES',
  65. 'VAR', 'VIRTUAL',
  66. 'WHILE', 'WITH',
  67. 'XOR');
  68. KeywordAsmIndex = 2;
  69. procedure DoPascalHighlighting(var flags: Byte; source, dest: PChar);
  70. var
  71. dp: Integer; // Destination position - current offset in dest
  72. LastSHPos: Integer; // Position of last highlighting character, or 0
  73. procedure AddSH(sh: Byte);
  74. begin
  75. ASSERT(sh > 0);
  76. if (LastSHPos > 0) and (dp = LastSHPos + 1) then Dec(dp, 2);
  77. dest[dp] := LF_Escape; Inc(dp);
  78. LastSHPos := dp;
  79. dest[dp] := Chr(sh); Inc(dp);
  80. end;
  81. procedure PutChar;
  82. begin
  83. dest[dp] := source[0]; Inc(dp); Inc(source);
  84. end;
  85. procedure PutChars(S : String);
  86. Var
  87. C : char;
  88. begin
  89. for C in S do
  90. begin
  91. dest[dp] := c;
  92. Inc(dp);
  93. Inc(source);
  94. end;
  95. end;
  96. procedure ProcessComment1;
  97. begin
  98. while source[0] <> #0 do begin
  99. if source[0] = '}' then begin
  100. PutChar;
  101. flags := flags and not LF_SH_Comment1;
  102. AddSH(shDefault);
  103. break;
  104. end;
  105. PutChar;
  106. end;
  107. end;
  108. procedure ProcessComment2;
  109. begin
  110. while source[0] <> #0 do begin
  111. if (source[0] = '*') and (source[1] = ')') then begin
  112. PutChar; PutChar;
  113. flags := flags and not LF_SH_Comment2;
  114. AddSH(shDefault);
  115. break;
  116. end;
  117. PutChar;
  118. end;
  119. end;
  120. { Checks if we are at the beginning of a comment (or directive) and processes
  121. all types of comments and directives, or returns False }
  122. function CheckForComment: Boolean;
  123. begin
  124. Result := True;
  125. if source[0] = '{' then begin
  126. if source[1] = '$' then
  127. AddSH(shDirective)
  128. else
  129. AddSH(shComment);
  130. PutChar;
  131. flags := flags or LF_SH_Comment1;
  132. ProcessComment1;
  133. end else if (source[0] = '(') and (source[1] = '*') then begin
  134. AddSH(shComment);
  135. PutChar; PutChar;
  136. flags := flags or LF_SH_Comment2;
  137. ProcessComment2;
  138. end else if (source[0] = '/') and (source[1] = '/') then begin
  139. AddSH(shComment);
  140. repeat PutChar until source[0] = #0;
  141. AddSH(shDefault);
  142. end else
  143. Result := False;
  144. end;
  145. procedure ProcessAsm;
  146. var
  147. LastChar: Char;
  148. begin
  149. LastChar := ' ';
  150. while source[0] <> #0 do begin
  151. if (LastChar in [' ', #9, #10, #13]) and
  152. (UpCase(source[0]) = 'E') and (UpCase(source[1]) = 'N') and
  153. (UpCase(source[2]) = 'D') then begin
  154. AddSH(shKeyword);
  155. PutChar; PutChar; PutChar;
  156. flags := flags and not LF_SH_Asm;
  157. AddSH(shDefault);
  158. break;
  159. end else
  160. if CheckForComment then LastChar := ' '
  161. else begin
  162. LastChar := source[0];
  163. PutChar;
  164. end;
  165. end;
  166. end;
  167. procedure ProcessSymbol;
  168. begin
  169. AddSH(shSymbol);
  170. if (source[0] = ':') and (source[1] = '=') then
  171. PutChar;
  172. PutChar;
  173. AddSH(shDefault);
  174. end;
  175. function CheckForKeyword: Boolean;
  176. var
  177. keyword, ukeyword: string;
  178. i, j: Integer;
  179. begin
  180. i := 1;
  181. SetLength(KeyWord,MaxKeywordLength);
  182. SetLength(UKeyWord,MaxKeywordLength);
  183. while (source[i] <> #0) and (i <= MaxKeywordLength) and
  184. (source[i] in ['0'..'9', 'A'..'Z', 'a'..'z']) do begin
  185. keyword[i] := source[i];
  186. ukeyword[i] := UpCase(source[i]);
  187. Inc(i);
  188. end;
  189. SetLength(keyword,I-1);
  190. SetLength(ukeyword,I-1);
  191. Result := False;
  192. if i < MaxKeywordLength then
  193. for j := 0 to MaxKeyword do
  194. if KeywordTable[j]=ukeyword then begin
  195. Result := True; break;
  196. end;
  197. if not Result then exit;
  198. Inc(source, i);
  199. AddSH(shKeyword);
  200. PutChars(keyword);
  201. if j <> KeywordAsmIndex then
  202. AddSH(shDefault)
  203. else begin
  204. AddSH(shAssembler);
  205. flags := flags or LF_SH_Asm;
  206. ProcessAsm;
  207. end;
  208. end;
  209. var
  210. StringLength: Integer;
  211. begin
  212. if Source=Nil then exit;
  213. dp := 0;
  214. LastSHPos := 0;
  215. if (flags and LF_SH_Comment1) <> 0 then begin
  216. AddSH(shComment);
  217. ProcessComment1;
  218. end;
  219. if (flags and LF_SH_Comment2) <> 0 then begin
  220. AddSH(shComment);
  221. ProcessComment2;
  222. end;
  223. if (flags and LF_SH_Asm) <> 0 then begin
  224. AddSH(shAssembler);
  225. ProcessAsm;
  226. end;
  227. while source[0] <> #0 do begin
  228. if CheckForComment then continue;
  229. case source[0] of
  230. ',', ';', ':', '.', '(', ')', '[', ']', '<', '>', '=',
  231. '*', '/', '+', '-', '^', '&', '@': ProcessSymbol;
  232. '#': begin
  233. AddSH(shCharacters);
  234. PutChar;
  235. if source[0] = '$' then PutChar;
  236. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  237. AddSH(shDefault);
  238. end;
  239. '$': begin
  240. AddSH(shNumbers);
  241. PutChar;
  242. while source[0] in ['0'..'9', 'A'..'F', 'a'..'f'] do PutChar;
  243. AddSH(shDefault);
  244. end;
  245. '0'..'9': begin
  246. AddSH(shNumbers);
  247. PutChar;
  248. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  249. AddSH(shDefault);
  250. end;
  251. '''': begin
  252. AddSH(shStrings);
  253. PutChar;
  254. StringLength := 0;
  255. while source[0] <> #0 do begin
  256. if source[0] = '''' then
  257. if source[1] = '''' then PutChar
  258. else begin
  259. PutChar; break;
  260. end;
  261. Inc(StringLength);
  262. PutChar;
  263. end;
  264. if StringLength = 1 then
  265. dest[LastSHPos] := Chr(shCharacters);
  266. if (source[0] = #0) and (dest[dp - 1] <> '''') then
  267. dest[LastSHPos] := Chr(shInvalid);
  268. AddSH(shDefault);
  269. end;
  270. '_', 'A'..'Z', 'a'..'z': begin
  271. if not CheckForKeyword then
  272. repeat
  273. PutChar
  274. until not (source[0] in ['0'..'9', '_', 'A'..'Z', 'a'..'z']);
  275. end;
  276. ' ': PutChar;
  277. else begin
  278. AddSH(shInvalid);
  279. PutChar; // = found an invalid char!
  280. AddSH(shDefault);
  281. end;
  282. end;
  283. end;
  284. dest[dp] := #0;
  285. end;
  286. end.