XPKeyWords.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:9k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit XPKeyWords;
  2. {
  3.  $Source: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/DelphiExperts/Common/XPKeyWords.pas,v $
  4.  $Revision: 1.2 $
  5.  $Date: 2004/05/03 15:07:15 $
  6.  Last amended by $Author: pvspain $
  7.  $State: Exp $
  8.  XPKeyWords:
  9.  * TXPKeyWords is a class which provides efficient, case-insensitive
  10.    ObjectPascal reserved word, directive and miscellaneous keyword comparisons.
  11.    See Delphi Help topics "Reserved Words" and "Directives" for more
  12.    information.
  13.  Copyright (c) 2001 by The Excellent Programming Company Pty Ltd
  14.  (ABN 27 005 394 918). All rights reserved. This source code is not to be
  15.  redistributed without prior permission from the copyright holder.
  16.  Contact Paul Spain via email: paul@xpro.com.au
  17.  }
  18. interface
  19. type
  20.   TXPResWord = (
  21.     rwAnd, rwArray, rwAs, rwAsm, rwBegin, rwCase, rwClass, rwConst,
  22.     rwConstructor, rwDestructor, rwDispinterface, rwDiv, rwDo, rwDownto,
  23.     rwElse, rwEnd, rwExcept, rwExports, rwFile, rwFinalization, rwFinally,
  24.     rwFor, rwFunction, rwGoto, rwIf, rwImplementation, rwIn, rwInherited,
  25.     rwInitialization, rwInline, rwInterface, rwIs, rwLabel, rwLibrary, rwMod,
  26.     rwNil, rwNot, rwObject, rwOf, rwOr, rwOut, rwPacked, rwProcedure,
  27.     rwProgram, rwProperty, rwRaise, rwRecord, rwRepeat, rwResourcestring,
  28.     rwSet, rwShl, rwShr, rwString, rwThen, rwThreadvar, rwTo, rwTry, rwType,
  29.     rwUnit, rwUntil, rwUses, rwVar, rwWhile, rwWith, rwXor );
  30.   TXPResWords = set of TXPResWord;
  31.   TXPDirective = (
  32.     dAbsolute, dAbstract, dAssembler, dAutomated, dCdecl, dContains, dDefault,
  33.     dDispid, dDynamic, dExport, dExternal, dFar, dForward, dImplements, dIndex,
  34.     dMessage, dName, dNear, dNodefault, dOverload, dOverride, dPackage,
  35.     dPascal, dPrivate, dProtected, dPublic, dPublished, dRead, dReadonly,
  36.     dRegister, dReintroduce, dRequires, dResident, dSafecall, dStdcall,
  37.     dStored, dVirtual, dWrite, dWriteonly );
  38.   TXPDirectives = set of TXPDirective;
  39.   
  40.   TXPMisc = ( mAt, mOn );
  41.   TXPKeyWordKind = ( kwResWord, kwDirective, kwMisc );
  42.   TXPKeyWord = record
  43.     case Kind: TXPKeyWordKind of
  44.       kwResWord: (ResWord: TXPResWord);
  45.       kwDirective: (Directive: TXPDirective);
  46.       kwMisc: (Misc: TXPMisc);
  47.     end;
  48.   TXPKeyWordEntry = record
  49.     Text: string;
  50.     KeyWord: TXPKeyWord;
  51.     end;
  52.   {
  53.     This hash table class implementation uses a double hashing technique for
  54.     insertion and extraction(matching).
  55.     [Ref: Sedgewick, R. 'Algorithms in C' Ch 16: Hashing]
  56.   }
  57.   TXPKeyWords = class(TObject)
  58.     private
  59.     FKeys: array of TXPKeyWordEntry;
  60.     FCount, FHashPrime: integer;
  61.     function Hash(const Key: string): integer;
  62.     function SecondHash(const Key: string): integer;
  63.     procedure Insert(const Key: string; const Kind: TXPKeyWordKind;
  64.       const Index: integer);
  65.     property Count: integer read FCount;
  66.     property Size: integer read FHashPrime;
  67.     public
  68.     constructor Create;
  69.     destructor Destroy; override;
  70.     function Match(Str: string; out KeyWord: TXPKeyWord): boolean;
  71.     class function KeyWordAsText(const KeyWord: TXPKeyWord): string;
  72.     end;
  73. implementation
  74. uses
  75. {$IFDEF XPKEYWORDS_DEBUG}
  76.     KWMain,
  77. {$ENDIF}
  78.     SysUtils;
  79. const
  80.   CVSID: string = '$Header: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/DelphiExperts/Common/XPKeyWords.pas,v 1.2 2004/05/03 15:07:15 pvspain Exp $';
  81. const ResWordStrings: array [TXPResWord] of string = (
  82.     'and', 'array', 'as', 'asm', 'begin', 'case', 'class', 'const',
  83.     'constructor', 'destructor', 'dispinterface', 'div', 'do', 'downto',
  84.     'else', 'end', 'except', 'exports', 'file', 'finalization', 'finally',
  85.     'for', 'function', 'goto', 'if', 'implementation', 'in', 'inherited',
  86.     'initialization', 'inline', 'interface', 'is', 'label', 'library', 'mod',
  87.     'nil', 'not', 'object', 'of', 'or', 'out', 'packed', 'procedure',
  88.     'program', 'property', 'raise', 'record', 'repeat', 'resourcestring',
  89.     'set', 'shl', 'shr', 'string','then', 'threadvar', 'to', 'try', 'type',
  90.     'unit', 'until', 'uses', 'var', 'while', 'with', 'xor' );
  91. const DirectiveStrings: array [TXPDirective] of string = (
  92.     'absolute', 'abstract', 'assembler', 'automated', 'cdecl', 'contains',
  93.     'default', 'dispid', 'dynamic', 'export', 'external', 'far', 'forward',
  94.     'implements', 'index', 'message', 'name', 'near', 'nodefault', 'overload',
  95.     'override', 'package', 'pascal', 'private', 'protected', 'public',
  96.     'published', 'read', 'readonly', 'register', 'reintroduce', 'requires',
  97.     'resident', 'safecall', 'stdcall', 'stored', 'virtual', 'write',
  98.     'writeonly' );
  99. const MiscStrings: array [TXPMisc] of string = ( 'at', 'on' );
  100. constructor TXPKeyWords.Create;
  101.   var
  102.   idx, Max: integer;
  103. {$IFDEF XPKEYWORDS_DEBUG}
  104.   jdx : integer;
  105.   KeyWord: TXPKeyWord;
  106.   Matched: boolean;
  107. {$ENDIF}
  108.   begin
  109.   inherited Create;
  110.   FHashPrime := 853;
  111.   System.SetLength(FKeys, FHashPrime);
  112.   Max := System.Ord(High(TXPResWord));
  113.   // Insert reserved keywords
  114.   for idx := 0 to Max do
  115.     Insert(ResWordStrings[TXPResWord(idx)], kwResWord, idx);
  116.   Max := System.Ord(High(TXPDirective));
  117.   // Insert directive keywords
  118.   for idx := 0 to Max do
  119.     Insert(DirectiveStrings[TXPDirective(idx)], kwDirective, idx);
  120.   Max := System.Ord(High(TXPMisc));
  121.   // Insert miscellaneous keywords
  122.   for idx := 0 to Max do
  123.     Insert(MiscStrings[TXPMisc(idx)], kwMisc, idx);
  124. {$IFDEF XPKEYWORDS_DEBUG}
  125.   Form1.HashTable.Lines.Clear;
  126.   for jdx := 0 to FHashPrime - 1 do
  127.     Form1.HashTable.Lines.Add(Format('%3d: %3d %s',
  128.       [jdx, Ord(FKeys[jdx].KeyWord.ResWord), FKeys[jdx].Text]));
  129.   for idx := 0 to Ord(High(TXPResWord)) do
  130.     begin
  131.     Matched := Match(ResWordStrings[TXPResWord(idx)], KeyWord);
  132.     Form1.Log.Lines.Add(Format('%d %s:%s %3d',
  133.       [Ord(Matched), ResWordStrings[TXPResWord(idx)],
  134.         ResWordStrings[KeyWord.ResWord], Ord(KeyWord.ResWord)]));
  135.     end;
  136.   for idx := 0 to Ord(High(TXPDirective)) do
  137.     begin
  138.     Matched := Match(DirectiveStrings[TXPDirective(idx)], KeyWord);
  139.     Form1.Log.Lines.Add(Format('%d %s:%s %3d',
  140.       [Ord(Matched), DirectiveStrings[TXPDirective(idx)],
  141.         DirectiveStrings[KeyWord.Directive], Ord(KeyWord.Directive)]));
  142.     end;
  143.   for idx := 0 to Ord(High(TXPMisc)) do
  144.     begin
  145.     Matched := Match(MiscStrings[TXPMisc(idx)], KeyWord);
  146.     Form1.Log.Lines.Add(Format('%d %s:%s %3d',
  147.       [Ord(Matched), MiscStrings[TXPMisc(idx)], MiscStrings[KeyWord.Misc],
  148.       Ord(KeyWord.Misc)]));
  149.     end;
  150.    Form1.Count.Text := IntToStr(Count);
  151. {$ENDIF}
  152.   end;
  153. destructor TXPKeyWords.Destroy;
  154.    begin
  155.    FKeys := nil;
  156.    inherited Destroy;
  157.    end;
  158. function TXPKeyWords.Hash(const Key: string): integer;
  159.     var
  160.     KeyChar: ^Byte;
  161.     begin
  162.     Result := 0;
  163.     KeyChar := Pointer(Key);
  164.     while KeyChar^ <> 0 do
  165.        begin
  166.        Result := ((Result shl 6) + KeyChar^) mod FHashPrime;
  167.        System.Inc(KeyChar);
  168.        end;
  169.     end;
  170. function TXPKeyWords.SecondHash(const Key: string): integer;
  171.     begin
  172.     { Returns a number in the range 0-8, based on the last 3 bits of <Key> }
  173.     Result := 8 - (System.Ord(Key[System.Length(Key)])) mod 8;
  174.     end;
  175. procedure TXPKeyWords.Insert(const Key: string; const Kind: TXPKeyWordKind;
  176.       const Index: integer);
  177.   var
  178.   idx, offset: integer;
  179.   {$IFDEF XPKEYWORDS_DEBUG}
  180.   Insertlog: string;
  181.   {$ENDIF}
  182.   begin
  183.   { Check for available space. }
  184.   if Count < Size then
  185.     System.Inc(FCount)
  186.   else
  187.     exit;
  188.   { Assume <Key> is always lower-cased. }
  189.   idx := Hash(Key);
  190.   offset := SecondHash(Key);
  191. {$IFDEF XPKEYWORDS_DEBUG}
  192.     Insertlog := Format('%3d:', [Index]);
  193. {$ENDIF}
  194.   { Second condition ensures no duplicate keys in table. }
  195.   while not((System.Length(FKeys[idx].Text) = 0)
  196.     or (SysUtils.AnsiCompareStr(FKeys[idx].Text, Key) = 0)) do
  197.     begin
  198. {$IFDEF XPKEYWORDS_DEBUG}
  199.     Insertlog := Format('%s %3d:%s',
  200.     [InsertLog, idx, FKeys[idx].Text]);
  201. {$ENDIF}
  202.     idx := (idx + offset) mod FHashPrime;
  203.     end;
  204.   FKeys[idx].Text := Key;
  205.   FKeys[idx].KeyWord.Kind := Kind;
  206.   case Kind of
  207.     kwResWord: FKeys[idx].KeyWord.ResWord := TXPResWord(Index);
  208.     kwDirective: FKeys[idx].KeyWord.Directive := TXPDirective(Index);
  209.     kwMisc: FKeys[idx].KeyWord.Misc := TXPMisc(Index);
  210.     end;
  211. {$IFDEF XPKEYWORDS_DEBUG}
  212.   Insertlog := Format('%s %3d:%s'#13#10,
  213.   [InsertLog, idx, FKeys[idx].Text]);
  214.   Form1.Log.Lines.Add(InsertLog);
  215. {$ENDIF}
  216.   end;
  217. function TXPKeyWords.Match(Str: string; out KeyWord: TXPKeyWord): boolean;
  218.     var
  219.     idx, offset: integer;
  220.     begin
  221.     Str := SysUtils.AnsiLowerCase(Str);
  222.     idx := Hash(Str);
  223.     offset := SecondHash(Str);
  224.     { Bail on empty slot or match. }
  225.     while not ((System.Length(FKeys[idx].Text) = 0)
  226.       or (SysUtils.AnsiCompareStr(FKeys[idx].Text, Str) = 0)) do
  227.         idx := (idx + offset) mod FHashPrime;
  228.     { Result = not bailed on miss. }
  229.     Result := not (System.Length(FKeys[idx].Text) = 0);
  230.     if Result then
  231.       KeyWord := FKeys[idx].KeyWord;
  232.     end;
  233. class function TXPKeyWords.KeyWordAsText(const KeyWord: TXPKeyWord): string;
  234.   begin
  235.   case KeyWord.Kind of
  236.     kwResWord:
  237.       Result := ResWordStrings[KeyWord.ResWord];
  238.     kwDirective:
  239.       Result := DirectiveStrings[KeyWord.Directive];
  240.     kwMisc:
  241.       Result := MiscStrings[KeyWord.Misc];
  242.     end;
  243.   end;
  244. end.