zeoslib  UNKNOWN
 All Files
ZSqLiteToken.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { String tokenizing classes for SQLite }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
20 { }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
39 { }
40 { }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZSqLiteToken;
53 
54 interface
55 
56 {$I ZParseSql.inc}
57 
58 uses
59  Classes, {$IFDEF MSEgui}mclasses,{$ENDIF}
60  ZTokenizer, ZGenericSqlToken;
61 
62 type
63 
64  {** Implements a SQLite-specific number state object. }
65  TZSQLiteNumberState = class (TZNumberState)
66  public
67  function NextToken(Stream: TStream; FirstChar: Char;
68  Tokenizer: TZTokenizer): TZToken; override;
69  end;
70 
71  {** Implements a SQLite-specific quote string state object. }
72  TZSQLiteQuoteState = class (TZQuoteState)
73  public
74  function NextToken(Stream: TStream; FirstChar: Char;
75  Tokenizer: TZTokenizer): TZToken; override;
76 
77  function EncodeString(const Value: string; QuoteChar: Char): string; override;
78  function DecodeString(const Value: string; QuoteChar: Char): string; override;
79  end;
80 
81  {**
82  This state will either delegate to a comment-handling
83  state, or return a token with just a slash in it.
84  }
85  TZSQLiteCommentState = class (TZCppCommentState)
86  public
87  function NextToken(Stream: TStream; FirstChar: Char;
88  Tokenizer: TZTokenizer): TZToken; override;
89  end;
90 
91  {** Implements a symbol state object. }
92  TZSQLiteSymbolState = class (TZSymbolState)
93  public
94  constructor Create;
95  end;
96 
97  {** Implements a word state object. }
98  TZSQLiteWordState = class (TZGenericSQLWordState)
99  public
100  constructor Create;
101  end;
102 
103  {** Implements a default tokenizer object. }
104  TZSQLiteTokenizer = class (TZTokenizer)
105  public
106  constructor Create;
107  end;
108 
109 implementation
110 
111 uses SysUtils, ZCompatibility;
112 
113 { TZSQLiteNumberState }
114 
115 {**
116  Return a number token from a reader.
117  @return a number token from a reader
118 }
119 function TZSQLiteNumberState.NextToken(Stream: TStream; FirstChar: Char;
120  Tokenizer: TZTokenizer): TZToken;
121 var
122  TempChar: Char;
123  FloatPoint: Boolean;
124  LastChar: Char;
125 
126  function ReadDecDigits: string;
127  begin
128  Result := '';
129  LastChar := #0;
130  while Stream.Read(LastChar, SizeOf(Char)) > 0 do
131  begin
132  if CharInSet(LastChar, ['0'..'9']) then
133  begin
134  Result := Result + LastChar;
135  LastChar := #0;
136  end
137  else
138  begin
139  Stream.Seek(-SizeOf(Char), soFromCurrent);
140  Break;
141  end;
142  end;
143  end;
144 
145 begin
146  FloatPoint := FirstChar = '.';
147  Result.Value := FirstChar;
148  Result.TokenType := ttUnknown;
149  LastChar := #0;
150 
151  { Reads the first part of the number before decimal point }
152  if not FloatPoint then
153  begin
154  Result.Value := Result.Value + ReadDecDigits;
155  FloatPoint := LastChar = '.';
156  if FloatPoint then
157  begin
158  Stream.Read(TempChar, SizeOf(Char));
159  Result.Value := Result.Value + TempChar;
160  end;
161  end;
162 
163  { Reads the second part of the number after decimal point }
164  if FloatPoint then
165  Result.Value := Result.Value + ReadDecDigits;
166 
167  { Reads a power part of the number }
168  if CharInSet(LastChar, ['e','E']) then
169  begin
170  Stream.Read(TempChar, SizeOf(Char));
171  Result.Value := Result.Value + TempChar;
172  FloatPoint := True;
173 
174  Stream.Read(TempChar, SizeOf(Char));
175  if CharInSet(TempChar, ['0'..'9','-','+']) then
176  Result.Value := Result.Value + TempChar + ReadDecDigits
177  else
178  begin
179  Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1);
180  Stream.Seek(-2*SizeOf(Char), soFromCurrent);
181  end;
182  end;
183 
184  { Prepare the result }
185  if Result.Value = '.' then
186  begin
187  if Tokenizer.SymbolState <> nil then
188  Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer);
189  end
190  else
191  begin
192  if FloatPoint then
193  Result.TokenType := ttFloat
194  else Result.TokenType := ttInteger;
195  end;
196 end;
197 
198 { TZSQLiteQuoteState }
199 
200 {**
201  Return a quoted string token from a reader. This method
202  will collect characters until it sees a match to the
203  character that the tokenizer used to switch to this state.
204 
205  @return a quoted string token from a reader
206 }
207 function TZSQLiteQuoteState.NextToken(Stream: TStream; FirstChar: Char;
208  Tokenizer: TZTokenizer): TZToken;
209 var
210  ReadChar: Char;
211  LastChar: Char;
212 begin
213  Result.Value := FirstChar;
214  LastChar := #0;
215  while Stream.Read(ReadChar, SizeOf(Char)) > 0 do
216  begin
217  if ((LastChar = FirstChar) and (ReadChar <> FirstChar)
218  and (FirstChar <> '[')) or ((FirstChar = '[') and (LastChar = ']')) then
219  begin
220  Stream.Seek(-SizeOf(Char), soFromCurrent);
221  Break;
222  end;
223  Result.Value := Result.Value + ReadChar;
224  if (LastChar = FirstChar) and (ReadChar = FirstChar) then
225  LastChar := #0
226  else LastChar := ReadChar;
227  end;
228 
229  if CharInSet(FirstChar, ['"', '[']) then
230  Result.TokenType := ttWord
231  else Result.TokenType := ttQuoted;
232 end;
233 
234 {**
235  Encodes a string value.
236  @param Value a string value to be encoded.
237  @param QuoteChar a string quote character.
238  @returns an encoded string.
239 }
240 function TZSQLiteQuoteState.EncodeString(const Value: string; QuoteChar: Char): string;
241 begin
242  if QuoteChar = '[' then
243  Result := '[' + Value + ']'
244  else if CharInSet(QuoteChar, [#39, '"']) then
245  Result := QuoteChar + Value + QuoteChar
246  else Result := Value;
247 end;
248 
249 {**
250  Decodes a string value.
251  @param Value a string value to be decoded.
252  @param QuoteChar a string quote character.
253  @returns an decoded string.
254 }
255 function TZSQLiteQuoteState.DecodeString(const Value: string; QuoteChar: Char): string;
256 begin
257  Result := Value;
258  if Length(Value) >= 2 then
259  begin
260  if CharInSet(QuoteChar, [#39, '"']) and (Value[1] = QuoteChar)
261  and (Value[Length(Value)] = QuoteChar) then
262  begin
263  if Length(Value) > 2 then
264  Result := AnsiDequotedStr(Value, QuoteChar)
265  else Result := '';
266  end
267  else if (QuoteChar = '[') and (Value[1] = QuoteChar)
268  and (Value[Length(Value)] = ']') then
269  Result := Copy(Value, 2, Length(Value) - 2)
270  end;
271 end;
272 
273 { TZSQLiteCommentState }
274 
275 {**
276  Gets a SQLite specific comments like # or /* */.
277  @return either just a slash token, or the results of
278  delegating to a comment-handling state
279 }
280 function TZSQLiteCommentState.NextToken(Stream: TStream; FirstChar: Char;
281  Tokenizer: TZTokenizer): TZToken;
282 var
283  ReadChar: Char;
284  ReadNum: Integer;
285 begin
286  Result.Value := FirstChar;
287  Result.TokenType := ttUnknown;
288 
289  if FirstChar = '-' then
290  begin
291  ReadNum := Stream.Read(ReadChar, SizeOf(Char));
292  if (ReadNum > 0) and (ReadChar = '-') then
293  begin
294  Result.TokenType := ttComment;
295  Result.Value := '--' + GetSingleLineComment(Stream);
296  end
297  else
298  begin
299  if ReadNum > 0 then
300  Stream.Seek(-SizeOf(Char), soFromCurrent);
301  end;
302  end
303  else if FirstChar = '/' then
304  begin
305  ReadNum := Stream.Read(ReadChar, SizeOf(Char));
306  if (ReadNum > 0) and (ReadChar = '*') then
307  begin
308  Result.TokenType := ttComment;
309  Result.Value := '/*' + GetMultiLineComment(Stream);
310  end
311  else
312  begin
313  if ReadNum > 0 then
314  Stream.Seek(-SizeOf(Char), soFromCurrent);
315  end;
316  end;
317 
318  if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then
319  Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer);
320 end;
321 
322 { TZSQLiteSymbolState }
323 
324 {**
325  Creates this SQLite-specific symbol state object.
326 }
327 constructor TZSQLiteSymbolState.Create;
328 begin
329  inherited Create;
330  Add('<=');
331  Add('>=');
332  Add('<>');
333  Add('!=');
334  Add('==');
335  Add('<<');
336  Add('>>');
337  Add('||');
338 end;
339 
340 { TZSQLiteWordState }
341 
342 {**
343  Constructs this SQLite-specific word state object.
344 }
345 constructor TZSQLiteWordState.Create;
346 begin
347  SetWordChars(#0, #255, False);
348  SetWordChars('a', 'z', True);
349  SetWordChars('A', 'Z', True);
350  SetWordChars('0', '9', True);
351  SetWordChars('_', '_', True);
352 end;
353 
354 { TZSQLiteTokenizer }
355 
356 {**
357  Constructs a tokenizer with a default state table (as
358  described in the class comment).
359 }
360 constructor TZSQLiteTokenizer.Create;
361 begin
362  EscapeState := TZEscapeState.Create;
363  WhitespaceState := TZWhitespaceState.Create;
364 
365  SymbolState := TZSQLiteSymbolState.Create;
366  NumberState := TZSQLiteNumberState.Create;
367  QuoteState := TZSQLiteQuoteState.Create;
368  WordState := TZSQLiteWordState.Create;
369  CommentState := TZSQLiteCommentState.Create;
370 
371  SetCharacterState(#0, #32, WhitespaceState);
372  SetCharacterState(#33, #191, SymbolState);
373  SetCharacterState(#192, High(Char), WordState);
374 
375  SetCharacterState('a', 'z', WordState);
376  SetCharacterState('A', 'Z', WordState);
377  SetCharacterState('_', '_', WordState);
378 
379  SetCharacterState('0', '9', NumberState);
380  SetCharacterState('.', '.', NumberState);
381 
382  SetCharacterState('"', '"', QuoteState);
383  SetCharacterState(#39, #39, QuoteState);
384  SetCharacterState('[', '[', QuoteState);
385  SetCharacterState(']', ']', QuoteState);
386 
387  SetCharacterState('/', '/', CommentState);
388  SetCharacterState('-', '-', CommentState);
389 end;
390 
391 end.
392