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

Email服务器

开发平台:

Delphi

  1. unit xpParse;
  2. (*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * This code was inspired to expidite the creation of unit tests 
  14.  * for use the Dunit test frame work.
  15.  * 
  16.  * The Initial Developer of XPGen is Michael A. Johnson.
  17.  * Portions created The Initial Developer is Copyright (C) 2000.
  18.  * Portions created by The DUnit Group are Copyright (C) 2000.
  19.  * All rights reserved.
  20.  *
  21.  * Contributor(s):
  22.  * Michael A. Johnson <majohnson@golden.net>
  23.  * Juanco A馿z <juanco@users.sourceforge.net>
  24.  * Chris Morris <chrismo@users.sourceforge.net>
  25.  * Jeff Moore <JeffMoore@users.sourceforge.net>
  26.  * The DUnit group at SourceForge <http://dunit.sourceforge.net>
  27.  *
  28.  *)
  29. {
  30. Unit        : xpParse
  31. Description : defines the real "parser" that recognizes the necessary parts of
  32.               a delphi file.  The parse step generates parse nodes that are
  33.               then useful in generating the test stubs for inclusion in dunit.
  34. Programmer  : Michael A. Johnson
  35. Date        : 03-Jul-2000
  36. }
  37. interface
  38. uses
  39.   xpLex,
  40.   Classes,
  41.   ParseDef,
  42.   SysUtils;
  43. type
  44.   EUnitIDExpected = class(Exception);
  45.   EEqualExpected = class(Exception);
  46.   EBadConstInit = class(Exception);
  47.   lex_token = record
  48.     Str: string;
  49.     token_type: token_enum;
  50.   end;
  51.   TParseNodeClass = class
  52.     fNameClass: string;
  53.     fPubMethodList: TStringList;
  54.     fPrtMethodList: TStringList;
  55.     fPvtMethodList: TSTringList;
  56.   public
  57.     constructor Create(newName: string); virtual;
  58.     destructor Destroy; override;
  59.     property PubMethodList: TStringList read fpubMethodList write fpubMethodList;
  60.     property PrtMethodList: TStringList read fPrtMethodList write fPrtMethodList;
  61.     property PvtMethodList: TSTringList read fPvtMethodList write fPvtMethodList;
  62.     property NameClass: string read fNameClass write fNameClass;
  63.   end;
  64.   TXPStubParser = class
  65.   protected
  66.     funitName: string;
  67.     lex: TLexer;
  68.     fSrcStream: TStream;
  69.     fParseNodeList: TList;
  70.     procedure SetSrcStream(NewStream: TStream);
  71.     procedure NewClassNode(NameOfNode: string);
  72.     procedure NewPubMethodIdent(NameOfMethod: string);
  73.     procedure NewPvtMethodIdent(NameOfMethod: string);
  74.     procedure NewPrtMethodIdent(NameOfMethod: string);
  75.     function Get_Token(lex: TLexer): lex_token;
  76.     function Parse_Unit_Heading(lex: TLexer): lex_token;
  77.     function Parse_const_Paragraph(lex: TLexer): lex_token;
  78.     function Parse_type_Paragraph(lex: TLexer): lex_token;
  79.     function Parse_var_paragraph(lex: TLexer): lex_token;
  80.     function Parse_uses_clause(lex: TLexer): lex_token;
  81.     function Parse_typedef(ident: string; lex: TLexer): lex_token;
  82.     function Parse_tobject_derived(token: lex_token; lex: TLexer): lex_token;
  83.     function Parse_derived(ident: string; lex: TLexer): lex_token;
  84.     function SyncToken(target: token_enum; lex: TLexer): lex_token;
  85.     function ParseEventDef(token : lex_token;lex: TLexer): lex_token;
  86.     procedure EmptyParseNodeList;
  87.   public
  88.     constructor Create; virtual;
  89.     destructor Destroy; override;
  90.     procedure Parse;
  91.     property SrcStream: TStream read fSrcStream write SetSrcStream;
  92.     property unitName: string read funitName write funitName;
  93.     property ParseNodeList: TList read fParseNodeList write fParseNodeList;
  94.   end;
  95. implementation
  96. uses
  97.   ListSupport;
  98. function TXPStubParser.Get_Token(lex: TLexer): lex_token;
  99. begin
  100.   result.Str := lex.tokenString;
  101.   result.token_type := TokenToTokenType(result.str);
  102.   lex.NextToken;
  103. end;
  104. function TXPStubParser.Parse_const_Paragraph(lex: TLexer): lex_token;
  105. begin
  106.   result := Get_Token(lex);
  107.   repeat
  108.     case result.token_type of
  109.       kw_ident:
  110.         begin
  111.           result := Get_Token(lex);
  112.           case result.token_type of
  113.             { typical const }
  114.             kw_equal:
  115.               begin
  116.                 result := SyncToken(kw_semi, lex);
  117.                 result := Get_Token(lex);
  118.               end;
  119.             { typed constant }
  120.             kw_colon:
  121.               begin
  122.                 result := SyncToken(kw_equal, lex);
  123.                 result := Get_Token(lex);               
  124.                 case result.token_type of
  125.                   kw_openParen:
  126.                     begin
  127.                       result := SyncToken(kw_closeParen, lex);
  128.                       repeat
  129.                         result := Get_Token(lex);
  130.                       until (lex.Token = toEof) or (result.token_type = kw_semi);
  131.                       result := Get_Token(lex);
  132.                     end;
  133.                   kw_openbracket:
  134.                     begin
  135.                      result := SyncToken(kw_closebracket, lex);
  136.                      repeat
  137.                         result := Get_Token(lex);
  138.                       until (lex.Token = toEof) or (result.token_type = kw_semi);
  139.                       result := Get_Token(lex);
  140.                     end;  
  141.                   kw_ident:
  142.                     begin
  143.                       result := SyncToken(kw_semi,lex);
  144.                       result := Get_Token(lex);
  145.                     end;
  146.                   else
  147.                     raise EBadConstInit.create('Expected '' or ( after constant assignment');  
  148.                 end
  149.               end;
  150.           end;
  151.         end;
  152.       else
  153.         exit;                           { anything else should be handled by something else }
  154.     end;
  155.   until (lex.token = toEof);
  156. end;
  157. function TXPStubParser.parse_type_Paragraph(lex: TLexer): lex_token;
  158. begin
  159.   result := Get_Token(lex);
  160.   repeat
  161.     case result.token_type of
  162.       kw_ident: result := parse_typedef(result.Str, lex);
  163.       kw_semi: result := Get_Token(lex);
  164.       kw_end:
  165.         begin
  166.           result := Get_Token(lex);
  167.         end;
  168.       else
  169.         exit;                           { anything else should be handled by something else }
  170.     end;
  171.   until (lex.token = toEof);
  172. end;
  173. function TXPStubParser.Parse_Unit_Heading(lex: TLexer): lex_token;
  174. begin
  175.   result := Get_Token(lex);
  176.   case result.token_type of
  177.     kw_ident:
  178.       begin
  179.         funitName := result.str;
  180.         result := SyncToken(kw_semi, lex);
  181.       end
  182.     else
  183.       raise EUnitIDExpected.create('Unit Name Identifier Expected');
  184.   end;
  185. end;
  186. function TXPStubParser.parse_var_paragraph(lex: TLexer): lex_token;
  187. begin
  188.   result := Get_Token(lex);
  189.   repeat
  190.     case result.token_type of
  191.       kw_ident:
  192.         begin
  193.           result := SyncToken(kw_semi, lex);
  194.           result := Get_Token(lex);
  195.         end;
  196.       else
  197.         exit;
  198.     end;
  199.   until (lex.Token = toEof);
  200. end;
  201. function TXPStubParser.parse_uses_clause(lex: TLexer): lex_token;
  202. begin
  203.   { skip tokens until we get to the end of the uses clause }
  204.   result := SyncToken(kw_semi, lex);
  205. end;
  206. function TXPStubParser.parse_typedef(ident: string; lex: TLexer): lex_token;
  207. begin
  208.   result := Get_Token(lex);
  209.   case result.token_type of
  210.     kw_equal:
  211.       begin
  212.         result := Get_Token(lex);
  213.         case result.token_type of
  214.           kw_class:
  215.             begin
  216.               result := Get_Token(lex);
  217.               case result.token_type of
  218.                 kw_protected,
  219.                   kw_public,
  220.                   kw_private,
  221.                   kw_ident:
  222.                   begin {
  223.                     fo0 = class
  224.                     end;
  225.                    }
  226.                     NewClassNode(ident);
  227.                     result := parse_tobject_derived(result, lex);
  228.                   end;
  229.                 kw_openParen:
  230.                   begin
  231.                     NewClassNode(ident);
  232.                     result := parse_derived(result.Str, lex);
  233.                   end;
  234.                 kw_of :
  235.                   begin
  236.                     result := SyncToken(kw_semi,lex);
  237.                   end;  
  238.                 kw_semi:
  239.                   begin
  240.                     { nop to ignore forward def. }
  241.                     { i.e tform2 = class; }
  242.                     exit;
  243.                   end;
  244.               end;
  245.             end;
  246.           kw_ptr:
  247.             begin
  248.               { skip ptr def - ie intPtr = ^integer; }
  249.               result := SyncToken(kw_semi, lex);
  250.             end;
  251.           kw_procedure  :
  252.             begin
  253.               result := ParseEventDef(result,lex);
  254. {              SyncToken(kw_rightParen, lex);}
  255.             end;
  256.           kw_interface :
  257.             begin
  258.               result := Get_Token(lex);
  259.               if result.token_type <> kw_semi then
  260.                 begin
  261.                  { scan to the end of the interface def }
  262.                  result := SyncToken(kw_end, lex);
  263.                  { skip the trailing semi }
  264.                  result := SyncToken(kw_semi, lex);                
  265.                 end;
  266.             end;  
  267.           kw_record:
  268.             begin
  269.               { scan to the end of the record def }
  270.               result := SyncToken(kw_end, lex);
  271.               { skip the trailing semi }
  272.               result := SyncToken(kw_semi, lex);
  273.             end;
  274.           kw_openParen:
  275.             begin
  276.               result := SyncToken(kw_closeParen,lex);
  277.               result := SyncToken(kw_semi, lex);
  278.             end;  
  279.         end;
  280.       end
  281.     else
  282.       raise EEqualExpected.Create('= expected but found : ' + result.str+' srcLine : '+IntToStr(lex.sourceLine));
  283.   end;
  284. end;
  285. function TXPStubParser.parse_derived(ident: string; lex: TLexer): lex_token;
  286. begin
  287.   result := Get_Token(lex);
  288.   if result.token_type = kw_ident then
  289.     begin
  290.       result := Get_Token(lex);
  291.       if result.token_type = kw_comma then
  292.         result := SyncToken(kw_closeParen,lex);
  293.       if result.token_type = kw_CloseParen then
  294.         begin
  295.           result := Get_Token(lex);
  296.           case result.token_type of
  297.             { TODO 5 -oMAJ -cYAGNI : decide if alias derivations (ie. myException = class(exception) ) should be purged and not mentioned in the generated code. }
  298.             kw_semi: exit;
  299.             else
  300.               result := parse_tobject_derived(result, lex);
  301.           end;
  302.         end;
  303.     end;
  304. end;
  305. function TXPStubParser.parse_tobject_derived(token: lex_token; lex: TLexer): lex_token;
  306. var
  307.   Visibility: MethodVisibility;
  308. begin
  309.   { assume class was compiled in $M+ state, even it it wasn't so that non
  310.     specified members are assumed public }
  311.   Visibility := kw_public;
  312.   result := token;
  313.   repeat
  314.     case result.token_type of
  315.       kw_ident:
  316.         begin
  317.           result := SyncToken(kw_semi, lex);
  318.         end;
  319.       kw_function:
  320.         begin
  321.           result := Get_Token(lex);
  322.           if result.token_type = kw_ident then
  323.             begin
  324.               case visibility of
  325.                 kw_private: NewPvtMethodIdent(result.str);
  326.                 kw_protected: NewPrtMethodIdent(result.str);
  327.                 kw_published,
  328.                   kw_public,
  329.                   kw_automated:
  330.                   NewPubMethodIdent(result.str);
  331.               end;
  332.               result := Get_Token(lex);
  333.               case result.token_type of
  334.                 kw_colon:
  335.                   begin
  336.                     result := SyncToken(kw_semi, lex);
  337.                     result := Get_Token(lex);
  338.                   end;
  339.                 kw_openParen:
  340.                   begin
  341.                     result := SyncToken(kw_closeParen, lex);
  342.                     result := SyncToken(kw_semi, lex);
  343.                     result := Get_Token(lex);
  344.                   end;
  345.                 else
  346.                   raise exception.create('expected paramlist or return type');
  347.               end;
  348.             end;
  349.         end;
  350.       kw_procedure:
  351.         begin
  352.           result := Get_Token(lex);
  353.           if result.token_type = kw_ident then
  354.             begin
  355.               case visibility of
  356.                 kw_private: NewPvtMethodIdent(result.str);
  357.                 kw_protected: NewPrtMethodIdent(result.str);
  358.                 kw_published,
  359.                   kw_public,
  360.                   kw_automated:
  361.                   NewPubMethodIdent(result.str);
  362.               end;
  363.               result := Get_Token(lex);
  364.               case result.token_type of
  365.                 kw_semi: result := Get_Token(lex);
  366.                 kw_openParen:
  367.                   begin
  368.                     result := SyncToken(kw_closeParen, lex);
  369.                     result := Get_Token(lex);
  370.                   end;
  371.               end
  372.             end
  373.           else
  374.             raise exception.create('ident expected');
  375.         end;
  376.       kw_private,
  377.         kw_protected,
  378.         kw_published,
  379.         kw_public,
  380.         kw_automated:
  381.         begin
  382.           Visibility := result.token_type;
  383.           result := Get_Token(lex);
  384.         end;
  385.       else
  386.         result := Get_Token(lex);
  387.     end;
  388.   until (lex.token = toEof) or (result.token_type = kw_end);
  389. end;
  390. function TXPStubParser.SyncToken(target: token_enum; lex: TLexer): lex_token;
  391. begin
  392.   repeat
  393.     result := Get_Token(lex);
  394.   until (lex.token = toEof) or (result.token_type = target);
  395. end;
  396. procedure TXPStubParser.SetSrcStream(newStream: TStream);
  397. begin
  398.   fSrcStream := newStream;
  399. end;
  400. constructor TXPStubParser.Create;
  401. begin
  402.   lex := nil;
  403.   fSrcStream := nil;
  404.   fParseNodeList := TList.Create;
  405.   inherited Create;
  406. end;
  407. procedure TXPStubParser.Parse;
  408. var
  409.   token: lex_token;
  410. begin
  411.   EmptyParseNodeList;
  412.   Lex := nil;
  413.   try
  414.     Lex := TLexer.create(fSrcStream);
  415.     token := Get_Token(lex);
  416.     while lex.Token <> toEof do
  417.       begin
  418.         case token.token_type of
  419.           Kw_unit:
  420.             token := Parse_Unit_Heading(lex);
  421.           kw_uses:
  422.             token := parse_uses_clause(lex);
  423.           Kw_const:
  424.             token := Parse_const_Paragraph(lex);
  425.           Kw_type:
  426.             token := parse_type_Paragraph(lex);
  427.           kw_interface:
  428.             token := Get_Token(lex);
  429.           kw_var:
  430.             token :=
  431.               parse_var_paragraph(lex);
  432.           kw_implementation:
  433.             break;                      { stop when we hit the implemation kw }
  434.           else
  435.             token := Get_Token(lex);
  436.         end;
  437.       end;
  438.   finally
  439.     Lex.Free;
  440.   end;
  441. end;
  442. destructor TXPStubParser.Destroy;
  443. begin
  444.   { clean up any left over parseNodes }
  445.   ListFreeObjectItems(fParseNodeList);
  446.   fParseNodeList.Free;
  447.   inherited Destroy;
  448. end;
  449. { TParseNodeClass }
  450. constructor TParseNodeClass.Create(newName: string);
  451. begin
  452.   fNameClass := newName;
  453.   fpubMethodList := TStringList.Create;
  454.   fPrtMethodList := TStringList.Create;
  455.   fPvtMethodList := TSTringList.Create;
  456.   inherited Create;
  457. end;
  458. destructor TParseNodeClass.Destroy;
  459. begin
  460.   fpubMethodList.Free;
  461.   fPrtMethodList.Free;
  462.   fPvtMethodList.Free;
  463.   inherited Destroy;
  464. end;
  465. procedure TXPStubParser.NewClassNode(nameOfNode: string);
  466. begin
  467.   fParseNodeList.Add(TParseNodeClass.Create(NameOfNode));
  468. end;
  469. procedure TXPStubParser.NewPubMethodIdent(nameOfMethod: string);
  470. var
  471.   currentNode: Tobject;
  472. begin
  473.   currentNode := fParseNodeList.Last;
  474.   if currentNode <> nil then
  475.     begin
  476.       if currentNode is TParseNodeClass then
  477.         begin
  478.           with currentNode as TParseNodeClass do
  479.             begin
  480.               PubMethodList.Add(NameOfMethod);
  481.             end;
  482.         end;
  483.     end;
  484. end;
  485. procedure TXPStubParser.NewPrtMethodIdent(NameOfMethod: string);
  486. var
  487.   currentNode: Tobject;
  488. begin
  489.   currentNode := fParseNodeList.Last;
  490.   if currentNode <> nil then
  491.     begin
  492.       if currentNode is TParseNodeClass then
  493.         begin
  494.           with currentNode as TParseNodeClass do
  495.             begin
  496.               PrtMethodList.Add(NameOfMethod);
  497.             end;
  498.         end;
  499.     end;
  500. end;
  501. procedure TXPStubParser.NewPvtMethodIdent(NameOfMethod: string);
  502. var
  503.   currentNode: Tobject;
  504. begin
  505.   currentNode := fParseNodeList.Last;
  506.   if currentNode <> nil then
  507.     begin
  508.       if currentNode is TParseNodeClass then
  509.         begin
  510.           with currentNode as TParseNodeClass do
  511.             begin
  512.               PvtMethodList.Add(NameOfMethod);
  513.             end;
  514.         end;
  515.     end;
  516. end;
  517. procedure TXPStubParser.EmptyParseNodeList;
  518. begin
  519.   { get rid of any pre-existing parse nodes }
  520.   ListFreeObjectItems(fParseNodeList);
  521. end;
  522. function TXPStubParser.ParseEventDef(token: lex_token;
  523.   lex: TLexer): lex_token;
  524. {
  525.  event defs follow the form:
  526.  <ident> <eq> <kw_proc> <l_paren> <ident_list> <r_paren> <of> <kw_object> <kw_semi>
  527. }  
  528. begin
  529.  result := SyncToken(kw_Openparen, lex);
  530.  result := SyncToken(kw_Closeparen, lex);
  531.  result := SyncToken(kw_object, lex);
  532.  result := SyncToken(kw_semi,lex);
  533. end;
  534. end.