00001 {*********************************************************}
00002 { }
00003 { Zeos Database Objects }
00004 { String tokenizing classes for Expressions }
00005 { }
00006 { Originally written by Sergey Seroukhov }
00007 { }
00008 {*********************************************************}
00009
00010 {@********************************************************}
00011 { Copyright (c) 1999-2006 Zeos Development Group }
00012 { }
00013 { License Agreement: }
00014 { }
00015 { This library is distributed in the hope that it will be }
00016 { useful, but WITHOUT ANY WARRANTY; without even the }
00017 { implied warranty of MERCHANTABILITY or FITNESS FOR }
00018 { A PARTICULAR PURPOSE. See the GNU Lesser General }
00019 { Public License for more details. }
00020 { }
00021 { The source code of the ZEOS Libraries and packages are }
00022 { distributed under the Library GNU General Public }
00023 { License (see the file COPYING / COPYING.ZEOS) }
00024 { with the following modification: }
00025 { As a special exception, the copyright holders of this }
00026 { library give you permission to link this library with }
00027 { independent modules to produce an executable, }
00028 { regardless of the license terms of these independent }
00029 { modules, and to copy and distribute the resulting }
00030 { executable under terms of your choice, provided that }
00031 { you also meet, for each linked independent module, }
00032 { the terms and conditions of the license of that module. }
00033 { An independent module is a module which is not derived }
00034 { from or based on this library. If you modify this }
00035 { library, you may extend this exception to your version }
00036 { of the library, but you are not obligated to do so. }
00037 { If you do not wish to do so, delete this exception }
00038 { statement from your version. }
00039 { }
00040 { }
00041 { The project web site is located on: }
00042 { http:
00043 { http:
00044 { svn:
00045 { }
00046 { http:
00047 { http:
00048 { }
00049 { }
00050 { }
00051 { Zeos Development Group. }
00052 {********************************************************@}
00053
00054 unit ZExprToken;
00055
00056 interface
00057
00058 {$I ZCore.inc}
00059
00060 uses
00061 Classes, SysUtils, ZSysUtils, ZTokenizer;
00062
00063 type
00064
00065 {** Implements an Expression-specific number state object. }
00066 TZExpressionNumberState = class (TZNumberState)
00067 public
00068 function NextToken(Stream: TStream; FirstChar: Char;
00069 Tokenizer: TZTokenizer): TZToken; override;
00070 end;
00071
00072 {** Implements an Expression-specific quote string state object. }
00073 TZExpressionQuoteState = class (TZQuoteState)
00074 public
00075 function NextToken(Stream: TStream; FirstChar: Char;
00076 Tokenizer: TZTokenizer): TZToken; override;
00077
00078 function EncodeString(const Value: string; QuoteChar: Char): string; override;
00079 function DecodeString(const Value: string; QuoteChar: Char): string; override;
00080 end;
00081
00082 {**
00083 This state will either delegate to a comment-handling
00084 state, or return a token with just a slash in it.
00085 }
00086 TZExpressionCommentState = class (TZCppCommentState)
00087 public
00088 function NextToken(Stream: TStream; FirstChar: Char;
00089 Tokenizer: TZTokenizer): TZToken; override;
00090 end;
00091
00092 {** Implements a symbol state object. }
00093 TZExpressionSymbolState = class (TZSymbolState)
00094 public
00095 constructor Create;
00096 end;
00097
00098 {** Implements a word state object. }
00099 TZExpressionWordState = class (TZWordState)
00100 public
00101 constructor Create;
00102 function NextToken(Stream: TStream; FirstChar: Char;
00103 Tokenizer: TZTokenizer): TZToken; override;
00104 end;
00105
00106 {** Implements a default tokenizer object. }
00107 TZExpressionTokenizer = class (TZTokenizer)
00108 public
00109 constructor Create;
00110 end;
00111
00112 implementation
00113
00114 const
00115 {** List of keywords. }
00116 Keywords: array [0..8] of string = (
00117 'AND','OR','NOT','XOR','LIKE','IS','NULL','TRUE','FALSE'
00118 );
00119
00120 { TZExpressionNumberState }
00121
00122 {**
00123 Return a number token from a reader.
00124 @return a number token from a reader
00125 }
00126 function TZExpressionNumberState.NextToken(Stream: TStream; FirstChar: Char;
00127 Tokenizer: TZTokenizer): TZToken;
00128 var
00129 TempChar: Char;
00130 FloatPoint: Boolean;
00131 LastChar: Char;
00132
00133 function ReadDecDigits: string;
00134 begin
00135 Result := '';
00136 LastChar := #0;
00137 while Stream.Read(LastChar, 1) > 0 do
00138 begin
00139 if LastChar in ['0'..'9'] then
00140 begin
00141 Result := Result + LastChar;
00142 LastChar := #0;
00143 end
00144 else
00145 begin
00146 Stream.Seek(-1, soFromCurrent);
00147 Break;
00148 end;
00149 end;
00150 end;
00151
00152 begin
00153 FloatPoint := FirstChar = '.';
00154 Result.Value := FirstChar;
00155 Result.TokenType := ttUnknown;
00156 LastChar := #0;
00157
00158 { Reads the first part of the number before decimal point }
00159 if not FloatPoint then
00160 begin
00161 Result.Value := Result.Value + ReadDecDigits;
00162 FloatPoint := LastChar = '.';
00163 if FloatPoint then
00164 begin
00165 Stream.Read(TempChar, 1);
00166 Result.Value := Result.Value + TempChar;
00167 end;
00168 end;
00169
00170 { Reads the second part of the number after decimal point }
00171 if FloatPoint then
00172 Result.Value := Result.Value + ReadDecDigits;
00173
00174 { Reads a power part of the number }
00175 if LastChar in ['e','E'] then
00176 begin
00177 Stream.Read(TempChar, 1);
00178 Result.Value := Result.Value + TempChar;
00179 FloatPoint := True;
00180
00181 Stream.Read(TempChar, 1);
00182 if TempChar in ['0'..'9','-','+'] then
00183 Result.Value := Result.Value + TempChar + ReadDecDigits
00184 else
00185 begin
00186 Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1);
00187 Stream.Seek(-2, soFromCurrent);
00188 end;
00189 end;
00190
00191 { Prepare the result }
00192 if Result.Value = '.' then
00193 begin
00194 if Tokenizer.SymbolState <> nil then
00195 Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer);
00196 end
00197 else
00198 begin
00199 if FloatPoint then
00200 Result.TokenType := ttFloat
00201 else Result.TokenType := ttInteger;
00202 end;
00203 end;
00204
00205 { TZExpressionSQLQuoteState }
00206
00207 {**
00208 Return a quoted string token from a reader. This method
00209 will collect characters until it sees a match to the
00210 character that the tokenizer used to switch to this state.
00211
00212 @return a quoted string token from a reader
00213 }
00214 function TZExpressionQuoteState.NextToken(Stream: TStream;
00215 FirstChar: Char; Tokenizer: TZTokenizer): TZToken;
00216 var
00217 ReadChar: Char;
00218 LastChar: Char;
00219 begin
00220 if FirstChar = '"' then
00221 Result.TokenType := ttWord
00222 else Result.TokenType := ttQuoted;
00223 Result.Value := FirstChar;
00224 LastChar := #0;
00225
00226 while Stream.Read(ReadChar, 1) > 0 do
00227 begin
00228 if (LastChar = FirstChar) and (ReadChar <> FirstChar) then
00229 begin
00230 Stream.Seek(-1, soFromCurrent);
00231 Break;
00232 end;
00233 Result.Value := Result.Value + ReadChar;
00234 if LastChar = '\' then
00235 LastChar := #0
00236 else if (LastChar = FirstChar) and (ReadChar = FirstChar) then
00237 LastChar := #0
00238 else LastChar := ReadChar;
00239 end;
00240 end;
00241
00242 {**
00243 Encodes a string value.
00244 @param Value a string value to be encoded.
00245 @param QuoteChar a string quote character.
00246 @returns an encoded string.
00247 }
00248 function TZExpressionQuoteState.EncodeString(const Value: string;
00249 QuoteChar: Char): string;
00250 begin
00251 if QuoteChar in [#39, '"'] then
00252 Result := QuoteChar + EncodeCString(Value) + QuoteChar
00253 else Result := Value;
00254 end;
00255
00256 {**
00257 Decodes a string value.
00258 @param Value a string value to be decoded.
00259 @param QuoteChar a string quote character.
00260 @returns an decoded string.
00261 }
00262 function TZExpressionQuoteState.DecodeString(const Value: string;
00263 QuoteChar: Char): string;
00264 begin
00265 if (Length(Value) >= 2) and (QuoteChar in [#39, '"'])
00266 and (Value[1] = QuoteChar) and (Value[Length(Value)] = QuoteChar) then
00267 Result := DecodeCString(Copy(Value, 2, Length(Value) - 2))
00268 else Result := Value;
00269 end;
00270
00271 { TZExpressionCommentState }
00272
00273 {**
00274 Gets an Expression specific comments like .
00275 @return either just a slash token, or the results of
00276 delegating to a comment-handling state
00277 }
00278 function TZExpressionCommentState.NextToken(Stream: TStream;
00279 FirstChar: Char; Tokenizer: TZTokenizer): TZToken;
00280 var
00281 ReadChar: Char;
00282 ReadNum: Integer;
00283 begin
00284 Result.TokenType := ttUnknown;
00285 Result.Value := FirstChar;
00286
00287 if FirstChar = '/' then
00288 begin
00289 ReadNum := Stream.Read(ReadChar, 1);
00290 if (ReadNum > 0) and (ReadChar = '*') then
00291 begin
00292 Result.TokenType := ttComment;
00293 Result.Value := '
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392