/Source/FR_PARS.PAS

http://github.com/FastReports/FreeReport · Pascal · 482 lines · 452 code · 21 blank · 9 comment · 98 complexity · 598c5d7de215a6c6517c7866f0de800a MD5 · raw file

  1. {*****************************************}
  2. { }
  3. { FastReport v2.3 }
  4. { Expression parser }
  5. { }
  6. { Copyright (c) 1998-99 by Tzyganenko A. }
  7. { }
  8. {*****************************************}
  9. unit FR_Pars;
  10. interface
  11. {$I FR.inc}
  12. type
  13. TGetPValueEvent = procedure(const s: String; var v: Variant) of object;
  14. TFunctionEvent = procedure(const Name: String; p1, p2, p3: Variant;
  15. var Val: String) of object;
  16. TfrParser = class
  17. private
  18. FOnGetValue: TGetPValueEvent;
  19. FOnFunction: TFunctionEvent;
  20. function GetIdentify(const s: String; var i: Integer): String;
  21. function GetString(const s: String; var i: Integer):String;
  22. procedure Get3Parameters(const s: String; var i: Integer;
  23. var s1, s2, s3: String);
  24. public
  25. function Str2OPZ(s: String): String;
  26. function CalcOPZ(const s: String): Variant;
  27. function Calc(const s: String): Variant;
  28. property OnGetValue: TGetPValueEvent read FOnGetValue write FOnGetValue;
  29. property OnFunction: TFunctionEvent read FOnFunction write FOnFunction;
  30. end;
  31. function GetBrackedVariable(s: String; var i, j: Integer): String;
  32. implementation
  33. uses SysUtils;
  34. const
  35. ttGe = #1; ttLe = #2;
  36. ttNe = #3; ttOr = #4; ttAnd = #5;
  37. ttInt = #6; ttFrac = #7;
  38. ttUnMinus = #9; ttUnPlus = #10; ttStr = #11;
  39. ttNot = #12; ttMod = #13; ttRound = #14;
  40. function GetBrackedVariable(s: String; var i, j: Integer): String;
  41. var
  42. c: Integer;
  43. fl1, fl2: Boolean;
  44. begin
  45. j := i; fl1 := True; fl2 := True; c := 0;
  46. Result := '';
  47. if s = '' then Exit;
  48. Dec(j);
  49. repeat
  50. Inc(j);
  51. if fl1 and fl2 then
  52. if s[j] = '[' then
  53. begin
  54. if c = 0 then i := j;
  55. Inc(c);
  56. end
  57. else if s[j] = ']' then Dec(c);
  58. if fl1 then
  59. if s[j] = '"' then fl2 := not fl2;
  60. if fl2 then
  61. if s[j] = '''' then fl1 := not fl1;
  62. until (c = 0) or (j >= Length(s));
  63. Result := Copy(s, i + 1, j - i - 1);
  64. end;
  65. function TfrParser.CalcOPZ(const s: String): Variant;
  66. var
  67. i, j, k, i1, st: Integer;
  68. s1: String;
  69. nm: Array[1..8] of Variant;
  70. Format: (fNone, fDate, fTime);
  71. begin
  72. st := 1;
  73. i := 1;
  74. Format := fNone;
  75. while i <= Length(s) do
  76. begin
  77. j := i;
  78. case s[i] of
  79. '+', ttOr:
  80. nm[st - 2] := nm[st - 2] + nm[st - 1];
  81. '-':
  82. nm[st - 2] := nm[st - 2] - nm[st - 1];
  83. '*', ttAnd:
  84. nm[st - 2] := nm[st - 2] * nm[st - 1];
  85. '/':
  86. if nm[st - 1] <> 0 then
  87. nm[st - 2] := nm[st - 2] / nm[st - 1] else
  88. nm[st - 2] := 0;
  89. '>':
  90. if nm[st - 2] > nm[st - 1] then nm[st - 2] := 1
  91. else nm[st - 2] := 0;
  92. '<':
  93. if nm[st - 2] < nm[st - 1] then nm[st - 2] := 1
  94. else nm[st - 2] := 0;
  95. '=':
  96. if nm[st - 2] = nm[st - 1] then nm[st - 2] := 1
  97. else nm[st - 2] := 0;
  98. ttNe:
  99. if nm[st - 2] <> nm[st - 1] then nm[st - 2] := 1
  100. else nm[st - 2] := 0;
  101. ttGe:
  102. if nm[st - 2] >= nm[st - 1] then nm[st - 2] := 1
  103. else nm[st - 2] := 0;
  104. ttLe:
  105. if nm[st - 2] <= nm[st - 1] then nm[st - 2] := 1
  106. else nm[st - 2] := 0;
  107. ttInt:
  108. nm[st - 1] := Int(nm[st - 1]);
  109. ttFrac:
  110. nm[st - 1] := Frac(nm[st - 1]);
  111. ttRound:
  112. nm[st - 1] := Integer(Round(nm[st - 1]));
  113. ttUnMinus:
  114. nm[st - 1] := -nm[st - 1];
  115. ttUnPlus:;
  116. ttStr:
  117. begin
  118. s1 := nm[st - 1];
  119. nm[st - 1] := s1;
  120. end;
  121. ttNot:
  122. if nm[st - 1] = 0 then nm[st - 1] := 1 else nm[st - 1] := 0;
  123. ttMod:
  124. nm[st - 2] := nm[st - 2] mod nm[st - 1];
  125. '%':
  126. begin
  127. if s[i + 1] in ['d', 'D'] then Format := fDate;
  128. if s[i + 1] in ['t', 'T'] then Format := fTime;
  129. Inc(i);
  130. end;
  131. ' ': ;
  132. '[':
  133. begin
  134. k := i;
  135. s1 := GetBrackedVariable(s, k, i);
  136. if Assigned(FOnGetValue) then
  137. FOnGetValue(s1, nm[st]);
  138. Inc(st);
  139. end
  140. else
  141. begin
  142. if s[i] = '''' then
  143. begin
  144. s1 := GetString(s, i);
  145. while Pos('''' + '''', s1) <> 0 do
  146. Delete(s1,Pos('''' + '''', s1), 1);
  147. s1 := Copy(s1, 2, Length(s1) - 2);
  148. if Format = fNone then
  149. nm[st] := s1
  150. else if Format = fDate then
  151. nm[st] := StrToDate(s1)
  152. else if Format = fTime then
  153. nm[st] := StrToTime(s1);
  154. Format := fNone;
  155. k := i;
  156. end
  157. else
  158. begin
  159. k := i;
  160. s1 := GetIdentify(s, k);
  161. if s1[1] in ['0'..'9', '.', ','] then
  162. begin
  163. for i1 := 1 to Length(s1) do
  164. if s1[i1] in ['.', ','] then s1[i1] := DecimalSeparator;
  165. nm[st] := StrToFloat(s1);
  166. end
  167. else
  168. if Assigned(FOnGetValue) then
  169. FOnGetValue(AnsiUpperCase(s1), nm[st]);
  170. end;
  171. i := k;
  172. Inc(st);
  173. end;
  174. end;
  175. if s[j] in ['+', '-', '*', '/', '>', '<', '=', ttGe, ttLe, ttNe,
  176. ttOr, ttAnd, ttMod] then
  177. Dec(st);
  178. Inc(i);
  179. end;
  180. Result := nm[1];
  181. end;
  182. function TfrParser.GetIdentify(const s: String; var i: Integer): String;
  183. var
  184. k, n: Integer;
  185. begin
  186. n := 0;
  187. while (i <= Length(s)) and (s[i] = ' ') do
  188. Inc(i);
  189. k := i; Dec(i);
  190. repeat
  191. Inc(i);
  192. while (i <= Length(s)) and
  193. not (s[i] in [' ', '+', '-', '*', '/', '>', '<', '=', '(', ')']) do
  194. begin
  195. if s[i] = '"' then Inc(n);
  196. Inc(i);
  197. end;
  198. until n mod 2 = 0;
  199. Result := Copy(s, k, i - k);
  200. end;
  201. function TfrParser.GetString(const s: String; var i: Integer): String;
  202. var
  203. k: Integer;
  204. f: Boolean;
  205. begin
  206. k := i; Inc(i);
  207. repeat
  208. while (i <= Length(s)) and (s[i] <> '''') do
  209. Inc(i);
  210. f := True;
  211. if (i < Length(s)) and (s[i + 1] = '''') then
  212. begin
  213. f := False;
  214. Inc(i, 2);
  215. end;
  216. until f;
  217. Result := Copy(s, k, i - k + 1);
  218. Inc(i);
  219. end;
  220. procedure TfrParser.Get3Parameters(const s: String; var i: Integer;
  221. var s1, s2, s3: String);
  222. var
  223. c, d, oi, ci: Integer;
  224. begin
  225. s1 := ''; s2 := ''; s3 := '';
  226. c := 1; d := 1; oi := i + 1; ci := 1;
  227. repeat
  228. Inc(i);
  229. if s[i] = '(' then Inc(c)
  230. else if s[i] = ')' then Dec(c);
  231. if s[i] = '''' then
  232. if d = 1 then Inc(d) else d := 1;
  233. if (s[i] = ',') and (c = 1) and (d = 1) then
  234. begin
  235. if ci = 1 then
  236. s1 := Copy(s, oi, i - oi) else
  237. s2 := Copy(s, oi, i - oi);
  238. oi := i + 1; Inc(ci);
  239. end;
  240. until (c = 0) or (i >= Length(s));
  241. case ci of
  242. 1: s1 := Copy(s, oi, i - oi);
  243. 2: s2 := Copy(s, oi, i - oi);
  244. 3: s3 := Copy(s, oi, i - oi);
  245. end;
  246. Inc(i);
  247. end;
  248. function TfrParser.Str2OPZ(s: String): String;
  249. label 1;
  250. var
  251. i, i1, j, p, ci, cn: Integer;
  252. stack: String;
  253. res, s1, s2, s3, s4, sr: String;
  254. vr: Boolean;
  255. c: Char;
  256. function Priority(c: Char): Integer;
  257. begin
  258. case c of
  259. '(': Priority := 5;
  260. ')': Priority := 4;
  261. '=', '>', '<', ttGe, ttLe, ttNe: Priority := 3;
  262. '+', '-', ttUnMinus, ttUnPlus: Priority := 2;
  263. '*', '/', ttOr, ttAnd, ttNot, ttMod: Priority := 1;
  264. ttInt, ttFrac, ttRound, ttStr: Priority := 0;
  265. else Priority := 0;
  266. end;
  267. end;
  268. procedure ProcessQuotes(var s: String);
  269. var
  270. i: Integer;
  271. begin
  272. if (Length(s) = 0) or (s[1] <> '''') then Exit;
  273. i := 2;
  274. if Length(s) > 2 then
  275. while i <= Length(s) do
  276. begin
  277. if (s[i] = '''') and (i < Length(s)) then
  278. begin
  279. Insert('''', s, i);
  280. Inc(i);
  281. end;
  282. Inc(i);
  283. end;
  284. end;
  285. begin
  286. res := '';
  287. stack := '';
  288. i := 1; vr := False;
  289. while i <= Length(s) do
  290. begin
  291. case s[i] of
  292. '(':
  293. begin
  294. stack := '(' + stack;
  295. vr := False;
  296. end;
  297. ')':
  298. begin
  299. p := Pos('(', stack);
  300. res := res + Copy(stack, 1, p - 1);
  301. stack := Copy(stack, p + 1, Length(stack) - p);
  302. end;
  303. '+', '-', '*', '/', '>', '<', '=':
  304. begin
  305. if (s[i] = '<') and (s[i + 1] = '>') then
  306. begin
  307. Inc(i);
  308. s[i] := ttNe;
  309. end else
  310. if (s[i] = '>') and (s[i + 1] = '=') then
  311. begin
  312. Inc(i);
  313. s[i] := ttGe;
  314. end else
  315. if (s[i] = '<') and (s[i + 1] = '=') then
  316. begin
  317. Inc(i);
  318. s[i] := ttLe;
  319. end;
  320. 1: if not vr then
  321. begin
  322. if s[i] = '-' then s[i] := ttUnMinus;
  323. if s[i] = '+' then s[i] := ttUnPlus;
  324. end;
  325. vr := False;
  326. if stack = '' then stack := s[i] + stack
  327. else
  328. if Priority(s[i]) < Priority(stack[1]) then
  329. stack := s[i] + stack
  330. else
  331. begin
  332. repeat
  333. res := res + stack[1];
  334. stack := Copy(stack, 2, Length(stack) - 1);
  335. until (stack = '') or (Priority(stack[1]) > Priority(s[i]));
  336. stack := s[i] + stack;
  337. end;
  338. end;
  339. ';': break;
  340. ' ': ;
  341. else
  342. begin
  343. vr := True;
  344. s2 := '';
  345. i1 := i;
  346. if s[i] = '%' then
  347. begin
  348. s2 := '%' + s[i + 1];
  349. Inc(i, 2);
  350. end;
  351. if s[i] = '''' then
  352. s2 := s2 + GetString(s, i)
  353. else if s[i] = '[' then
  354. begin
  355. s2 := s2 + '[' + GetBrackedVariable(s, i, j) + ']';
  356. i := j + 1;
  357. end
  358. else
  359. s2 := s2 + GetIdentify(s, i);
  360. c := s[i];
  361. if (Length(s2) > 0) and (s2[1] in ['0'..'9', '.', ',']) then
  362. res := res + s2 + ' '
  363. else
  364. begin
  365. s1 := AnsiUpperCase(s2);
  366. if s1 = 'INT' then
  367. begin
  368. s[i - 1] := ttInt;
  369. Dec(i);
  370. goto 1;
  371. end
  372. else if s1 = 'FRAC' then
  373. begin
  374. s[i - 1] := ttFrac;
  375. Dec(i);
  376. goto 1;
  377. end
  378. else if s1 = 'ROUND' then
  379. begin
  380. s[i - 1] := ttRound;
  381. Dec(i);
  382. goto 1;
  383. end
  384. else if s1 = 'OR' then
  385. begin
  386. s[i - 1] := ttOr;
  387. Dec(i);
  388. goto 1;
  389. end
  390. else if s1 = 'AND' then
  391. begin
  392. s[i - 1] := ttAnd;
  393. Dec(i);
  394. goto 1;
  395. end
  396. else if s1 = 'NOT' then
  397. begin
  398. s[i - 1] := ttNot;
  399. Dec(i);
  400. goto 1;
  401. end
  402. else if s1 = 'STR' then
  403. begin
  404. s[i - 1] := ttStr;
  405. Dec(i);
  406. goto 1;
  407. end
  408. else if s1 = 'MOD' then
  409. begin
  410. s[i - 1] := ttMod;
  411. Dec(i);
  412. goto 1;
  413. end
  414. else if s1 = 'COPY' then
  415. begin
  416. Get3Parameters(s, i, s2, s3, s4);
  417. ci := StrToInt(CalcOPZ(Str2OPZ(s3)));
  418. cn := StrToInt(CalcOPZ(Str2OPZ(s4)));
  419. s1 := '''' + Copy(CalcOPZ(Str2OPZ(s2)), ci, cn) + '''';
  420. ProcessQuotes(s1);
  421. Delete(s, i1, i - i1);
  422. Insert('(' + s1 + ')', s, i1);
  423. i := i1;
  424. end
  425. else if s1 = 'IF' then
  426. begin
  427. Get3Parameters(s, i, s2, s3, s4);
  428. if Int(StrToFloat(CalcOPZ(Str2OPZ(s2)))) > 0 then
  429. s1 := s3 else
  430. s1 := s4;
  431. ProcessQuotes(s1);
  432. Delete(s, i1, i - i1);
  433. Insert('(' + s1 + ')', s, i1);
  434. i := i1;
  435. end
  436. else if c = '(' then // other function
  437. begin
  438. Get3Parameters(s, i, s2, s3, s4);
  439. sr := '';
  440. if Assigned(FOnFunction) then
  441. FOnFunction(s1, s2, s3, s4, sr);
  442. ProcessQuotes(sr);
  443. Delete(s, i1, i - i1);
  444. Insert('(' + sr + ')', s, i1);
  445. i := i1;
  446. end
  447. else res := res + s2 + ' ';
  448. end;
  449. Dec(i);
  450. end;
  451. end;
  452. Inc(i);
  453. end;
  454. if stack <> '' then res := res + stack;
  455. Result := res;
  456. end;
  457. function TfrParser.Calc(const s: String): Variant;
  458. begin
  459. Result := CalcOPZ(Str2OPZ(s));
  460. end;
  461. end.