expr.pp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. {$ifdef win32}
  2. {$H-}
  3. {$endif}
  4. {$ifndef fpc}{$N+}{$endif}
  5. Unit Expr;
  6. interface
  7. const
  8. IntSize2:longbool=false;
  9. PROCEDURE Eval(Formula : String; { Expression to be evaluated}
  10. VAR Value : double; { Return value }
  11. VAR ErrPos : Integer); { error position }
  12. {
  13. Simple recursive expression parser based on the TCALC example of TP3.
  14. Written by Lars Fosdal 1987
  15. Released to the public domain 1993
  16. }
  17. implementation
  18. type
  19. real=double;
  20. PROCEDURE Eval(Formula : String; { Expression to be evaluated}
  21. VAR Value : double; { Return value }
  22. VAR ErrPos : Integer); { error position }
  23. CONST
  24. Digit: Set of Char = ['0'..'9'];
  25. VAR
  26. Posn : Integer; { Current position in Formula}
  27. CurrChar : Char; { character at Posn in Formula }
  28. PROCEDURE ParseNext; { returnerer neste tegn i Formulaen }
  29. BEGIN
  30. REPEAT
  31. Posn:=Posn+1;
  32. IF Posn<=Length(Formula) THEN CurrChar:=Formula[Posn]
  33. ELSE CurrChar:=^M;
  34. UNTIL CurrChar<>' ';
  35. END { ParseNext };
  36. FUNCTION add_subt: Real;
  37. VAR
  38. E : Real;
  39. Opr : Char;
  40. FUNCTION mult_DIV: Real;
  41. VAR
  42. S : Real;
  43. Opr : Char;
  44. FUNCTION Power: Real;
  45. VAR
  46. T : Real;
  47. FUNCTION SignedOp: Real;
  48. FUNCTION UnsignedOp: Real;
  49. TYPE
  50. StdFunc = (fabs, fsqrt, fsqr, fsin, fcos,
  51. farctan, fln, flog, fexp, ffact,
  52. fpred,fsucc,fround,ftrunc);
  53. StdFuncList = ARRAY[StdFunc] of String[6];
  54. CONST
  55. StdFuncName: StdFuncList =
  56. ('ABS','SQRT','SQR','SIN','COS',
  57. 'ARCTAN','LN','LOG','EXP','FACT',
  58. 'PRED','SUCC','ROUND','TRUNC');
  59. VAR
  60. L, Start : Integer;
  61. Funnet : Boolean;
  62. F : Real;
  63. Sf : StdFunc;
  64. FUNCTION Fact(I: Integer): Real;
  65. BEGIN
  66. IF I > 0 THEN BEGIN Fact:=I*Fact(I-1); END
  67. ELSE Fact:=1;
  68. END { Fact };
  69. BEGIN { FUNCTION UnsignedOp }
  70. IF CurrChar in Digit THEN
  71. BEGIN
  72. Start:=Posn;
  73. REPEAT ParseNext UNTIL not (CurrChar in Digit);
  74. IF CurrChar='.' THEN REPEAT ParseNext UNTIL not (CurrChar in Digit);
  75. IF CurrChar='E' THEN
  76. BEGIN
  77. ParseNext;
  78. REPEAT ParseNext UNTIL not (CurrChar in Digit);
  79. END;
  80. Val(Copy(Formula,Start,Posn-Start),F,ErrPos);
  81. END ELSE
  82. IF CurrChar='(' THEN
  83. BEGIN
  84. ParseNext;
  85. F:=add_subt;
  86. IF CurrChar=')' THEN ParseNext ELSE ErrPos:=Posn;
  87. END ELSE
  88. BEGIN
  89. Funnet:=False;
  90. FOR sf:=fabs TO ftrunc DO
  91. IF not Funnet THEN
  92. BEGIN
  93. l:=Length(StdFuncName[sf]);
  94. IF Copy(Formula,Posn,l)=StdFuncName[sf] THEN
  95. BEGIN
  96. Posn:=Posn+l-1; ParseNext;
  97. f:=UnsignedOp{$ifdef fpc}(){$endif};
  98. CASE sf of
  99. fabs: f:=abs(f);
  100. fsqrt: f:=SqrT(f);
  101. fsqr: f:=Sqr(f);
  102. fsin: f:=Sin(f);
  103. fcos: f:=Cos(f);
  104. farctan: f:=ArcTan(f);
  105. fln : f:=LN(f);
  106. flog: f:=LN(f)/LN(10);
  107. fexp: f:=EXP(f);
  108. ffact: f:=fact(Trunc(f));
  109. fpred:f:=f-1;
  110. fsucc:f:=f+1;
  111. fround:f:=round(f)+0.0;
  112. ftrunc:f:=trunc(f)+0.0;
  113. END;
  114. Funnet:=True;
  115. END;
  116. END;
  117. IF not Funnet THEN
  118. BEGIN
  119. ErrPos:=Posn;
  120. f:=0;
  121. END;
  122. END;
  123. UnsignedOp:=F;
  124. END { UnsignedOp};
  125. BEGIN { SignedOp }
  126. IF CurrChar='-' THEN
  127. BEGIN
  128. ParseNext; SignedOp:=-UnsignedOp;
  129. END
  130. ELSE IF CurrChar='!' THEN
  131. BEGIN
  132. ParseNext; SignedOp:=not longint(round(UnsignedOp))+0.0;
  133. END
  134. ELSE SignedOp:=UnsignedOp;
  135. END { SignedOp };
  136. BEGIN { Power }
  137. T:=SignedOp;
  138. WHILE CurrChar='^' DO
  139. BEGIN
  140. ParseNext;
  141. IF t<>0 THEN t:=EXP(LN(abs(t))*SignedOp) ELSE t:=0;
  142. END;
  143. Power:=t;
  144. END { Power };
  145. BEGIN { mult_DIV }
  146. s:=Power;
  147. WHILE CurrChar in ['*','/','&','¬','\','«','¯'] DO
  148. BEGIN
  149. Opr:=CurrChar; ParseNext;
  150. CASE Opr of
  151. '*': s:=s*Power;
  152. '/': s:=s/Power;
  153. '&': s:=longint(round(s)) and longint(round(power))+0.0;
  154. '¬': s:=longint(round(s)) mod longint(round(power))+0.0;
  155. '\': s:=trunc(s/Power);
  156. '«': s:=longint(round(s)) shl longint(round(power))+0.0;
  157. '¯': s:=longint(round(s)) shr longint(round(power))+0.0;
  158. END;
  159. END;
  160. mult_DIV:=s;
  161. END { mult_DIV };
  162. BEGIN { add_subt }
  163. E:=mult_DIV;
  164. WHILE CurrChar in ['+','-','|','å'] DO
  165. BEGIN
  166. Opr:=CurrChar; ParseNext;
  167. CASE Opr of
  168. '+': e:=e+mult_DIV;
  169. '-': e:=e-mult_DIV;
  170. '|': e:=longint(round(e))or longint(round(mult_DIV))+0.0;
  171. 'å': e:=longint(round(e))xor longint(round(mult_DIV))+0.0;
  172. END;
  173. END;
  174. add_subt:=E;
  175. END { add_subt };
  176. procedure Replace(const _from,_to:string);
  177. var
  178. p:longint;
  179. begin
  180. repeat
  181. p:=pos(_from,formula);
  182. if p>0 then
  183. begin
  184. delete(formula,p,length(_from));
  185. insert(_to,formula,p);
  186. end;
  187. until p=0;
  188. end;
  189. function HexToDecS:longbool;
  190. var
  191. DecError:longbool;
  192. procedure Decim(const pattern:string);
  193. var
  194. p,b:longint;
  195. x: Longword;
  196. ss,st:string;
  197. begin
  198. repeat
  199. p:=pos(pattern,formula);
  200. if p>0 then
  201. begin
  202. b:=p+length(pattern);
  203. ss:='';
  204. if b<=length(formula)then
  205. begin
  206. while formula[b]in['0'..'9','a'..'f','A'..'F']do
  207. begin
  208. ss:=ss+formula[b];
  209. inc(b);
  210. if b>length(formula)then
  211. break;
  212. end;
  213. val('$'+ss,x,posn);
  214. DecError:=posn<>0;
  215. str(x:0,st);
  216. delete(formula,p,length(pattern)+length(ss));
  217. insert(st,formula,p);
  218. end;
  219. end;
  220. until p=0;
  221. end;
  222. begin
  223. DecError:=false;
  224. Decim('0x');
  225. if not DecError then
  226. Decim('$');
  227. HexToDecS:=not DecError;
  228. end;
  229. BEGIN {PROC Eval}
  230. if not HexToDecS then
  231. begin
  232. value:=0;
  233. ErrPos:=Posn;
  234. exit;
  235. end;
  236. IF Formula[1]='.'
  237. THEN Formula:='0'+Formula;
  238. IF Formula[1]='+'
  239. THEN Delete(Formula,1,1);
  240. FOR Posn:=1 TO Length(Formula)
  241. DO Formula[Posn] := Upcase(Formula[Posn]);
  242. replace('<<','«');
  243. replace('>>','¯');
  244. replace('^','å');
  245. replace('**','^');
  246. replace('DIV','\');
  247. replace('MOD','¬');
  248. replace('AND','&');
  249. replace('XOR','å');
  250. replace('SHR','¯');
  251. replace('SHL','«');
  252. replace('NOT','!');
  253. replace('OR','|');
  254. Posn:=0;
  255. ParseNext;
  256. Value:=add_subt;
  257. IF CurrChar=^M THEN ErrPos:=0 ELSE ErrPos:=Posn;
  258. END {PROC Eval};
  259. END.