home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kompon / d456 / JANSQL.ZIP / janSQLDemo / components / janSQLTokenizer.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-04-02  |  20.5 KB  |  839 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: janSQLTokenizer.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: 25-mar-2002
  21. Current Version: 1.1
  22.  
  23. Notes: This is a SQL oriented tokenizer.
  24.  
  25. Known Issues:
  26.  
  27.  
  28. History:
  29.   1.1 25-mar-2002
  30.       - TRUNC alias for FIX function
  31.       - added FORMAT function
  32.       - added DATE constant
  33.       - added TIME constant
  34.       - added YEAR function
  35.       - added MONTH function
  36.       - added DAY function
  37.       - added DATEADD function
  38.       - added DATEDIFF function
  39.       - added EASTER function
  40.       - added WEEKNUMBER function
  41.       - added ISNUMERIC function      
  42.       - added ISDATE function
  43.   1.0 24-mar-2002 : original release
  44.  
  45. -----------------------------------------------------------------------------}
  46.  
  47. unit janSQLTokenizer;
  48.  
  49. interface
  50.  
  51. uses
  52.   Classes,SysUtils,janSQLStrings,dialogs;
  53.  
  54. const
  55.   delimiters=['+','-','*','/',' ','(',')','=','>','<'];
  56.   numberchars=['0'..'9','.'];
  57.   identchars=['a'..'z','A'..'Z','0'..'9','.','_'];
  58.   alphachars=['a'..'z','A'..'Z'];
  59.  
  60. type
  61.  
  62.   TSubExpressionEvent=procedure(sender:Tobject;const subexpression:string;var subexpressionValue:variant;var handled:boolean) of object;
  63.  
  64.   TTokenKind=(tkKeyword,tkOperator, tkOperand, tkOpen, tkClose,
  65.     tkComma,tkHash);
  66.  
  67.  
  68.   TTokenOperator=(toNone,toString,toNumber,toVariable,
  69.      toComma,toOpen,toClose,toHash,
  70.      tosqlCount, tosqlSum, tosqlAvg, tosqlMAX, tosqlMIN, tosqlStdDev,
  71.      toEq,toNe,toGt,toGe,toLt,toLe,
  72.      toAdd,toSubtract,toMultiply,toDivide,
  73.      toAnd,toOr,toNot,toLike,
  74.      tosqlALTER,tosqlTABLE,tosqlCOLUMN,
  75.      tosqlADD,tosqlDROP,tosqlCOMMIT,tosqlCREATE,
  76.      tosqlDELETE,tosqlFROM,tosqlWHERE,
  77.      tosqlINSERT,tosqlINTO,tosqlVALUES,
  78.      tosqlSELECT,tosqlAS,tosqlORDER,tosqlUPDATE,
  79.      tosqlSET,tosqlCONNECT, tosqlASSIGN,
  80.      tosqlSAVETABLE, tosqlRELEASETABLE,
  81.      tosqlGROUP, tosqlASC, tosqlDESC, tosqlHAVING,
  82.      tosqlIN,
  83.      toLOWER,toUPPER,toTRIM,toSoundex,
  84.      toSin, toCos, toSqr, toSqrt,
  85.      toAsNumber,toLeft, toRight, toMid,
  86.      tosubstr_after, tosubstr_before,
  87.      toFormat,
  88.      toDateAdd,
  89.      toYear, toMonth, toDay, toEaster, toWeekNumber,
  90.      toLen, toFix, toCeil, toFloor,
  91.      toIsNumeric, toIsDate,
  92.      toReplace);
  93.  
  94.  
  95.  
  96.   TToken=class(TObject)
  97.   private
  98.     Fname: string;
  99.     Ftokenkind: TTokenKind;
  100.     Foperator: TTokenOperator;
  101.     Fvalue: variant;
  102.     Flevel: integer;
  103.     Fexpression: string;
  104.     procedure Setname(const Value: string);
  105.     procedure Setoperator(const Value: TTokenOperator);
  106.     procedure Settokenkind(const Value: TTokenKind);
  107.     procedure Setvalue(const Value: variant);
  108.     procedure Setlevel(const Value: integer);
  109.     procedure Setexpression(const Value: string);
  110.   public
  111.     function copy:TToken;
  112.     property name:string read Fname write Setname;
  113.     property value:variant read Fvalue write Setvalue;
  114.     property tokenkind:TTokenKind read Ftokenkind write Settokenkind;
  115.     property operator: TTokenOperator read Foperator write Setoperator;
  116.     property level:integer read Flevel write Setlevel;
  117.     property expression:string read Fexpression write Setexpression;
  118.   end;
  119.  
  120.   TjanSQLTokenizer=class(TObject)
  121.   private
  122.     FSource:string;
  123.     FList:TList;
  124.     idx: integer; // scan index
  125.     SL:integer; // source length
  126.     FToken:string;
  127.     FTokenKind:TTokenKind;
  128.     FTokenValue:variant;
  129.     FTokenOperator:TTokenOperator;
  130.     FTokenLevel:integer;
  131.     FTokenExpression:string;
  132.     FonSubExpression: TSubExpressionEvent;
  133.     procedure AddToken(list:TList);
  134.     function GetToken: boolean;
  135.     function IsKeyWord(value: string): boolean;
  136.     function IsFunction(value: string): boolean;
  137.     function LookAhead(var index:integer):string;
  138.     function getTokenCount: integer;
  139.     function getsubExpression:boolean;
  140.     procedure SetonSubExpression(const Value: TSubExpressionEvent);
  141.   public
  142.     function Tokenize(source:string;list:TList):boolean;
  143.     property TokenCount:integer read getTokenCount;
  144.     property onSubExpression:TSubExpressionEvent read FonSubExpression write SetonSubExpression;
  145.   end;
  146.  
  147.  
  148. implementation
  149.  
  150. const
  151.   cr = chr(13)+chr(10);
  152.  
  153.  
  154. { TjanSQLTokenizer }
  155.  
  156. function TjanSQLTokenizer.Tokenize(source: string; list: TList): boolean;
  157. begin
  158.   result:=true;
  159.   FSource:=source;
  160.   idx:=1;
  161.   SL:=length(source);
  162.   while getToken do AddToken(list);
  163. end;
  164.  
  165.  
  166.  
  167. procedure TjanSQLTokenizer.AddToken(list:TList);
  168. var
  169.   tok:TToken;
  170. begin
  171.   tok:=TToken.Create;
  172.   tok.name:=FToken;
  173.   tok.tokenkind:=FTokenKind;
  174.   tok.value:=FTokenValue;
  175.   tok.operator:=FTokenOperator;
  176.   tok.level:=FtokenLevel;
  177.   tok.expression:=FTokenExpression;
  178.   List.Add(tok);
  179. end;
  180.  
  181.  
  182. function TjanSQLTokenizer.GetToken: boolean;
  183. var
  184.   bot:char;
  185.  
  186.   function sqldatestring:string;
  187.   var
  188.     ayear,amonth,aday:word;
  189.   begin
  190.     decodedate(now,ayear,amonth,aday);
  191.     result:=format('%.4d',[ayear])+'-'+format('%.2d',[amonth])+'-'+format('%.2d',[aday])
  192.   end;
  193.  
  194.   function sqltimestring:string;
  195.   var
  196.     ahour,amin,asec,amsec:word;
  197.   begin
  198.     decodetime(time,ahour,amin,asec,amsec);
  199.     result:=format('%.2d',[ahour])+':'+format('%.2d',[amin])+':'+format('%.2d',[asec]);
  200.   end;
  201.  
  202. begin
  203.   result:=false;
  204.   FToken:='';
  205.   while (idx<=SL) and (FSource[idx]=' ') do inc(idx);
  206.   if idx>SL then exit;
  207.   bot:=FSource[idx]; // begin of token
  208.   if bot='''' then begin  // string
  209.     inc(idx);
  210.     while (idx<=SL) and (FSource[idx]<>'''' ) do begin
  211.       FToken:=FToken+Fsource[idx];
  212.       inc(idx);
  213.     end;
  214.     if idx>SL then exit;
  215.     inc(idx);
  216.     FTokenValue:=FToken;
  217.     FTokenKind:=tkOperand;
  218.     FTokenOperator:=toString;
  219.     result:=true;
  220.   end
  221.   else if bot=',' then begin
  222.     FToken:=FToken+Fsource[idx];
  223.     inc(idx);
  224.     FTokenValue:=FToken;
  225.     FTokenKind:=tkComma;
  226.     FTokenOperator:=toComma;
  227.     result:=true;
  228.   end
  229.   else if bot='#' then begin
  230.     FToken:=FToken+Fsource[idx];
  231.     inc(idx);
  232.     FTokenValue:=FToken;
  233.     FTokenKind:=tkHash;
  234.     FTokenOperator:=toHash;
  235.     result:=true;
  236.   end
  237.   else if bot in ['A'..'Z','a'..'z'] then begin  // identifier
  238.     while (idx<=SL) and (FSource[idx] in identchars) do begin
  239.       FToken:=FToken+Fsource[idx];
  240.       inc(idx);
  241.     end;
  242.     if isKeyword(Ftoken) then begin
  243.       result:=true;
  244.     end
  245.     else if lowercase(FToken)='or' then begin
  246.         FTokenKind:=tkOperator;
  247.         FTokenLevel:=0;
  248.         FTokenOperator:=toOr;
  249.     end
  250.     else if lowercase(FToken)='and' then begin
  251.         FTokenKind:=tkOperator;
  252.         FTokenLevel:=0;
  253.         FTokenOperator:=toAnd;
  254.     end
  255.     else if lowercase(FToken)='pi' then begin
  256.         FTokenKind:=tkOperand;
  257.         FTokenValue:=pi;
  258.         FTokenOperator:=toNumber;
  259.     end
  260.     else if lowercase(FToken)='date' then begin
  261.         FTokenKind:=tkOperand;
  262.         FTokenValue:=sqldatestring;
  263.         FTokenOperator:=tostring;
  264.     end
  265.     else if lowercase(FToken)='time' then begin
  266.         FTokenKind:=tkOperand;
  267.         FTokenValue:=sqltimestring;
  268.         FTokenOperator:=tostring;
  269.     end
  270.     else if ISFunction(lowercase(FToken)) then begin
  271.     end
  272.     else begin
  273.         FTokenKind:=tkOperand;
  274.         FTokenOperator:=toVariable;
  275.     end;
  276.     result:=true;
  277.   end
  278.   else if bot in ['0'..'9'] then begin // number
  279.     while (idx<=SL) and (FSource[idx] in numberchars) do begin
  280.       FToken:=FToken+Fsource[idx];
  281.       inc(idx);
  282.     end;
  283.     FTokenKind:=tkOperand;
  284.     try
  285.       FTokenValue:=strtofloat(FToken);
  286.       FTokenOperator:=toNumber;
  287.     except
  288.       exit;
  289.     end;
  290.     result:=true;
  291.   end
  292.   else if bot='(' then begin
  293.     FToken:='(';
  294.     FTokenKind:=tkOpen;
  295.     FTokenOperator:=toOpen;
  296.     FtokenLevel:=1;
  297.     inc(idx);
  298.     result:=true;
  299.   end
  300.   else if bot=')' then begin
  301.     FToken:=')';
  302.     FTokenKind:=tkClose;
  303.     FTokenOperator:=toClose;
  304.     FtokenLevel:=1;
  305.     inc(idx);
  306.     result:=true;
  307.   end
  308.   else if bot in delimiters then begin
  309.     FToken:=FToken+Fsource[idx];
  310.     inc(idx);
  311.     FTokenKind:=tkOperator;
  312.     case bot of
  313.     '=': begin  FTokenOperator:=toEq;;FTokenLevel:=3;end;
  314.     '+': begin  FTokenOperator:=toAdd;FTokenLevel:=4;end;
  315.     '-': begin  FTokenOperator:=toSubtract;FTokenLevel:=3;end;
  316.     '*': begin  FTokenOperator:=toMultiply;FTokenLevel:=6;end;
  317.     '/': begin  FTokenOperator:=toDivide; FtokenLevel:=5;end;
  318.     '>': begin
  319.            if idx>SL then exit;
  320.            FTokenLevel:=3;
  321.            if FSource[idx]='=' then begin
  322.              FToken:=FToken+Fsource[idx];
  323.              inc(idx);
  324.              FTokenOperator:=toGe;
  325.            end
  326.            else
  327.              FTokenOperator:=toGt
  328.          end;
  329.     '<': begin
  330.            if idx>SL then exit;
  331.            FTokenLevel:=3;
  332.            if FSource[idx]='=' then begin
  333.              FToken:=FToken+Fsource[idx];
  334.              inc(idx);
  335.              FTokenOperator:=toLe;
  336.            end
  337.            else if FSource[idx]='>' then begin
  338.              FToken:=FToken+Fsource[idx];
  339.              inc(idx);
  340.              FTokenOperator:=toNe;
  341.            end
  342.            else
  343.              FTokenOperator:=toLt;
  344.          end;
  345.     end;
  346.     result:=true;
  347.   end
  348.   else
  349.     exit;
  350. end;
  351.  
  352.  
  353. function TjanSQLTokenizer.IsFunction(value: string): boolean;
  354. begin
  355.   result:=false;
  356.   if value='sin' then begin
  357.     FtokenKind:=tkOperator;
  358.     FTokenOperator:=tosin;
  359.     FtokenLevel:=7;
  360.     result:=true;
  361.   end
  362.   else if value='cos' then begin
  363.     FtokenKind:=tkOperator;
  364.     FTokenOperator:=tocos;
  365.     FtokenLevel:=7;
  366.     result:=true;
  367.   end
  368.   else if value='sqr' then begin
  369.     FtokenKind:=tkOperator;
  370.     FTokenOperator:=tosqr;
  371.     FtokenLevel:=7;
  372.     result:=true;
  373.   end
  374.   else if value='sqrt' then begin
  375.     FtokenKind:=tkOperator;
  376.     FTokenOperator:=tosqrt;
  377.     FtokenLevel:=7;
  378.     result:=true;
  379.   end
  380.   else if value='easter' then begin
  381.     FtokenKind:=tkOperator;
  382.     FTokenOperator:=toEaster;
  383.     FtokenLevel:=7;
  384.     result:=true;
  385.   end
  386.   else if value='weeknumber' then begin
  387.     FtokenKind:=tkOperator;
  388.     FTokenOperator:=toWeekNumber;
  389.     FtokenLevel:=7;
  390.     result:=true;
  391.   end
  392.   else if value='year' then begin
  393.     FtokenKind:=tkOperator;
  394.     FTokenOperator:=toyear;
  395.     FtokenLevel:=7;
  396.     result:=true;
  397.   end
  398.   else if value='month' then begin
  399.     FtokenKind:=tkOperator;
  400.     FTokenOperator:=tomonth;
  401.     FtokenLevel:=7;
  402.     result:=true;
  403.   end
  404.   else if value='day' then begin
  405.     FtokenKind:=tkOperator;
  406.     FTokenOperator:=today;
  407.     FtokenLevel:=7;
  408.     result:=true;
  409.   end
  410.  
  411.   else if value='soundex' then begin
  412.     FtokenKind:=tkOperator;
  413.     FTokenOperator:=toSoundex;
  414.     FtokenLevel:=7;
  415.     result:=true;
  416.   end
  417.   else if value='lower' then begin
  418.     FtokenKind:=tkOperator;
  419.     FTokenOperator:=toLOWER;
  420.     FtokenLevel:=7;
  421.     result:=true;
  422.   end
  423.   else if value='upper' then begin
  424.     FtokenKind:=tkOperator;
  425.     FTokenOperator:=toUPPER;
  426.     FtokenLevel:=7;
  427.     result:=true;
  428.   end
  429.   else if value='trim' then begin
  430.     FtokenKind:=tkOperator;
  431.     FTokenOperator:=toTRIM;
  432.     FtokenLevel:=7;
  433.     result:=true;
  434.   end
  435.   else if value='in' then begin
  436.     FtokenKind:=tkOperator;
  437.     FTokenOperator:=tosqlIN;
  438.     FtokenLevel:=7;
  439.     result:=getsubexpression;
  440.   end
  441.   else if value='not' then begin
  442.     FtokenKind:=tkOperator;
  443.     FTokenOperator:=toNot;
  444.     FtokenLevel:=7;
  445.     result:=true;
  446.   end
  447.   else if value='like' then begin
  448.     FtokenKind:=tkOperator;
  449.     FTokenOperator:=toLike;
  450.     FtokenLevel:=7;
  451.     result:=true;
  452.   end
  453.   else if value='asnumber' then begin
  454.     FtokenKind:=tkOperator;
  455.     FTokenOperator:=toAsNumber;
  456.     FtokenLevel:=7;
  457.     result:=true;
  458.   end
  459.   else if value='dateadd' then begin
  460.     FtokenKind:=tkOperator;
  461.     FTokenOperator:=todateadd;
  462.     FtokenLevel:=7;
  463.     result:=true;
  464.   end
  465.   else if value='left' then begin
  466.     FtokenKind:=tkOperator;
  467.     FTokenOperator:=toleft;
  468.     FtokenLevel:=7;
  469.     result:=true;
  470.   end
  471.   else if value='right' then begin
  472.     FtokenKind:=tkOperator;
  473.     FTokenOperator:=toRight;
  474.     FtokenLevel:=7;
  475.     result:=true;
  476.   end
  477.   else if value='mid' then begin
  478.     FtokenKind:=tkOperator;
  479.     FTokenOperator:=toMid;
  480.     FtokenLevel:=7;
  481.     result:=true;
  482.   end
  483.   else if value='substr_after' then begin
  484.     FtokenKind:=tkOperator;
  485.     FTokenOperator:=tosubstr_after;
  486.     FtokenLevel:=7;
  487.     result:=true;
  488.   end
  489.   else if value='substr_before' then begin
  490.     FtokenKind:=tkOperator;
  491.     FTokenOperator:=tosubstr_before;
  492.     FtokenLevel:=7;
  493.     result:=true;
  494.   end
  495.   else if value='format' then begin
  496.     FtokenKind:=tkOperator;
  497.     FTokenOperator:=toFormat;
  498.     FtokenLevel:=7;
  499.     result:=true;
  500.   end
  501.   else if value='length' then begin
  502.     FtokenKind:=tkOperator;
  503.     FTokenOperator:=toLen;
  504.     FtokenLevel:=7;
  505.     result:=true;
  506.   end
  507.   else if (value='fix') or (value='trunc') then begin
  508.     FtokenKind:=tkOperator;
  509.     FTokenOperator:=toFix;
  510.     FtokenLevel:=7;
  511.     result:=true;
  512.   end
  513.   else if value='ceil' then begin
  514.     FtokenKind:=tkOperator;
  515.     FTokenOperator:=toCeil;
  516.     FtokenLevel:=7;
  517.     result:=true;
  518.   end
  519.   else if value='floor' then begin
  520.     FtokenKind:=tkOperator;
  521.     FTokenOperator:=toFloor;
  522.     FtokenLevel:=7;
  523.     result:=true;
  524.   end
  525.   else if value='isnumeric' then begin
  526.     FtokenKind:=tkOperator;
  527.     FTokenOperator:=toIsNumeric;
  528.     FtokenLevel:=7;
  529.     result:=true;
  530.   end
  531.   else if value='isdate' then begin
  532.     FtokenKind:=tkOperator;
  533.     FTokenOperator:=toIsDate;
  534.     FtokenLevel:=7;
  535.     result:=true;
  536.   end
  537.   else if value='replace' then begin
  538.     FtokenKind:=tkOperator;
  539.     FTokenOperator:=toReplace;
  540.     FtokenLevel:=7;
  541.     result:=true;
  542.   end
  543.  
  544. end;
  545.  
  546. function TjanSQLTokenizer.getTokenCount: integer;
  547. begin
  548.   result:=FList.count;
  549. end;
  550.  
  551. function TjanSQLTokenizer.IsKeyWord(value: string): boolean;
  552. var
  553.   tmp:string;
  554.   i:integer;
  555. begin
  556.   result:=false;
  557.   tmp:=uppercase(value);
  558.   if tmp='SELECT' then begin
  559.     FTokenOperator:=tosqlSELECT;
  560.     result:=true;
  561.   end
  562.   else if tmp='AS' then begin
  563.     FTokenOperator:=tosqlAS;
  564.     result:=true;
  565.   end
  566.   else if tmp='SAVE' then begin
  567.     if uppercase(lookahead(i))<>'TABLE' then exit;
  568.     FTokenOperator:=tosqlSAVETABLE;
  569.     result:=true;
  570.     idx:=i;
  571.   end
  572.   else if tmp='RELEASE' then begin
  573.     if uppercase(lookahead(i))<>'TABLE' then exit;
  574.     FTokenOperator:=tosqlRELEASETABLE;
  575.     result:=true;
  576.     idx:=i;
  577.   end
  578.   else if tmp='ASSIGN' then begin
  579.     if uppercase(lookahead(i))<>'TO' then exit;
  580.     FTokenOperator:=tosqlASSIGN;
  581.     result:=true;
  582.     idx:=i;
  583.   end
  584.   else if tmp='UPDATE' then begin
  585.     FTokenOperator:=tosqlUPDATE;
  586.     result:=true;
  587.   end
  588.   else if tmp='INSERT' then begin
  589.     FTokenOperator:=tosqlINSERT;
  590.     result:=true;
  591.   end
  592.   else if tmp='INTO' then begin
  593.     FTokenOperator:=tosqlINTO;
  594.     result:=true;
  595.   end
  596.   else if tmp='DELETE' then begin
  597.     FTokenOperator:=tosqlDELETE;
  598.     result:=true;
  599.   end
  600.   else if tmp='CONNECT' then begin
  601.     if uppercase(lookahead(i))<>'TO' then exit;
  602.     FTokenOperator:=tosqlCONNECT;
  603.     result:=true;
  604.     idx:=i;
  605.   end
  606.   else if tmp='COMMIT' then begin
  607.     FTokenOperator:=tosqlCOMMIT;
  608.     result:=true;
  609.   end
  610.   else if tmp='FROM' then begin
  611.     FTokenOperator:=tosqlFROM;
  612.     result:=true;
  613.   end
  614.   else if tmp='WHERE' then begin
  615.     FTokenOperator:=tosqlWHERE;
  616.     result:=true;
  617.   end
  618.   else if tmp='ORDER' then begin
  619.     if uppercase(lookahead(i))<>'BY' then exit;
  620.     FTokenOperator:=tosqlORDER;
  621.     result:=true;
  622.     idx:=i;
  623.   end
  624.   else if tmp='ASC' then begin
  625.     FTokenOperator:=tosqlASC;
  626.     result:=true;
  627.   end
  628.   else if tmp='DESC' then begin
  629.     FTokenOperator:=tosqlDESC;
  630.     result:=true;
  631.   end
  632.   else if tmp='SET' then begin
  633.     FTokenOperator:=tosqlSET;
  634.     result:=true;
  635.   end
  636.   else if tmp='VALUES' then begin
  637.     FTokenOperator:=tosqlVALUES;
  638.     result:=true;
  639.   end
  640.   else if tmp='CREATE' then begin
  641.     FTokenOperator:=tosqlCREATE;
  642.     result:=true;
  643.   end
  644.   else if tmp='TABLE' then begin
  645.     FTokenOperator:=tosqlTABLE;
  646.     result:=true;
  647.   end
  648.   else if tmp='DROP' then begin
  649.     FTokenOperator:=tosqlDROP;
  650.     result:=true;
  651.   end
  652.   else if tmp='ALTER' then begin
  653.     FTokenOperator:=tosqlALTER;
  654.     result:=true;
  655.   end
  656.   else if tmp='ADD' then begin
  657.     FTokenOperator:=tosqlADD;
  658.     result:=true;
  659.   end
  660.   else if tmp='COLUMN' then begin
  661.     FTokenOperator:=tosqlCOLUMN;
  662.     result:=true;
  663.   end
  664.   else if tmp='GROUP' then begin
  665.     if uppercase(lookahead(i))<>'BY' then exit;
  666.     FTokenOperator:=tosqlgroup;
  667.     result:=true;
  668.     idx:=i;
  669.   end
  670.   else if tmp='HAVING' then begin
  671.     FTokenOperator:=tosqlHAVING;
  672.     result:=true;
  673.   end;
  674.  
  675.   if result then begin
  676.     FtokenKind:=tkKeyword;
  677.     FtokenLevel:=0;
  678.   end;
  679. end;
  680.  
  681. function TjanSQLTokenizer.getsubExpression: boolean;
  682. var
  683.   tmp:string;
  684.   b:boolean;
  685.   i,c,L:integer;
  686.   tokenizer:TjanSQLTokenizer;
  687.   sublist:TList;
  688.   handled:boolean;
  689.   subvalue:variant;
  690.   brackets:integer;
  691.  
  692.   procedure clearsublist;
  693.   var
  694.     ii,cc:integer;
  695.   begin
  696.     cc:=sublist.count;
  697.     if cc<>0 then
  698.       for ii:=0 to cc-1 do
  699.         TToken(sublist[ii]).free;
  700.     sublist.clear;
  701.   end;
  702. begin
  703.   result:=False;
  704.   while (idx<=SL) and (FSource[idx]=' ') do inc(idx);
  705.   if idx>SL then exit;
  706.   if FSource[idx]<>'(' then exit;
  707.   inc(idx);
  708.   brackets:=1; // keep track of open/close brackets
  709.   while (idx<=SL) do begin
  710.     if FSource[idx]='(' then
  711.       inc(brackets)
  712.     else if FSource[idx]=')' then begin
  713.       dec(brackets);
  714.       if (brackets=0) then break;
  715.     end
  716.     else
  717.       tmp:=tmp+FSource[idx];
  718.     inc(idx);
  719.   end;
  720.   if idx>SL then exit;
  721.   inc(idx);
  722.   tmp:=trim(tmp);
  723.   if postext('select ',tmp)=1 then begin
  724.     if assigned(onSubExpression) then begin
  725.       onSubExpression(self,tmp,subvalue,handled);
  726.       if handled then begin
  727.         FtokenExpression:=subvalue;
  728.         result:=true;
  729.       end;
  730.     end;
  731.     exit;
  732.   end;
  733.   try
  734.     sublist:=TList.create;
  735.     tokenizer:=TjanSQLTokenizer.create;
  736.     b:=tokenizer.Tokenize(tmp,sublist);
  737.   finally
  738.     tokenizer.free;
  739.   end;
  740.   if not b then begin
  741.     clearsublist;
  742.     sublist.free;
  743.     exit;
  744.   end;
  745.   c:=sublist.Count;
  746.   if c>0 then begin
  747.     tmp:='[';
  748.     for i:=0 to c-1 do begin
  749.       if Ttoken(sublist[i]).tokenkind=tkComma then
  750.         tmp:=tmp+']['
  751.       else
  752.         tmp:=tmp+TToken(sublist[i]).name;
  753.     end;
  754.     tmp:=tmp+']';
  755.   end;
  756.   FtokenExpression:=tmp;
  757.   clearsublist;
  758.   sublist.free;
  759.   result:=true;
  760. end;
  761.  
  762. procedure TjanSQLTokenizer.SetonSubExpression(
  763.   const Value: TSubExpressionEvent);
  764. begin
  765.   FonSubExpression := Value;
  766. end;
  767. // some sql clauses consist of 2 wordes
  768. // eg GROUP BY
  769. function TjanSQLTokenizer.LookAhead(var index:integer): string;
  770. var
  771.   i:integer;
  772.   tmp:string;
  773. begin
  774.   result:='';
  775.   i:=idx;
  776.   //skip spaces
  777.   while (i<=SL) and (FSource[i]=' ') do inc(i);
  778.   if i>SL then exit;
  779.   // only alpha
  780.   if not (Fsource[i] in alphachars) then exit;
  781.   while (i<=SL) and (Fsource[i] in alphachars) do begin
  782.     tmp:=tmp+FSource[i];
  783.     inc(i);
  784.   end;
  785.   if (i>SL) then
  786.     result:=tmp
  787.   else if Fsource[i]=' ' then
  788.     result:=tmp;
  789.   index:=i;
  790. end;
  791.  
  792. { TToken }
  793.  
  794. function TToken.copy: TToken;
  795. begin
  796.   result:=TToken.Create;
  797.   result.name:=name;
  798.   result.value:=value;
  799.   result.tokenkind:=tokenkind;
  800.   result.operator:=operator;
  801.   result.level:=level;
  802.   result.expression:=expression;
  803. end;
  804.  
  805. procedure TToken.Setexpression(const Value: string);
  806. begin
  807.   Fexpression := Value;
  808. end;
  809.  
  810. procedure TToken.Setlevel(const Value: integer);
  811. begin
  812.   Flevel := Value;
  813. end;
  814.  
  815. procedure TToken.Setname(const Value: string);
  816. begin
  817.   Fname := Value;
  818. end;
  819.  
  820. procedure TToken.Setoperator(const Value: TTokenOperator);
  821. begin
  822.   Foperator := Value;
  823. end;
  824.  
  825. procedure TToken.Settokenkind(const Value: TTokenKind);
  826. begin
  827.   Ftokenkind := Value;
  828. end;
  829.  
  830. procedure TToken.Setvalue(const Value: variant);
  831. begin
  832.   Fvalue := Value;
  833. end;
  834.  
  835.  
  836.  
  837.  
  838. end.
  839.