sh_pas.pp 7.9 KB

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