Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 

1926 Zeilen
64 KiB

  1. unit HeaderGenerator;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, DOM, uutlGenerics, variants;
  6. type
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. THeaderGenerator = class(TObject)
  9. private type
  10. TStringTree = class(TObject)
  11. public type
  12. TItemList = specialize TutlList<TStringTree>;
  13. TItemMap = specialize TutlMap<string, TStringTree>;
  14. private
  15. fLinesBefore: TStringList;
  16. fLinesAfter: TStringList;
  17. fItemList: TItemList;
  18. fItemMap: TItemMap;
  19. function GetItem(const aName: String): TStringTree;
  20. function GetItemCount: Integer;
  21. function GetItemsByIndex(const aIndex: Integer): TStringTree;
  22. function GetLinesAfter: TStrings;
  23. function GetLinesBefore: TStrings;
  24. function GetText: String;
  25. public
  26. property Text: String read GetText;
  27. property LinesBefore: TStrings read GetLinesBefore;
  28. property LinesAfter: TStrings read GetLinesAfter;
  29. property ItemCount: Integer read GetItemCount;
  30. property Items [const aName: String]: TStringTree read GetItem;
  31. property ItemsByIndex[const aIndex: Integer]: TStringTree read GetItemsByIndex;
  32. function IndexOf(const aItem: TStringTree): Integer;
  33. function GetOrCreateItem(const aName: String): TStringTree;
  34. function CreateItemAt(const aName: String; const aIndex: Integer): TStringTree;
  35. function DestroyItem(const aName: String): Boolean;
  36. procedure Clear;
  37. constructor Create;
  38. destructor Destroy; override;
  39. end;
  40. ////////////////////////////////////////////////////////////////////////////////////////////
  41. TvkObjectType = (
  42. otUnknown,
  43. otType,
  44. otHandle,
  45. otEnum,
  46. otConst,
  47. otFuncPtr,
  48. otStruct,
  49. otCommand);
  50. TvkObjectTypes = set of TvkObjectType;
  51. TvkObject = class;
  52. TvkObjectList = class(specialize TutlList<TvkObject>)
  53. public
  54. function IndexOfObj(const aName: WideString; const aTypes: TvkObjectTypes): Integer;
  55. function FindObj(const aName: WideString; const aTypes: TvkObjectTypes; out aObject): Boolean;
  56. function GetPascalName(const aName: WideString; const aPointer: Integer; const aArrSize: WideString = ''): WideString;
  57. function GenerateCode(const aName: WideString; const aCode: TStringTree): Boolean;
  58. procedure AddObject(const aObj: TvkObject);
  59. end;
  60. ////////////////////////////////////////////////////////////////////////////////////////////
  61. TvkObject = class(TObject)
  62. private
  63. fType: TvkObjectType;
  64. fName: WideString;
  65. fComment: WideString;
  66. fList: TvkObjectList;
  67. protected
  68. function GetDependencyOrder: Integer; virtual;
  69. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); virtual;
  70. {%H-}constructor Create(const aType: TvkObjectType);
  71. public
  72. property VkType: TvkObjectType read fType;
  73. property Name: WideString read fName write fName;
  74. property Comment: WideString read fComment write fComment;
  75. property List: TvkObjectList read fList write fList;
  76. function GetPascalName(const aPointer: Integer; const aArrSize: WideString): WideString;
  77. procedure ReadXml(const xml: TDOMNode); virtual;
  78. procedure GenerateCode(const aCode: TStringTree); virtual;
  79. public
  80. class procedure CreateFromXml(const xml: TDOMNode; const aList: TvkObjectList);
  81. end;
  82. ////////////////////////////////////////////////////////////////////////////////////////////
  83. TvkTypeBase = class(TvkObject)
  84. private
  85. fParent: WideString;
  86. fAlias: WideString;
  87. protected
  88. function GetDependencyOrder: Integer; override;
  89. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  90. public
  91. property Parent: WideString read fParent write fParent;
  92. property Alias: WideString read fAlias write fAlias;
  93. procedure GenerateCode(const aCode: TStringTree); override;
  94. end;
  95. ////////////////////////////////////////////////////////////////////////////////////////////
  96. TvkType = class(TvkTypeBase)
  97. public
  98. procedure ReadXml(const xml: TDOMNode); override;
  99. constructor Create;
  100. end;
  101. ////////////////////////////////////////////////////////////////////////////////////////////
  102. TvkHandle = class(TvkTypeBase)
  103. private
  104. fNonDispatchable: Boolean;
  105. public
  106. property NonDispatchable: Boolean read fNonDispatchable write fNonDispatchable;
  107. procedure ReadXml(const xml: TDOMNode); override;
  108. procedure GenerateCode(const aCode: TStringTree); override;
  109. constructor Create;
  110. end;
  111. ////////////////////////////////////////////////////////////////////////////////////////////
  112. TvkFunctionBase = class(TvkObject)
  113. private type
  114. TArgument = class(TObject)
  115. Typ: WideString;
  116. Name: WideString;
  117. IsPointer: Integer;
  118. IsConst: Boolean;
  119. end;
  120. TArgumentList = specialize TutlList<TArgument>;
  121. private
  122. fReturnValue: TArgument;
  123. fArguments: TArgumentList;
  124. protected
  125. function GetDependencyOrder: Integer; override;
  126. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  127. procedure GenerateFunctionPtr(const aCode, aSub: TStringTree);
  128. {%H-}constructor Create(const aType: TvkObjectType);
  129. public
  130. property ReturnValue: TArgument read fReturnValue;
  131. property Arguments: TArgumentList read fArguments;
  132. destructor Destroy; override;
  133. end;
  134. ////////////////////////////////////////////////////////////////////////////////////////////
  135. TvkFunctionPtr = class(TvkFunctionBase)
  136. public
  137. procedure ReadXml(const xml: TDOMNode); override;
  138. procedure GenerateCode(const aCode: TStringTree); override;
  139. constructor Create;
  140. end;
  141. ////////////////////////////////////////////////////////////////////////////////////////////
  142. TvkCommand = class(TvkFunctionBase)
  143. public
  144. procedure ReadXml(const xml: TDOMNode); override;
  145. procedure GenerateCode(const aCode: TStringTree); override;
  146. constructor Create;
  147. end;
  148. ////////////////////////////////////////////////////////////////////////////////////////////
  149. TvkStruct = class(TvkObject)
  150. private type
  151. TMember = class(TObject)
  152. Typ: WideString;
  153. Name: WideString;
  154. ArrSize: WideString;
  155. IsPointer: Integer;
  156. IsConst: Boolean;
  157. end;
  158. TMemberList = specialize TutlList<TMember>;
  159. private
  160. fIsUnion: Boolean;
  161. fMember: TMemberList;
  162. protected
  163. function GetDependencyOrder: Integer; override;
  164. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  165. public
  166. property Member: TMemberList read fMember;
  167. property IsUnion: Boolean read fIsUnion write fIsUnion;
  168. procedure ReadXml(const xml: TDOMNode); override;
  169. procedure GenerateCode(const aCode: TStringTree); override;
  170. constructor Create;
  171. destructor Destroy; override;
  172. end;
  173. ////////////////////////////////////////////////////////////////////////////////////////////
  174. TvkEnum = class(TvkObject)
  175. private type
  176. TValue = class(TObject)
  177. Name: WideString;
  178. Value: Variant;
  179. IsBit: Boolean;
  180. end;
  181. TValueList = specialize TutlList<TValue>;
  182. private
  183. fExpands: WideString;
  184. fValues: TValueList;
  185. protected
  186. procedure GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString); override;
  187. public
  188. property Expands: WideString read fExpands write fExpands;
  189. property Values: TValueList read fValues;
  190. procedure ReadXml(const xml: TDOMNode); override;
  191. procedure GenerateCode(const aCode: TStringTree); override;
  192. constructor Create;
  193. destructor Destroy; override;
  194. end;
  195. ////////////////////////////////////////////////////////////////////////////////////////////
  196. TvkConst = class(TvkObject)
  197. private
  198. fValue: Variant;
  199. public
  200. property Value: Variant read fValue write fValue;
  201. procedure GenerateCode(const aCode: TStringTree); override;
  202. constructor Create;
  203. end;
  204. private const
  205. VK_OBJECT_TYPES: TvkObjectTypes = [ otType, otHandle, otFuncPtr, otStruct, otEnum ];
  206. VK_OBJECT_ALL: TvkObjectTypes = [ low(TvkObjectType) .. high(TvkObjectType) ];
  207. private
  208. fDocument: TXMLDocument;
  209. fObjects: TvkObjectList;
  210. fComment: WideString;
  211. public
  212. procedure ReadFile(const aFilename: String);
  213. procedure ReadFile(const aStream: TStream);
  214. procedure GenerateCode(const aName: WideString; const aTemplate: String; const aOutput: String);
  215. procedure Clear;
  216. constructor Create;
  217. destructor Destroy; override;
  218. end;
  219. implementation
  220. uses
  221. Math, XMLRead, RegExpr;
  222. type
  223. XmlException = class(Exception)
  224. public
  225. xml: TDOMNode;
  226. constructor Create(const aMsg: WideString; const aXml: TDOMNode);
  227. end;
  228. const
  229. KEYWORD_INTF = 'INTERFACE';
  230. KEYWORD_CONST = 'CONST';
  231. KEYWORD_TYPES = 'TYPES';
  232. KEYWORD_ENUM = 'ENUM';
  233. KEYWORD_ENUM_VALUES = 'ENUM_VALUES';
  234. KEYWORD_STRUCT = 'STRUCT';
  235. KEYWORD_FUNCPTR = 'FUNCPTR';
  236. KEYWORD_COMMAND = 'COMMAND';
  237. KEYWORD_IMPL = 'IMPLEMENTATION';
  238. KEYWORD_COMMENT = 'COMMENT';
  239. KEYWORD_VAR = 'VAR';
  240. KEYWORD_CODE = 'CODE';
  241. KEYWORD_INSTANCE_COMMANDS = 'INSTANCE_COMMANDS';
  242. KEYWORD_DEVICE_COMMANDS = 'DEVICE_COMMANDS';
  243. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  244. function PointerCount(const aStr: AnsiString): Integer;
  245. var i: Integer;
  246. begin
  247. result := 0;
  248. i := Length(aStr);
  249. while (i > 0) do begin
  250. if (aStr[i] = '*') then
  251. inc(result);
  252. dec(i);
  253. end;
  254. end;
  255. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  256. function StrToValue(s: String): Variant;
  257. var
  258. f: TFormatSettings;
  259. rx: TRegExpr;
  260. begin
  261. f.DecimalSeparator := '.';
  262. rx := TRegExpr.Create;
  263. try
  264. result := Unassigned;
  265. rx.Expression := '^-?([0-9]+)$';
  266. if rx.Exec(s) then
  267. result := StrToInt(rx.Match[0]);
  268. rx.Expression := '^0x([0-9A-Fa-f]+)$';
  269. if rx.Exec(s) then
  270. result := '$' + rx.Match[1];
  271. rx.Expression := '^([0-9\.]+)(f|d)?$';
  272. if rx.Exec(s) then begin
  273. result := StrToFloat(rx.Match[1], f);
  274. if (rx.Match[2] = 'd') then
  275. result := Double(result);
  276. end;
  277. rx.Expression := '^\(~0U([L]*)\)$';
  278. if rx.Exec(s) then begin
  279. if (rx.Match[2] = '')
  280. then result := '$' + IntToHex(High(UInt32), 2 * sizeof(UInt32))
  281. else result := '$' + IntToHex(High(UInt64), 2 * sizeof(UInt64));
  282. end;
  283. finally
  284. FreeAndNil(rx);
  285. end;
  286. end;
  287. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  288. function PrepareName(const aName, aType: WideString): WideString;
  289. var
  290. rx: TRegExpr;
  291. s: WideString;
  292. begin
  293. result := aName;
  294. s := '';
  295. if (result = 'type') then
  296. s := 'Type'
  297. else if (result = 'object') then
  298. s := 'Object';
  299. if (s <> '') then begin
  300. rx := TRegExpr.Create('^(T|P)?(Vk)?(.)');
  301. try
  302. if rx.Exec(String(aType))
  303. then result := WideString(LowerCase(rx.Match[3])) + s
  304. else result := 'm' + s;
  305. finally
  306. FreeAndNil(rx);
  307. end;
  308. end;
  309. end;
  310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. function FormatType(const aType: THeaderGenerator.TvkObjectType): WideString;
  312. begin
  313. case aType of
  314. otType: result := 'TYPE';
  315. otHandle: result := 'HANDLE';
  316. otFuncPtr: result := 'FUNCPTR';
  317. otStruct: result := 'STRUCT';
  318. otEnum: result := 'ENUM';
  319. otConst: result := 'CONSTANT';
  320. otCommand: result := 'COMMAND';
  321. else
  322. result := '';
  323. end;
  324. end;
  325. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  326. procedure WriteResolveWarning(const aName: WideString);
  327. begin
  328. WriteLn('WARNING! unable to resolve identifier: ' + aName);
  329. end;
  330. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  331. function GetNodeValue(xml: TDOMNode; const aName: WideString): WideString;
  332. var x: TDOMNode;
  333. begin
  334. x := xml.FindNode(aName);
  335. if not Assigned(x) then
  336. raise XmlException.Create(xml.NodeName + ' without child ''' + aName + '''', xml);
  337. result := x.TextContent;
  338. end;
  339. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  340. function TryGetNodeValue(xml: TDOMNode; const aName: WideString; out aValue: WideString): Boolean;
  341. var x: TDOMNode;
  342. begin
  343. x := xml.FindNode(aName);
  344. result := Assigned(x);
  345. if result then
  346. aValue := x.TextContent;
  347. end;
  348. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  349. function GetNodeValue(xml: TDOMNode; const aName: WideString; const aDefault: WideString): WideString;
  350. var x: TDOMNode;
  351. begin
  352. x := xml.FindNode(aName);
  353. if not Assigned(x)
  354. then result := aDefault
  355. else result := x.TextContent;
  356. end;
  357. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  358. function GetNodeAttrib(xml: TDOMNode; const aName: WideString): WideString;
  359. var x: TDOMNode;
  360. begin
  361. if xml.HasAttributes then begin
  362. x := xml.Attributes.GetNamedItem(aName);
  363. if Assigned(x) then begin
  364. result := x.TextContent;
  365. exit;
  366. end;
  367. end;
  368. raise XmlException.Create(xml.NodeName + ' without ''' + aName + ''' attribute', xml);
  369. end;
  370. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  371. function TryGetNodeAttrib(xml: TDOMNode; const aName: WideString; out aValue: WideString): Boolean;
  372. var x: TDOMNode;
  373. begin
  374. result := true;
  375. if xml.HasAttributes then begin
  376. x := xml.Attributes.GetNamedItem(aName);
  377. if Assigned(x) then begin
  378. aValue := x.TextContent;
  379. exit;
  380. end;
  381. end;
  382. result := false;
  383. end;
  384. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  385. function GetNodeAttrib(xml: TDOMNode; const aName: WideString; const aDefault: WideString): WideString;
  386. var x: TDOMNode;
  387. begin
  388. result := aDefault;
  389. if xml.HasAttributes then begin
  390. x := xml.Attributes.GetNamedItem(aName);
  391. if Assigned(x) then
  392. result := x.TextContent;
  393. end;
  394. end;
  395. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  396. //XmlException//////////////////////////////////////////////////////////////////////////////////////////////////////////
  397. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  398. constructor XmlException.Create(const aMsg: WideString; const aXml: TDOMNode);
  399. begin
  400. inherited Create(String(aMsg + ': ' + aXml.TextContent));
  401. xml := aXml;
  402. end;
  403. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  404. //THeaderGenerator.TStringTree//////////////////////////////////////////////////////////////////////////////////////////
  405. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  406. function THeaderGenerator.TStringTree.GetLinesAfter: TStrings;
  407. begin
  408. result := fLinesAfter;
  409. end;
  410. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  411. function THeaderGenerator.TStringTree.GetLinesBefore: TStrings;
  412. begin
  413. result := fLinesBefore;
  414. end;
  415. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. function THeaderGenerator.TStringTree.GetItem(const aName: String): TStringTree;
  417. begin
  418. result := fItemMap[aName];
  419. end;
  420. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  421. function THeaderGenerator.TStringTree.GetItemCount: Integer;
  422. begin
  423. result := fItemList.Count;
  424. end;
  425. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  426. function THeaderGenerator.TStringTree.GetItemsByIndex(const aIndex: Integer): TStringTree;
  427. begin
  428. result := fItemList[aIndex];
  429. end;
  430. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  431. function THeaderGenerator.TStringTree.GetText: String;
  432. var
  433. i: Integer;
  434. s: String;
  435. procedure AddText(const aText: String; const aCanAddEmpty: Boolean);
  436. begin
  437. if not aCanAddEmpty and (aText = '') then
  438. exit;
  439. result := result + aText + sLineBreak;
  440. end;
  441. begin
  442. result := '';
  443. for i := 0 to fLinesBefore.Count-1 do
  444. AddText(fLinesBefore[i], true);
  445. for i := 0 to fItemList.Count-1 do begin
  446. s := fItemList[i].Text;
  447. if (UpperCase(Trim(s)) = '{$ENDIF}') then
  448. result := TrimRight(result) + sLineBreak;
  449. AddText(s, false);
  450. end;
  451. for i := 0 to fLinesAfter.Count-1 do
  452. AddText(fLinesAfter[i], true);
  453. result := copy(result, 0, Length(result) - Length(sLineBreak));
  454. end;
  455. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  456. function THeaderGenerator.TStringTree.IndexOf(const aItem: TStringTree): Integer;
  457. begin
  458. result := fItemList.IndexOf(aItem);
  459. end;
  460. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  461. function THeaderGenerator.TStringTree.GetOrCreateItem(const aName: String): TStringTree;
  462. begin
  463. result := GetItem(aName);
  464. if not Assigned(result) then begin
  465. result := TStringTree.Create;
  466. fItemMap.Add(aName, result);
  467. fItemList.Add(result);
  468. end;
  469. end;
  470. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  471. function THeaderGenerator.TStringTree.CreateItemAt(const aName: String; const aIndex: Integer): TStringTree;
  472. begin
  473. result := TStringTree.Create;
  474. fItemMap.Add(aName, result);
  475. fItemList.Insert(aIndex, result);
  476. end;
  477. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  478. function THeaderGenerator.TStringTree.DestroyItem(const aName: String): Boolean;
  479. var t: TStringTree;
  480. begin
  481. t := GetItem(aName);
  482. result := Assigned(t);
  483. if result then begin
  484. fItemList.Remove(t);
  485. fItemMap.Delete(aName);
  486. end;
  487. end;
  488. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  489. procedure THeaderGenerator.TStringTree.Clear;
  490. begin
  491. fItemList.Clear;
  492. fItemMap.Clear;
  493. end;
  494. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  495. constructor THeaderGenerator.TStringTree.Create;
  496. begin
  497. inherited Create;
  498. fLinesBefore := TStringList.Create;
  499. fLinesAfter := TStringList.Create;
  500. fItemList := TItemList.Create(false);
  501. fItemMap := TItemMap.Create(true);
  502. end;
  503. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  504. destructor THeaderGenerator.TStringTree.Destroy;
  505. begin
  506. FreeAndNil(fItemList);
  507. FreeAndNil(fItemMap);
  508. FreeAndNil(fLinesBefore);
  509. FreeAndNil(fLinesAfter);
  510. inherited Destroy;
  511. end;
  512. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  513. //THeaderGenerator.TvkObjectList////////////////////////////////////////////////////////////////////////////////////////
  514. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  515. function THeaderGenerator.TvkObjectList.IndexOfObj(const aName: WideString; const aTypes: TvkObjectTypes): Integer;
  516. var o: TvkObject;
  517. begin
  518. if (aName = '') then
  519. raise Exception.Create('empty name');
  520. for result := 0 to Count-1 do begin
  521. o := GetItem(result);
  522. if (o.VkType in aTypes) and (o.Name = aName) then
  523. exit;
  524. end;
  525. result := -1;
  526. end;
  527. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  528. function THeaderGenerator.TvkObjectList.FindObj(const aName: WideString; const aTypes: TvkObjectTypes; out aObject): Boolean;
  529. var i: Integer;
  530. begin
  531. i := IndexOfObj(aName, aTypes);
  532. result := (i >= 0);
  533. if result
  534. then TvkObject(aObject) := GetItem(i)
  535. else TvkObject(aObject) := nil;
  536. end;
  537. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  538. function THeaderGenerator.TvkObjectList.GetPascalName(const aName: WideString; const aPointer: Integer;
  539. const aArrSize: WideString): WideString;
  540. var o: TvkObject;
  541. begin
  542. if FindObj(aName, VK_OBJECT_TYPES, o)
  543. then result := o.GetPascalName(aPointer, aArrSize)
  544. else result := aName;
  545. end;
  546. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  547. function THeaderGenerator.TvkObjectList.GenerateCode(const aName: WideString; const aCode: TStringTree): Boolean;
  548. var o: TvkObject;
  549. begin
  550. result := FindObj(aName, VK_OBJECT_ALL, o);
  551. if result then
  552. o.GenerateCode(aCode);
  553. end;
  554. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  555. procedure THeaderGenerator.TvkObjectList.AddObject(const aObj: TvkObject);
  556. begin
  557. if Assigned(aObj) then begin
  558. Add(aObj);
  559. aObj.List := self;
  560. WriteLn(Format(' %-10s%s', [FormatType(aObj.VkType), aObj.Name]));
  561. end;
  562. end;
  563. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  564. //THeaderGenerator.TvkObject////////////////////////////////////////////////////////////////////////////////////////////
  565. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  566. function THeaderGenerator.TvkObject.GetDependencyOrder: Integer;
  567. begin
  568. result := 0;
  569. end;
  570. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  571. procedure THeaderGenerator.TvkObject.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  572. var
  573. i: Integer;
  574. begin
  575. if (aName = '') then begin
  576. aName := fName;
  577. if (aName = 'void') then
  578. aName := 'VkVoid';
  579. for i := 0 to aPointer-1 do
  580. aName := 'P' + aName;
  581. end;
  582. if (aName = 'VkVoid') then
  583. raise Exception.Create('void can not be used as type');
  584. if (aArrSize <> '') then begin
  585. if TryStrToInt(String(aArrSize), i)
  586. then aName := WideString(Format('array[0..%d] of %s', [i, aName]))
  587. else aName := WideString(Format('array[0..%s-1] of %s', [aArrSize, aName]));
  588. end;
  589. end;
  590. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  591. constructor THeaderGenerator.TvkObject.Create(const aType: TvkObjectType);
  592. begin
  593. inherited Create;
  594. fType := aType;
  595. end;
  596. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  597. function THeaderGenerator.TvkObject.GetPascalName(const aPointer: Integer; const aArrSize: WideString): WideString;
  598. begin
  599. result := '';
  600. GenPascalName(result, aPointer, aArrSize);
  601. end;
  602. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  603. procedure THeaderGenerator.TvkObject.ReadXml(const xml: TDOMNode);
  604. begin
  605. // DUMMY
  606. end;
  607. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  608. procedure THeaderGenerator.TvkObject.GenerateCode(const aCode: TStringTree);
  609. begin
  610. // DUMMY
  611. end;
  612. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  613. class procedure THeaderGenerator.TvkObject.CreateFromXml(const xml: TDOMNode; const aList: TvkObjectList);
  614. var
  615. s, n: WideString;
  616. procedure GenerateVersionEnum;
  617. var
  618. c: TvkConst;
  619. rx: TRegExpr;
  620. begin
  621. rx := TRegExpr.Create('\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)');
  622. try
  623. if not rx.Exec(String(xml.TextContent)) then
  624. raise XmlException.Create('VK_API_VERSION with malformed version', xml);
  625. c := TvkConst.Create;
  626. try
  627. c.Name := 'VK_API_VERSION';
  628. c.Value := (StrToInt(rx.Match[1]) shl 22) or
  629. (StrToInt(rx.Match[2]) shl 12) or
  630. (StrToInt(rx.Match[3]) shl 0);
  631. aList.AddObject(c);
  632. except
  633. FreeAndNil(c);
  634. raise
  635. end;
  636. c := TvkConst.Create;
  637. try
  638. c.Name := 'VK_API_VERSION_MAJOR';
  639. c.Value := StrToInt(rx.Match[1]);
  640. aList.AddObject(c);
  641. except
  642. FreeAndNil(c);
  643. raise
  644. end;
  645. c := TvkConst.Create;
  646. try
  647. c.Name := 'VK_API_VERSION_MINOR';
  648. c.Value := StrToInt(rx.Match[2]);
  649. aList.AddObject(c);
  650. except
  651. FreeAndNil(c);
  652. raise
  653. end;
  654. c := TvkConst.Create;
  655. try
  656. c.Name := 'VK_API_VERSION_BUGFIX';
  657. c.Value := StrToInt(rx.Match[3]);
  658. aList.AddObject(c);
  659. except
  660. FreeAndNil(c);
  661. raise
  662. end;
  663. finally
  664. FreeAndNil(rx);
  665. end;
  666. end;
  667. procedure GenerateConstants;
  668. var
  669. x: TDOMNode;
  670. c: TvkConst;
  671. begin
  672. x := xml.FirstChild;
  673. while Assigned(x) do begin
  674. if (x.NodeName = 'enum') then begin
  675. c := TvkConst.Create;
  676. try
  677. c.Name := GetNodeAttrib(x, 'name');
  678. c.Value := StrToValue(String(GetNodeAttrib(x, 'value')));
  679. if (c.Value = Unassigned) then
  680. raise Exception.Create('Invalid constant value: ' + String(GetNodeAttrib(x, 'value')));
  681. aList.AddObject(c);
  682. except
  683. FreeAndNil(c);
  684. raise;
  685. end;
  686. end;
  687. x := x.NextSibling;
  688. end;
  689. end;
  690. var
  691. obj: TvkObject;
  692. begin
  693. try
  694. obj := nil;
  695. if (xml.NodeName = 'type') and TryGetNodeAttrib(xml, 'category', s) then begin
  696. if (s = 'basetype') or (s = 'bitmask') then
  697. obj := TvkType.Create
  698. else if (s = 'handle') then
  699. obj := TvkHandle.Create
  700. else if (s = 'funcpointer') then
  701. obj := TvkFunctionPtr.Create
  702. else if (s = 'struct') or (s = 'union') then
  703. obj := TvkStruct.Create
  704. else if (s = 'define') and TryGetNodeValue(xml, 'name', n) and (n = 'VK_API_VERSION') then
  705. GenerateVersionEnum;
  706. end else if (xml.NodeName = 'command') then
  707. obj := TvkCommand.Create
  708. else if (xml.NodeName = 'enums') then begin
  709. if not TryGetNodeAttrib(xml, 'type', s) then
  710. GenerateConstants
  711. else if (s = 'enum') or (s = 'bitmask') then
  712. obj := TvkEnum.Create;
  713. end;
  714. if Assigned(obj) then begin
  715. obj.ReadXml(xml);
  716. aList.AddObject(obj);
  717. end;
  718. except
  719. FreeAndNil(obj);
  720. raise;
  721. end;
  722. end;
  723. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  724. //THeaderGenerator.TvkTypeBase//////////////////////////////////////////////////////////////////////////////////////////
  725. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  726. function THeaderGenerator.TvkTypeBase.GetDependencyOrder: Integer;
  727. begin
  728. result := inherited GetDependencyOrder;
  729. if Assigned(List) and (fParent <> '') then
  730. result := max(result, List.IndexOfObj(fParent, VK_OBJECT_TYPES) + 1);
  731. end;
  732. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  733. procedure THeaderGenerator.TvkTypeBase.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  734. var i: Integer;
  735. begin
  736. if (fAlias <> '')
  737. then aName := fAlias
  738. else aName := fName;
  739. if (aName = 'void') then
  740. aName := 'VkVoid';
  741. for i := 0 to aPointer-1 do
  742. aName := 'P' + aName;
  743. if (aName = 'VkVoid') then
  744. raise Exception.Create('void can not be used as type');
  745. inherited GenPascalName(aName, aPointer, aArrSize);
  746. end;
  747. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  748. procedure THeaderGenerator.TvkTypeBase.GenerateCode(const aCode: TStringTree);
  749. var st: TStringTree;
  750. begin
  751. inherited GenerateCode(aCode);
  752. if Assigned(fList) and (fParent <> '') then
  753. fList.GenerateCode(fParent, aCode);
  754. if Assigned(fList) and (fAlias <> '') then
  755. fList.GenerateCode(fAlias, aCode);
  756. st := aCode.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(KEYWORD_TYPES);
  757. if (st.LinesBefore.Count = 0) then
  758. st.LinesBefore.Add('type { simple types }');
  759. st := st.GetOrCreateItem(String(fName));
  760. if (st.LinesBefore.Count = 0) and (fParent <> '') and Assigned(List) then begin
  761. st.LinesBefore.Add(Format(' %-62s = %s;', [ fName, List.GetPascalName(fParent, 0) ]));
  762. st.LinesBefore.Add(Format(' P%-61s = ^%0:s;', [ fName ]));
  763. st.LinesBefore.Add(Format(' PP%-60s = ^P%0:s;', [ fName ]));
  764. st.LinesBefore.Add('');
  765. end;
  766. end;
  767. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  768. //THeaderGenerator.TvkType//////////////////////////////////////////////////////////////////////////////////////////////
  769. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  770. procedure THeaderGenerator.TvkType.ReadXml(const xml: TDOMNode);
  771. begin
  772. inherited ReadXml(xml);
  773. Name := GetNodeValue(xml, 'name');
  774. Parent := GetNodeValue(xml, 'type');
  775. end;
  776. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  777. constructor THeaderGenerator.TvkType.Create;
  778. begin
  779. inherited Create(otType);
  780. end;
  781. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  782. //THeaderGenerator.TvkHandle////////////////////////////////////////////////////////////////////////////////////////////
  783. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  784. constructor THeaderGenerator.TvkHandle.Create;
  785. begin
  786. inherited Create(otHandle);
  787. end;
  788. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  789. procedure THeaderGenerator.TvkHandle.ReadXml(const xml: TDOMNode);
  790. begin
  791. inherited ReadXml(xml);
  792. Name := GetNodeValue (xml, 'name');
  793. fNonDispatchable := (GetNodeValue(xml, 'type') = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE');
  794. Parent := GetNodeAttrib(xml, 'parent', '');
  795. end;
  796. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  797. procedure THeaderGenerator.TvkHandle.GenerateCode(const aCode: TStringTree);
  798. var
  799. st: TStringTree;
  800. s: String;
  801. begin
  802. if Assigned(fList) and (fParent <> '') then
  803. fList.GenerateCode(fParent, aCode);
  804. if Assigned(fList) and (fAlias <> '') then
  805. fList.GenerateCode(fAlias, aCode);
  806. st := aCode.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(KEYWORD_TYPES);
  807. if (st.LinesBefore.Count = 0) then
  808. st.LinesBefore.Add('type { simple types }');
  809. st := st.GetOrCreateItem(String(fName));
  810. if (st.LinesBefore.Count = 0) then begin
  811. s := '^_' + String(fName);
  812. if fNonDispatchable then
  813. s := '{$IFDEF VK_CPU64}' + s + '{$ELSE}VkNonDispatchableHandle{$ENDIF}';
  814. st.LinesBefore.Add(Format(' %-62s = record end;', [ '_' + fName, s ]));
  815. st.LinesBefore.Add(Format(' %-62s = %s;', [ fName, s ]));
  816. st.LinesBefore.Add(Format(' P%-61s = ^%0:s;', [ fName ]));
  817. st.LinesBefore.Add(Format(' PP%-60s = ^P%0:s;', [ fName ]));
  818. st.LinesBefore.Add('');
  819. end;
  820. end;
  821. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  822. function THeaderGenerator.TvkFunctionBase.GetDependencyOrder: Integer;
  823. var a: TArgument;
  824. begin
  825. result := inherited GetDependencyOrder;
  826. if not Assigned(List) then
  827. exit;
  828. for a in fArguments do
  829. result := max(result, List.IndexOfObj(a.Typ, VK_OBJECT_TYPES));
  830. end;
  831. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  832. procedure THeaderGenerator.TvkFunctionBase.GenPascalName(var aName: WideString; const aPointer: Integer;
  833. const aArrSize: WideString);
  834. var rx: TRegExpr;
  835. begin
  836. if (aPointer > 0) then
  837. Exception.Create('function pointer can not be used as pointer type');
  838. if (aArrSize <> '') then
  839. Exception.Create('function pointer can not be used as array type');
  840. rx := TRegExpr.Create('PFN_([-_A-Za-z0-9]+)');
  841. try
  842. if rx.Exec(String(fName))
  843. then aName := 'T' + WideString(rx.Match[1])
  844. else aName := 'T' + fName;
  845. finally
  846. FreeAndNil(rx);
  847. end;
  848. end;
  849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  850. procedure THeaderGenerator.TvkFunctionBase.GenerateFunctionPtr(const aCode, aSub: TStringTree);
  851. var
  852. st: TStringTree;
  853. i: Integer;
  854. s: WideString;
  855. a: TArgument;
  856. begin
  857. if Assigned(fList) then begin
  858. fList.GenerateCode(fReturnValue.Typ, aCode);
  859. for a in fArguments do
  860. fList.GenerateCode(a.Typ, aCode);
  861. end;
  862. st := aSub.GetOrCreateItem(String(GetPascalName(0, '')));
  863. if (st.LinesBefore.Count = 0) then begin
  864. // head
  865. s := WideString(Format(' %s', [ GetPascalName(0, '') ]));
  866. if (ReturnValue.Typ = 'void') and (ReturnValue.IsPointer = 0)
  867. then s := s + ' = procedure('
  868. else s := s + ' = function (';
  869. st.LinesBefore.Add(String(s));
  870. // params
  871. for i := 0 to fArguments.Count-1 do begin
  872. s := ' ';
  873. a := fArguments[i];
  874. if a.IsConst
  875. then s := s + 'const '
  876. else s := s + ' ';
  877. s := s + WideString(Format('%-30s%s', [ PrepareName(a.Name, a.Typ)+':', List.GetPascalName(a.Typ, a.IsPointer) ]));
  878. if (i < fArguments.Count-1) then
  879. s := s + '; ';
  880. st.LinesBefore.Add(String(s));
  881. end;
  882. // result
  883. s := ' )';
  884. if (ReturnValue.Typ <> 'void') or (ReturnValue.IsPointer > 0) then
  885. s := s + ': ' + List.GetPascalName(ReturnValue.Typ, ReturnValue.IsPointer);
  886. s := s + '; {$IFDEF VK_CDECL}cdecl{$ELSE}stdcall{$ENDIF};';
  887. st.LinesBefore.Add(String(s));
  888. st.LinesBefore.Add('');
  889. end;
  890. end;
  891. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  892. constructor THeaderGenerator.TvkFunctionBase.Create(const aType: TvkObjectType);
  893. begin
  894. inherited Create(aType);
  895. fReturnValue := TArgument.Create;
  896. fArguments := TArgumentList.Create;
  897. end;
  898. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  899. destructor THeaderGenerator.TvkFunctionBase.Destroy;
  900. begin
  901. FreeAndNil(fReturnValue);
  902. FreeAndNil(fArguments);
  903. inherited Destroy;
  904. end;
  905. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  906. //THeaderGenerator.TvkFunctionPtr///////////////////////////////////////////////////////////////////////////////////
  907. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  908. procedure THeaderGenerator.TvkFunctionPtr.ReadXml(const xml: TDOMNode);
  909. var
  910. x, p: TDOMNode;
  911. a: TArgument;
  912. rx: TRegExpr;
  913. begin
  914. x := xml.FindNode('name');
  915. if not Assigned(x) then
  916. raise XmlException.Create(xml.NodeName + ' witout child ''name''', xml);
  917. Name := x.TextContent;
  918. p := x.PreviousSibling;
  919. if not Assigned(p) then
  920. raise XmlException.Create(xml.NodeName + ' witout return type', xml);
  921. rx := TRegExpr.Create('typedef\s+((const)?)\s*([-_A-Za-z0-9\s]+?)\s*((\*\s*(const)?\s*)*)\s*\(');
  922. try
  923. if not rx.Exec(String(p.TextContent)) then
  924. raise XmlException.Create('unable to parse return type of function pointer', xml);
  925. ReturnValue.IsConst := (Trim(rx.Match[1]) = 'const');
  926. ReturnValue.Typ := WideString(Trim(rx.Match[3]));
  927. ReturnValue.IsPointer := PointerCount(Trim(rx.Match[4]));
  928. x := xml.FirstChild;
  929. while Assigned(x) do begin
  930. if (x.NodeName = 'type') then begin
  931. a := TArgument.Create;
  932. try
  933. p := x.PreviousSibling;
  934. if not Assigned(p) then
  935. raise XmlException.Create('unable to parse function pointer arguments', xml);
  936. rx.Expression := '[A-Za-z]*';
  937. a.IsConst := rx.Exec(String(p.TextContent)) and (rx.Match[0] = 'const');
  938. a.Typ := x.TextContent;
  939. p := x.NextSibling;
  940. if not Assigned(p) then
  941. raise XmlException.Create('unable to parse function pointer arguments', xml);
  942. rx.Expression := '((\*\s*(const)?\s*)*)\s*([-_A-Za-z0-9]+)';
  943. if not rx.Exec(String(p.TextContent)) then
  944. raise XmlException.Create('unable to parse function pointer arguments', xml);
  945. a.IsPointer := PointerCount((rx.Match[1]));
  946. a.Name := WideString(Trim(rx.Match[4]));
  947. Arguments.Add(a);
  948. except
  949. FreeAndNil(a)
  950. end;
  951. end;
  952. x := x.NextSibling;
  953. end;
  954. finally
  955. FreeAndNil(rx);
  956. end;
  957. end;
  958. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  959. procedure THeaderGenerator.TvkFunctionPtr.GenerateCode(const aCode: TStringTree);
  960. var st: TStringTree;
  961. begin
  962. inherited GenerateCode(aCode);
  963. st := aCode.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(KEYWORD_FUNCPTR);
  964. if (st.LinesBefore.Count = 0) then
  965. st.LinesBefore.Add('type { function pointers }');
  966. GenerateFunctionPtr(aCode, st);
  967. end;
  968. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  969. constructor THeaderGenerator.TvkFunctionPtr.Create;
  970. begin
  971. inherited Create(otFuncPtr);
  972. end;
  973. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  974. //THeaderGenerator.TvkCommand///////////////////////////////////////////////////////////////////////////////////////
  975. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  976. procedure THeaderGenerator.TvkCommand.ReadXml(const xml: TDOMNode);
  977. procedure ParseProto(const x: TDOMNode);
  978. begin
  979. Name := GetNodeValue(x, 'name');
  980. ReturnValue.Typ := GetNodeValue(x, 'type');
  981. end;
  982. procedure ParseParam(const x: TDOMNode);
  983. var
  984. p: TDOMNode;
  985. a: TArgument;
  986. rx: TRegExpr;
  987. begin
  988. a := TArgument.Create;
  989. rx := TRegExpr.Create;
  990. try try
  991. p := x.FindNode('name');
  992. if not Assigned(p) then
  993. raise XmlException.Create('unable to parse command; param without name', xml);
  994. a.Name := p.TextContent;
  995. p := x.FindNode('type');
  996. if not Assigned(p) then
  997. raise XmlException.Create('unable to parse command; param without type', xml);
  998. a.Typ := p.TextContent;
  999. a.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  1000. rx.Expression := '((\*\s*(const)?\s*)*)';
  1001. if Assigned(p.NextSibling) and rx.Exec(String(p.NextSibling.TextContent)) then
  1002. a.IsPointer := PointerCount(rx.Match[0]);
  1003. Arguments.Add(a);
  1004. finally
  1005. FreeAndNil(rx);
  1006. end;
  1007. except
  1008. FreeAndNil(a);
  1009. raise;
  1010. end;
  1011. end;
  1012. var
  1013. x: TDOMNode;
  1014. begin
  1015. inherited ReadXml(xml);
  1016. x := xml.FirstChild;
  1017. while Assigned(x) do begin
  1018. if (x.NodeName = 'proto') then
  1019. ParseProto(x)
  1020. else if (x.NodeName = 'param') then
  1021. ParseParam(x);
  1022. x := x.NextSibling;
  1023. end;
  1024. end;
  1025. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1026. procedure THeaderGenerator.TvkCommand.GenerateCode(const aCode: TStringTree);
  1027. function GetStringTree(const aType: WideString): TStringTree;
  1028. var h: TvkTypeBase;
  1029. begin
  1030. result := nil;
  1031. if (fName = 'vkGetInstanceProcAddr') then
  1032. exit;
  1033. if (aType = 'VkInstance') or (fName = 'vkGetDeviceProcAddr') then begin
  1034. result := aCode.GetOrCreateItem(KEYWORD_INSTANCE_COMMANDS);
  1035. exit;
  1036. end;
  1037. if (aType = 'VkDevice') then begin
  1038. result := aCode.GetOrCreateItem(KEYWORD_DEVICE_COMMANDS);
  1039. exit;
  1040. end;
  1041. if not Assigned(List) or not List.FindObj(aType, [otHandle, otType], h) or (h.Parent = '') then
  1042. exit;
  1043. result := GetStringTree(h.Parent);
  1044. end;
  1045. var
  1046. st: TStringTree;
  1047. begin
  1048. inherited GenerateCode(aCode);
  1049. st := aCode.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(KEYWORD_COMMAND);
  1050. if (st.LinesBefore.Count = 0) then
  1051. st.LinesBefore.Add('type { commands }');
  1052. GenerateFunctionPtr(aCode, st);
  1053. st := nil;
  1054. if (Arguments.Count > 0) then
  1055. st := GetStringTree(Arguments[0].Typ);
  1056. if Assigned(st) then begin
  1057. with st.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(String(fName)) do begin
  1058. if (LinesBefore.Count = 0) then
  1059. LinesBefore.Add(Format('%-50s%s;', [fName + ':', GetPascalName(0, '')]));
  1060. end;
  1061. with st.GetOrCreateItem(KEYWORD_IMPL).GetOrCreateItem(String(fName)) do begin
  1062. if (LinesBefore.Count = 0) then
  1063. LinesBefore.Add(Format('%-50s := T%0:-50s(GetProcAddress(''%0:s''));', [fName]));
  1064. end;
  1065. end else begin
  1066. st := aCode.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(KEYWORD_VAR);
  1067. if (st.LinesBefore.Count = 0) then
  1068. st.LinesBefore.Add('var');
  1069. st := st.GetOrCreateItem(String(fName));
  1070. if (st.LinesBefore.Count = 0) then
  1071. st.LinesBefore.Add(Format(' %-50s%s;', [fName + ':', GetPascalName(0, '')]));
  1072. st := aCode.GetOrCreateItem(KEYWORD_IMPL).GetOrCreateItem(KEYWORD_CODE).GetOrCreateItem(String(fName));
  1073. if (st.LinesBefore.Count = 0) then
  1074. st.LinesBefore.Add(Format('%-50s := T%0:-50s(GetProcAddress(''%0:s''));', [fName]));
  1075. end;
  1076. end;
  1077. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1078. constructor THeaderGenerator.TvkCommand.Create;
  1079. begin
  1080. inherited Create(otCommand);
  1081. end;
  1082. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1083. //THeaderGenerator.TvkStruct////////////////////////////////////////////////////////////////////////////////////////
  1084. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1085. function THeaderGenerator.TvkStruct.GetDependencyOrder: Integer;
  1086. var
  1087. m: TMember;
  1088. begin
  1089. result := inherited GetDependencyOrder;
  1090. if not Assigned(List) then
  1091. exit;
  1092. for m in fMember do
  1093. result := max(result, List.IndexOfObj(m.Typ, VK_OBJECT_TYPES) + 1);
  1094. end;
  1095. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1096. procedure THeaderGenerator.TvkStruct.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  1097. var i: Integer;
  1098. begin
  1099. if (aPointer > 0) then begin
  1100. aName := fName;
  1101. for i := 0 to aPointer-1 do
  1102. aName := 'P' + aName;
  1103. end else
  1104. aName := 'T' + fName;
  1105. inherited GenPascalName(aName, aPointer, aArrSize);
  1106. end;
  1107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1108. procedure THeaderGenerator.TvkStruct.ReadXml(const xml: TDOMNode);
  1109. var
  1110. x, p: TDOMNode;
  1111. m: TMember;
  1112. rx: TRegExpr;
  1113. begin
  1114. Name := GetNodeAttrib(xml, 'name');
  1115. IsUnion := (GetNodeAttrib(xml, 'category') = 'union');
  1116. x := xml.FirstChild;
  1117. while Assigned(x) do begin
  1118. if (x.NodeName = 'member') then begin
  1119. m := TMember.Create;
  1120. rx := TRegExpr.Create('');
  1121. try try
  1122. // read name
  1123. p := x.FindNode('name');
  1124. if not Assigned(p) then
  1125. raise XmlException.Create('struct member without name', xml);
  1126. m.Name := p.TextContent;
  1127. p := p.NextSibling;
  1128. while Assigned(p) do begin
  1129. m.Name := m.Name + p.TextContent;
  1130. p := p.NextSibling;
  1131. end;
  1132. m.Name := Trim(m.Name);
  1133. rx.Expression := '([-_A-Za-z0-9]+)\s*\[\s*([-_A-Za-z0-9]+)\s*\]';
  1134. if rx.Exec(String(m.Name)) then begin
  1135. m.Name := WideString(rx.Match[1]);
  1136. m.ArrSize := WideString(rx.Match[2]);
  1137. end;
  1138. // read type
  1139. p := x.FindNode('type');
  1140. if not Assigned(p) then
  1141. raise XmlException.Create('struct member without type', xml);
  1142. m.Typ := p.TextContent;
  1143. m.IsConst := Assigned(p.PreviousSibling) and (Trim(p.PreviousSibling.TextContent) = 'const');
  1144. rx.Expression := '((\*\s*(const)?\s*)*)';
  1145. if Assigned(p.NextSibling) and rx.Exec(String(p.NextSibling.TextContent)) then
  1146. m.IsPointer := PointerCount(rx.Match[0]);
  1147. Member.Add(m);
  1148. finally
  1149. FreeAndNil(rx);
  1150. end;
  1151. except
  1152. FreeAndNil(m);
  1153. end;
  1154. end;
  1155. x := x.NextSibling;
  1156. end;
  1157. end;
  1158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1159. procedure THeaderGenerator.TvkStruct.GenerateCode(const aCode: TStringTree);
  1160. var
  1161. m: TMember;
  1162. st: TStringTree;
  1163. postfix, prefix: String;
  1164. i, indent: Integer;
  1165. begin
  1166. inherited GenerateCode(aCode);
  1167. if Assigned(fList) then begin
  1168. for m in fMember do begin
  1169. if (m.ArrSize <> '') then
  1170. fList.GenerateCode(m.ArrSize, aCode);
  1171. fList.GenerateCode(m.Typ, aCode);
  1172. end;
  1173. end;
  1174. st := aCode.GetOrCreateItem(KEYWORD_INTF).GetOrCreateItem(KEYWORD_STRUCT);
  1175. if (st.LinesBefore.Count = 0) then
  1176. st.LinesBefore.Add('type { structures }');
  1177. st := st.GetOrCreateItem(String(GetPascalName(0, '')));
  1178. if (st.LinesBefore.Count = 0) then begin
  1179. postfix := ';';
  1180. indent := 50;
  1181. st.LinesBefore.Add(' T%s = record', [ fName ]);
  1182. if IsUnion then begin
  1183. st.LinesBefore.Add(' case Integer of');
  1184. postfix := ');';
  1185. indent := 42;
  1186. end;
  1187. for i := 0 to fMember.Count-1 do begin
  1188. m := fMember[i];
  1189. if IsUnion
  1190. then prefix := Format(' %.3d: (', [ i ])
  1191. else prefix := ' ';
  1192. st.LinesBefore.Add(Format('%s%-*s%s%s', [ prefix, indent, PrepareName(m.Name, m.Typ) + ': ', List.GetPascalName(m.Typ, m.IsPointer, m.ArrSize), postfix ]));
  1193. end;
  1194. st.LinesAfter.Add(' end;');
  1195. st.LinesAfter.Add(' P%s = ^T%0:s;', [ fName ]);
  1196. st.LinesAfter.Add(' PP%s = ^P%0:s;', [ fName ]);
  1197. st.LinesAfter.Add('');
  1198. end;
  1199. end;
  1200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1201. constructor THeaderGenerator.TvkStruct.Create;
  1202. begin
  1203. inherited Create(otStruct);
  1204. fMember := TMemberList.Create;
  1205. end;
  1206. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1207. destructor THeaderGenerator.TvkStruct.Destroy;
  1208. begin
  1209. FreeAndNil(fMember);
  1210. inherited Destroy;
  1211. end;
  1212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1213. //THeaderGenerator.TvkEnum//////////////////////////////////////////////////////////////////////////////////////////
  1214. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1215. procedure THeaderGenerator.TvkEnum.GenPascalName(var aName: WideString; const aPointer: Integer; const aArrSize: WideString);
  1216. var i: Integer;
  1217. begin
  1218. if (fName = '') then
  1219. raise Exception.Create('enum with empty name');
  1220. if (aPointer > 0) then begin
  1221. aName := fName;
  1222. for i := 0 to aPointer-1 do
  1223. aName := 'P' + aName;
  1224. end else
  1225. aName := 'T' + fName;
  1226. inherited GenPascalName(aName, aPointer, aArrSize);
  1227. end;
  1228. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1229. procedure THeaderGenerator.TvkEnum.ReadXml(const xml: TDOMNode);
  1230. var
  1231. x, p: TDOMNode;
  1232. v: TValue;
  1233. begin
  1234. Name := GetNodeAttrib(xml, 'name');
  1235. Expands := GetNodeAttrib(xml, 'expand', '');
  1236. x := xml.FirstChild;
  1237. while Assigned(x) do begin
  1238. if (x.NodeName = 'enum') then begin
  1239. v := TValue.Create;
  1240. try
  1241. v.Name := GetNodeAttrib(x, 'name');
  1242. p := x.Attributes.GetNamedItem('value');
  1243. if Assigned(p) then begin
  1244. v.IsBit := false;
  1245. v.Value := StrToValue(String(p.TextContent));
  1246. end else begin
  1247. p := x.Attributes.GetNamedItem('bitpos');
  1248. if not Assigned(p) then
  1249. raise XmlException.Create('enum without value or bitpos', xml);
  1250. v.IsBit := true;
  1251. v.Value := StrToValue(String(p.TextContent));
  1252. end;
  1253. if (v.Value = Unassigned) then
  1254. raise XmlException.Create(WideString('invalid enum value (' + p.TextContent + ')'), xml);
  1255. Values.Add(v);
  1256. except
  1257. FreeAndNil(v);
  1258. raise;
  1259. end;
  1260. end;
  1261. x := x.NextSibling;
  1262. end;
  1263. end;
  1264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1265. procedure THeaderGenerator.TvkEnum.GenerateCode(const aCode: TStringTree);
  1266. var
  1267. st, vt: TStringTree;
  1268. i: Integer;
  1269. v: TValue;
  1270. postfix: String;
  1271. begin
  1272. inherited GenerateCode(aCode);
  1273. st := aCode
  1274. .GetOrCreateItem(KEYWORD_INTF)
  1275. .GetOrCreateItem(KEYWORD_ENUM);
  1276. if (st.LinesBefore.Count = 0) then
  1277. st.LinesBefore.Add('type { enumerations }');
  1278. st := st.GetOrCreateItem(String(fName));
  1279. if (st.LinesBefore.Count = 0) then begin
  1280. st.LinesBefore.Add(Format(' %s = (', [GetPascalName(0, '')]));
  1281. postfix := ',';
  1282. vt := st.GetOrCreateItem(KEYWORD_ENUM_VALUES);
  1283. for i := 0 to fValues.Count-1 do begin
  1284. v := fValues[i];
  1285. if (i = fValues.Count-1) and (fExpands = '') then
  1286. postfix := '';
  1287. if (v.IsBit)
  1288. then vt.LinesBefore.Add(Format(' %-60s = (1 shl %s)%s', [v.Name, v.Value, postfix]))
  1289. else vt.LinesBefore.Add(Format(' %-60s = %s%s', [v.Name, v.Value, postfix]));
  1290. end;
  1291. if (fExpands <> '') then
  1292. st.LinesAfter.Add(Format(' %-60s = %s', [fExpands + '_MAX_ENUM', '$7FFFFFFF']));
  1293. st.LinesAfter.Add(' );');
  1294. st.LinesAfter.Add(' P%s = ^T%0:s;', [ fName ]);
  1295. st.LinesAfter.Add(' PP%s = ^P%0:s;', [ fName ]);
  1296. st.LinesAfter.Add('');
  1297. end;
  1298. end;
  1299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1300. constructor THeaderGenerator.TvkEnum.Create;
  1301. begin
  1302. inherited Create(otEnum);
  1303. fValues := TValueList.Create;
  1304. end;
  1305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1306. destructor THeaderGenerator.TvkEnum.Destroy;
  1307. begin
  1308. FreeAndNil(fValues);
  1309. inherited Destroy;
  1310. end;
  1311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1312. //THeaderGenerator.TvkConst/////////////////////////////////////////////////////////////////////////////////////////////
  1313. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1314. procedure THeaderGenerator.TvkConst.GenerateCode(const aCode: TStringTree);
  1315. var
  1316. st: TStringTree;
  1317. begin
  1318. inherited GenerateCode(aCode);
  1319. st := aCode
  1320. .GetOrCreateItem(KEYWORD_INTF)
  1321. .GetOrCreateItem(KEYWORD_CONST);
  1322. if (st.LinesBefore.Count = 0) then
  1323. st.LinesBefore.Add('const');
  1324. st := st.GetOrCreateItem(String(fName));
  1325. if (st.LinesBefore.Count = 0) then
  1326. st.LinesBefore.Add(Format(' %-62s = %s;', [fName, fValue]));
  1327. end;
  1328. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1329. constructor THeaderGenerator.TvkConst.Create;
  1330. begin
  1331. inherited Create(otConst);
  1332. end;
  1333. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1334. //THeaderGenerator//////////////////////////////////////////////////////////////////////////////////////////////////////
  1335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1336. procedure THeaderGenerator.GenerateCode(const aName: WideString; const aTemplate: String; const aOutput: String);
  1337. type
  1338. TPosMap = specialize TutlMap<string, Integer>;
  1339. var
  1340. CurrentName: WideString;
  1341. CurrentNumber: Integer;
  1342. Code: TStringTree;
  1343. PosMap: TPosMap;
  1344. procedure UpdateComment(const aNames: array of String);
  1345. var
  1346. i: Integer;
  1347. name, s, tmp: String;
  1348. st: TStringTree;
  1349. begin
  1350. name := '';
  1351. st := Code;
  1352. for s in aNames do begin
  1353. st := st.GetOrCreateItem(s);
  1354. name := name + '.' + s;
  1355. end;
  1356. if PosMap.TryGetValue(name, i) and (st.ItemCount > i) and (CurrentName <> '') then
  1357. with st.CreateItemAt(name + String(CurrentName), i).LinesBefore do begin
  1358. s := ' ' + String(CurrentName) + ' ';
  1359. if ((Length(s) and 1) = 1) then
  1360. s := s + '=';
  1361. tmp := StringOfChar('=', (100 - Length(s)) div 2);
  1362. s := '{ ' + tmp + s + tmp + ' }';
  1363. Add('');
  1364. Add(s);
  1365. end;
  1366. PosMap[name] := st.ItemCount;
  1367. end;
  1368. procedure UpdateComments;
  1369. begin
  1370. UpdateComment([KEYWORD_INTF, KEYWORD_CONST]);
  1371. UpdateComment([KEYWORD_INTF, KEYWORD_TYPES]);
  1372. UpdateComment([KEYWORD_INTF, KEYWORD_ENUM]);
  1373. UpdateComment([KEYWORD_INTF, KEYWORD_FUNCPTR]);
  1374. UpdateComment([KEYWORD_INTF, KEYWORD_STRUCT]);
  1375. UpdateComment([KEYWORD_INTF, KEYWORD_COMMAND]);
  1376. UpdateComment([KEYWORD_INTF, KEYWORD_VAR]);
  1377. UpdateComment([KEYWORD_IMPL, KEYWORD_VAR]);
  1378. UpdateComment([KEYWORD_INSTANCE_COMMANDS, KEYWORD_INTF]);
  1379. UpdateComment([KEYWORD_INSTANCE_COMMANDS, KEYWORD_IMPL]);
  1380. UpdateComment([KEYWORD_DEVICE_COMMANDS, KEYWORD_INTF]);
  1381. UpdateComment([KEYWORD_DEVICE_COMMANDS, KEYWORD_IMPL]);
  1382. end;
  1383. procedure AddGuard(const aTree: TStringTree; const aName: String);
  1384. var
  1385. i: Integer;
  1386. begin
  1387. for i := 0 to aTree.ItemCount-1 do
  1388. AddGuard(aTree.ItemsByIndex[i], aName);
  1389. with aTree.GetOrCreateItem('GUARD' + aName).LinesBefore do begin
  1390. Add('{$IFDEF ' + aName + '}');
  1391. end;
  1392. end;
  1393. procedure RemoveGuard(const aTree: TStringTree; const aName: String);
  1394. var
  1395. i: Integer;
  1396. g: TStringTree;
  1397. begin
  1398. for i := 0 to aTree.ItemCount-1 do
  1399. RemoveGuard(aTree.ItemsByIndex[i], aName);
  1400. g := aTree.GetOrCreateItem('GUARD' + aName);
  1401. if (g = aTree.ItemsByIndex[aTree.ItemCount-1])
  1402. then aTree.DestroyItem('GUARD' + aName)
  1403. else with aTree.GetOrCreateItem('GUARD_END'+ aName).LinesAfter do begin
  1404. Add('{$ENDIF}');
  1405. Add('');
  1406. end;
  1407. end;
  1408. procedure CreateGuard(const aName: String);
  1409. begin
  1410. if (aName = '') then
  1411. exit;
  1412. AddGuard(Code, aName);
  1413. end;
  1414. procedure CloseGuard(const aName: String);
  1415. begin
  1416. if (aName = '') then
  1417. exit;
  1418. RemoveGuard(Code, aName);
  1419. end;
  1420. procedure GenerateFeatureCode(const aName: String);
  1421. var
  1422. i: Integer;
  1423. begin
  1424. i := fObjects.IndexOfObj(WideString(aName), VK_OBJECT_ALL);
  1425. if (i >= 0) then
  1426. fObjects[i].GenerateCode(Code);
  1427. end;
  1428. function GenerateEnum(const xml: TDOMNode): Boolean;
  1429. var
  1430. name: WideString;
  1431. ex: WideString;
  1432. value: WideString;
  1433. offset: Integer;
  1434. s: String;
  1435. c: TvkConst;
  1436. begin
  1437. result := false;
  1438. name := GetNodeAttrib(xml, 'name');
  1439. if TryGetNodeAttrib(xml, 'extends', ex) then begin
  1440. if (CurrentNumber <= 0) then
  1441. raise Exception.Create('current extension has no number');
  1442. offset := StrToInt(String(GetNodeAttrib(xml, 'offset')));
  1443. offset := 1000000000 + 1000 * (CurrentNumber-1) + offset;
  1444. if (GetNodeAttrib(xml, 'dir', '') = '-') then
  1445. offset := -1 * offset;
  1446. Code
  1447. .GetOrCreateItem(KEYWORD_INTF)
  1448. .GetOrCreateItem(KEYWORD_ENUM)
  1449. .GetOrCreateItem(String(ex))
  1450. .GetOrCreateItem(KEYWORD_ENUM_VALUES)
  1451. .LinesBefore.Add(Format(' %-60s = %s,', [name, IntToStr(offset)]));
  1452. end else begin
  1453. if not TryGetNodeAttrib(xml, 'value', value) then
  1454. exit;
  1455. s := StringReplace(string(value), '"', '''', [rfReplaceAll]);
  1456. c := TvkConst.Create;
  1457. try
  1458. c.Name := name;
  1459. c.Value := s;
  1460. fObjects.AddObject(c);
  1461. except
  1462. FreeAndNil(c);
  1463. raise;
  1464. end;
  1465. c.GenerateCode(Code);
  1466. end;
  1467. result := true;
  1468. end;
  1469. procedure GenerateFeatureCode(const xml: TDOMNode);
  1470. var
  1471. x: TDOMNode;
  1472. begin
  1473. x := xml.FirstChild;
  1474. while Assigned(x) do begin
  1475. if (x.NodeName = 'type') or
  1476. (x.NodeName = 'command') then
  1477. begin
  1478. GenerateFeatureCode(String(GetNodeAttrib(x, 'name')));
  1479. end else if (x.NodeName = 'enum') then begin
  1480. if not GenerateEnum(x) then
  1481. GenerateFeatureCode(String(GetNodeAttrib(x, 'name')));
  1482. end;
  1483. x := x.NextSibling;
  1484. end;
  1485. end;
  1486. procedure Generate(const xml: TDOMNode);
  1487. var
  1488. x: TDOMNode;
  1489. g: WideString;
  1490. begin
  1491. UpdateComments;
  1492. g := GetNodeAttrib(xml, 'protect', '');
  1493. CreateGuard(String(g));
  1494. try
  1495. CurrentName := GetNodeAttrib(xml, 'name');
  1496. if not TryStrToInt(String(GetNodeAttrib(xml, 'number', '-1')), CurrentNumber) then
  1497. CurrentNumber := -1;
  1498. WriteLn('generate code for feature: ', CurrentName);
  1499. x := xml.FirstChild;
  1500. while Assigned(x) do begin
  1501. if (x.NodeName = 'require') then
  1502. GenerateFeatureCode(x);
  1503. x := x.NextSibling;
  1504. end;
  1505. finally
  1506. CloseGuard(String(g));
  1507. UpdateComments;
  1508. CurrentName := '';
  1509. end;
  1510. end;
  1511. procedure EnableFeature;
  1512. var x: TDOMNode;
  1513. begin
  1514. GenerateFeatureCode('VK_API_VERSION');
  1515. GenerateFeatureCode('VK_API_VERSION_MAJOR');
  1516. GenerateFeatureCode('VK_API_VERSION_MINOR');
  1517. GenerateFeatureCode('VK_API_VERSION_BUGFIX');
  1518. x := fDocument.DocumentElement.FirstChild;
  1519. while Assigned(x) do begin
  1520. if (x.NodeName = 'feature') and (GetNodeAttrib(x, 'api', '') = aName) then
  1521. Generate(x);
  1522. x := x.NextSibling;
  1523. end;
  1524. end;
  1525. procedure EnableExtensions;
  1526. var
  1527. x: TDOMNode;
  1528. begin
  1529. x := fDocument.DocumentElement.FindNode('extensions');
  1530. if not Assigned(x) then
  1531. exit;
  1532. x := x.FirstChild;
  1533. while Assigned(x) do begin
  1534. if (x.NodeName = 'extension') and (GetNodeAttrib(x, 'supported', '') = aName) then
  1535. Generate(x);
  1536. x := x.NextSibling;
  1537. end;
  1538. end;
  1539. procedure RemoveEmptyLines(const aText: TStrings);
  1540. var
  1541. i: Integer;
  1542. b: Boolean;
  1543. rx: TRegExpr;
  1544. begin
  1545. i := 0;
  1546. rx := TRegExpr.Create('{%.*?%}');
  1547. try
  1548. while (i < aText.Count) do begin
  1549. if (rx.Exec(aText[i])) then begin
  1550. aText.Delete(i);
  1551. continue;
  1552. end;
  1553. if (Trim(aText[i]) = '') then begin
  1554. if b then begin
  1555. aText.Delete(i);
  1556. continue;
  1557. end else
  1558. b := true;
  1559. end else
  1560. b := false;
  1561. inc(i);
  1562. end;
  1563. finally
  1564. FreeAndNil(rx);
  1565. end;
  1566. end;
  1567. procedure PrepareTemplate;
  1568. var
  1569. sl, tk: TStringList;
  1570. s, n: String;
  1571. st: TStringTree;
  1572. p0, p1, SpaceCount, i: Integer;
  1573. begin
  1574. sl := TStringList.Create;
  1575. tk := TStringList.Create;
  1576. try
  1577. tk.Delimiter := '.';
  1578. sl.LoadFromFile(aTemplate);
  1579. s := sl.Text;
  1580. p0 := Pos('{%', s);
  1581. while (p0 > 0) do begin
  1582. SpaceCount := 0;
  1583. while (p0-1 > 0) and (s[p0-1] = ' ') do begin
  1584. inc(SpaceCount);
  1585. dec(p0);
  1586. end;
  1587. p1 := Pos('%}', s, p0);
  1588. if (p1 <= 0) then
  1589. raise Exception.Create('unclosed tag in template');
  1590. n := Trim(Copy(s, p0+SpaceCount+2, p1-p0-SpaceCount-2));
  1591. tk.DelimitedText := n;
  1592. st := Code;
  1593. for n in tk do
  1594. st := st.GetOrCreateItem(n);
  1595. n := Copy(s, p0, p1 - p0 + 2);
  1596. if Assigned(st) then begin
  1597. sl.Text := st.Text;
  1598. for i := 0 to sl.Count-1 do
  1599. sl[i] := StringOfChar(' ', SpaceCount) + sl[i];
  1600. s := StringReplace(s, n, sl.Text, [rfReplaceAll])
  1601. end else
  1602. s := StringReplace(s, n, '', [rfReplaceAll]);
  1603. p0 := Pos('{%', s, p0);
  1604. end;
  1605. sl.Text := Trim(s);
  1606. RemoveEmptyLines(sl);
  1607. sl.SaveToFile(aOutput);
  1608. finally
  1609. FreeAndNil(tk);
  1610. FreeAndNil(sl);
  1611. end;
  1612. end;
  1613. begin
  1614. if not Assigned(fDocument) then
  1615. raise Exception.Create('no xml file loaded, did you call ReadFile before?');
  1616. Code := TStringTree.Create;
  1617. PosMap := TPosMap.Create;
  1618. try
  1619. Code.GetOrCreateItem(KEYWORD_COMMENT).LinesBefore.Text := Trim(String(fComment));
  1620. with Code.GetOrCreateItem(KEYWORD_INTF) do begin
  1621. GetOrCreateItem(KEYWORD_CONST).LinesAfter.Add('');
  1622. GetOrCreateItem(KEYWORD_TYPES).LinesAfter.Add('');
  1623. GetOrCreateItem(KEYWORD_ENUM).LinesAfter.Add('');
  1624. GetOrCreateItem(KEYWORD_FUNCPTR).LinesAfter.Add('');
  1625. GetOrCreateItem(KEYWORD_STRUCT).LinesAfter.Add('');
  1626. GetOrCreateItem(KEYWORD_COMMAND).LinesAfter.Add('');
  1627. GetOrCreateItem(KEYWORD_VAR).LinesAfter.Add('');
  1628. end;
  1629. with Code.GetOrCreateItem(KEYWORD_IMPL) do begin
  1630. GetOrCreateItem(KEYWORD_CODE).LinesAfter.Add('');
  1631. end;
  1632. Code.GetOrCreateItem(KEYWORD_IMPL);
  1633. EnableFeature;
  1634. EnableExtensions;
  1635. PrepareTemplate;
  1636. finally
  1637. FreeAndNil(PosMap);
  1638. FreeAndNil(Code);
  1639. end;
  1640. end;
  1641. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1642. procedure THeaderGenerator.ReadFile(const aFilename: String);
  1643. var
  1644. fs: TFileStream;
  1645. begin
  1646. if not FileExists(aFilename) then
  1647. raise Exception.Create('file does not exist: ' + aFilename);
  1648. fs := TFileStream.Create(aFilename, fmOpenRead);
  1649. try
  1650. ReadFile(fs);
  1651. finally
  1652. FreeAndNil(fs);
  1653. end;
  1654. end;
  1655. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1656. procedure THeaderGenerator.ReadFile(const aStream: TStream);
  1657. var
  1658. xml: TDOMNode;
  1659. procedure ParseTypes(const xml: TDOMNode);
  1660. var
  1661. x: TDOMNode;
  1662. begin
  1663. x := xml.FirstChild;
  1664. while Assigned(x) do begin
  1665. TvkObject.CreateFromXml(x, fObjects);
  1666. x := x.NextSibling;
  1667. end;
  1668. end;
  1669. begin
  1670. Clear;
  1671. ReadXMLFile(fDocument, aStream);
  1672. WriteLn('read xml data');
  1673. xml := fDocument.DocumentElement.FirstChild;
  1674. while Assigned(xml) do begin
  1675. if (xml.NodeName = 'types') or (xml.NodeName = 'commands') then
  1676. ParseTypes(xml)
  1677. else if (xml.NodeName = 'enums') then
  1678. TvkObject.CreateFromXml(xml, fObjects)
  1679. else if (xml.NodeName = 'comment') then
  1680. fComment := WideString(Trim(String(xml.TextContent)));
  1681. xml := xml.NextSibling;
  1682. end;
  1683. end;
  1684. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1685. procedure THeaderGenerator.Clear;
  1686. procedure CreateBaseType(const aName, aAlias, aParent: WideString);
  1687. var t: TvkTypeBase;
  1688. begin
  1689. t := TvkTypeBase.Create(otType);
  1690. try
  1691. t.Name := aName;
  1692. t.Alias := aAlias;
  1693. t.Parent := aParent;
  1694. t.List := fObjects;
  1695. fObjects.Add(t);
  1696. except
  1697. FreeAndNil(t);
  1698. raise;
  1699. end;
  1700. end;
  1701. begin
  1702. fObjects.Clear;
  1703. CreateBaseType('void', 'VkVoid', '');
  1704. CreateBaseType('uint8_t', 'VkUint8', '');
  1705. CreateBaseType('uint16_t', 'VkUint16', '');
  1706. CreateBaseType('uint32_t', 'VkUint32', '');
  1707. CreateBaseType('uint64_t', 'VkUint64', '');
  1708. CreateBaseType('int16_t', 'VkInt16', '');
  1709. CreateBaseType('int32_t', 'VkInt32', '');
  1710. CreateBaseType('int64_t', 'VkInt64', '');
  1711. CreateBaseType('float', 'VkFloat', '');
  1712. CreateBaseType('double', 'VkDouble', '');
  1713. CreateBaseType('char', 'VkChar', '');
  1714. CreateBaseType('size_t', 'VkSize', '');
  1715. end;
  1716. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1717. constructor THeaderGenerator.Create;
  1718. begin
  1719. inherited Create;
  1720. fObjects := TvkObjectList.Create;
  1721. end;
  1722. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1723. destructor THeaderGenerator.Destroy;
  1724. begin
  1725. FreeAndNil(fObjects);
  1726. FreeAndNil(fDocument);
  1727. inherited Destroy;
  1728. end;
  1729. end.