zeoslib  UNKNOWN
 All Files
ZSybaseToken.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { String tokenizing classes for Sybase }
5 { }
6 { Originally written by Janos Fegyverneki }
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 ZSybaseToken;
53 
54 interface
55 
56 {$I ZParseSql.inc}
57 
58 uses
59  Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60  ZTokenizer, ZCompatibility, ZGenericSqlToken;
61 
62 type
63 
64  {** Implements a Sybase-specific number state object. }
65  TZSybaseNumberState = class (TZNumberState)
66  public
67  function NextToken(Stream: TStream; FirstChar: Char;
68  Tokenizer: TZTokenizer): TZToken; override;
69  end;
70 
71  {** Implements a Sybase-specific quote string state object. }
72  TZSybaseQuoteState = 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  TZSybaseCommentState = 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  TZSybaseSymbolState = class (TZSymbolState)
93  public
94  constructor Create;
95  end;
96 
97  {** Implements a word state object. }
98  TZSybaseWordState = class (TZGenericSQLWordState)
99  public
100  constructor Create;
101  end;
102 
103  {** Implements a default tokenizer object. }
104  TZSybaseTokenizer = class (TZTokenizer)
105  public
106  constructor Create;
107  end;
108 
109 implementation
110 
111 { TZSybaseNumberState }
112 
113 {**
114  Return a number token from a reader.
115  @return a number token from a reader
116 }
117 function TZSybaseNumberState.NextToken(Stream: TStream; FirstChar: Char;
118  Tokenizer: TZTokenizer): TZToken;
119 var
120  HexDecimal: Boolean;
121  FloatPoint: Boolean;
122  LastChar: Char;
123 
124  function ReadHexDigits: string;
125  begin
126  Result := '';
127  LastChar := #0;
128  while Stream.Read(LastChar, SizeOf(Char)) > 0 do
129  begin
130  if CharInSet(LastChar, ['0'..'9','a'..'f','A'..'F']) then
131  begin
132  Result := Result + LastChar;
133  HexDecimal := HexDecimal or CharInSet(LastChar, ['a'..'f','A'..'F']);
134  LastChar := #0;
135  end
136  else
137  begin
138  Stream.Seek(-SizeOf(Char), soFromCurrent);
139  Break;
140  end;
141  end;
142  end;
143 
144  function ReadDecDigits: string;
145  begin
146  Result := '';
147  LastChar := #0;
148  while Stream.Read(LastChar, SizeOf(Char)) > 0 do
149  begin
150  if CharInSet(LastChar, ['0'..'9']) then
151  begin
152  Result := Result + LastChar;
153  LastChar := #0;
154  end
155  else
156  begin
157  Stream.Seek(-SizeOf(Char), soFromCurrent);
158  Break;
159  end;
160  end;
161  end;
162 
163 begin
164  HexDecimal := False;
165  FloatPoint := FirstChar = '.';
166  LastChar := #0;
167 
168  Result.Value := FirstChar;
169  Result.TokenType := ttUnknown;
170 
171  { Reads the first part of the number before decimal point }
172  if not FloatPoint then
173  begin
174  Result.Value := Result.Value + ReadDecDigits;
175  FloatPoint := (LastChar = '.') and not HexDecimal;
176  if FloatPoint then
177  begin
178  Stream.Read(LastChar, SizeOf(Char));
179  Result.Value := Result.Value + LastChar;
180  end;
181  end;
182 
183  { Reads the second part of the number after decimal point }
184  if FloatPoint then
185  Result.Value := Result.Value + ReadDecDigits;
186 
187  { Reads a power part of the number }
188  if not HexDecimal and CharInSet(LastChar, ['e','E']) then
189  begin
190  Stream.Read(LastChar, SizeOf(Char));
191  Result.Value := Result.Value + LastChar;
192  FloatPoint := True;
193 
194  Stream.Read(LastChar, SizeOf(Char));
195  if CharInSet(LastChar, ['0'..'9','-','+']) then
196  Result.Value := Result.Value + LastChar + ReadDecDigits
197  else
198  begin
199  Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1);
200  Stream.Seek(-2*SizeOf(Char), soFromCurrent);
201  end;
202  end;
203 
204  { Reads the nexdecimal number }
205  if (Result.Value = '0') and CharInSet(LastChar, ['x','X']) then
206  begin
207  Stream.Read(LastChar, SizeOf(Char));
208  Result.Value := Result.Value + LastChar + ReadHexDigits;
209  HexDecimal := True;
210  end;
211 
212  { Prepare the result }
213  if Result.Value = '.' then
214  begin
215  if Tokenizer.SymbolState <> nil then
216  Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer);
217  end
218  else
219  begin
220  if HexDecimal then
221  Result.TokenType := ttHexDecimal
222  else if FloatPoint then
223  Result.TokenType := ttFloat
224  else Result.TokenType := ttInteger;
225  end;
226 end;
227 
228 { TZSybaseQuoteState }
229 
230 {**
231  Return a quoted string token from a reader. This method
232  will collect characters until it sees a match to the
233  character that the tokenizer used to switch to this state.
234 
235  @return a quoted string token from a reader
236 }
237 function TZSybaseQuoteState.NextToken(Stream: TStream; FirstChar: Char;
238  Tokenizer: TZTokenizer): TZToken;
239 var
240  ReadChar: Char;
241  LastChar: Char;
242 begin
243  Result.Value := FirstChar;
244  LastChar := #0;
245  while Stream.Read(ReadChar, SizeOf(Char)) > 0 do
246  begin
247  if ((LastChar = FirstChar) and (ReadChar <> FirstChar)
248  and (FirstChar <> '[')) or ((FirstChar = '[') and (LastChar = ']')) then
249  begin
250  Stream.Seek(-SizeOf(Char), soFromCurrent);
251  Break;
252  end;
253  Result.Value := Result.Value + ReadChar;
254  if (LastChar = FirstChar) and (ReadChar = FirstChar) then
255  LastChar := #0
256  else LastChar := ReadChar;
257  end;
258 
259  if CharInSet(FirstChar, ['"', '[']) then
260  Result.TokenType := ttWord
261  else Result.TokenType := ttQuoted;
262 end;
263 
264 {**
265  Encodes a string value.
266  @param Value a string value to be encoded.
267  @param QuoteChar a string quote character.
268  @returns an encoded string.
269 }
270 function TZSybaseQuoteState.EncodeString(const Value: string; QuoteChar: Char): string;
271 begin
272  if QuoteChar = '[' then
273  Result := '[' + Value + ']'
274  else if CharInSet(QuoteChar, [#39, '"']) then
275  Result := QuoteChar + Value + QuoteChar
276  else Result := Value;
277 end;
278 
279 {**
280  Decodes a string value.
281  @param Value a string value to be decoded.
282  @param QuoteChar a string quote character.
283  @returns an decoded string.
284 }
285 function TZSybaseQuoteState.DecodeString(const Value: string; QuoteChar: Char): string;
286 begin
287  Result := Value;
288  if Length(Value) >= 2 then
289  begin
290  if CharInSet(QuoteChar, [#39, '"']) and (Value[1] = QuoteChar)
291  and (Value[Length(Value)] = QuoteChar) then
292  begin
293  if Length(Value) > 2 then
294  Result := AnsiDequotedStr(Value, QuoteChar)
295  else Result := '';
296  end
297  else if (QuoteChar = '[') and (Value[1] = QuoteChar)
298  and (Value[Length(Value)] = ']') then
299  Result := Copy(Value, 2, Length(Value) - 2)
300  end;
301 end;
302 
303 { TZSybaseCommentState }
304 
305 {**
306  Gets a Sybase specific comments like # or /* */.
307  @return either just a slash token, or the results of
308  delegating to a comment-handling state
309 }
310 function TZSybaseCommentState.NextToken(Stream: TStream; FirstChar: Char;
311  Tokenizer: TZTokenizer): TZToken;
312 var
313  ReadChar: Char;
314  ReadNum: Integer;
315 begin
316  Result.Value := FirstChar;
317  Result.TokenType := ttUnknown;
318 
319  if FirstChar = '-' then
320  begin
321  ReadNum := Stream.Read(ReadChar, SizeOf(Char));
322  if (ReadNum > 0) and (ReadChar = '-') then
323  begin
324  Result.TokenType := ttComment;
325  Result.Value := '--' + GetSingleLineComment(Stream);
326  end
327  else
328  begin
329  if ReadNum > 0 then
330  Stream.Seek(-SizeOf(Char), soFromCurrent);
331  end;
332  end
333  else if FirstChar = '/' then
334  begin
335  ReadNum := Stream.Read(ReadChar, SizeOf(Char));
336  if (ReadNum > 0) and (ReadChar = '*') then
337  begin
338  Result.TokenType := ttComment;
339  Result.Value := '/*' + GetMultiLineComment(Stream);
340  end
341  else
342  begin
343  if ReadNum > 0 then
344  Stream.Seek(-SizeOf(Char), soFromCurrent);
345  end;
346  end;
347 
348  if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then
349  Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer);
350 end;
351 
352 { TZSybaseSymbolState }
353 
354 {**
355  Creates this Sybase-specific symbol state object.
356 }
357 constructor TZSybaseSymbolState.Create;
358 begin
359  inherited Create;
360  Add('<=');
361  Add('>=');
362  Add('<>');
363  Add('!<');
364  Add('!>');
365  Add('!=');
366 end;
367 
368 { TZSybaseWordState }
369 
370 {**
371  Constructs this Sybase-specific word state object.
372 }
373 constructor TZSybaseWordState.Create;
374 begin
375  SetWordChars(#0, #191, False);
376  SetWordChars(#192, high(char), True);
377  SetWordChars('a', 'z', True);
378  SetWordChars('A', 'Z', True);
379  SetWordChars('0', '9', True);
380  SetWordChars('$', '$', True);
381  SetWordChars('_', '_', True);
382  SetWordChars('@', '@', True);
383  SetWordChars('#', '#', True);
384 end;
385 
386 { TZSybaseTokenizer }
387 
388 {**
389  Constructs a tokenizer with a default state table (as
390  described in the class comment).
391 }
392 constructor TZSybaseTokenizer.Create;
393 begin
394  EscapeState := TZEscapeState.Create;
395  WhitespaceState := TZWhitespaceState.Create;
396 
397  SymbolState := TZSybaseSymbolState.Create;
398  NumberState := TZSybaseNumberState.Create;
399  QuoteState := TZSybaseQuoteState.Create;
400  WordState := TZSybaseWordState.Create;
401  CommentState := TZSybaseCommentState.Create;
402 
403  SetCharacterState(#0, #32, WhitespaceState);
404  SetCharacterState(#33, #191, SymbolState);
405  SetCharacterState(#192, High(Char), WordState);
406 
407  SetCharacterState('a', 'z', WordState);
408  SetCharacterState('A', 'Z', WordState);
409  SetCharacterState('_', '_', WordState);
410  SetCharacterState('$', '$', WordState);
411  SetCharacterState('@', '@', WordState);
412  SetCharacterState('#', '#', WordState);
413 
414  SetCharacterState('0', '9', NumberState);
415  SetCharacterState('.', '.', NumberState);
416 
417  SetCharacterState('"', '"', QuoteState);
418  SetCharacterState('''', '''', QuoteState);
419  SetCharacterState('[', '[', QuoteState);
420  SetCharacterState(']', ']', QuoteState);
421 
422  SetCharacterState('/', '/', CommentState);
423  SetCharacterState('-', '-', CommentState);
424 end;
425 
426 end.
427 
428