ISPP.Parser.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  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.Parser;
  10. interface
  11. uses
  12. ISPP.Intf, ISPP.Base, ISPP.IdentMan, ISPP.CTokenizer;
  13. type
  14. TParser = class(TCTokenizer)
  15. private
  16. FIdentMan: IIdentManager;
  17. FOptions: PIsppParserOptions;
  18. function CheckLValue(const LValue: TIsppVariant): TIsppVariant;
  19. function PrefixIncDec(LValue: TIsppVariant; Dec: Boolean): TIsppVariant;
  20. function PostfixIncDec(LValue: TIsppVariant; Dec: Boolean): TIsppVariant;
  21. function AssignOperation(LValue, RValue: TIsppVariant; Op: TTokenKind): TIsppVariant;
  22. function PerformOperation(Op1, Op2: TIsppVariant; Op: TTokenKind): TIsppVariant;
  23. function UnaryOperation(Op: TTokenKind; Op1: TIsppVariant): TIsppVariant;
  24. protected
  25. function Chain(Level: Integer; DoEval: Boolean): TIsppVariant;
  26. function Factor(DoEval: Boolean): TIsppVariant;
  27. function Assignment(DoEval: Boolean): TIsppVariant;
  28. function Conditional(DoEval: Boolean): TIsppVariant;
  29. function Sequentional(DoEval: Boolean): TIsppVariant;
  30. public
  31. constructor Create(const IdentMan: IIdentManager; const Expression: string;
  32. Offset: NativeInt; Options: PIsppParserOptions);
  33. function Evaluate: TIsppVariant;
  34. function Expr(const StopOnComma: Boolean; const DoMakeRValue: Boolean = False): TIsppVariant;
  35. function IntExpr(const StopOnComma: Boolean): Int64;
  36. function IntegerExpr(const StopOnComma: Boolean): Integer;
  37. function StrExpr(const StopOnComma: Boolean): string;
  38. end;
  39. function Parse(const VarMan: IIdentManager; const AExpr: string; Offset: NativeInt; Options: PIsppParserOptions): TIsppVariant;
  40. function ParseStr(const VarMan: IIdentManager; const AExpr: string; Offset: NativeInt; Options: PIsppParserOptions): string;
  41. function ParseInt(const VarMan: IIdentManager; const AExpr: string; Offset: NativeInt; Options: PIsppParserOptions): Int64;
  42. implementation
  43. uses
  44. SysUtils, ISPP.Sessions, ISPP.Consts, ISPP.VarUtils;
  45. function Parse(const VarMan: IIdentManager; const AExpr: string; Offset: NativeInt; Options: PIsppParserOptions): TIsppVariant;
  46. begin
  47. with TParser.Create(VarMan, AExpr, Offset, Options) do
  48. try
  49. Result := Evaluate
  50. finally
  51. Free
  52. end;
  53. end;
  54. function ParseStr(const VarMan: IIdentManager; const AExpr: string; Offset: NativeInt; Options: PIsppParserOptions): string;
  55. begin
  56. with TParser.Create(VarMan, AExpr, Offset, Options) do
  57. try
  58. Result := StrExpr(True);
  59. EndOfExpr;
  60. finally
  61. Free
  62. end;
  63. end;
  64. function ParseInt(const VarMan: IIdentManager; const AExpr: string; Offset: NativeInt; Options: PIsppParserOptions): Int64;
  65. begin
  66. with TParser.Create(VarMan, AExpr, Offset, Options) do
  67. try
  68. Result := IntExpr(True);
  69. EndOfExpr;
  70. finally
  71. Free
  72. end;
  73. end;
  74. { TParser }
  75. constructor TParser.Create(const IdentMan: IIdentManager;
  76. const Expression: string; Offset: NativeInt; Options: PIsppParserOptions);
  77. begin
  78. inherited Create(Expression, not (optPascalStrings in Options^.Options));
  79. FExprOffset := Offset;
  80. FIdentMan := IdentMan;
  81. FOptions := Options;
  82. end;
  83. function TParser.Evaluate: TIsppVariant;
  84. begin
  85. Result := Expr(False, True);
  86. EndOfExpr;
  87. end;
  88. function TParser.Sequentional(DoEval: Boolean): TIsppVariant;
  89. begin
  90. Result := Assignment(DoEval);
  91. while PeekAtNextToken = tkComma do
  92. begin
  93. NextToken;
  94. Result := Assignment(DoEval)
  95. end;
  96. end;
  97. function TParser.Expr(const StopOnComma, DoMakeRValue: Boolean): TIsppVariant;
  98. begin
  99. if StopOnComma then
  100. Result := Assignment(True)
  101. else
  102. Result := Sequentional(True);
  103. if DoMakeRValue then
  104. MakeRValue(Result);
  105. end;
  106. function TParser.Factor(DoEval: Boolean): TIsppVariant;
  107. procedure PopulateCallContext(const CallContext: ICallContext);
  108. const
  109. Brackets: array[TArgGroupingStyle, Boolean] of TTokenKind =
  110. ((tkError, tkError), (tkOpenParen, tkCloseParen),
  111. (tkOpenBracket, tkCloseBracket), (tkOpenBrace, tkCloseBrace));
  112. type
  113. TArgNamingState = (ansUnknown, ansNamed, ansUnnamed);
  114. var
  115. V: TIsppVariant;
  116. ArgName: string;
  117. ArgNamingState: TArgNamingState;
  118. T: TTokenKind;
  119. ArgFound: Boolean;
  120. procedure GetExpression;
  121. begin
  122. V := Assignment(DoEval);
  123. Store;
  124. T := NextTokenExpect([tkComma, Brackets[CallContext.GroupingStyle, True]]);
  125. Restore;
  126. ArgFound := True;
  127. end;
  128. begin
  129. ArgNamingState := ansUnknown;
  130. ArgFound := False;
  131. if PeekAtNextToken = Brackets[CallContext.GroupingStyle, False] then
  132. begin
  133. NextToken;
  134. V := NULL;
  135. ArgName := '';
  136. T := PeekAtNextToken;
  137. while True do
  138. case T of
  139. tkComma:
  140. begin
  141. NextToken;
  142. CallContext.Add(ArgName, V);
  143. V := NULL;
  144. T := PeekAtNextToken;
  145. end;
  146. tkCloseParen, tkCloseBracket, tkCloseBrace:
  147. begin
  148. NextToken;
  149. if ArgFound then CallContext.Add(ArgName, V);
  150. V := NULL;
  151. Break
  152. end;
  153. tkIdent:
  154. begin
  155. Store;
  156. NextToken;
  157. ArgName := TokenString;
  158. if PeekAtNextToken <> opAssign then
  159. begin
  160. if ArgNamingState = ansNamed then Error(SActualParamsNamingConflict);
  161. ArgNamingState := ansUnnamed;
  162. ArgName := '';
  163. Restore;
  164. GetExpression;
  165. end
  166. else
  167. begin
  168. if ArgNamingState = ansUnnamed then Error(SActualParamsNamingConflict);
  169. ArgNamingState := ansNamed;
  170. NextToken;
  171. GetExpression;
  172. end;
  173. end;
  174. else
  175. begin
  176. if ArgNamingState = ansNamed then Error(SActualParamsNamingConflict);
  177. ArgNamingState := ansUnnamed;
  178. ArgName := '';
  179. GetExpression;
  180. end;
  181. end;
  182. end;
  183. end;
  184. var
  185. I: Int64;
  186. IdentType: TIdentType;
  187. CallContext: ICallContext;
  188. Op: TTokenKind;
  189. ParenthesesUsed: Boolean;
  190. begin
  191. FillChar(Result, SizeOf(Result), 0);
  192. case NextTokenExpect(ExpressionStartTokens) of
  193. tkOpenParen:
  194. begin
  195. Result := Sequentional(DoEval);
  196. NextTokenExpect([tkCloseParen])
  197. end;
  198. tkPtr:
  199. begin
  200. NextTokenExpect([tkIdent]);
  201. Result.Typ := evCallContext;
  202. if not (FIdentMan.GetIdent(TokenString, Result.AsCallContext) in
  203. [itVariable, itMacro, itFunc]) then
  204. Error('Variable, macro, or function required');
  205. end;
  206. tkIdent:
  207. begin
  208. CallContext := nil;
  209. IdentType := FIdentMan.GetIdent(TokenString, CallContext);
  210. case IdentType of
  211. itUnknown:
  212. if (optAllowUndeclared in FOptions.Options) and not
  213. (PeekAtNextToken in [tkOpenParen, tkOpenBracket, tkOpenBrace]) then
  214. begin
  215. Result.Typ := evNull;
  216. WarningMsg(SUndeclaredIdentifier, [TokenString]);
  217. end
  218. else
  219. ErrorFmt(SUndeclaredIdentifier, [TokenString]);
  220. itVariable, itMacro, itFunc:
  221. begin
  222. PopulateCallContext(CallContext);
  223. if DoEval then
  224. Result := CallContext.Call
  225. end;
  226. itDefinedFunc:
  227. begin
  228. ParenthesesUsed := PeekAtNextToken = tkOpenParen;
  229. if ParenthesesUsed then NextToken;
  230. NextTokenExpect([tkIdent]);
  231. if DoEval then
  232. MakeBool(Result, FIdentMan.Defined(TokenString));
  233. if ParenthesesUsed then NextTokenExpect([tkCloseParen])
  234. end;
  235. itTypeOfFunc:
  236. begin
  237. ParenthesesUsed := PeekAtNextToken = tkOpenParen;
  238. if ParenthesesUsed then NextToken;
  239. NextTokenExpect([tkIdent]);
  240. if DoEval then
  241. MakeInt(Result, FIdentMan.TypeOf(TokenString));
  242. if ParenthesesUsed then NextTokenExpect([tkCloseParen]);
  243. end;
  244. itDimOfFunc:
  245. begin
  246. ParenthesesUsed := PeekAtNextToken = tkOpenParen;
  247. if ParenthesesUsed then NextToken;
  248. NextTokenExpect([tkIdent]);
  249. if DoEval then
  250. MakeInt(Result, FIdentMan.DimOf(TokenString));
  251. if ParenthesesUsed then NextTokenExpect([tkCloseParen])
  252. end;
  253. end;
  254. end;
  255. tkNumber:
  256. begin
  257. if not TryStrToInt64(TokenString, I) then
  258. ErrorFmt(SCannotConvertToInteger, [TokenString]);
  259. MakeInt(Result, I);
  260. end;
  261. tkString: MakeStr(Result, TokenString);
  262. opInc, opDec:
  263. begin
  264. Op := Token;
  265. if DoEval then
  266. Result := PrefixIncDec(CheckLValue(Factor(True)), Op = opDec)
  267. else
  268. Result := Factor(False);
  269. end;
  270. else
  271. begin
  272. Op := Token;
  273. if DoEval then
  274. Result := UnaryOperation(Op, Factor(True))
  275. else
  276. Factor(False)
  277. end;
  278. end;
  279. Op := PeekAtNextToken;
  280. while Op in [opInc, opDec] do
  281. begin
  282. if DoEval then
  283. Result := PostfixIncDec(CheckLValue(Result), Op = opDec);
  284. NextToken;
  285. Op := PeekAtNextToken;
  286. end;
  287. end;
  288. function TParser.PerformOperation(Op1, Op2: TIsppVariant; Op: TTokenKind): TIsppVariant;
  289. var
  290. A, B: Int64;
  291. AsBool: Boolean;
  292. begin
  293. MakeRValue(Op1);
  294. MakeRValue(Op2);
  295. if Op1.Typ = evNull then
  296. case Op2.Typ of
  297. evNull:
  298. begin
  299. MakeInt(Op1, 0);
  300. MakeInt(Op2, 0);
  301. end;
  302. evInt: MakeInt(Op1, 0);
  303. evStr: MakeStr(Op1, '');
  304. end
  305. else
  306. if Op2.Typ = evNull then
  307. case Op1.Typ of
  308. evInt: MakeInt(Op2, 0);
  309. evStr: MakeStr(Op2, '');
  310. end;
  311. if (Op1.Typ <> Op2.Typ) or ((Op in [opSubtract..opShr]) and (Op1.Typ = evStr))
  312. then Error(SOperatorNotApplicableToThisOpera);
  313. AsBool := False;
  314. with Result do
  315. try
  316. if Op1.Typ = evStr then
  317. begin
  318. if Op = opAdd then MakeStr(Result, Op1.AsStr + Op2.AsStr)
  319. else
  320. begin
  321. Typ := evInt;
  322. A := CompareText(Op1.AsStr, Op2.AsStr);
  323. case Op of
  324. opGreater: AsBool := A > 0;
  325. opLess: AsBool := A < 0;
  326. opGreaterEqual: AsBool := A >= 0;
  327. opLessEqual: AsBool := A <= 0;
  328. opEqual: AsBool := A = 0;
  329. opNotEqual: AsBool := A <> 0;
  330. end;
  331. AsInt64 := Int64(AsBool)
  332. end;
  333. end
  334. else
  335. if Op1.Typ = evInt then
  336. begin
  337. A := Op1.AsInt64;
  338. B := Op2.AsInt64;
  339. Typ := evInt;
  340. case Op of
  341. opGreater: AsBool := A > B;
  342. opLess: AsBool := A < B;
  343. opGreaterEqual: AsBool := A >= B;
  344. opLessEqual: AsBool := A <= B;
  345. opEqual: AsBool := A = B;
  346. opNotEqual: AsBool := A <> B;
  347. opAdd: AsInt64 := A + B;
  348. opSubtract: AsInt64 := A - B;
  349. opOr: AsBool := (A <> 0) or (B <> 0);
  350. opBwOr: AsInt64 := A or B;
  351. opXor: AsInt64 := A xor B;
  352. opMul: AsInt64 := A * B;
  353. opDiv: AsInt64 := A div B;
  354. opAnd: AsBool := (A <> 0) and (B <> 0);
  355. opBwAnd: AsInt64 := A and B;
  356. opShl: AsInt64 := A shl B;
  357. opShr: AsInt64 := A shr B;
  358. opMod: AsInt64 := A mod B;
  359. end;
  360. if Op in [opGreater..opNotEqual, opOr, opAnd] then
  361. AsInt64 := Int64(AsBool)
  362. end
  363. except
  364. on E: Exception do Error(E.Message);
  365. end;
  366. end;
  367. function TParser.UnaryOperation(Op: TTokenKind; Op1: TIsppVariant): TIsppVariant;
  368. var
  369. A: Int64;
  370. begin
  371. MakeRValue(Op1);
  372. A := 0; // satisfy compiler
  373. case Op1.Typ of
  374. evNull:;
  375. evInt: A := Op1.AsInt64
  376. else
  377. Error(SWrongUnaryOperator);
  378. end;
  379. case Op of
  380. opNot: MakeBool(Result, A = 0);
  381. opBwNot: MakeInt(Result, not A);
  382. opAdd: MakeInt(Result, A);
  383. opSubtract: MakeInt(Result, -A)
  384. end;
  385. end;
  386. type
  387. TShortCircuitEvalMode = (scemNone, scemStandard, scemOptional);
  388. const
  389. OperatorPrecedence: array[0..9] of record
  390. Operators: set of TTokenKind;
  391. SCBE: TShortCircuitEvalMode;
  392. SCBEValue: Boolean;
  393. end =
  394. ((Operators: [opOr]; SCBE: scemStandard; SCBEValue: True),
  395. (Operators: [opAnd]; SCBE: scemStandard; SCBEValue: False),
  396. (Operators: [opBwOr]; SCBE: scemNone; SCBEValue: False),
  397. (Operators: [opXor]; SCBE: scemNone; SCBEValue: False),
  398. (Operators: [opBwAnd]; SCBE: scemNone; SCBEValue: False),
  399. (Operators: [opEqual, opNotEqual]; SCBE: scemNone; SCBEValue: False),
  400. (Operators: [opLess, opLessEqual,
  401. opGreater, opGreaterEqual]; SCBE: scemNone; SCBEValue: False),
  402. (Operators: [opShl, opShr]; SCBE: scemOptional; SCBEValue: False),
  403. (Operators: [opAdd, opSubtract]; SCBE: scemNone; SCBEValue: False),
  404. (Operators: [opMul, opDiv, opMod]; SCBE: scemOptional; SCBEValue: False));
  405. function TParser.Chain(Level: Integer; DoEval: Boolean): TIsppVariant;
  406. function CallNext: TIsppVariant;
  407. begin
  408. if Level = High(OperatorPrecedence) then
  409. Result := Factor(DoEval)
  410. else
  411. Result := Chain(Level + 1, DoEval);
  412. end;
  413. var
  414. Operator: TTokenKind;
  415. R: Shortint;
  416. begin
  417. Result := CallNext;
  418. while PeekAtNextToken in OperatorPrecedence[Level].Operators do
  419. begin
  420. if DoEval and (OperatorPrecedence[Level].SCBE <> scemNone) and
  421. (GetOption(FOptions.Options, 'B') or // short circuit bool eval
  422. GetOption(FOptions.Options, 'M')) then // short circuit mul eval
  423. begin
  424. with GetRValue(Result) do
  425. case Typ of
  426. evInt: if AsInt64 = 0 then R := 0 else R := 1;
  427. evStr: R := -1
  428. else
  429. R := 0;
  430. end;
  431. if R <> -1 then
  432. begin
  433. if (OperatorPrecedence[Level].SCBE = scemStandard) and GetOption(FOptions.Options, 'B')
  434. or (OperatorPrecedence[Level].SCBE = scemOptional) and GetOption(FOptions.Options, 'M') then
  435. DoEval := not (OperatorPrecedence[Level].SCBEValue = Boolean(R))
  436. end;
  437. end;
  438. Operator := NextToken;
  439. if DoEval then
  440. Result := PerformOperation(Result, CallNext, Operator)
  441. else
  442. CallNext;
  443. end;
  444. end;
  445. function TParser.IntExpr(const StopOnComma: Boolean): Int64;
  446. begin
  447. Result := 0; { silence compiler }
  448. var V := Expr(StopOnComma, True);
  449. if V.Typ = evInt then
  450. Result := V.AsInt64
  451. else
  452. Error(SIntegerExpressionExpected);
  453. end;
  454. function TParser.IntegerExpr(const StopOnComma: Boolean): Integer;
  455. begin
  456. Result := 0; { silence compiler }
  457. var V := Expr(StopOnComma, True);
  458. if V.Typ = evInt then begin
  459. try
  460. Result := V.AsInteger;
  461. except on E: Exception do
  462. Error(E.Message);
  463. end;
  464. end else
  465. Error(SIntegerExpressionExpected);
  466. end;
  467. function TParser.StrExpr(const StopOnComma: Boolean): string;
  468. begin
  469. var V := Expr(StopOnComma, True);
  470. case V.Typ of
  471. evNull: Result := '';
  472. evStr: Result := V.AsStr;
  473. else
  474. Error(SStringExpressionExpected);
  475. end;
  476. end;
  477. function TParser.Assignment(DoEval: Boolean): TIsppVariant;
  478. var
  479. Op: TTokenKind;
  480. begin
  481. Result := Conditional(DoEval);
  482. while PeekAtNextToken in [opAssign..opAgnMod] do
  483. begin
  484. Op := NextToken;
  485. if DoEval then
  486. Result := AssignOperation(CheckLValue(Result), Assignment(DoEval), Op)
  487. else
  488. Assignment(DoEval)
  489. end;
  490. end;
  491. function TParser.Conditional(DoEval: Boolean): TIsppVariant;
  492. var
  493. R: Boolean;
  494. T, F: TIsppVariant;
  495. begin
  496. Result := Chain(0, DoEval);
  497. while PeekAtNextToken = tkQuestion do
  498. begin
  499. NextToken;
  500. if DoEval then
  501. R := GetRValue(Result).AsBoolean
  502. else
  503. R := False;
  504. T := Sequentional(DoEval and R);
  505. NextTokenExpect([tkColon]);
  506. F := Conditional(DoEval and not R);
  507. if DoEval then
  508. if R then
  509. Result := T
  510. else
  511. Result := F;
  512. end;
  513. end;
  514. function TParser.AssignOperation(LValue, RValue: TIsppVariant;
  515. Op: TTokenKind): TIsppVariant;
  516. begin
  517. SimplifyLValue(LValue);
  518. if Op = opAssign then
  519. begin
  520. LValue.AsPtr^ := GetRValue(RValue);
  521. Result := LValue;
  522. end
  523. else
  524. begin
  525. Result := PerformOperation(LValue, RValue, TTokenKind(Ord(Op) - (Ord(opAgnAdd) - Ord(opAdd))));
  526. LValue.AsPtr^ := Result;
  527. end;
  528. end;
  529. function TParser.PostfixIncDec(LValue: TIsppVariant; Dec: Boolean): TIsppVariant;
  530. var
  531. V: TIsppVariant;
  532. begin
  533. Result := GetRValue(LValue);
  534. SimplifyLValue(LValue);
  535. if Dec then MakeInt(V, -1) else MakeInt(V, 1);
  536. LValue.AsPtr^ := PerformOperation(Result, V, opAdd);
  537. end;
  538. function TParser.PrefixIncDec(LValue: TIsppVariant;
  539. Dec: Boolean): TIsppVariant;
  540. var
  541. V: TIsppVariant;
  542. begin
  543. SimplifyLValue(LValue);
  544. if Dec then MakeInt(V, -1) else MakeInt(V, 1);
  545. LValue.AsPtr^ := PerformOperation(GetRValue(LValue), V, opAdd);
  546. Result := LValue;
  547. end;
  548. function TParser.CheckLValue(const LValue: TIsppVariant): TIsppVariant;
  549. begin
  550. if LValue.Typ <> evLValue then Error(SLValueRequired);
  551. Result := LValue;
  552. end;
  553. end.