Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

334 linhas
11 KiB

  1. unit uengShaderFileParser;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. Classes, SysUtils
  7. {$IFDEF USE_BITSPACE_UTILS}
  8. , uutlGenerics
  9. {$ELSE}
  10. , fgl
  11. {$ENDIF}
  12. ;
  13. type
  14. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  15. TengTokenParameter = packed record
  16. Name: String;
  17. Quoted: Boolean;
  18. Line: Integer;
  19. Col: Integer;
  20. end;
  21. TengTokenParameterList = class(specialize TutlSimpleList<TengTokenParameter>)
  22. private
  23. fFilename: String;
  24. public
  25. property Filename: String read fFilename;
  26. constructor Create(const aFilename: String);
  27. end;
  28. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  29. TengParseArgs = class
  30. private
  31. fFilename: String;
  32. fCode: TStringList;
  33. fLineLength: Integer;
  34. fLineCount: Integer;
  35. fCurrentLine: String;
  36. fCurrentChar: Char;
  37. fCol: Integer;
  38. fLine: Integer;
  39. procedure SetCol(const aValue: Integer);
  40. procedure SetLine(const aValue: Integer);
  41. function GetEndOfLine: Boolean;
  42. function GetEndOfFile: Boolean;
  43. function GetCode: TStrings;
  44. public
  45. property Code: TStrings read GetCode;
  46. property LineLength: Integer read fLineLength;
  47. property LineCount: Integer read fLineCount;
  48. property CurrentLine: String read fCurrentLine;
  49. property CurrentChar: Char read fCurrentChar;
  50. property EndOfLine: Boolean read GetEndOfLine;
  51. property EndOfFile: Boolean read GetEndOfFile;
  52. property Filename: String read fFilename;
  53. property Col: Integer read fCol write SetCol;
  54. property Line: Integer read fLine write SetLine;
  55. procedure NextCol;
  56. procedure NextLine;
  57. function ExtractToken(const aParameters: TengTokenParameterList): Boolean;
  58. function GetTokenPreview(var aToken: String): Boolean;
  59. constructor Create(const aStream: TStream; const aFilename: String);
  60. destructor Destroy; override;
  61. end;
  62. implementation
  63. uses
  64. uengShaderFileConstants, uengShaderFileTypes;
  65. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. //TengTokenParameterList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  67. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. constructor TengTokenParameterList.Create(const aFilename: String);
  69. begin
  70. inherited Create(true);
  71. fFilename := aFilename;
  72. end;
  73. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  74. //TengParseArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  75. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  76. procedure TengParseArgs.SetCol(const aValue: Integer);
  77. begin
  78. fCol := aValue;
  79. if not EndOfLine
  80. then fCurrentChar := fCurrentLine[fCol]
  81. else fCurrentChar := #0;
  82. end;
  83. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  84. procedure TengParseArgs.SetLine(const aValue: Integer);
  85. begin
  86. fLine := aValue;
  87. if not EndOfFile then begin
  88. fCurrentLine := fCode[fLine];
  89. fLineLength := Length(fCurrentLine);
  90. end else begin
  91. fCurrentLine := '';
  92. fLineLength := 0;
  93. end;
  94. Col := 1;
  95. end;
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. function TengParseArgs.GetEndOfLine: Boolean;
  98. begin
  99. result := (fCol > fLineLength)
  100. end;
  101. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  102. function TengParseArgs.GetEndOfFile: Boolean;
  103. begin
  104. result := (fLine >= fLineCount);
  105. end;
  106. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  107. procedure TengParseArgs.NextCol;
  108. begin
  109. Col := Col + 1;
  110. end;
  111. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  112. procedure TengParseArgs.NextLine;
  113. begin
  114. Line := Line + 1;
  115. end;
  116. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  117. function TengParseArgs.ExtractToken(const aParameters: TengTokenParameterList): Boolean;
  118. type
  119. TCharType = (
  120. ctUnknown,
  121. ctValidTokenChar,
  122. ctInvalidTokenChar
  123. );
  124. TParseFlag = (
  125. pfQuote,
  126. pfInToken,
  127. pfIsComment,
  128. pfCommentTokenAdded
  129. );
  130. TParseFlags = set of TParseFlag;
  131. var
  132. flags: TParseFlags;
  133. ct: TCharType;
  134. s: String;
  135. pLine, pCol, oldLine, oldCol: Integer;
  136. procedure AddPart(const aTrimAndCheck: Boolean = true);
  137. var
  138. len: Integer;
  139. p: TengTokenParameter;
  140. begin
  141. if aTrimAndCheck then
  142. s := Trim(s);
  143. if not aTrimAndCheck or (s <> '') then begin
  144. len := Length(s);
  145. if aTrimAndCheck and
  146. ( (s[1] = TOKEN_CHAR_QUOTE) and
  147. (s[len] = TOKEN_CHAR_QUOTE)) then
  148. begin
  149. if not (s[1] = TOKEN_CHAR_QUOTE) then
  150. raise EengShaderPart.Create('missing leading quote char', Line, Col, Filename);
  151. if not (s[len] = TOKEN_CHAR_QUOTE) then
  152. raise EengShaderPart.Create('missing trailing quote char', Line, Col, Filename);
  153. delete(s, len, 1);
  154. delete(s, 1, 1);
  155. p.Quoted := true;
  156. end else
  157. p.Quoted := false;
  158. p.Name := s;
  159. p.Line := pLine;
  160. p.Col := pCol;
  161. aParameters.Add(p);
  162. end;
  163. s := '';
  164. pLine := Line;
  165. pCol := Col;
  166. ct := ctUnknown;
  167. end;
  168. begin
  169. result := false;
  170. aParameters.Clear;
  171. if (CurrentChar <> TOKEN_CHAR_BEGIN) or
  172. (Col + 1 > LineLength) or
  173. ( (CurrentLine[Col+1] <> TOKEN_CHAR_IDENT) and
  174. (CurrentLine[Col+1] <> TOKEN_CHAR_COMMENT))
  175. then
  176. exit;
  177. result := true;
  178. s := '';
  179. ct := ctUnknown;
  180. oldLine := Line;
  181. oldCol := Col;
  182. flags := [];
  183. if (CurrentLine[Col+1] = TOKEN_CHAR_COMMENT) then
  184. Include(flags, pfIsComment);
  185. AddPart; // initialize
  186. while not EndOfFile do begin
  187. while not EndOfLine do begin
  188. case CurrentChar of
  189. TOKEN_CHAR_BEGIN: begin
  190. if (pfQuote in flags) then
  191. s := s + CurrentChar
  192. else if not (pfInToken in flags) then
  193. Include(flags, pfInToken)
  194. else
  195. EengShaderPart.Create('invalid char in token', Line, Col, Filename);
  196. end;
  197. TOKEN_CHAR_END: begin
  198. if not (pfQuote in flags) then begin
  199. AddPart(not (pfIsComment in flags));
  200. NextCol;
  201. if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_CHAR_IDENT) then
  202. raise EengShaderPart.Create('empty token', Line, Col, Filename);
  203. exit;
  204. end else
  205. s := s + CurrentChar;
  206. end;
  207. TOKEN_CHAR_QUOTE: begin
  208. if not (pfQuote in flags) and not (pfIsComment in flags) then
  209. AddPart;
  210. s := s + CurrentChar;
  211. if (pfQuote in flags)
  212. then exclude(flags, pfQuote)
  213. else include(flags, pfQuote);
  214. if not (pfQuote in flags) and not (pfIsComment in flags) then
  215. AddPart;
  216. end;
  217. TOKEN_CHAR_COMMENT: begin
  218. s := s + CurrentChar;
  219. if (pfIsComment in flags) and not (pfCommentTokenAdded in flags) then begin
  220. include(flags, pfCommentTokenAdded);
  221. AddPart(false);
  222. end;
  223. end;
  224. else
  225. if not (pfQuote in flags) and not (pfIsComment in flags) then begin
  226. if (CurrentChar in TOKEN_SPLIT_CHARS) then begin
  227. AddPart;
  228. end else if (CurrentChar in VALID_TOKEN_CHARS) then begin
  229. if (ct <> ctValidTokenChar) then
  230. AddPart;
  231. ct := ctValidTokenChar;
  232. end else begin
  233. if (ct <> ctInvalidTokenChar) then
  234. AddPart;
  235. ct := ctInvalidTokenChar;
  236. end;
  237. end;
  238. s := s + CurrentChar;
  239. end;
  240. NextCol;
  241. end;
  242. s := s + sLineBreak;
  243. NextLine;
  244. end;
  245. raise EengShaderPart.Create('incomplete token', oldLine, oldCol, Filename);
  246. end;
  247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. function TengParseArgs.GetCode: TStrings;
  249. begin
  250. result := fCode;
  251. end;
  252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  253. function TengParseArgs.GetTokenPreview(var aToken: String): Boolean;
  254. var
  255. c: Integer;
  256. begin
  257. result := false;
  258. if (CurrentChar <> TOKEN_CHAR_BEGIN) or
  259. (Col >= LineLength) or
  260. not (CurrentLine[Col + 1] in [TOKEN_CHAR_IDENT, TOKEN_CHAR_COMMENT])
  261. then exit;
  262. result := true;
  263. aToken := CurrentChar;
  264. if (aToken = TOKEN_CHAR_COMMANT_END) then
  265. exit;
  266. c := Col + 1;
  267. case CurrentLine[c] of
  268. TOKEN_CHAR_IDENT: begin
  269. aToken := '';
  270. repeat
  271. aToken := aToken + CurrentLine[c];
  272. inc(c);
  273. until (c > LineLength) or not (CurrentLine[c] in VALID_TOKEN_CHARS);
  274. aToken := Trim(aToken);
  275. if (aToken = TOKEN_CHAR_IDENT) then
  276. raise EengInvalidToken.Create('empty token', Line, Col, Filename);
  277. end;
  278. TOKEN_CHAR_COMMENT:
  279. aToken := TOKEN_CHAR_COMMENT;
  280. end;
  281. end;
  282. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. constructor TengParseArgs.Create(const aStream: TStream; const aFilename: String);
  284. begin
  285. inherited Create;
  286. fFilename := aFilename;
  287. fCode := TStringList.Create;
  288. fCode.LoadFromStream(aStream);
  289. fLineCount := fCode.Count;
  290. Line := 0;
  291. end;
  292. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  293. destructor TengParseArgs.Destroy;
  294. begin
  295. FreeAndNil(fCode);
  296. inherited Destroy;
  297. end;
  298. end.