home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kompon / d456 / JANSQL.ZIP / janSQLDemo / components / janSQLExpression2.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-04-01  |  22.9 KB  |  1,110 lines

  1. {-----------------------------------------------------------------------------
  2. The contents of this file are subject to the Mozilla Public License Version
  3. 1.1 (the "License"); you may not use this file except in compliance with the
  4. License. You may obtain a copy of the License at
  5. http://www.mozilla.org/NPL/NPL-1_1Final.html
  6.  
  7. Software distributed under the License is distributed on an "AS IS" basis,
  8. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  9. the specific language governing rights and limitations under the License.
  10.  
  11. The Original Code is: janSQLExpression2.pas, released March 24, 2002.
  12.  
  13. The Initial Developer of the Original Code is Jan Verhoeven
  14. (jan1.verhoeven@wxs.nl or http://jansfreeware.com).
  15. Portions created by Jan Verhoeven are Copyright (C) 2002 Jan Verhoeven.
  16. All Rights Reserved.
  17.  
  18. Contributor(s): ___________________.
  19.  
  20. Last Modified: 24-mar-2002
  21. Current Version: 1.0
  22.  
  23. Notes: This is a very fast expression compiler and evaluator
  24.  
  25. Known Issues:
  26.  
  27. History:
  28.   1.1 26-mar-2002
  29.       - added functions:
  30.       - FORMAT, FORMATDATE, FORMATTIME
  31.       - YEAR, MONTH, DAY
  32.       - DATEADD, EASTER
  33.       - WEEKNUMBER
  34.       - ISNUMERIC, ISDATE function
  35.       - REPLACE function
  36.       - added constants:
  37.       - DATE, TIME
  38.   1.0 24-mar-2002 : original release
  39.  
  40.  
  41. -----------------------------------------------------------------------------}
  42.  
  43.  
  44. unit janSQLExpression2;
  45.  
  46. interface
  47.  
  48. uses
  49.   Classes,SysUtils,Math,janSQLStrings,dialogs,janSQLTokenizer;
  50.  
  51. const
  52.   delimiters=['+','-','*','/',' ','(',')','=','>','<'];
  53.   numberchars=['0'..'9','.'];
  54.   identchars=['a'..'z','A'..'Z','0'..'9','.','_'];
  55.  
  56. type
  57.   TVariableEvent=procedure(sender:Tobject;const VariableName:string;var VariableValue:variant;var handled:boolean) of object;
  58.  
  59.  
  60.  
  61.  
  62.   TjanSQLExpression2=class(TObject)
  63.   private
  64.     FInFix:TList;
  65.     FPostFix:TList;
  66.     FStack:TList;
  67.     Fsource: string;
  68.     VStack:array[0..100] of variant;
  69.     SP:integer;
  70.     idx: integer; // scan index
  71.     SL:integer; // source length
  72.     FToken:string;
  73.     FTokenKind:TTokenKind;
  74.     FTokenValue:variant;
  75.     FTokenOperator:TTokenOperator;
  76.     FTokenLevel:integer;
  77.     FTokenExpression:string;
  78.     FPC:integer;
  79.     FonGetVariable: TVariableEvent;
  80.     procedure Setsource(const Value: string);
  81.     function Parse:boolean;
  82.     procedure AddToken;
  83.     procedure ClearInfix;
  84.     procedure ClearPostFix;
  85.     procedure ClearStack;
  86.     function InFixToStack(index:integer):boolean;
  87.     function InfixToPostFix(index:integer):boolean;
  88.     function StackToPostFix:boolean;
  89.     function ConvertInFixToPostFix:boolean;
  90.     procedure procString;
  91.     procedure procNumber;
  92.     procedure procVariable;
  93.     procedure procEq;
  94.     procedure procNe;
  95.     procedure procGt;
  96.     procedure procGe;
  97.     procedure procLt;
  98.     procedure procLe;
  99.     procedure procAdd;
  100.     procedure procSubtract;
  101.     procedure procMultiply;
  102.     procedure procDivide;
  103.     procedure procAnd;
  104.     procedure procOr;
  105.     procedure procNot;
  106.     procedure procLike;
  107. // numerical functions
  108.     procedure procSin;
  109.     procedure procCos;
  110.     procedure procSqr;
  111.     procedure procSqrt;
  112.     procedure procCeil;
  113.     procedure procFloor;
  114.     procedure procIsNumeric;
  115.     procedure procIsDate;
  116.     procedure procsqlIn;
  117. // string functions
  118.     procedure procUPPER;
  119.     procedure procLOWER;
  120.     procedure procTRIM;
  121.     procedure procSoundex;
  122.     procedure procLeft;
  123.     procedure procRight;
  124.     procedure procMid;
  125.     procedure procsubstr_after;
  126.     procedure procsubstr_before;
  127.     procedure procReplace;
  128.     procedure procLen;
  129.     procedure procFix;
  130.     procedure procFormat;
  131.     procedure procYear;
  132.     procedure procMonth;
  133.     procedure procDay;
  134.     procedure procDateAdd;
  135.     procedure procEaster;
  136.     procedure procWeekNumber;
  137.     // conversion functions
  138.     procedure procAsNumber;
  139.     function CloseStackToPostFix: boolean;
  140.     function OperatorsToPostFix(Level:integer): boolean;
  141.     function FlushStackToPostFix: boolean;
  142.     function runpop:variant;
  143.     procedure runpush(value:variant);
  144.     procedure SetonGetVariable(const Value: TVariableEvent);
  145.     function IsLike(v1,v2:variant):boolean;
  146.     procedure runOperator(op: TTokenOperator);
  147.   public
  148.     constructor Create;
  149.     destructor  Destroy; override;
  150.     procedure Clear;
  151.     procedure getInFix(list:TStrings);
  152.     procedure getPostFix(list:TStrings);
  153.     function Evaluate:variant;
  154.     procedure GetTokenList(list:TList;from,till:integer);
  155.     property Expression:string read Fsource write Setsource;
  156.     property onGetVariable:TVariableEvent read FonGetVariable write SetonGetVariable;
  157.   end;
  158.  
  159. implementation
  160.  
  161.  
  162. { TjanSQLExpression2 }
  163.  
  164.  
  165. procedure TjanSQLExpression2.AddToken;
  166. var
  167.   tok:TToken;
  168. begin
  169.   tok:=TToken.Create;
  170.   tok.name:=FToken;
  171.   tok.tokenkind:=FTokenKind;
  172.   tok.value:=FTokenValue;
  173.   tok.operator:=FTokenOperator;
  174.   tok.level:=FtokenLevel;
  175.   tok.expression:=FTokenExpression;
  176.   FInFix.Add(tok);
  177. end;
  178.  
  179. procedure TjanSQLExpression2.Clear;
  180. begin
  181.   ClearInfix;
  182.   ClearPostFix;
  183.   ClearStack;
  184. end;
  185.  
  186. procedure TjanSQLExpression2.ClearInfix;
  187. var
  188.   i,c:integer;
  189. begin
  190.   c:=FInFix.Count;
  191.   if c=0 then exit;
  192.   for i:=c-1 downto 0 do
  193.     TObject(FInFix.items[i]).free;
  194.   FInFix.clear;
  195. end;
  196.  
  197. procedure TjanSQLExpression2.ClearPostFix;
  198. var
  199.   i,c:integer;
  200. begin
  201.   c:=FPostFix.Count;
  202.   if c=0 then exit;
  203.   for i:=c-1 downto 0 do
  204.     TObject(FPostFix.items[i]).free;
  205.   FPostFix.clear;
  206. end;
  207.  
  208. procedure TjanSQLExpression2.ClearStack;
  209. var
  210.   i,c:integer;
  211. begin
  212.   c:=FStack.Count;
  213.   if c=0 then exit;
  214.   for i:=c-1 downto 0 do
  215.     TObject(FStack.items[i]).free;
  216.   FStack.clear;
  217. end;
  218. {
  219. For each token in INPUT do the following:
  220.  
  221. If the token is an operand, enqueue it in OUTPUT.
  222.  
  223. If the token is an open bracket - push it on STACK.
  224.  
  225. If the token is a closing bracket:
  226.   - pop operators off STACK and enqueue them in OUTPUT,
  227.   until you encounter an open bracket.
  228.   Discard the opening bracket. If you reach the bottom of STACK without seeing an open bracket this indicates that the parentheses in the infix expression do not match, and so you should indicate an error.
  229.  
  230. If the token is an operator - pop operators off STACK and enqueue them in OUTPUT, until one of the following occurs:
  231. - STACK is empty
  232. - the operator at the top of STACK has lower precedence than the token
  233. - the operator at the top of the stack has the same precedence as the token and the token is right associative.
  234. Once you have done that push the token on STACK.
  235.  
  236. When INPUT becomes empty pop any remaining operators from STACK and enqueue them in OUTPUT. If one of the operators on STACK happened to be an open bracket, that means that its closing bracket never came, so an an error should be indicated.
  237. }
  238. function TjanSQLExpression2.ConvertInFixToPostFix: boolean;
  239. var
  240.   i,c,level:integer;
  241.   tok:TToken;
  242. begin
  243.   result:=false;
  244.   c:=FInfix.count;
  245.   if c=0 then exit;
  246.   for i:=0 to c-1 do begin
  247.     tok:=TToken(FInfix[i]);
  248.     case tok.tokenkind of
  249.     tkOperand: if not InFixToPostFix(i) then exit;
  250.     tkOpen: if not InFixToStack(i) then exit;
  251.     tkClose: if not CloseStackToPostFix then exit;
  252.     tkOperator:
  253.       begin
  254.         if not OperatorsToPostFix(tok.level) then exit;
  255.         InFixToStack(i);
  256.       end;
  257.     end;
  258.   end;
  259.   result:=FlushStackToPostFix;
  260. end;
  261.  
  262. {
  263. If the token is a closing bracket:
  264.   - pop operators off STACK and enqueue them in OUTPUT,
  265.   until you encounter an open bracket.
  266.   Discard the opening bracket. If you reach the bottom of STACK without seeing an open bracket this indicates that the parentheses in the infix expression do not match, and so you should indicate an error.
  267.  
  268. }
  269. function TjanSQLExpression2.CloseStackToPostFix: boolean;
  270. begin
  271.   result:=false;
  272.   while (FStack.count<>0) and (TToken(Fstack[FStack.count-1]).tokenkind<>tkOpen) do
  273.     StackToPostFix;
  274.   if FStack.count<>0 then begin
  275.     TToken(FStack[FStack.count-1]).free;
  276.     Fstack.Delete(FStack.count-1);
  277.     result:=true;
  278.   end;
  279. end;
  280.  
  281. {
  282. If the token is an operator - pop operators off STACK and enqueue them in OUTPUT, until one of the following occurs:
  283. - STACK is empty
  284. - the operator at the top of STACK has lower precedence than the token
  285. - the operator at the top of the stack has the same precedence as the token and the token is right associative.
  286. Once you have done that push the token on STACK.
  287. }
  288. function TjanSQLExpression2.OperatorsToPostFix(Level:integer): boolean;
  289. begin
  290.   while (FStack.count<>0) and (TToken(Fstack[FStack.count-1]).level>=level) do
  291.     StackToPostFix;
  292.   result:=true;
  293. end;
  294.  
  295. {
  296. When INPUT becomes empty pop any remaining operators from STACK and enqueue them in OUTPUT. If one of the operators on STACK happened to be an open bracket, that means that its closing bracket never came, so an an error should be indicated.
  297. }
  298. function TjanSQLExpression2.FlushStackToPostFix: boolean;
  299. begin
  300.   result:=false;
  301.   while (FStack.count<>0) and (TToken(Fstack[FStack.count-1]).tokenkind<>tkOpen) do
  302.     StackToPostFix;
  303.   result:=FStack.count=0;
  304. end;
  305.  
  306. constructor TjanSQLExpression2.Create;
  307. begin
  308.   FInFix:=TList.create;
  309.   FPostFix:=TList.create;
  310.   FStack:=TList.create;
  311. end;
  312.  
  313. destructor TjanSQLExpression2.Destroy;
  314. begin
  315.   Clear;
  316.   FInFix.free;
  317.   FPostFix.free;
  318.   Fstack.free;
  319.   inherited;
  320. end;
  321.  
  322. procedure TjanSQLExpression2.getInFix(list: TStrings);
  323. var
  324.   i,c:integer;
  325. begin
  326.   list.Clear;
  327.   c:=FInFix.Count;
  328.   if c=0 then exit;
  329.   for i:=0 to c-1 do begin
  330.     list.append(TToken(FInFix[i]).name);
  331.   end;
  332. end;
  333.  
  334. procedure TjanSQLExpression2.getPostFix(list:Tstrings);
  335. var
  336.   i,c:integer;
  337. begin
  338.   list.Clear;
  339.   c:=FPostFix.Count;
  340.   if c=0 then exit;
  341.   for i:=0 to c-1 do begin
  342.     list.append(TToken(FPostFix[i]).name);
  343.   end;
  344. end;
  345.  
  346.  
  347.  
  348. function TjanSQLExpression2.InfixToPostFix(index: integer): boolean;
  349. begin
  350.   result:=false;
  351.   if (index<0) or (index>=FInFix.count) then exit;
  352.   FPostFix.add(TToken(FInfix[index]).copy);
  353.   result:=true;
  354. end;
  355.  
  356.  
  357. function TjanSQLExpression2.InFixToStack(index: integer): boolean;
  358. begin
  359.   result:=false;
  360.   if (index<0) or (index>=FInFix.count) then exit;
  361.   FStack.add(TToken(FInfix[index]).copy);
  362.   result:=true;
  363. end;
  364.  
  365. function TjanSQLExpression2.Parse;
  366. var
  367.   tokenizer:TjanSQLTokenizer;
  368. begin
  369.   clear;
  370.   try
  371.     tokenizer:=TjanSQLTokenizer.create;
  372.     result:=Tokenizer.Tokenize(FSource,FInfix);
  373.   finally
  374.     tokenizer.free;
  375.   end;
  376. end;
  377.  
  378. procedure TjanSQLExpression2.procAdd;
  379. var
  380.   v1,v2:variant;
  381. begin
  382.   v1:=runpop;
  383.   v2:=runpop;
  384.   runpush(v2 + v1);
  385. end;
  386.  
  387. procedure TjanSQLExpression2.procAnd;
  388. var
  389.   v1,v2:variant;
  390. begin
  391.   v1:=runpop;
  392.   v2:=runpop;
  393.   runpush(v2 and v1);
  394. end;
  395.  
  396. procedure TjanSQLExpression2.procDivide;
  397. var
  398.   v1,v2:variant;
  399. begin
  400.   v1:=runpop;
  401.   v2:=runpop;
  402.   runpush(v2/v1);
  403. end;
  404.  
  405. procedure TjanSQLExpression2.procEq;
  406. var
  407.   v1,v2:variant;
  408.   b:boolean;
  409. begin
  410.   v1:=runpop;
  411.   v2:=runpop;
  412.   runpush(v2=v1);
  413. end;
  414.  
  415. procedure TjanSQLExpression2.procGe;
  416. var
  417.   v1,v2:variant;
  418. begin
  419.   v1:=runpop;
  420.   v2:=runpop;
  421.   runpush(v2>=v1);
  422. end;
  423.  
  424. procedure TjanSQLExpression2.procGt;
  425. var
  426.   v1,v2:variant;
  427. begin
  428.   v1:=runpop;
  429.   v2:=runpop;
  430.   runpush(v2>v1);
  431. end;
  432.  
  433. procedure TjanSQLExpression2.procLe;
  434. var
  435.   v1,v2:variant;
  436. begin
  437.   v1:=runpop;
  438.   v2:=runpop;
  439.   runpush(v2<=v1);
  440. end;
  441.  
  442. procedure TjanSQLExpression2.procLt;
  443. var
  444.   v1,v2:variant;
  445. begin
  446.   v1:=runpop;
  447.   v2:=runpop;
  448.   runpush(v2<v1);
  449. end;
  450.  
  451. procedure TjanSQLExpression2.procMultiply;
  452. begin
  453.   runpush(runpop* runpop);
  454. end;
  455.  
  456. procedure TjanSQLExpression2.procNe;
  457. var
  458.   v1,v2:variant;
  459. begin
  460.   v1:=runpop;
  461.   v2:=runpop;
  462.   runpush(v2<>v1);
  463. end;
  464.  
  465. procedure TjanSQLExpression2.procNumber;
  466. begin
  467.   runpush(TToken(FPostFix[FPC]).value);
  468. end;
  469.  
  470. procedure TjanSQLExpression2.procOr;
  471. var
  472.   v1,v2:variant;
  473. begin
  474.   v1:=runpop;
  475.   v2:=runpop;
  476.   runpush(v2 or v1);
  477. end;
  478.  
  479. procedure TjanSQLExpression2.procString;
  480. begin
  481.   runpush(TToken(FPostFix[FPC]).value);
  482.  
  483. end;
  484.  
  485. procedure TjanSQLExpression2.procSubtract;
  486. var
  487.   v1,v2:variant;
  488. begin
  489.   v1:=runpop;
  490.   v2:=runpop;
  491.   runpush(v2-v1);
  492. end;
  493.  
  494. procedure TjanSQLExpression2.Setsource(const Value: string);
  495. begin
  496.   Fsource := Value;
  497.   SL:=length(FSource);
  498.   parse;
  499.   ConvertInFixToPostFix;
  500. end;
  501.  
  502. function TjanSQLExpression2.StackToPostFix: boolean;
  503. var
  504.   tok:TToken;
  505. begin
  506.   result:=false;
  507.   if FStack.count=0 then exit;
  508.   tok:=TToken(FStack[FStack.count-1]);
  509.   FPostFix.Add(tok);
  510.   FStack.Delete(FStack.count-1);
  511.   result:=true;
  512. end;
  513.  
  514. procedure TjanSQLExpression2.runOperator(op:TTokenOperator);
  515. begin
  516.   case op of
  517.     toString: procString;
  518.     toNumber: procNumber;
  519.     toVariable: procVariable;
  520.     toEq: procEq;
  521.     toNe: procNe;
  522.     toGt: procGt;
  523.     toGe: procGe;
  524.     toLt: procLt;
  525.     toLe: procLe;
  526.     toAdd: procAdd;
  527.     toSubtract: procSubtract;
  528.     toMultiply: procMultiply;
  529.     toDivide: procDivide;
  530.     toAnd: procAnd;
  531.     toOr: procOr;
  532.     toNot: procNot;
  533.     toLike: procLike;
  534.     toSin: procSin;
  535.     toCos: procCos;
  536.     toSqr: procSqr;
  537.     toSqrt: procSqrt;
  538.     tosqlIN: procsqlIN;
  539.     toUPPER: procUPPER;
  540.     toLOWER: procLOWER;
  541.     toTRIM: procTRIM;
  542.     toSoundex: procSoundex;
  543.     toLeft:procLeft;
  544.     toRight:procRight;
  545.     toMid:procMid;
  546.     toLen:procLen;
  547.     toFix:procFix;
  548.     toCeil:procCeil;
  549.     toFloor:procFloor;
  550.     toAsNumber: procAsNumber;
  551.     toFormat: procFormat;
  552.     toYear: procYear;
  553.     toMonth: procMonth;
  554.     toDay: procDay;
  555.     toDateAdd: procDateAdd;
  556.     toEaster: procEaster;
  557.     toWeekNumber:procWeekNumber;
  558.     toIsNumeric: procIsNumeric;
  559.     toIsDate: procIsDate;
  560.     toReplace:procReplace;
  561.     toSubstr_After:procSubstr_After;
  562.     toSubstr_Before:procSubstr_Before;
  563.   end;
  564. end;
  565.  
  566. function TjanSQLExpression2.Evaluate: variant;
  567. var
  568.   i,c:integer;
  569.   op:TTokenOperator;
  570. begin
  571.   result:=null;
  572.   c:=FPostFix.Count;
  573.   if c=0 then exit;
  574.   SP:=0;
  575.   for i:=0 to c-1 do begin
  576.     FPC:=i;
  577.     op:=TToken(FPostFix[i]).operator;
  578.     try
  579.       runoperator(op);
  580.     except
  581.       exit;
  582.     end;
  583.   end;
  584.   result:=runpop;
  585. end;
  586.  
  587.  
  588.  
  589. function TjanSQLExpression2.runpop: variant;
  590. begin
  591.   if SP=0 then
  592.     result:=null
  593.   else begin
  594.     dec(SP);
  595.     result:=Vstack[sp];
  596.   end;
  597.  
  598. end;
  599.  
  600. procedure TjanSQLExpression2.runpush(value: variant);
  601. begin
  602.   VStack[SP]:=value;
  603.   inc(SP);
  604. end;
  605.  
  606. procedure TjanSQLExpression2.procVariable;
  607. var
  608.   VariableName:string;
  609.   VariableValue:Variant;
  610.   handled:boolean;
  611. begin
  612.   VariableName:=TToken(FPostFix[FPC]).name;
  613.   if assigned(onGetVariable) then begin
  614.     handled:=false;
  615.     ongetvariable(self,VariableName,VariableValue,handled);
  616.     if not handled then
  617.      VariableValue:=VariableName;
  618.   end
  619.   else
  620.     VariableValue:=VariableName;
  621.   runpush(VariableValue);
  622. end;
  623.  
  624. procedure TjanSQLExpression2.SetonGetVariable(const Value: TVariableEvent);
  625. begin
  626.   FonGetVariable := Value;
  627. end;
  628.  
  629.  
  630. procedure TjanSQLExpression2.procSin;
  631. var
  632.   v1:variant;
  633. begin
  634.   v1:=runpop;
  635.   runpush(sin(v1));
  636. end;
  637.  
  638. procedure TjanSQLExpression2.procNot;
  639. var
  640.   v1:variant;
  641. begin
  642.   v1:=runpop;
  643.   runpush(not(v1));
  644. end;
  645.  
  646. procedure TjanSQLExpression2.procLike;
  647. var
  648.   v1,v2:variant;
  649. begin
  650.   v1:=runpop;
  651.   v2:=runpop;
  652.   runpush(IsLike(v1,v2));
  653. end;
  654.  
  655. function TjanSQLExpression2.IsLike(v1, v2: variant): boolean;
  656. var
  657.   p1,p2:integer;
  658.   s1,s2:string;
  659. begin
  660.   s1:=v1;
  661.   s2:=v2;
  662.   if posstr('%',s1)=0 then begin
  663.     result:=ansisametext(s1,s2)
  664.   end
  665.   else if (copy(s1,1,1)='%') and (copy(s1,length(s1),1)='%') then begin
  666.     s1:=copy(s1,2,length(s1)-2);
  667.     result:=postext(s1,s2)>0;
  668.   end
  669.   else if (copy(s1,1,1)='%') then begin
  670.     s1:=copy(s1,2,maxint);
  671.     p1:=postext(s1,s2);
  672.     result:=p1=length(s2)-length(s1)+1;
  673.   end
  674.   else if (copy(s1,length(s1),1)='%') then begin
  675.     s1:=copy(s1,1,length(s1)-1);
  676.     result:=postext(s1,s2)=1;
  677.   end;
  678. end;
  679.  
  680.  
  681.  
  682.  
  683.  
  684. procedure TjanSQLExpression2.procsqlIn;
  685. var
  686.   v1:variant;
  687.   se,s2:string;
  688.   b:boolean;
  689.   p1,p2,L,L2:integer;
  690. begin
  691.   v1:=runpop;
  692.   s2:=v1;
  693.   se:=TToken(FPostFix[FPC]).expression;
  694.   runpush(postext('['+s2+']',se)>0);
  695. end;
  696.  
  697. procedure TjanSQLExpression2.GetTokenList(list: TList; from,
  698.   till: integer);
  699. var
  700.   tok:TToken;
  701.   i:integer;
  702.  
  703. begin
  704.   Clear;
  705.   for i:=from to till do
  706.     FInFix.Add(TToken(list[i]).copy);
  707.   ConvertInFixToPostFix;
  708. end;
  709.  
  710. procedure TjanSQLExpression2.procLOWER;
  711. var
  712.   v1:variant;
  713.   s1:string;
  714. begin
  715.   v1:=runpop;
  716.   s1:=v1;
  717.   runpush(lowercase(s1));
  718. end;
  719.  
  720. procedure TjanSQLExpression2.procTRIM;
  721. var
  722.   v1:variant;
  723.   s1:string;
  724. begin
  725.   v1:=runpop;
  726.   s1:=v1;
  727.   runpush(trim(s1));
  728. end;
  729.  
  730. procedure TjanSQLExpression2.procUPPER;
  731. var
  732.   v1:variant;
  733.   s1:string;
  734. begin
  735.   v1:=runpop;
  736.   s1:=v1;
  737.   runpush(uppercase(s1));
  738. end;
  739.  
  740. procedure TjanSQLExpression2.procSoundex;
  741. var
  742.   v1:variant;
  743.   s1:string;
  744. begin
  745.   v1:=runpop;
  746.   s1:=v1;
  747.   runpush(soundex(s1));
  748. end;
  749.  
  750. procedure TjanSQLExpression2.procAsNumber;
  751. var
  752.   v1:variant;
  753.   s1:string;
  754.   d1:double;
  755. begin
  756.   v1:=runpop;
  757.   try
  758.     s1:=v1;
  759.     v1:=strtofloat(s1);
  760.   except
  761.     v1:=0;
  762.   end;
  763.   s1:=v1;
  764.   runpush(v1);
  765. end;
  766.  
  767. procedure TjanSQLExpression2.procLeft;
  768. var
  769.   asize,atext:variant;
  770.   s1:string;
  771.   p:integer;
  772. begin
  773.   asize:=runpop;
  774.   atext:=runpop;
  775.   s1:=atext;
  776.   p:=asize;
  777.   s1:=copy(s1,1,p);
  778.   runpush(s1);
  779. end;
  780.  
  781. procedure TjanSQLExpression2.procRight;
  782. var
  783.   asize,atext:variant;
  784.   s1:string;
  785.   p:integer;
  786. begin
  787.   asize:=runpop;
  788.   atext:=runpop;
  789.   s1:=atext;
  790.   p:=asize;
  791.   s1:=copy(s1,length(s1)-p+1,p);
  792.   runpush(s1);
  793. end;
  794.  
  795. procedure TjanSQLExpression2.procMid;
  796. var
  797.   vcount,vfrom,vtext:variant;
  798.   s1:string;
  799.   p,c:integer;
  800. begin
  801.   vcount:=runpop;
  802.   vfrom:=runpop;
  803.   vtext:=runpop;
  804.   s1:=vtext;
  805.   p:=vfrom;
  806.   c:=vcount;
  807.   s1:=copy(s1,p,c);
  808.   runpush(s1);
  809. end;
  810.  
  811. procedure TjanSQLExpression2.procCos;
  812. var
  813.   v1:variant;
  814. begin
  815.   v1:=runpop;
  816.   runpush(cos(v1));
  817. end;
  818.  
  819. procedure TjanSQLExpression2.procSqr;
  820. var
  821.   v1:variant;
  822. begin
  823.   v1:=runpop;
  824.   runpush(sqr(v1));
  825. end;
  826.  
  827.  
  828.  
  829. procedure TjanSQLExpression2.procSqrt;
  830. var
  831.   v1:variant;
  832. begin
  833.   v1:=runpop;
  834.   runpush(sqrt(v1));
  835. end;
  836.  
  837. procedure TjanSQLExpression2.procLen;
  838. var
  839.   v1:variant;
  840.   s1:string;
  841. begin
  842.   v1:=runpop;
  843.   s1:=v1;
  844.   runpush(length(s1));
  845. end;
  846.  
  847. procedure TjanSQLExpression2.procFix;
  848. var
  849.   vfloat,vdecimals:variant;
  850.   s1,s2:string;
  851.   d1:double;
  852. begin
  853.   vdecimals:=runpop;
  854.   vfloat:=runpop;
  855.   s1:=vfloat;
  856.   s2:=vdecimals;
  857.   try
  858.     d1:=strtofloat(s1);
  859.     s1:=format('%.'+s2+'f',[d1]);
  860.   except
  861.   end;
  862.   runpush(s1);
  863. end;
  864.  
  865. procedure TjanSQLExpression2.procCeil;
  866. var
  867.   v1:variant;
  868. begin
  869.   v1:=runpop;
  870.   runpush(ceil(v1));
  871. end;
  872.  
  873. procedure TjanSQLExpression2.procFloor;
  874. var
  875.   v1:variant;
  876. begin
  877.   v1:=runpop;
  878.   runpush(floor(v1));
  879. end;
  880.  
  881. procedure TjanSQLExpression2.procFormat;
  882. var
  883.   vfloat,vformat:variant;
  884.   s1,s2:string;
  885.   d1:double;
  886.   i1:integer;
  887. begin
  888.   vformat:=runpop;
  889.   vfloat:=runpop;
  890.   s1:=vfloat;
  891.   s2:=vformat;
  892.   if s2='' then begin
  893.     runpush(s1);
  894.     exit;
  895.   end;
  896.   if s2[length(s2)] in ['d','x'] then
  897.   try
  898.     i1:=strtoint(s1);
  899.     s1:=format(s2,[i1]);
  900.   except
  901.   end
  902.   else if s2[length(s2)] in ['s'] then
  903.   try
  904.     s1:=format(s2,[s1]);
  905.   except
  906.   end
  907.   else
  908.   try
  909.     d1:=strtofloat(s1);
  910.     s1:=format(s2,[d1]);
  911.   except
  912.   end;
  913.   runpush(s1);
  914. end;
  915.  
  916.  
  917. procedure TjanSQLExpression2.procDay;
  918. {return the day part as integer from a 'yyyy-mm-dd' string}
  919. var
  920.   v1:variant;
  921.   s1:string;
  922.   i1:integer;
  923. begin
  924.   v1:=runpop;
  925.   s1:=v1;
  926.   i1:=strtointdef(copy(s1,9,2),0);
  927.   runpush(i1);
  928. end;
  929.  
  930. procedure TjanSQLExpression2.procMonth;
  931. {return the month part as integer from a 'yyyy-mm-dd' string}
  932. var
  933.   v1:variant;
  934.   s1:string;
  935.   i1:integer;
  936. begin
  937.   v1:=runpop;
  938.   s1:=v1;
  939.   i1:=strtointdef(copy(s1,6,2),0);
  940.   runpush(i1);
  941. end;
  942.  
  943. procedure TjanSQLExpression2.procYear;
  944. {return the year part as integer from a 'yyyy-mm-dd' string}
  945. var
  946.   v1:variant;
  947.   s1:string;
  948.   i1:integer;
  949. begin
  950.   v1:=runpop;
  951.   s1:=v1;
  952.   i1:=strtointdef(copy(s1,1,4),0);
  953.   runpush(i1);
  954. end;
  955.  
  956. procedure TjanSQLExpression2.procDateAdd;
  957. {add number of intervals to date}
  958. var
  959.   vinterval,vnumber,vdate:variant;
  960.   ayear,amonth,aday:word;
  961.   adate:TDateTime;
  962.   sinterval,sdate:string;
  963.   inumber:integer;
  964. begin
  965.   vdate:=runpop;
  966.   vnumber:=runpop;
  967.   vinterval:=runpop;
  968.   sinterval:=lowercase(vinterval);
  969.   inumber:=vnumber;
  970.   sdate:=vdate;
  971.   try
  972.     ayear:=strtoint(copy(sdate,1,4));
  973.     amonth:=strtoint(copy(sdate,6,2));
  974.     aday:=strtoint(copy(sdate,9,2));
  975.     adate:=encodedate(ayear,amonth,aday);
  976.     if sinterval='d' then
  977.       adate:=adate+1
  978.     else if sinterval='m' then
  979.       adate:=incmonth(adate,inumber)
  980.     else if sinterval='y' then
  981.       adate:=encodedate(ayear+inumber,amonth,aday)
  982.     else if sinterval='w' then
  983.       adate:=adate+7*inumber
  984.     else if sinterval='q' then
  985.       adate:=incmonth(adate,inumber*3);
  986.     decodedate(adate,ayear,amonth,aday);
  987.     sdate:=format('%.4d',[ayear])+'-'+format('%.2d',[amonth])+'-'+format('%.2d',[aday]);
  988.   except
  989.   end;
  990.   runpush(sdate);
  991. end;
  992.  
  993.  
  994. procedure TjanSQLExpression2.procEaster;
  995. // returns the easter date of a given year
  996. var
  997.   vyear:variant;
  998.   ayear:integer;
  999.   s1:string;
  1000.   adate:TDateTime;
  1001. begin
  1002.   vyear:=runpop;
  1003.   s1:='';
  1004.   try
  1005.     ayear:=vyear;
  1006.     s1:=datetosqlstring(easter(ayear));
  1007.   except
  1008.   end;
  1009.   runpush(s1);
  1010. end;
  1011.  
  1012. procedure TjanSQLExpression2.procWeekNumber;
  1013. var
  1014.   v1:variant;
  1015.   s1:string;
  1016.   i1:integer;
  1017.   d1:TDateTime;
  1018. begin
  1019.   v1:=runpop;
  1020.   i1:=0;
  1021.   try
  1022.     s1:=v1;
  1023.     d1:=SQLStringToDate(s1);
  1024.     i1:=Date2WeekNo(d1);
  1025.   except
  1026.   end;
  1027.   runpush(i1);
  1028. end;
  1029.  
  1030. procedure TjanSQLExpression2.procIsNumeric;
  1031. var
  1032.   v1:variant;
  1033.   s1:string;
  1034.   d1:extended;
  1035. begin
  1036.   v1:=runpop;
  1037.   s1:=v1;
  1038.   try
  1039.     d1:=strtofloat(s1);
  1040.     runpush(true)
  1041.   except
  1042.     runpush(false)
  1043.   end;
  1044. end;
  1045.  
  1046. procedure TjanSQLExpression2.procIsDate;
  1047. var
  1048.   v1:variant;
  1049.   s1:string;
  1050.   d1:extended;
  1051. begin
  1052.   v1:=runpop;
  1053.   s1:=v1;
  1054.   runpush(SQLStringToDate(s1)<>0);
  1055. end;
  1056.  
  1057. procedure TjanSQLExpression2.procReplace;
  1058. // replace(source, oldpattern, newpattern)
  1059. var
  1060.   vsource, vold, vnew:variant;
  1061.   ssource, sold, snew:string;
  1062. begin
  1063.   vnew:=runpop;
  1064.   vold:=runpop;
  1065.   vsource:=runpop;
  1066.   ssource:=vsource;
  1067.   sold:=vold;
  1068.   snew:=vnew;
  1069.   ssource:=stringreplace(ssource,sold,snew,[rfreplaceall,rfignorecase]);
  1070.   runpush(ssource);
  1071. end;
  1072.  
  1073. procedure TjanSQLExpression2.procsubstr_after;
  1074. var
  1075.   vsource,vsubstr:variant;
  1076.   ssubstr,ssource,s1:string;
  1077.   p:integer;
  1078. begin
  1079.   vsubstr:=runpop;
  1080.   vsource:=runpop;
  1081.   ssubstr:=vsubstr;
  1082.   ssource:=vsource;
  1083.   p:=postext(ssubstr,ssource);
  1084.   if p>0 then
  1085.     s1:=copy(ssource,p+length(ssubstr),maxint)
  1086.   else
  1087.     s1:='';
  1088.   runpush(s1);
  1089. end;
  1090.  
  1091. procedure TjanSQLExpression2.procsubstr_before;
  1092. var
  1093.   vsource,vsubstr:variant;
  1094.   ssubstr,ssource,s1:string;
  1095.   p:integer;
  1096. begin
  1097.   vsubstr:=runpop;
  1098.   vsource:=runpop;
  1099.   ssubstr:=vsubstr;
  1100.   ssource:=vsource;
  1101.   p:=postext(ssubstr,ssource);
  1102.   if p>0 then
  1103.     s1:=copy(ssource,1,p-1)
  1104.   else
  1105.     s1:='';
  1106.   runpush(s1);
  1107. end;
  1108.  
  1109. end.
  1110.