ISPP.Preprocessor.pas 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869
  1. {
  2. Inno Setup Preprocessor
  3. Copyright (C) 2001-2002 Alex Yackimoff
  4. Inno Setup
  5. Copyright (C) 1997-2025 Jordan Russell
  6. Portions by Martijn Laan
  7. For conditions of distribution and use, see LICENSE.TXT.
  8. }
  9. unit ISPP.Preprocessor;
  10. interface
  11. uses
  12. Windows, SysUtils, Classes, Shared.PreprocInt, IniFiles, Registry, ISPP.Intf,
  13. ISPP.Base, ISPP.Stack, ISPP.IdentMan, ISPP.Parser;
  14. type
  15. TPreprocessor = class;
  16. EPreprocError = class(Exception)
  17. FileName: string;
  18. LineNumber: Integer;
  19. ColumnNumber: Integer;
  20. constructor Create(Preproc: TPreprocessor; const Msg: string);
  21. end;
  22. TConditionalBlockInfo = record
  23. BlockState, Fired, HadElse, Reserved: Boolean;
  24. end;
  25. TConditionalVerboseMsg = (cvmIf, cvmElif, cvmElse, cvmEndif);
  26. TConditionalTranslationStack = class(TStack)
  27. private
  28. FPreproc: TPreprocessor;
  29. FCache: Boolean;
  30. FCacheValid: Boolean;
  31. procedure VerboseMsg(Msg: TConditionalVerboseMsg; Eval: Boolean);
  32. protected
  33. function Last: TConditionalBlockInfo;
  34. procedure UpdateLast(const Value: TConditionalBlockInfo);
  35. public
  36. constructor Create(Preproc: TPreprocessor);
  37. procedure IfInstruction(Eval: Boolean);
  38. procedure ElseIfInstruction(Eval: Boolean);
  39. procedure ElseInstruction;
  40. procedure EndIfInstruction;
  41. function Include: Boolean;
  42. procedure Resolved;
  43. end;
  44. TPreprocessorCommand = (pcError, pcIf, pcIfDef, pcIfNDef, pcIfExist,
  45. pcIfNExist, pcElseIf, pcElse, pcEndIf, pcDefine, pcUndef, pcInclude,
  46. pcErrorDir, pcPragma, pcLine, pcImport, pcEmit, pcEnv, pcFile,
  47. pcExpr, pcInsert, pcAppend, pcDim, pcSub, pcEndSub, pcEndLoop,
  48. pcFor, pcReDim);
  49. TDropGarbageProc = procedure(Item: Pointer);
  50. TIsppMessageType = (imtStatus, imtWarning);
  51. TPreprocessor = class(TObject, IIdentManager)
  52. private
  53. FCompilerParams: TPreprocessScriptParams;
  54. FCompilerPath: string;
  55. FCounter: Integer;
  56. FCurrentFile: Integer;
  57. FCurrentLine: Integer;
  58. FDefaultScope: TDefineScope;
  59. FFileStack: TStringList; { strs: files being included }
  60. FIncludes: TStringList; { strs: files been included, for error msgs }
  61. FIncludePath: string;
  62. FInsertionPoint: Integer;
  63. FLinePointer: Integer;
  64. FMainCounter: Integer;
  65. FOutput: TStringList; { strs: translation }
  66. FQueuedLine: string;
  67. FQueuedLineCount: Integer;
  68. FSourcePath: string;
  69. FStack: TConditionalTranslationStack;
  70. FIdentManager: TIdentManager;
  71. FInProcBody: Boolean;
  72. FInForBody: Boolean;
  73. FProcs: TStringList;
  74. FGarbageCollection: TList;
  75. procedure DropGarbage;
  76. function ProcessInlineDirectives(P: PChar): string;
  77. function ProcessPreprocCommand(Command: TPreprocessorCommand;
  78. var Params: string; ParamsOffset: Integer): Boolean;
  79. procedure PushFile(const FileName: string);
  80. procedure PopFile;
  81. function CheckFile(const FileName: string): Boolean;
  82. function EmitDestination: TStringList;
  83. procedure SendMsg(Msg: string; Typ: TIsppMessageType);
  84. function GetFileName(Code: Integer): string;
  85. function GetLineNumber(Code: Integer): Integer;
  86. procedure RaiseErrorEx(const Message: string; Column: Integer);
  87. procedure ExecProc(Body: TStrings);
  88. protected
  89. function GetDefaultScope: TDefineScope;
  90. procedure SetDefaultScope(Scope: TDefineScope);
  91. procedure InternalAddLine(const LineRead: string; FileIndex, LineNo: Integer;
  92. NonISS: Boolean);
  93. function InternalQueueLine(const LineRead: string; FileIndex, LineNo: Integer;
  94. NonISS: Boolean): Integer;
  95. function ParseFormalParams(Parser: TParser; var ParamList: PParamList): Integer;
  96. { IUnknown }
  97. function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
  98. function _AddRef: Integer; stdcall;
  99. function _Release: Integer; stdcall;
  100. { IIdentManager }
  101. function LookupPredefined(Name: string; Value: PIsppVariant): Boolean;
  102. function Defined(const Name: String): Boolean;
  103. function GetIdent(const Name: String;
  104. out CallContext: ICallContext): TIdentType;
  105. function TypeOf(const Name: String): Byte;
  106. function DimOf(const Name: String): Integer;
  107. public
  108. FOptions: TISPPOptions;
  109. constructor Create(const CompilerParams: TPreprocessScriptParams;
  110. VarManager: TIdentManager; const Options: TIsppOptions;
  111. const SourcePath: string; const CompilerPath: string; const FileName: string = '');
  112. destructor Destroy; override;
  113. procedure CallIdleProc;
  114. procedure VerboseMsg(Level: Integer; const Msg: string); overload;
  115. procedure VerboseMsg(Level: Integer; const Msg: string; const Args: array of const); overload;
  116. procedure StatusMsg(const Msg: string); overload;
  117. procedure StatusMsg(const Msg: string; const Args: array of const); overload;
  118. procedure WarningMsg(const Msg: string); overload;
  119. procedure WarningMsg(const Msg: string; const Args: array of const); overload;
  120. function GetNextOutputLine(var LineFilename: string; var LineNumber: Integer;
  121. var LineText: string): Boolean;
  122. procedure GetNextOutputLineReset;
  123. procedure IncludeFile(FileName: string; Builtins, UseIncludePathOnly, ResetCurrentFile: Boolean);
  124. procedure QueueLine(const LineRead: string);
  125. function PrependDirName(const FileName, Dir: string): string;
  126. procedure RegisterFunction(const Name: string; Handler: TIsppFunction; Ext: NativeInt);
  127. procedure RaiseError(const Message: string);
  128. procedure SaveToFile(const FileName: string);
  129. procedure CollectGarbage(Item: Pointer; Proc: TDropGarbageProc);
  130. procedure UncollectGarbage(Item: Pointer);
  131. property IncludedFiles: TStringList read FIncludes;
  132. property IncludePath: string read FIncludePath write FIncludePath;
  133. property SourcePath: string read FSourcePath;
  134. property StringList: TStringList read FOutput;
  135. property Stack: TConditionalTranslationStack read FStack;
  136. property VarMan: TIdentManager read FIdentManager;
  137. end;
  138. implementation
  139. uses
  140. PathFunc, UnsignedFunc,
  141. Shared.CommonFunc, Shared.FileClass, Shared.Struct,
  142. ISPP.Consts, ISPP.Funcs, ISPP.VarUtils, ISPP.Sessions, ISPP.CTokenizer;
  143. const
  144. PreprocCommands: array[TPreprocessorCommand] of String =
  145. ('', 'if', 'ifdef', 'ifndef', 'ifexist', 'ifnexist', 'elif', 'else',
  146. 'endif', 'define', 'undef', 'include', 'error', 'pragma', 'line', 'import',
  147. 'emit', 'env', 'file', 'expr', 'insert', 'append', 'dim', 'sub', 'endsub',
  148. 'endloop', 'for', 'redim');
  149. PpCmdSynonyms: array[TPreprocessorCommand] of Char =
  150. (#0, '?', #0, #0, #0, #0, #0, '^', '.', ':', #0, '+', #0, #0, #0, #0,
  151. '=', '%', #0, '!', #0, #0, #0, #0, #0, #0, #0, #0);
  152. function GetEnv(const EnvVar: String): String;
  153. function AdjustLength(var S: String; const Res: Cardinal): Boolean;
  154. begin
  155. Result := Integer(Res) < Length(S);
  156. SetLength (S, Res);
  157. end;
  158. var
  159. Res: DWORD;
  160. begin
  161. SetLength(Result, 255);
  162. repeat
  163. Res := GetEnvironmentVariable(PChar(EnvVar), PChar(Result), ULength(Result));
  164. if Res = 0 then begin
  165. Result := '';
  166. Break;
  167. end;
  168. until AdjustLength(Result, Res);
  169. end;
  170. function ParsePreprocCommand(var P: PChar; ExtraTerminator: Char): TPreprocessorCommand;
  171. begin
  172. for Result := TPreprocessorCommand(1) to High(TPreprocessorCommand) do
  173. begin
  174. if (P^ = PpCmdSynonyms[Result]) then
  175. Inc(P)
  176. else if (StrLIComp(P, @PreprocCommands[Result][1], ULength(PreprocCommands[Result])) = 0) and
  177. CharInSet(P[Length(PreprocCommands[Result])], [#0..#32, ExtraTerminator]) then
  178. Inc(P, Length(PreprocCommands[Result]))
  179. else
  180. Continue;
  181. Exit;
  182. end;
  183. if StrLIComp('echo', P, 4) = 0 then
  184. begin
  185. Result := pcEmit;
  186. Inc(P, 4)
  187. end
  188. else if StrLIComp('call', P, 4) = 0 then
  189. begin
  190. Result := pcExpr;
  191. Inc(P, 4);
  192. end
  193. else
  194. Result := pcError;
  195. end;
  196. { EPreprocError }
  197. constructor EPreprocError.Create(Preproc: TPreprocessor; const Msg: string);
  198. begin
  199. inherited Create(AddPeriod(Msg));
  200. FileName := Preproc.GetFileName(-1);
  201. LineNumber := Preproc.GetLineNumber(-1);
  202. end;
  203. { TPreprocessor }
  204. function CheckReservedIdent(const Ident: string): string;
  205. begin
  206. Result := UpperCase(Ident);
  207. if (Result = SLocal) or
  208. (Result = SGlobal) or
  209. (Result = SInt) or
  210. (Result = SStr) or
  211. (Result = SAny) then
  212. raise EParsingError.CreateFmt(SExpectedButFound, [SIdent, '''' + Result + '''']);
  213. Result := Ident;
  214. end;
  215. constructor TPreprocessor.Create(const CompilerParams: TPreprocessScriptParams;
  216. VarManager: TIdentManager; const Options: TIsppOptions;
  217. const SourcePath, CompilerPath, FileName: string);
  218. begin
  219. PushPreproc(Self);
  220. if VarManager = nil then
  221. FIdentManager := TIdentManager.Create(Self, NativeInt(Self))
  222. else
  223. FIdentManager := VarManager;
  224. FOptions := Options;
  225. FIdentManager._AddRef;
  226. FIdentManager.BeginLocal;
  227. FCompilerParams := CompilerParams;
  228. FCompilerPath := CompilerPath;
  229. FSourcePath := SourcePath;
  230. FFileStack := TStringList.Create;
  231. FIncludes := TStringList.Create;
  232. FIncludes.Add(FileName); //main file - no name
  233. FInsertionPoint := -1;
  234. FOutput := TStringList.Create;
  235. FProcs := TStringList.Create;
  236. FStack := TConditionalTranslationStack.Create(Self);
  237. if VarManager = nil then ISPP.Funcs.RegisterFunctions(Self);
  238. end;
  239. destructor TPreprocessor.Destroy;
  240. begin
  241. DropGarbage;
  242. if PopPreproc <> Self then
  243. RaiseError('Internal error: FSP');
  244. FStack.Free;
  245. FProcs.Free;
  246. FOutput.Free;
  247. FIncludes.Free;
  248. if FFileStack.Count <> 0 then
  249. RaiseError('Internal error: FNE');
  250. FFileStack.Free;
  251. FIdentManager.EndLocal;
  252. FIdentManager._Release;
  253. end;
  254. function TPreprocessor.GetFileName(Code: Integer): string;
  255. begin
  256. if Code = -1 then
  257. Result := FIncludes[FCurrentFile]
  258. else
  259. Result := FIncludes[Integer(FOutput.Objects[Code]) shr 16];
  260. end;
  261. function TPreprocessor.GetLineNumber(Code: Integer): Integer;
  262. begin
  263. if Code = -1 then
  264. Result := FCurrentLine
  265. else
  266. Result := Integer(FOutput.Objects[Code]) and $FFFF
  267. end;
  268. function TPreprocessor.GetNextOutputLine(var LineFilename: string; var LineNumber: Integer;
  269. var LineText: string): Boolean;
  270. begin
  271. Result := False;
  272. if FLinePointer < FOutput.Count then
  273. begin
  274. LineFilename := GetFileName(FLinePointer);
  275. LineNumber := GetLineNumber(FLinePointer);
  276. LineText := FOutput[FLinePointer];
  277. Inc(FLinePointer);
  278. Result := True;
  279. end;
  280. end;
  281. procedure TPreprocessor.GetNextOutputLineReset;
  282. begin
  283. FLinePointer := 0;
  284. end;
  285. procedure TPreprocessor.InternalAddLine(const LineRead: string; FileIndex, LineNo: Integer;
  286. NonISS: Boolean);
  287. var
  288. IncludeLine: Boolean;
  289. P, P1: PChar;
  290. Command: TPreprocessorCommand;
  291. DirectiveOffset: Integer;
  292. State: Boolean;
  293. S, S1: string;
  294. begin
  295. try
  296. Inc(LineNo);
  297. FCurrentFile := FileIndex;
  298. FCurrentLine := LineNo;
  299. P := PChar(LineRead);
  300. IncludeLine := True;
  301. if P^ <> #0 then
  302. begin
  303. P1 := P;
  304. while CharInSet(P^, [#1..#32]) do Inc(P);
  305. if P^ = '#' then
  306. begin
  307. Inc(P);
  308. while CharInSet(P^, [#1..#32]) do Inc(P);
  309. IncludeLine := FInProcBody;
  310. Command := ParsePreprocCommand(P, #0);
  311. if FInProcBody then
  312. begin
  313. case Command of
  314. pcError: RaiseError(SUnknownPreprocessorDirective);
  315. pcSub: RaiseError('Nested procedure declaration not allowed');
  316. pcEndSub:
  317. begin
  318. S := P;
  319. ProcessPreprocCommand(Command, S, P - P1);
  320. IncludeLine := False;
  321. end
  322. else
  323. S := LineRead;
  324. end;
  325. end
  326. else
  327. begin
  328. State := FStack.Include;
  329. DirectiveOffset := P - P1;
  330. //S := Copy(LineRead, DirectiveOffset + 1, MaxInt);
  331. S := P;
  332. case Command of
  333. pcIf..pcIfNExist:
  334. FStack.IfInstruction(FStack.Include and
  335. ProcessPreprocCommand(Command, S, DirectiveOffset));
  336. pcElseIf:
  337. FStack.ElseIfInstruction(FStack.Last.Fired or
  338. (FStack.Include or not FStack.Last.BlockState) and
  339. ProcessPreprocCommand(Command, S, DirectiveOffset));
  340. pcElse: FStack.ElseInstruction;
  341. pcEndIf: FStack.EndIfInstruction
  342. else
  343. if State then
  344. case Command of
  345. pcEmit, pcEnv:
  346. begin
  347. ProcessPreprocCommand(Command, S, DirectiveOffset);
  348. VerboseMsg(8, SLineEmitted, [S]);
  349. IncludeLine := True
  350. end;
  351. pcFile: RaiseError(SFileDirectiveCanBeOnlyInline);
  352. else
  353. ProcessPreprocCommand(Command, S, DirectiveOffset);
  354. end;
  355. end
  356. end;
  357. end
  358. else
  359. if not FInProcBody and not FStack.Include then
  360. IncludeLine := False
  361. else
  362. if ((P^ = '/') and (P[1] = '/')) or
  363. ((P^ = #0) and not (optEmitEmptyLines in FOptions.Options)) then //P^ is #0 if the line was all whitespace
  364. IncludeLine := False
  365. else
  366. if (P^ <> #0) and (P^ <> ';') and not FInProcBody then
  367. S := PChar(ProcessInlineDirectives(P1))
  368. else
  369. S := P1;
  370. end
  371. else
  372. begin
  373. S := '';
  374. IncludeLine := optEmitEmptyLines in FOptions.Options
  375. end;
  376. if IncludeLine then
  377. begin
  378. P := PChar(S);
  379. repeat
  380. P1 := P;
  381. while not CharInSet(P^, [#0, #10, #13]) do Inc(P);
  382. SetString(S1, P1, P - P1);
  383. if FInsertionPoint >= 0 then
  384. begin
  385. EmitDestination.InsertObject(FInsertionPoint, S1,
  386. TObject(FileIndex shl 16 or LineNo));
  387. Inc(FInsertionPoint);
  388. end
  389. else
  390. EmitDestination.AddObject(S1, TObject(FileIndex shl 16 or LineNo));
  391. while CharInSet(P^, [#10, #13]) do Inc(P);
  392. until P^ = #0;
  393. end;
  394. except
  395. on E: EParsingError do
  396. RaiseErrorEx(E.Message, E.Position);
  397. on E: EPreprocError do
  398. raise;
  399. on E: Exception do
  400. RaiseError(E.Message);
  401. end;
  402. end;
  403. function TPreprocessor.ProcessInlineDirectives(P: PChar): string;
  404. var
  405. S: string;
  406. Command: TPreprocessorCommand;
  407. LineStack: TConditionalTranslationStack;
  408. LineStart, P1, DStart, DEnd: PChar;
  409. function ScanForInlineStart(var P, D: PChar): Boolean;
  410. var
  411. I: Integer;
  412. begin
  413. Result := False;
  414. while P^ <> #0 do
  415. begin
  416. if P^ = FOptions.InlineStart[1] then
  417. begin
  418. D := P;
  419. Result := True;
  420. for I := 2 to Length(FOptions.InlineStart) do
  421. begin
  422. Inc(D);
  423. if D^ <> FOptions.InlineStart[I] then
  424. begin
  425. Result := False;
  426. Break;
  427. end;
  428. end;
  429. Inc(D);
  430. end;
  431. if Result then Break;
  432. Inc(P);
  433. end;
  434. end;
  435. function ScanForInlineEnd(var P: PChar): PChar;
  436. var
  437. I: Integer;
  438. begin
  439. Result := nil;
  440. while P^ <> #0 do
  441. begin
  442. if P^ = FOptions.InlineEnd[1] then
  443. begin
  444. Result := P;
  445. for I := 2 to Length(FOptions.InlineEnd) do
  446. begin
  447. Inc(P);
  448. if P^ <> FOptions.InlineEnd[I] then
  449. begin
  450. Result := nil;
  451. Break;
  452. end;
  453. end;
  454. Inc(P);
  455. end;
  456. if Result <> nil then Exit;
  457. Inc(P);
  458. end;
  459. RaiseError(SUnterminatedPreprocessorDirectiv);
  460. end;
  461. begin
  462. LineStack := TConditionalTranslationStack.Create(Self);
  463. try
  464. Result := '';
  465. LineStart := P;
  466. P1 := P;
  467. while ScanForInlineStart(P, DStart) do
  468. begin
  469. SetString(S, P1, P - P1);
  470. if LineStack.Include then Result := Result + S;
  471. Command := ParsePreprocCommand(DStart, Char(FOptions.InlineEnd[1]));
  472. if Command = pcError then
  473. Command := pcEmit;
  474. DEnd := DStart;
  475. SetString(S, DStart, ScanForInlineEnd(DEnd) - DStart);
  476. case Command of
  477. pcError: RaiseError(SUnknownPreprocessorDirective);
  478. pcIf..pcIfNExist:
  479. LineStack.IfInstruction(LineStack.Include and
  480. ProcessPreprocCommand(Command, S, DStart - LineStart));
  481. pcElseIf:
  482. LineStack.ElseIfInstruction(LineStack.Last.Fired or
  483. (LineStack.Include or not LineStack.Last.BlockState) and
  484. ProcessPreprocCommand(Command, S, DStart - LineStart));
  485. pcElse: LineStack.ElseInstruction;
  486. pcEndIf: LineStack.EndIfInstruction;
  487. else
  488. if LineStack.Include then
  489. case Command of
  490. pcInclude, pcInsert..pcEndSub:
  491. RaiseError(Format(SDirectiveCannotBeInline,
  492. [PreprocCommands[Command]]));
  493. pcEmit, pcEnv, pcFile:
  494. begin
  495. ProcessPreprocCommand(Command, S, DStart - LineStart);
  496. Result := Result + S;
  497. end;
  498. else
  499. ProcessPreprocCommand(Command, S, DStart - LineStart)
  500. end;
  501. end;
  502. P1 := DEnd;
  503. P := DEnd;
  504. //Inc(P);
  505. end;
  506. Result := Result + P1;
  507. LineStack.Resolved;
  508. finally
  509. LineStack.Free
  510. end;
  511. end;
  512. function TPreprocessor.GetDefaultScope: TDefineScope;
  513. begin
  514. if FFileStack.Count > 0 then
  515. Result := TDefineScope(FFileStack.Objects[FFileStack.Count - 1])
  516. else
  517. Result := FDefaultScope;
  518. end;
  519. procedure TPreprocessor.SetDefaultScope(Scope: TDefineScope);
  520. begin
  521. if Scope = dsAny then Scope := dsPublic;
  522. if FFileStack.Count > 0 then
  523. FFileStack.Objects[FFileStack.Count - 1] := TObject(Scope)
  524. else
  525. FDefaultScope := Scope;
  526. end;
  527. type
  528. TParserAccess = class(TParser);
  529. function TPreprocessor.ProcessPreprocCommand(Command: TPreprocessorCommand;
  530. var Params: string; ParamsOffset: Integer): Boolean;
  531. function ParseScope(Parser: TParser; ExpectedTokens: TTokenKinds = [tkIdent]): TDefineScope;
  532. const
  533. ScopeClauses: array[dsPublic..dsPrivate] of string =
  534. ('public', 'protected', 'private');
  535. begin
  536. Parser.NextTokenExpect([tkIdent]);
  537. for Result := Low(ScopeClauses) to High(ScopeClauses) do
  538. if CompareText(Parser.TokenString, ScopeClauses[Result]) = 0 then
  539. begin
  540. Parser.NextTokenExpect(ExpectedTokens);
  541. Exit;
  542. end;
  543. Result := dsAny;
  544. end;
  545. function GetScope(Parser: TParser): TDefineScope;
  546. begin
  547. Result := ParseScope(Parser);
  548. if Result = dsAny then Result := GetDefaultScope;
  549. end;
  550. procedure ParseDim(Parser: TParserAccess; ReDim: Boolean);
  551. var
  552. Name: string;
  553. N, NValues, I: Integer;
  554. Scope: TDefineScope;
  555. Values: array of TIsppVariant;
  556. begin
  557. with Parser do
  558. try
  559. Scope := GetScope(Parser);
  560. Name := CheckReservedIdent(TokenString);
  561. NextTokenExpect([tkOpenBracket]);
  562. N := IntegerExpr(True);
  563. NValues := 0;
  564. NextTokenExpect([tkCloseBracket]);
  565. if PeekAtNextToken = tkOpenBrace then
  566. begin
  567. NextToken;
  568. SetLength(Values, N);
  569. NValues := 0;
  570. while True do begin
  571. if NValues >= N then
  572. raise EIdentError.CreateFmt(SIndexIsOutOfArraySize, [NValues, Name]);
  573. Values[NValues] := Expr(True);
  574. MakeRValue(Values[NValues]);
  575. Inc(NValues);
  576. if PeekAtNextToken <> tkComma then
  577. Break;
  578. NextToken;
  579. end;
  580. NextTokenExpect([tkCloseBrace]);
  581. end;
  582. FIdentManager.DimVariable(Name, N, Scope, ReDim);
  583. if ReDim and (NValues <> 0) then
  584. Error('Initializers not allowed on #redim of existing array');
  585. for I := 0 to NValues-1 do
  586. FIdentManager.DefineVariable(Name, I, Values[I], Scope);
  587. finally
  588. //Free
  589. end;
  590. end;
  591. procedure ParseDefine(Parser: TParserAccess);
  592. var
  593. Name: string;
  594. Start, P: PChar;
  595. IsMacroDefine: Boolean;
  596. ParamList: PParamList;
  597. AExpr: string;
  598. VarIndex: Integer;
  599. Scope: TDefineScope;
  600. MacroExprPos: TExprPosition;
  601. begin
  602. with Parser do
  603. begin
  604. Start := FExpr;
  605. Scope := ParseScope(Parser, [tkEOF, tkIdent, tkSemicolon]);
  606. if Scope = dsAny then
  607. Scope := GetDefaultScope
  608. else
  609. if Token <> tkIdent then
  610. begin
  611. SetDefaultScope(Scope);
  612. Exit;
  613. end;
  614. Name := CheckReservedIdent(TokenString);
  615. IsMacroDefine := FExpr^ = '(';
  616. if IsMacroDefine then
  617. begin
  618. NextToken;
  619. const AParamCount = ParseFormalParams(Parser, ParamList);
  620. try
  621. Inc(FExpr);
  622. P := FExpr;
  623. MacroExprPos.FileIndex := FCurrentFile;
  624. MacroExprPos.Line := FCurrentLine;
  625. MacroExprPos.Column := (FExpr - Start) + ParamsOffset;
  626. while P^ <> #0 do Inc(P);
  627. SetString(AExpr, FExpr, P - FExpr);
  628. AExpr := Trim(AExpr);
  629. if AExpr = '' then RaiseError(SMacroExpressionExpected);
  630. FIdentManager.DefineMacro(Name, AExpr, MacroExprPos, FOptions.ParserOptions,
  631. Slice(ParamList^, AParamCount), Scope);
  632. finally
  633. Finalize(ParamList^[0], AParamCount);
  634. FreeMem(ParamList)
  635. end;
  636. end
  637. else
  638. begin
  639. VarIndex := -1;
  640. if PeekAtNextToken = tkOpenBracket then
  641. begin
  642. NextToken;
  643. VarIndex := IntegerExpr(True);
  644. NextTokenExpect([tkCloseBracket]);
  645. end;
  646. case PeekAtNextToken of
  647. opAssign: NextToken;
  648. tkEOF:
  649. begin
  650. FIdentManager.DefineVariable(Name, VarIndex, NULL, Scope);
  651. Exit;
  652. end
  653. end;
  654. FIdentManager.DefineVariable(Name, VarIndex, Evaluate, Scope);
  655. end;
  656. end;
  657. end;
  658. procedure ParseUndef(Parser: TParserAccess);
  659. var
  660. Scope: TDefineScope;
  661. begin
  662. with Parser do
  663. begin
  664. Scope := GetScope(Parser);
  665. FIdentManager.Delete(CheckReservedIdent(TokenString), Scope);
  666. EndOfExpr;
  667. end
  668. end;
  669. procedure IncludeFile(const Params: string);
  670. var
  671. FileName: string;
  672. function TryPascal: Boolean;
  673. begin
  674. Result := not (optPascalStrings in FOptions.ParserOptions.Options);
  675. if Result then
  676. begin
  677. Include(FOptions.ParserOptions.Options, optPascalStrings);
  678. try
  679. try
  680. FileName := ParseStr(Self, Params, ParamsOffset,
  681. @FOptions.ParserOptions);
  682. except
  683. Result := False
  684. end;
  685. finally
  686. Exclude(FOptions.ParserOptions.Options, optPascalStrings);
  687. end;
  688. end
  689. end;
  690. var
  691. IncludePathOnly: Boolean;
  692. begin
  693. FileName := Params;
  694. if Pos(';', FileName) > 0 then
  695. Delete(FileName, Pos(';', FileName), MaxInt);
  696. FileName := Trim(FileName);
  697. if (FileName <> '') and (FileName[1] = '<') and
  698. (FileName[Length(FileName)] = '>') then
  699. begin
  700. FileName := Copy(FileName, 2, Length(FileName) - 2);
  701. IncludePathOnly := True;
  702. end
  703. else
  704. begin
  705. try
  706. FileName := ParseStr(Self, Params, ParamsOffset, @FOptions.ParserOptions);
  707. except
  708. if not TryPascal then
  709. raise
  710. end;
  711. IncludePathOnly := False;
  712. end;
  713. Self.IncludeFile(FileName, False, IncludePathOnly, False);
  714. end;
  715. procedure Pragma(Parser: TParserAccess);
  716. var
  717. P: string;
  718. function StrPragma(AllowEmpty: Boolean): string;
  719. begin
  720. Result := Parser.StrExpr(True);
  721. if (Result = '') and not AllowEmpty then
  722. RaiseError(SNonEmptyStringExpected);
  723. Parser.EndOfExpr;
  724. end;
  725. procedure OptionPragma(var Options: TOptions);
  726. var
  727. C: Char;
  728. V: Boolean;
  729. begin
  730. with Parser do
  731. begin
  732. NextTokenExpect([opSubtract]);
  733. repeat
  734. NextTokenExpect([tkIdent]);
  735. if Length(TokenString) > 1 then
  736. RaiseError(SInvalidOptionName);
  737. C := TokenString[1];
  738. V := NextTokenExpect([opAdd, opSubtract]) = opAdd;
  739. SetOption(Options, C, V);
  740. until NextTokenExpect([tkEOF, opSubtract, tkSemicolon]) <> opSubtract;
  741. end;
  742. end;
  743. var
  744. CatchException: Boolean;
  745. ErrorMsg: string;
  746. begin
  747. CatchException := True;
  748. try
  749. with Parser do
  750. begin
  751. NextTokenExpect([tkIdent]);
  752. P := LowerCase(TokenString);
  753. if P = 'include' then
  754. FIncludePath := StrPragma(True)
  755. else if P = 'inlinestart' then
  756. FOptions.InlineStart := StrPragma(False)
  757. else if P = 'inlineend' then
  758. FOptions.InlineEnd := StrPragma(False)
  759. else if P = 'spansymbol' then
  760. FOptions.SpanSymbol := StrPragma(False)[1]
  761. else if P = 'parseroption' then
  762. OptionPragma(FOptions.ParserOptions.Options)
  763. else if P = 'option' then
  764. OptionPragma(FOptions.Options)
  765. else if P = 'verboselevel' then
  766. begin
  767. Include(FOptions.Options, optVerbose);
  768. FOptions.VerboseLevel := IntegerExpr(True);
  769. VerboseMsg(0, SChangedVerboseLevel, [FOptions.VerboseLevel]);
  770. EndOfExpr;
  771. end
  772. else if P = 'warning' then begin
  773. { Also see WarningFunc in IsppFuncs }
  774. WarningMsg(StrPragma(True))
  775. end else if P = 'message' then begin
  776. { Also see MessageFunc in IsppFuncs }
  777. StatusMsg(StrPragma(True))
  778. end else if P = 'error' then begin
  779. { Also see ErrorFunc in IsppFuncs }
  780. ErrorMsg := StrPragma(True);
  781. if ErrorMsg = '' then ErrorMsg := 'Error';
  782. CatchException := False;
  783. RaiseError(ErrorMsg)
  784. end
  785. else
  786. WarningMsg(SFailedToParsePragmaDirective);
  787. end;
  788. except
  789. if CatchException then
  790. WarningMsg(SFailedToParsePragmaDirective)
  791. else
  792. raise
  793. end;
  794. end;
  795. function DoFile(FileName: string): string;
  796. function GetTempFileName(const Original: string): string;
  797. var
  798. Path: string;
  799. begin
  800. SetLength(Path, MAX_PATH);
  801. SetLength(Path, GetTempPath(MAX_PATH, PChar(Path)));
  802. SetLength(Result, MAX_PATH);
  803. if Windows.GetTempFileName(PChar(Path), PChar(UpperCase(Original)), 0, PChar(Result)) <> 0 then
  804. SetLength(Result, StrLen(PChar(Result)))
  805. else
  806. RaiseLastOSError;
  807. end;
  808. var
  809. F: TTextFileReader;
  810. ALine: string;
  811. Preprocessor: TPreprocessor;
  812. NewOptions: TIsppOptions;
  813. begin
  814. FileName := PrependDirName(FileName, FSourcePath);
  815. if FileExists(FileName) then
  816. begin
  817. Result := GetTempFileName(PathExtractName(FileName));
  818. StatusMsg(SProcessingExternalFile, [FileName]);
  819. NewOptions := FOptions;
  820. Preprocessor := TPreprocessor.Create(FCompilerParams, FIdentManager,
  821. NewOptions, FSourcePath, FCompilerPath, FileName);
  822. try
  823. F := TTextFileReader.Create(Filename, fdOpenExisting, faRead, fsRead);
  824. try
  825. while not F.Eof do begin
  826. ALine := F.ReadLine;
  827. Preprocessor.QueueLine(ALine);
  828. end;
  829. finally
  830. F.Free;
  831. end;
  832. Preprocessor.SaveToFile(Result);
  833. QueueFileForDeletion(Result);
  834. VerboseMsg(1, STemporaryFileCreated, [Result]);
  835. finally
  836. Preprocessor.Free;
  837. end;
  838. end
  839. else
  840. RaiseError(Format(SFileNotFound, [FileName]));
  841. end;
  842. procedure ParseFor(Parser: TParserAccess);
  843. var
  844. Condition, Action, Body: PChar;
  845. begin
  846. Parser.NextTokenExpect([tkOpenBrace]);
  847. Parser.Expr(False);
  848. Parser.NextTokenExpect([tkSemicolon]);
  849. { Skip condition and remember it }
  850. Condition := Parser.FExpr;
  851. Parser.Sequentional(False);
  852. Parser.NextTokenExpect([tkSemicolon]);
  853. Action := Parser.FExpr;
  854. Parser.Sequentional(False);
  855. Parser.NextTokenExpect([tkCloseBrace]);
  856. Body := Parser.FExpr;
  857. Parser.Sequentional(False);
  858. Parser.EndOfExpr;
  859. Parser.SetPos(Condition);
  860. while Parser.IntExpr(False) <> 0 do
  861. begin
  862. Parser.SetPos(Body);
  863. Parser.Sequentional(True);
  864. Parser.SetPos(Action);
  865. Parser.Sequentional(True);
  866. Parser.SetPos(Condition);
  867. end;
  868. end;
  869. procedure BeginInsert(LineNo: Integer);
  870. begin
  871. if LineNo > FOutput.Count then
  872. RaiseError(Format(SInsertLineNoTooBig, [LineNo]));
  873. FInsertionPoint := LineNo;
  874. VerboseMsg(2, SChangingInsertionPointToLine, [FInsertionPoint]);
  875. end;
  876. procedure EndInsert;
  877. begin
  878. VerboseMsg(2, SResettingInsertionPoint);
  879. FInsertionPoint := -1;
  880. end;
  881. procedure BeginProcDecl(Parser: TParserAccess);
  882. var
  883. ProcName: string;
  884. begin
  885. if FInForBody or FInProcBody then
  886. RaiseError('Nested procedure declaration and compound loops not allowed');
  887. FInProcBody := True;
  888. Parser.NextTokenExpect([tkIdent]);
  889. ProcName := Parser.TokenString;
  890. Parser.EndOfExpr;
  891. FProcs.AddObject(ProcName, TStringList.Create);
  892. EmitDestination.Add('#define private');
  893. end;
  894. procedure EndProcDecl;
  895. begin
  896. if not FInProcBody then
  897. RaiseError('''endproc'' without ''procedure''');
  898. FInProcBody := False;
  899. end;
  900. var
  901. IfCondition: TIsppVariant;
  902. DummyContext: ICallContext;
  903. Parser: TParserAccess;
  904. begin
  905. Result := False;
  906. Parser := TParserAccess.Create(Self, Params, ParamsOffset, @FOptions.ParserOptions);
  907. with Parser do
  908. try
  909. case Command of
  910. pcError: RaiseError(SUnknownPreprocessorDirective);
  911. pcIf, pcElseIf:
  912. begin
  913. IfCondition := Evaluate;
  914. Result := IfCondition.AsBoolean;
  915. if IfCondition.Typ = evNull then
  916. WarningMsg(SSpecifiedConditionEvalatedToVoid);
  917. end;
  918. pcIfdef, pcIfndef:
  919. begin
  920. NextTokenExpect([tkIdent]);
  921. case GetIdent(TokenString, DummyContext) of
  922. itUnknown: Result := Command = pcIfNDef;
  923. itVariable, itMacro: Result := Command = pcIfDef;
  924. itFunc:
  925. begin
  926. Result := Command = pcIfDef;
  927. WarningMsg(SFuncIdentForIfdef);
  928. end;
  929. else
  930. begin
  931. Result := Command = pcIfNDef;
  932. WarningMsg(SSpecFuncIdentForIfdef);
  933. end;
  934. end;
  935. EndOfExpr;
  936. end;
  937. pcIfExist, pcIfNExist:
  938. Result := FileExists(PrependDirName(StrExpr(False), FSourcePath)) xor (Command = pcIfNExist);
  939. pcDefine: ParseDefine(Parser);
  940. pcDim: ParseDim(Parser, False);
  941. pcReDim: ParseDim(Parser, True);
  942. pcUndef: ParseUndef(Parser);
  943. pcInclude: IncludeFile(Params);
  944. pcErrorDir:
  945. begin
  946. { Also see ErrorFunc in IsppFuncs }
  947. if Params = '' then Params := 'Error';
  948. RaiseError(Params.Trim);
  949. end;
  950. pcPragma: Pragma(Parser);
  951. pcEmit: Params := ToStr(Evaluate).AsStr;
  952. pcEnv:
  953. begin
  954. NextTokenExpect([tkIdent]);
  955. Params := GetEnv(TokenString);
  956. EndOfExpr;
  957. end;
  958. pcFile: Params := DoFile(StrExpr(False));
  959. pcExpr: Evaluate;
  960. pcInsert: BeginInsert(IntegerExpr(False));
  961. pcAppend: EndInsert;
  962. pcFor: ParseFor(Parser);
  963. pcSub: BeginProcDecl(Parser);
  964. pcEndSub: EndProcDecl;
  965. else
  966. WarningMsg(SDirectiveNotYetSupported, [PreprocCommands[Command]])
  967. end;
  968. finally
  969. Free
  970. end;
  971. end;
  972. function TPreprocessor.InternalQueueLine(const LineRead: string;
  973. FileIndex, LineNo: Integer; NonISS: Boolean): Integer; //how many just been added
  974. var
  975. L: Integer;
  976. begin
  977. L := Length(LineRead);
  978. if (L > 2) and (LineRead[L] = FOptions.SpanSymbol) and (LineRead[L - 1] <= #32) then
  979. begin
  980. FQueuedLine := FQueuedLine + TrimLeft(Copy(LineRead, 1, L - 1));
  981. Inc(FQueuedLineCount);
  982. Result := 0;
  983. end
  984. else
  985. if FQueuedLineCount > 0 then
  986. begin
  987. InternalAddLine(FQueuedLine + TrimLeft(LineRead), FileIndex, LineNo, NonISS);
  988. FQueuedLine := '';
  989. Result := FQueuedLineCount + 1;
  990. FQueuedLineCount := 0;
  991. end
  992. else
  993. begin
  994. InternalAddLine(LineRead, FileIndex, LineNo, NonISS);
  995. Result := 1;
  996. end;
  997. end;
  998. procedure TPreprocessor.QueueLine(const LineRead: string);
  999. begin
  1000. Inc(FMainCounter, InternalQueueLine(LineRead, 0, FMainCounter, False));
  1001. end;
  1002. procedure TPreprocessor.RegisterFunction(const Name: string; Handler: TIsppFunction; Ext: NativeInt);
  1003. begin
  1004. FIdentManager.DefineFunction(Name, Handler, Ext);
  1005. end;
  1006. procedure TPreprocessor.SaveToFile(const FileName: string);
  1007. begin
  1008. var OldWriteBOM := FOutput.WriteBOM;
  1009. try
  1010. FOutput.WriteBOM := False;
  1011. FOutput.SaveToFile(FileName, TEncoding.UTF8);
  1012. finally
  1013. FOutput.WriteBOM := OldWriteBOM;
  1014. end;
  1015. end;
  1016. function TPreprocessor.CheckFile(const FileName: string): Boolean;
  1017. begin
  1018. Result := FFileStack.IndexOf(PathExpand(FileName)) < 0;
  1019. end;
  1020. procedure TPreprocessor.PopFile;
  1021. begin
  1022. FFileStack.Delete(FFileStack.Count - 1);
  1023. end;
  1024. procedure TPreprocessor.PushFile(const FileName: string);
  1025. begin
  1026. FFileStack.AddObject(PathExpand(FileName), TObject(dsPublic));
  1027. end;
  1028. procedure TPreprocessor.CallIdleProc;
  1029. begin
  1030. FCompilerParams.IdleProc(FCompilerParams.CompilerData);
  1031. end;
  1032. procedure TPreprocessor.VerboseMsg(Level: Integer; const Msg: string);
  1033. begin
  1034. if (optVerbose in FOptions.Options) and (FOptions.VerboseLevel >= Level) then
  1035. StatusMsg(Msg);
  1036. end;
  1037. procedure TPreprocessor.VerboseMsg(Level: Integer; const Msg: string;
  1038. const Args: array of const);
  1039. begin
  1040. VerboseMsg(Level, Format(Msg, Args));
  1041. end;
  1042. procedure TPreprocessor.StatusMsg(const Msg: string);
  1043. begin
  1044. SendMsg(Msg, imtStatus);
  1045. end;
  1046. procedure TPreprocessor.StatusMsg(const Msg: string; const Args: array of const);
  1047. begin
  1048. StatusMsg(Format(Msg, Args));
  1049. end;
  1050. procedure TPreprocessor.WarningMsg(const Msg: string);
  1051. begin
  1052. SendMsg(Msg, imtWarning);
  1053. end;
  1054. procedure TPreprocessor.WarningMsg(const Msg: string; const Args: array of const);
  1055. begin
  1056. WarningMsg(Format(Msg, Args));
  1057. end;
  1058. procedure TPreprocessor.SendMsg(Msg: string; Typ: TIsppMessageType);
  1059. const
  1060. MsgPrefixes: array[TIsppMessageType] of string = ('', 'Warning: ');
  1061. var
  1062. FileName: String;
  1063. begin
  1064. Msg := MsgPrefixes[Typ] + Msg;
  1065. const LineNumber = GetLineNumber(-1);
  1066. if LineNumber <> 0 then begin
  1067. FileName := GetFileName(-1);
  1068. if FileName <> '' then
  1069. Msg := Format('Line %d of %s: %s', [LineNumber, PathExtractName(FileName), Msg])
  1070. else
  1071. Msg := Format('Line %d: %s', [LineNumber, Msg]);
  1072. end;
  1073. FCompilerParams.StatusProc(FCompilerParams.CompilerData, PChar(Msg), Typ = imtWarning);
  1074. end;
  1075. function TPreprocessor.DimOf(const Name: String): Integer;
  1076. begin
  1077. Result := FIdentManager.DimOf(Name)
  1078. end;
  1079. function TPreprocessor.EmitDestination: TStringList;
  1080. begin
  1081. if FInProcBody then
  1082. Result := TStringList(FProcs.Objects[FProcs.Count - 1])
  1083. else
  1084. Result := FOutput;
  1085. end;
  1086. procedure TPreprocessor.ExecProc(Body: TStrings);
  1087. var
  1088. I: Integer;
  1089. begin
  1090. for I := 0 to Body.Count - 1 do
  1091. InternalAddLine(Body[I], Integer(Body.Objects[I]) shr 16,
  1092. Integer(Body.Objects[I]) and $FFFF - 1, False);
  1093. end;
  1094. { TConditionalTranslationStack }
  1095. constructor TConditionalTranslationStack.Create(Preproc: TPreprocessor);
  1096. begin
  1097. inherited Create;
  1098. FPreproc := Preproc;
  1099. FCache := True;
  1100. end;
  1101. procedure TConditionalTranslationStack.IfInstruction(Eval: Boolean);
  1102. var
  1103. A: TConditionalBlockInfo;
  1104. begin
  1105. A.BlockState := Eval;
  1106. A.Fired := Eval;
  1107. A.HadElse := False;
  1108. PushItem(Pointer(A));
  1109. FCacheValid := False;
  1110. VerboseMsg(cvmIf, Eval);
  1111. end;
  1112. procedure TConditionalTranslationStack.ElseIfInstruction(Eval: Boolean);
  1113. var
  1114. A: TConditionalBlockInfo;
  1115. begin
  1116. if AtLeast(1) then
  1117. begin
  1118. A := Last;
  1119. with A do
  1120. begin
  1121. if HadElse then FPreproc.RaiseError(SElifAfterElse);
  1122. BlockState := not Fired and Eval;
  1123. Fired := Fired or Eval;
  1124. FCacheValid := False;
  1125. end;
  1126. UpdateLast(A);
  1127. VerboseMsg(cvmElif, Eval);
  1128. end
  1129. else
  1130. FPreproc.RaiseError(SElseWithoutIf);
  1131. end;
  1132. procedure TConditionalTranslationStack.ElseInstruction;
  1133. var
  1134. A: TConditionalBlockInfo;
  1135. begin
  1136. if AtLeast(1) then
  1137. begin
  1138. A := Last;
  1139. with A do
  1140. begin
  1141. if HadElse then FPreproc.RaiseError(SDoubleElse);
  1142. BlockState := not Fired;
  1143. Fired := True;
  1144. HadElse := True;
  1145. FCacheValid := False;
  1146. end;
  1147. UpdateLast(A);
  1148. VerboseMsg(cvmElse, False);
  1149. end
  1150. else
  1151. FPreproc.RaiseError(SElseWithoutIf);
  1152. end;
  1153. procedure TConditionalTranslationStack.EndIfInstruction;
  1154. begin
  1155. if AtLeast(1) then
  1156. begin
  1157. PopItem;
  1158. FCacheValid := False;
  1159. VerboseMsg(cvmEndif, False);
  1160. end
  1161. else
  1162. FPreproc.RaiseError(SEndifWithoutIf);
  1163. end;
  1164. function TConditionalTranslationStack.Include: Boolean;
  1165. var
  1166. I: Integer;
  1167. begin
  1168. if FCacheValid then
  1169. Result := FCache
  1170. else
  1171. begin
  1172. FCacheValid := True;
  1173. if Count > 0 then
  1174. begin
  1175. Result := False;
  1176. FCache := False;
  1177. for I := Count - 1 downto 0 do
  1178. if not TConditionalBlockInfo(List[I]).BlockState then Exit;
  1179. end;
  1180. Result := True;
  1181. FCache := True;
  1182. end;
  1183. end;
  1184. procedure TConditionalTranslationStack.Resolved;
  1185. begin
  1186. if Count > 0 then FPreproc.RaiseError(SEndifExpected);
  1187. end;
  1188. function TConditionalTranslationStack.Last: TConditionalBlockInfo;
  1189. begin
  1190. Result := TConditionalBlockInfo(NativeInt(List.Last));
  1191. end;
  1192. procedure TConditionalTranslationStack.UpdateLast(
  1193. const Value: TConditionalBlockInfo);
  1194. begin
  1195. List[List.Count - 1] := Pointer(Value);
  1196. end;
  1197. procedure TConditionalTranslationStack.VerboseMsg(
  1198. Msg: TConditionalVerboseMsg; Eval: Boolean);
  1199. const
  1200. B: array[Boolean] of string = ('false', 'true');
  1201. var
  1202. M: string;
  1203. begin
  1204. case Msg of
  1205. cvmIf: M := SStartingConditionalInclusionIf;
  1206. cvmElif: M := SUpdatingConditionalInclusionElif;
  1207. cvmElse: M := SUpdatingConditionalInclusionElse;
  1208. else
  1209. begin
  1210. FPreproc.VerboseMsg(6, SFinishedConditionalInclusion);
  1211. Exit;
  1212. end;
  1213. end;
  1214. FPreproc.VerboseMsg(6, M);
  1215. end;
  1216. { TPreprocessor }
  1217. function TPreprocessor._AddRef: Integer;
  1218. begin
  1219. Result := -1
  1220. end;
  1221. function TPreprocessor._Release: Integer;
  1222. begin
  1223. Result := -1;
  1224. end;
  1225. function TPreprocessor.QueryInterface(const IID: TGUID; out Obj): HRESULT;
  1226. begin
  1227. if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE
  1228. end;
  1229. procedure TPreprocessor.RaiseError(const Message: string);
  1230. begin
  1231. RaiseErrorEx(Message, 0);
  1232. end;
  1233. procedure TPreprocessor.RaiseErrorEx(const Message: string; Column: Integer);
  1234. var
  1235. E: EPreprocError;
  1236. begin
  1237. E := EPreprocError.Create(Self, Message);
  1238. E.ColumnNumber := Column;
  1239. raise E;
  1240. end;
  1241. { TPredefinedVarCallContext }
  1242. type
  1243. TPredefinedVarCallContext = class(TInterfacedObject, ICallContext)
  1244. private
  1245. FValue: TIsppVariant;
  1246. public
  1247. constructor Create(const Value: TIsppVariant);
  1248. procedure Add(const Name: String; const Value: TIsppVariant);
  1249. function Call: TIsppVariant; dynamic;
  1250. function GroupingStyle: TArgGroupingStyle;
  1251. procedure Clone(out NewCallContext: ICallContext);
  1252. end;
  1253. TCounterCallContext = class(TPredefinedVarCallContext)
  1254. private
  1255. FCounter: PInteger;
  1256. public
  1257. constructor Create(Counter: PInteger);
  1258. function Call: TIsppVariant; override;
  1259. end;
  1260. TProcCallContext = class(TInterfacedObject, ICallContext)
  1261. private
  1262. FPreproc: TPreprocessor;
  1263. FBody: TStrings;
  1264. FScopeUpdated: Boolean;
  1265. FIndex: Integer;
  1266. procedure UpdateScope;
  1267. public
  1268. constructor Create(Proprocessor: TPreprocessor; ProcBody: TStrings);
  1269. procedure Add(const Name: String; const Value: TIsppVariant);
  1270. function Call: TIsppVariant;
  1271. procedure Clone(out NewContext: ICallContext);
  1272. function GroupingStyle: TArgGroupingStyle;
  1273. end;
  1274. constructor TCounterCallContext.Create(Counter: PInteger);
  1275. begin
  1276. FCounter := Counter;
  1277. end;
  1278. function TCounterCallContext.Call: TIsppVariant;
  1279. begin
  1280. MakeInt(Result, FCounter^);
  1281. Inc(FCounter^);
  1282. end;
  1283. constructor TPredefinedVarCallContext.Create(const Value: TIsppVariant);
  1284. begin
  1285. FValue := Value;
  1286. end;
  1287. procedure TPredefinedVarCallContext.Add(const Name: String;
  1288. const Value: TIsppVariant);
  1289. begin
  1290. raise EIdentError.Create(SParameterlessVariable);
  1291. end;
  1292. function TPredefinedVarCallContext.Call: TIsppVariant;
  1293. begin
  1294. Result := FValue;
  1295. end;
  1296. function TPredefinedVarCallContext.GroupingStyle: TArgGroupingStyle;
  1297. begin
  1298. Result := agsNone;
  1299. end;
  1300. { IIdentManager }
  1301. function LookupAlwaysDefined(const Name: string): Boolean;
  1302. const
  1303. AlwaysDefined: array[0..3] of string =
  1304. ('ISPP_INVOKED', 'WINDOWS', '__WIN32__', 'UNICODE');
  1305. var
  1306. I: Integer;
  1307. begin
  1308. Result := True;
  1309. for I := Low(AlwaysDefined) to High(AlwaysDefined) do
  1310. if CompareText(AlwaysDefined[I], Name) = 0 then Exit;
  1311. Result := False;
  1312. end;
  1313. const
  1314. SCounter = '__COUNTER__';
  1315. function TPreprocessor.Defined(const Name: String): Boolean;
  1316. begin
  1317. Result := LookupAlwaysDefined(Name) or LookupPredefined(Name, nil) or
  1318. (CompareText(Name, SCounter) = 0) or FIdentManager.Defined(Name);
  1319. end;
  1320. function TPreprocessor.GetIdent(const Name: String;
  1321. out CallContext: ICallContext): TIdentType;
  1322. var
  1323. V: TIsppVariant;
  1324. I: Integer;
  1325. begin
  1326. Result := itVariable;
  1327. I := FProcs.IndexOf(Name);
  1328. if I >= 0 then
  1329. begin
  1330. Result := itFunc;
  1331. CallContext := TProcCallContext.Create(Self, TStrings(FProcs.Objects[I]));
  1332. end
  1333. else
  1334. if LookupAlwaysDefined(Name) then
  1335. CallContext := TPredefinedVarCallContext.Create(NULL)
  1336. else
  1337. if LookupPredefined(Name, @V) then
  1338. CallContext := TPredefinedVarCallContext.Create(V)
  1339. else
  1340. if CompareText(Name, SCounter) = 0 then
  1341. CallContext := TCounterCallContext.Create(@FCounter)
  1342. else
  1343. Result := FIdentManager.GetIdent(Name, CallContext)
  1344. end;
  1345. function TPreprocessor.TypeOf(const Name: String): Byte;
  1346. var
  1347. V: TIsppVariant;
  1348. begin
  1349. if LookupAlwaysDefined(Name) then
  1350. Result := TYPE_NULL
  1351. else
  1352. if LookupPredefined(Name, @V) then
  1353. case V.Typ of
  1354. evInt: Result := TYPE_INTEGER;
  1355. evStr: Result := TYPE_STRING
  1356. else
  1357. Result := TYPE_NULL
  1358. end
  1359. else
  1360. if CompareText(Name, SCounter) = 0 then
  1361. Result := TYPE_INTEGER
  1362. else
  1363. Result := FIdentManager.TypeOf(Name)
  1364. end;
  1365. function TPreprocessor.LookupPredefined(Name: string;
  1366. Value: PIsppVariant): Boolean;
  1367. begin
  1368. Result := True;
  1369. Name := UpperCase(Name);
  1370. if (Name = '__FILENAME__') or (Name = '__FILE__') then
  1371. begin
  1372. if Value <> nil then MakeStr(Value^, PathExtractName(FIncludes[FCurrentFile]))
  1373. end
  1374. else if Name = '__PATHFILENAME__' then
  1375. begin
  1376. if Value <> nil then MakeStr(Value^, FIncludes[FCurrentFile])
  1377. end
  1378. else if Name = '__DIR__' then
  1379. begin
  1380. if Value <> nil then MakeStr(Value^, PathExtractDir(FIncludes[FCurrentFile]))
  1381. end
  1382. else if Name = '__LINE__' then
  1383. begin
  1384. if Value <> nil then MakeInt(Value^, FCurrentLine)
  1385. end
  1386. else if Name = 'PREPROCVER' then
  1387. begin
  1388. if Value <> nil then MakeInt(Value^, SetupBinVersion)
  1389. end
  1390. else if Name = '__INCLUDE__' then
  1391. begin
  1392. if Value <> nil then MakeStr(Value^, FIncludePath);
  1393. end
  1394. else if (Length(Name) = 9) and (Copy(Name, 1, 6) = '__OPT_') and
  1395. (Copy(Name, 8, 2) = '__') then
  1396. begin
  1397. if Value <> nil then Value^ := NULL;
  1398. Result := GetOption(FOptions.Options, Name[7]);
  1399. end
  1400. else if (Length(Name) = 10) and (Copy(Name, 1, 7) = '__POPT_') and
  1401. (Copy(Name, 9, 2) = '__') then
  1402. begin
  1403. if Value <> nil then Value^ := NULL;
  1404. Result := GetOption(FOptions.ParserOptions.Options, Name[8]);
  1405. end
  1406. else
  1407. Result := False;
  1408. end;
  1409. procedure TPredefinedVarCallContext.Clone(
  1410. out NewCallContext: ICallContext);
  1411. begin
  1412. NewCallContext := Self
  1413. end;
  1414. procedure TPreprocessor.CollectGarbage(Item: Pointer;
  1415. Proc: TDropGarbageProc);
  1416. begin
  1417. if (Item = nil) or (@Proc = nil) then Exit;
  1418. if FGarbageCollection = nil then
  1419. FGarbageCollection := TList.Create;
  1420. FGarbageCollection.Add(Item);
  1421. FGarbageCollection.Add(@Proc);
  1422. end;
  1423. procedure TPreprocessor.UncollectGarbage(Item: Pointer);
  1424. var
  1425. I: Integer;
  1426. begin
  1427. if FGarbageCollection = nil then Exit;
  1428. for I := 0 to FGarbageCollection.Count div 2 - 1 do
  1429. if FGarbageCollection.Items[I * 2] = Item then
  1430. begin
  1431. FGarbageCollection.Items[I * 2] := nil;
  1432. FGarbageCollection.Items[I * 2 + 1] := nil;
  1433. end;
  1434. FGarbageCollection.Pack;
  1435. if FGarbageCollection.Count = 0 then FreeAndNil(FGarbageCollection);
  1436. end;
  1437. procedure TPreprocessor.DropGarbage;
  1438. var
  1439. I: Integer;
  1440. Proc: TDropGarbageProc;
  1441. Item: Pointer;
  1442. begin
  1443. if FGarbageCollection <> nil then
  1444. try
  1445. for I := 0 to FGarbageCollection.Count div 2 - 1 do
  1446. begin
  1447. Item := FGarbageCollection.Items[I * 2];
  1448. Proc := FGarbageCollection.Items[I * 2 + 1];
  1449. try
  1450. if @Proc <> nil then
  1451. try
  1452. Proc(Item);
  1453. except
  1454. end
  1455. else
  1456. if Item <> nil then
  1457. begin
  1458. try
  1459. TObject(Item).Free
  1460. except
  1461. try Dispose(Item) except end;
  1462. end;
  1463. end;
  1464. finally
  1465. FGarbageCollection.Items[I * 2] := nil;
  1466. FGarbageCollection.Items[I * 2 + 1] := nil;
  1467. end;
  1468. end;
  1469. finally
  1470. FreeAndNil(FGarbageCollection);
  1471. end;
  1472. end;
  1473. function TPreprocessor.PrependDirName(const FileName, Dir: string): string;
  1474. var
  1475. P: PChar;
  1476. begin
  1477. P := FCompilerParams.PrependDirNameProc(FCompilerParams.CompilerData,
  1478. PChar(FileName), PChar(Dir), PChar(GetFileName(-1)), GetLineNumber(-1), 0);
  1479. if P = nil then
  1480. RaiseError('PrependDirNameProc failed');
  1481. Result := P;
  1482. end;
  1483. procedure TPreprocessor.IncludeFile(FileName: string;
  1484. Builtins, UseIncludePathOnly, ResetCurrentFile: Boolean);
  1485. function IsDotRelativePath(const Filename: String): Boolean;
  1486. begin
  1487. { Check for '.\' and '..\' }
  1488. if (Length(Filename) >= 2) and (Filename[1] = '.') and PathCharIsSlash(Filename[2]) then
  1489. Result := True
  1490. else if (Length(Filename) >= 3) and (Filename[1] = '.') and (Filename[2] = '.') and
  1491. PathCharIsSlash(Filename[3]) then
  1492. Result := True
  1493. else
  1494. Result := False;
  1495. end;
  1496. procedure AddToPath(var Path: string; const Dir: string);
  1497. begin
  1498. if (Dir <> '') and (Pos(';' + Dir + ';', ';' + Path + ';') = 0) then
  1499. begin
  1500. if Path <> '' then Path := Path + ';';
  1501. Path := Path + Dir;
  1502. end;
  1503. end;
  1504. function DoSearch(const SearchDirs: String): String;
  1505. var
  1506. FilePart: PChar;
  1507. begin
  1508. SetLength(Result, MAX_PATH);
  1509. SetLength(Result, SearchPath(PChar(SearchDirs), PChar(FileName), nil, MAX_PATH,
  1510. PChar(Result), FilePart));
  1511. end;
  1512. var
  1513. CurPath, SearchDirs, FullFileName: String;
  1514. FileHandle: TPreprocFileHandle;
  1515. FileIndex: Integer;
  1516. LineText: PChar;
  1517. LineTextStr: string;
  1518. begin
  1519. if ResetCurrentFile then begin
  1520. FCurrentFile := 0;
  1521. FCurrentLine := 0;
  1522. end;
  1523. { Expand any prefix on the filename (e.g. 'compiler:') }
  1524. FileName := PrependDirName(FileName, '');
  1525. if IsDotRelativePath(FileName) then
  1526. begin
  1527. { Make filenames beginning with '.\' and '..\' relative to the directory
  1528. containing the current file }
  1529. CurPath := PathExtractPath(FIncludes[FCurrentFile]);
  1530. if CurPath = '' then
  1531. CurPath := FSourcePath;
  1532. FileName := PathCombine(CurPath, FileName);
  1533. end
  1534. else if not PathIsRooted(FileName) then
  1535. begin
  1536. if not UseIncludePathOnly then
  1537. begin
  1538. for var I := FFileStack.Count - 1 downto 0 do
  1539. AddToPath(SearchDirs, PathExtractDir(FFileStack[I]));
  1540. if FIncludes[0] <> '' then
  1541. AddToPath(SearchDirs, PathExtractDir(FIncludes[0]));
  1542. AddToPath(SearchDirs, RemoveBackslashUnlessRoot(FSourcePath));
  1543. end;
  1544. AddToPath(SearchDirs, FIncludePath);
  1545. AddToPath(SearchDirs, GetEnv('INCLUDE'));
  1546. if not UseIncludePathOnly then
  1547. AddToPath(SearchDirs, RemoveBackslashUnlessRoot(FCompilerPath));
  1548. end;
  1549. FullFileName := DoSearch(SearchDirs);
  1550. if FullFileName <> '' then
  1551. begin
  1552. if not CheckFile(FullFileName) then
  1553. RaiseError(Format(SFileIsAlreadyBeingIncluded, [FullFileName]));
  1554. if not Builtins then
  1555. StatusMsg(SIncludingFile, [FullFileName]);
  1556. PushFile(FullFileName);
  1557. try
  1558. FileHandle := FCompilerParams.LoadFileProc(FCompilerParams.CompilerData,
  1559. PChar(FullFileName), PChar(GetFileName(-1)), GetLineNumber(-1), 0);
  1560. if FileHandle < 0 then
  1561. RaiseError('LoadFileProc failed');
  1562. FileIndex := FIncludes.Add(FullFileName);
  1563. FIdentManager.BeginLocal;
  1564. try
  1565. var I := 0;
  1566. var J := 0;
  1567. while True do
  1568. begin
  1569. LineText := FCompilerParams.LineInProc(FCompilerParams.CompilerData,
  1570. FileHandle, I);
  1571. if LineText = nil then
  1572. Break;
  1573. LineTextStr := LineText;
  1574. Inc(J, InternalQueueLine(LineTextStr, FileIndex, J, False));
  1575. Inc(I);
  1576. end;
  1577. finally
  1578. FIdentManager.EndLocal
  1579. end;
  1580. finally
  1581. PopFile;
  1582. end;
  1583. end
  1584. else
  1585. RaiseError(Format(SFileNotFound, [FileName]));
  1586. end;
  1587. // ParseFormalParams
  1588. // Parser must be behind the opening parenthesis
  1589. function TPreprocessor.ParseFormalParams(Parser: TParser;
  1590. var ParamList: PParamList): Integer;
  1591. var
  1592. Param: TIsppMacroParam;
  1593. Ident: string;
  1594. procedure Grow;
  1595. var
  1596. OldCapacity, NewCapacity: Integer;
  1597. begin
  1598. OldCapacity := ((Result div 4) * 4) * SizeOf(TIsppMacroParam);
  1599. NewCapacity := ((Result div 4 + 1) * 4);
  1600. if NewCapacity > High(Byte) then RaiseError(STooManyFormalParams);
  1601. NewCapacity := NewCapacity * SizeOf(TIsppMacroParam);
  1602. ReallocMem(ParamList, NewCapacity);
  1603. { Initializing to zeroes is required to prevent compiler's attempts to
  1604. finilize not existing strings }
  1605. FillChar(ParamList^[Result], NewCapacity - OldCapacity, 0)
  1606. end;
  1607. begin
  1608. with Parser do
  1609. begin
  1610. Result := 0;
  1611. ParamList := AllocMem(SizeOf(TIsppMacroParam) * 4);
  1612. while not (PeekAtNextToken in [tkEOF, tkCloseParen]) do
  1613. begin
  1614. Param.Name := '';
  1615. Param.DefValue.AsStr := '';
  1616. FillChar(Param, SizeOf(Param), 0);
  1617. Param.ParamFlags := [];
  1618. if NextTokenExpect([tkIdent, opMul]) = tkIdent then
  1619. begin
  1620. Ident := TokenString;
  1621. if not (PeekAtNextToken in [tkEOF, tkComma, tkCloseParen, opAssign]) then
  1622. begin
  1623. Ident := UpperCase(Ident);
  1624. if Ident = sAny then {do nothing }
  1625. else if Ident = sInt then Param.DefValue.Typ := evInt
  1626. else if Ident = sStr then Param.DefValue.Typ := evStr
  1627. else if Ident = 'FUNC' then
  1628. begin
  1629. Param.DefValue.Typ := evCallContext;
  1630. Include(Param.ParamFlags, pfFunc)
  1631. end
  1632. else if Ident = 'ARRAY' then Param.DefValue.Typ := evCallContext
  1633. else RaiseError(Format(SInvalidTypeId, [Ident]));
  1634. if Param.DefValue.Typ <> evSpecial then
  1635. Include(Param.ParamFlags, pfTypeDefined);
  1636. if NextTokenExpect([tkIdent, opMul]) = opMul then
  1637. begin
  1638. Include(Param.ParamFlags, pfByRef);
  1639. NextTokenExpect([tkIdent]);
  1640. end;
  1641. end;
  1642. end
  1643. else
  1644. begin
  1645. Include(Param.ParamFlags, pfByRef);
  1646. NextTokenExpect([tkIdent]);
  1647. end;
  1648. Ident := TokenString;
  1649. Param.Name := CheckReservedIdent(Ident);
  1650. if PeekAtNextToken = opAssign then
  1651. begin
  1652. if pfByRef in Param.ParamFlags then
  1653. RaiseError(SByRefNoDefault);
  1654. NextToken;
  1655. case Param.DefValue.Typ of
  1656. evSpecial: Param.DefValue := GetRValue(Expr(True));
  1657. evInt: Param.DefValue.AsInt64 := IntExpr(True);
  1658. evStr: Param.DefValue.AsStr := StrExpr(True);
  1659. end;
  1660. Include(Param.ParamFlags, pfHasDefault);
  1661. end;
  1662. ParamList^[Result] := Param;
  1663. Inc(Result);
  1664. if Result mod 4 = 0 then
  1665. Grow;
  1666. if NextTokenExpect([tkComma, tkCloseParen]) = tkCloseParen then Break;
  1667. end;
  1668. end;
  1669. end;
  1670. { TProcCallContext }
  1671. procedure TProcCallContext.Add(const Name: String;
  1672. const Value: TIsppVariant);
  1673. begin
  1674. UpdateScope;
  1675. if Name <> '' then
  1676. FPreproc.FIdentManager.DefineVariable(Name, -1, Value, dsPrivate);
  1677. FPreproc.FIdentManager.DefineVariable(SLocal, FIndex, Value, dsPrivate);
  1678. Inc(FIndex);
  1679. end;
  1680. function TProcCallContext.Call: TIsppVariant;
  1681. begin
  1682. UpdateScope;
  1683. try
  1684. FPreproc.ExecProc(FBody);
  1685. finally
  1686. FPreproc.FIdentManager.EndLocal
  1687. end;
  1688. end;
  1689. procedure TProcCallContext.Clone(out NewContext: ICallContext);
  1690. begin
  1691. NewContext := TProcCallContext.Create(FPreproc, FBody);
  1692. end;
  1693. constructor TProcCallContext.Create(Proprocessor: TPreprocessor;
  1694. ProcBody: TStrings);
  1695. begin
  1696. FPreproc := Proprocessor;
  1697. FBody := ProcBody
  1698. end;
  1699. function TProcCallContext.GroupingStyle: TArgGroupingStyle;
  1700. begin
  1701. Result := agsParenteses;
  1702. end;
  1703. procedure TProcCallContext.UpdateScope;
  1704. var
  1705. ReDim: Boolean;
  1706. begin
  1707. if not FScopeUpdated then
  1708. begin
  1709. FPreproc.FIdentManager.BeginLocal;
  1710. ReDim := False;
  1711. FPreproc.FIdentManager.DimVariable(SLocal, 16, dsPrivate, ReDim);
  1712. FScopeUpdated := True;
  1713. end;
  1714. end;
  1715. initialization
  1716. { The code above stuffs TConditionalBlockInfo records in a TList without additional allocations.
  1717. In other words, TConditionalBlockInfo must fit into a Pointer. }
  1718. if SizeOf(TConditionalBlockInfo) > SizeOf(Pointer) then
  1719. raise Exception.Create('SizeOf(TConditionalBlockInfo) > SizeOf(Pointer)');
  1720. end.