ISPP.Parser.pas 17 KB

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