Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

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