00001 {*********************************************************}
00002 { }
00003 { Zeos Database Objects }
00004 { String tokenizing classes for SQLite }
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 ZSqLiteToken;
00055
00056 interface
00057
00058 {$I ZParseSql.inc}
00059
00060 uses
00061 Classes, ZTokenizer, ZGenericSqlToken;
00062
00063 type
00064
00065 {** Implements a SQLite-specific number state object. }
00066 TZSQLiteNumberState = class (TZNumberState)
00067 public
00068 function NextToken(Stream: TStream; FirstChar: Char;
00069 Tokenizer: TZTokenizer): TZToken; override;
00070 end;
00071
00072 {** Implements a SQLite-specific quote string state object. }
00073 TZSQLiteQuoteState = 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 TZSQLiteCommentState = 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 TZSQLiteSymbolState = class (TZSymbolState)
00094 public
00095 constructor Create;
00096 end;
00097
00098 {** Implements a word state object. }
00099 TZSQLiteWordState = class (TZGenericSQLWordState)
00100 public
00101 constructor Create;
00102 end;
00103
00104 {** Implements a default tokenizer object. }
00105 TZSQLiteTokenizer = class (TZTokenizer)
00106 public
00107 constructor Create;
00108 end;
00109
00110 implementation
00111
00112 uses SysUtils, ZCompatibility;
00113
00114 { TZSQLiteNumberState }
00115
00116 {**
00117 Return a number token from a reader.
00118 @return a number token from a reader
00119 }
00120 function TZSQLiteNumberState.NextToken(Stream: TStream; FirstChar: Char;
00121 Tokenizer: TZTokenizer): TZToken;
00122 var
00123 TempChar: Char;
00124 FloatPoint: Boolean;
00125 LastChar: Char;
00126
00127 function ReadDecDigits: string;
00128 begin
00129 Result := '';
00130 LastChar := #0;
00131 while Stream.Read(LastChar, 1) > 0 do
00132 begin
00133 if LastChar in ['0'..'9'] then
00134 begin
00135 Result := Result + LastChar;
00136 LastChar := #0;
00137 end
00138 else
00139 begin
00140 Stream.Seek(-1, soFromCurrent);
00141 Break;
00142 end;
00143 end;
00144 end;
00145
00146 begin
00147 FloatPoint := FirstChar = '.';
00148 Result.Value := FirstChar;
00149 Result.TokenType := ttUnknown;
00150 LastChar := #0;
00151
00152 { Reads the first part of the number before decimal point }
00153 if not FloatPoint then
00154 begin
00155 Result.Value := Result.Value + ReadDecDigits;
00156 FloatPoint := LastChar = '.';
00157 if FloatPoint then
00158 begin
00159 Stream.Read(TempChar, 1);
00160 Result.Value := Result.Value + TempChar;
00161 end;
00162 end;
00163
00164 { Reads the second part of the number after decimal point }
00165 if FloatPoint then
00166 Result.Value := Result.Value + ReadDecDigits;
00167
00168 { Reads a power part of the number }
00169 if LastChar in ['e','E'] then
00170 begin
00171 Stream.Read(TempChar, 1);
00172 Result.Value := Result.Value + TempChar;
00173 FloatPoint := True;
00174
00175 Stream.Read(TempChar, 1);
00176 if TempChar in ['0'..'9','-','+'] then
00177 Result.Value := Result.Value + TempChar + ReadDecDigits
00178 else
00179 begin
00180 Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1);
00181 Stream.Seek(-2, soFromCurrent);
00182 end;
00183 end;
00184
00185 { Prepare the result }
00186 if Result.Value = '.' then
00187 begin
00188 if Tokenizer.SymbolState <> nil then
00189 Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer);
00190 end
00191 else
00192 begin
00193 if FloatPoint then
00194 Result.TokenType := ttFloat
00195 else Result.TokenType := ttInteger;
00196 end;
00197 end;
00198
00199 { TZSQLiteQuoteState }
00200
00201 {**
00202 Return a quoted string token from a reader. This method
00203 will collect characters until it sees a match to the
00204 character that the tokenizer used to switch to this state.
00205
00206 @return a quoted string token from a reader
00207 }
00208 function TZSQLiteQuoteState.NextToken(Stream: TStream; FirstChar: Char;
00209 Tokenizer: TZTokenizer): TZToken;
00210 var
00211 ReadChar: Char;
00212 LastChar: Char;
00213 begin
00214 Result.Value := FirstChar;
00215 LastChar := #0;
00216 while Stream.Read(ReadChar, 1) > 0 do
00217 begin
00218 if ((LastChar = FirstChar) and (ReadChar <> FirstChar)
00219 and (FirstChar <> '[')) or ((FirstChar = '[') and (LastChar = ']')) then
00220 begin
00221 Stream.Seek(-1, soFromCurrent);
00222 Break;
00223 end;
00224 Result.Value := Result.Value + ReadChar;
00225 if (LastChar = FirstChar) and (ReadChar = FirstChar) then
00226 LastChar := #0
00227 else LastChar := ReadChar;
00228 end;
00229
00230 if FirstChar in ['"', '['] then
00231 Result.TokenType := ttWord
00232 else Result.TokenType := ttQuoted;
00233 end;
00234
00235 {**
00236 Encodes a string value.
00237 @param Value a string value to be encoded.
00238 @param QuoteChar a string quote character.
00239 @returns an encoded string.
00240 }
00241 function TZSQLiteQuoteState.EncodeString(const Value: string; QuoteChar: Char): string;
00242 begin
00243 if QuoteChar = '[' then
00244 Result := '[' + Value + ']'
00245 else if QuoteChar in [#39, '"'] then
00246 Result := QuoteChar + Value + QuoteChar
00247 else Result := Value;
00248 end;
00249
00250 {**
00251 Decodes a string value.
00252 @param Value a string value to be decoded.
00253 @param QuoteChar a string quote character.
00254 @returns an decoded string.
00255 }
00256 function TZSQLiteQuoteState.DecodeString(const Value: string; QuoteChar: Char): string;
00257 begin
00258 Result := Value;
00259 if Length(Value) >= 2 then
00260 begin
00261 if (QuoteChar in [#39, '"']) and (Value[1] = QuoteChar)
00262 and (Value[Length(Value)] = QuoteChar) then
00263 begin
00264 if Length(Value) > 2 then
00265 Result := AnsiDequotedStr(Value, QuoteChar)
00266 else Result := '';
00267 end
00268 else if (QuoteChar = '[') and (Value[1] = QuoteChar)
00269 and (Value[Length(Value)] = ']') then
00270 Result := Copy(Value, 2, Length(Value) - 2)
00271 end;
00272 end;
00273
00274 { TZSQLiteCommentState }
00275
00276 {**
00277 Gets a SQLite specific comments like # or .
00278 @return either just a slash token, or the results of
00279 delegating to a comment-handling state
00280 }
00281 function TZSQLiteCommentState.NextToken(Stream: TStream; FirstChar: Char;
00282 Tokenizer: TZTokenizer): TZToken;
00283 var
00284 ReadChar: Char;
00285 ReadNum: Integer;
00286 begin
00287 Result.Value := FirstChar;
00288 Result.TokenType := ttUnknown;
00289
00290 if FirstChar = '-' then
00291 begin
00292 ReadNum := Stream.Read(ReadChar, 1);
00293 if (ReadNum > 0) and (ReadChar = '-') then
00294 begin
00295 Result.TokenType := ttComment;
00296 Result.Value := '--' + GetSingleLineComment(Stream);
00297 end
00298 else
00299 begin
00300 if ReadNum > 0 then
00301 Stream.Seek(-1, soFromCurrent);
00302 end;
00303 end
00304 else if FirstChar = '/' then
00305 begin
00306 ReadNum := Stream.Read(ReadChar, 1);
00307 if (ReadNum > 0) and (ReadChar = '*') then
00308 begin
00309 Result.TokenType := ttComment;
00310 Result.Value := '
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