home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Runimage / Delphi50 / Source / Internet / COPYPRSR.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-11  |  10.6 KB  |  450 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {       Parser object to allow on-the-fly parsing and   }
  6. {       text insertion                                  }
  7. {                                                       }
  8. {       Copyright (c) 1997,99 Inprise Corporation       }
  9. {                                                       }
  10. {*******************************************************}
  11.  
  12. unit CopyPrsr;
  13.  
  14. interface
  15.  
  16. uses Classes;
  17.  
  18. const
  19.   toEOL = Char(5);
  20.  
  21. type
  22. { TCopyParser }
  23.  
  24.   TCopyParser = class(TObject)
  25.   private
  26.     FStream: TStream;
  27.     FOutStream: TStream;
  28.     FOrigin: Longint;
  29.     FBuffer: PChar;
  30.     FBufPtr: PChar;
  31.     FBufEnd: PChar;
  32.     FSourcePtr: PChar;
  33.     FSourceEnd: PChar;
  34.     FTokenPtr: PChar;
  35.     FStringPtr: PChar;
  36.     FSourceLine: Integer;
  37.     FSaveChar: Char;
  38.     FToken: Char;
  39.     procedure ReadBuffer;
  40.     procedure SkipBlanks(DoCopy: Boolean);
  41.     function SkipToNextToken(CopyBlanks, DoCopy: Boolean): Char;
  42.     function CopySkipTo(Length: Integer; DoCopy: Boolean): string;
  43.     function CopySkipToToken(AToken: Char; DoCopy: Boolean): string;
  44.     function CopySkipToEOL(DoCopy: Boolean): string;
  45.     function CopySkipToEOF(DoCopy: Boolean): string;
  46.     procedure UpdateOutStream(StartPos: PChar);
  47.   public
  48.     constructor Create(Stream, OutStream: TStream);
  49.     destructor Destroy; override;
  50.     procedure CheckToken(T: Char);
  51.     procedure CheckTokenSymbol(const S: string);
  52.     function CopyTo(Length: Integer): string;
  53.     function CopyToToken(AToken: Char): string;
  54.     function CopyToEOL: string;
  55.     function CopyToEOF: string;
  56.     procedure CopyTokenToOutput;
  57.     procedure Error(const Ident: string);
  58.     procedure ErrorFmt(const Ident: string; const Args: array of const);
  59.     procedure ErrorStr(const Message: string);
  60.     function NextToken: Char;
  61.     function SkipToken(CopyBlanks: Boolean): Char;
  62.     procedure SkipEOL;
  63.     function SkipTo(Length: Integer): string;
  64.     function SkipToToken(AToken: Char): string;
  65.     function SkipToEOL: string;
  66.     function SkipToEOF: string;
  67.     function SourcePos: Longint;
  68.     function TokenComponentIdent: String;
  69.     function TokenFloat: Extended;
  70.     function TokenInt: Longint;
  71.     function TokenString: string;
  72.     function TokenSymbolIs(const S: string): Boolean;
  73.     property SourceLine: Integer read FSourceLine;
  74.     property Token: Char read FToken;
  75.   end;
  76.  
  77. implementation
  78.  
  79. uses SysUtils, Consts;
  80.  
  81. { TCopyParser }
  82.  
  83. const
  84.   ParseBufSize = 4096;
  85.  
  86. constructor TCopyParser.Create(Stream, OutStream: TStream);
  87. begin
  88.   FStream := Stream;
  89.   FOutStream := OutStream;
  90.   GetMem(FBuffer, ParseBufSize);
  91.   FBuffer[0] := #0;
  92.   FBufPtr := FBuffer;
  93.   FBufEnd := FBuffer + ParseBufSize;
  94.   FSourcePtr := FBuffer;
  95.   FSourceEnd := FBuffer;
  96.   FTokenPtr := FBuffer;
  97.   FSourceLine := 1;
  98.   SkipToken(True);
  99. end;
  100.  
  101. destructor TCopyParser.Destroy;
  102. begin
  103.   if FBuffer <> nil then
  104.   begin
  105.     FStream.Seek(Longint(FTokenPtr) - Longint(FBufPtr), 1);
  106.     FreeMem(FBuffer, ParseBufSize);
  107.   end;
  108. end;
  109.  
  110. procedure TCopyParser.CheckToken(T: Char);
  111. begin
  112.   if Token <> T then
  113.     case T of
  114.       toSymbol:
  115.         Error(SIdentifierExpected);
  116.       toString:
  117.         Error(SStringExpected);
  118.       toInteger, toFloat:
  119.         Error(SNumberExpected);
  120.     else
  121.       ErrorFmt(SCharExpected, [T]);
  122.     end;
  123. end;
  124.  
  125. procedure TCopyParser.CheckTokenSymbol(const S: string);
  126. begin
  127.   if not TokenSymbolIs(S) then ErrorFmt(SSymbolExpected, [S]);
  128. end;
  129.  
  130. function TCopyParser.CopySkipTo(Length: Integer; DoCopy: Boolean): string;
  131. var
  132.   P: PChar;
  133.   Temp: string;
  134. begin
  135.   Result := '';
  136.   repeat
  137.     P := FTokenPtr;
  138.     while (Length > 0) and (P^ <> #0) do
  139.     begin
  140.       Inc(P);
  141.       Dec(Length);
  142.     end;
  143.     if DoCopy and (FOutStream <> nil) then
  144.         FOutStream.WriteBuffer(FTokenPtr^, P - FTokenPtr);
  145.     SetString(Temp, FTokenPtr, P - FTokenPtr);
  146.     Result := Result + Temp;
  147.     if Length > 0 then ReadBuffer;
  148.   until (Length = 0) or (Token = toEOF);
  149.   FSourcePtr := P;
  150. end;
  151.  
  152. function TCopyParser.CopySkipToEOL(DoCopy: Boolean): string;
  153. var
  154.   P: PChar;
  155. begin
  156.   P := FTokenPtr;
  157.   while not (P^ in [#13, #10, #0]) do Inc(P);
  158.   SetString(Result, FTokenPtr, P - FTokenPtr);
  159.   if P^ = #13 then Inc(P);
  160.   FSourcePtr := P;
  161.   if DoCopy then UpdateOutStream(FTokenPtr);
  162.   NextToken;
  163. end;
  164.  
  165. function TCopyParser.CopySkipToEOF(DoCopy: Boolean): string;
  166. var
  167.   P: PChar;
  168.   Temp: string;
  169. begin
  170.   repeat
  171.     P := FTokenPtr;
  172.     while P^ <> #0 do Inc(P);
  173.     FSourcePtr := P;
  174.     SetString(Temp, FTokenPtr, P - FTokenPtr);
  175.     Result := Result + Temp;
  176.     if DoCopy then
  177.     begin
  178.       UpdateOutStream(FTokenPtr);
  179.       NextToken;
  180.     end else SkipToken(False);
  181.     FTokenPtr := FSourcePtr;
  182.   until Token = toEOF;
  183. end;
  184.  
  185. function TCopyParser.CopySkipToToken(AToken: Char; DoCopy: Boolean): string;
  186. var
  187.   S: PChar;
  188.   Temp: string;
  189.  
  190.   procedure InternalSkipBlanks;
  191.   begin
  192.     while True do
  193.     begin
  194.       case FSourcePtr^ of
  195.         #0:
  196.           begin
  197.             SetString(Temp, S, FSourcePtr - S);
  198.             Result := Result + Temp;
  199.             if DoCopy then UpdateOutStream(S);
  200.             ReadBuffer;
  201.             if FSourcePtr^ = #0 then Exit;
  202.             S := FSourcePtr;
  203.             Continue;
  204.           end;
  205.         #10:
  206.           Inc(FSourceLine);
  207.         #33..#255:
  208.           Break;
  209.       end;
  210.       Inc(FSourcePtr);
  211.     end;
  212.     if DoCopy then UpdateOutStream(S);
  213.   end;
  214.  
  215. begin
  216.   Result := '';
  217.   while (Token <> AToken) and (Token <> toEOF) do
  218.   begin
  219.     S := FSourcePtr;
  220.     InternalSkipBlanks;
  221.     if S <> FSourcePtr then
  222.     begin
  223.       SetString(Temp, S, FSourcePtr - S);
  224.       Result := Result + Temp;
  225.     end;
  226.     SkipToNextToken(DoCopy, DoCopy);
  227.     if Token <> AToken then
  228.     begin
  229.       SetString(Temp, FTokenPtr, FSourcePtr - FTokenPtr);
  230.       Result := Result + Temp;
  231.     end;
  232.   end;
  233. end;
  234.  
  235. function TCopyParser.CopyTo(Length: Integer): string;
  236. begin
  237.   Result := CopySkipTo(Length, True);
  238. end;
  239.  
  240. function TCopyParser.CopyToToken(AToken: Char): string;
  241. begin
  242.   Result := CopySkipToToken(AToken, True);
  243. end;
  244.  
  245. function TCopyParser.CopyToEOL: string;
  246. begin
  247.   Result := CopySkipToEOL(True);
  248. end;
  249.  
  250. function TCopyParser.CopyToEOF: string;
  251. begin
  252.   Result := CopySkipToEOF(True);
  253. end;
  254.  
  255. procedure TCopyParser.CopyTokenToOutput;
  256. begin
  257.   UpdateOutStream(FTokenPtr);
  258. end;
  259.  
  260. procedure TCopyParser.Error(const Ident: string);
  261. begin
  262.   ErrorStr(Ident);
  263. end;
  264.  
  265. procedure TCopyParser.ErrorFmt(const Ident: string; const Args: array of const);
  266. begin
  267.   ErrorStr(Format(Ident, Args));
  268. end;
  269.  
  270. procedure TCopyParser.ErrorStr(const Message: string);
  271. begin
  272.   raise EParserError.CreateResFmt(@SParseError, [Message, FSourceLine]);
  273. end;
  274.  
  275. function TCopyParser.NextToken: Char;
  276. begin
  277.   Result := SkipToNextToken(True, True);
  278. end;
  279.  
  280. function TCopyParser.SkipTo(Length: Integer): string;
  281. begin
  282.   Result := CopySkipTo(Length, False);
  283. end;
  284.  
  285. function TCopyParser.SkipToToken(AToken: Char): string;
  286. begin
  287.   Result := CopySkipToToken(AToken, False);
  288. end;
  289.  
  290. function TCopyParser.SkipToEOL: string;
  291. begin
  292.   Result := CopySkipToEOL(False);
  293. end;
  294.  
  295. function TCopyParser.SkipToEOF: string;
  296. begin
  297.   Result := CopySkipToEOF(False);
  298. end;
  299.  
  300. function TCopyParser.SkipToNextToken(CopyBlanks, DoCopy: Boolean): Char;
  301. var
  302.   P, StartPos: PChar;
  303. begin
  304.   SkipBlanks(CopyBlanks);
  305.   P := FSourcePtr;
  306.   FTokenPtr := P;
  307.   case P^ of
  308.     'A'..'Z', 'a'..'z', '_':
  309.       begin
  310.         Inc(P);
  311.         while P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_'] do Inc(P);
  312.         Result := toSymbol;
  313.       end;
  314.     #10:
  315.       begin
  316.         Inc(P);
  317.         Inc(FSourceLine);
  318.         Result := toEOL;
  319.       end;
  320.   else
  321.     Result := P^;
  322.     if Result <> toEOF then Inc(P);
  323.   end;
  324.   StartPos := FSourcePtr;
  325.   FSourcePtr := P;
  326.   if DoCopy then UpdateOutStream(StartPos);
  327.   FToken := Result;
  328. end;
  329.  
  330. function TCopyParser.SkipToken(CopyBlanks: Boolean): Char;
  331. begin
  332.   Result := SkipToNextToken(CopyBlanks, False);
  333. end;
  334.  
  335. procedure TCopyParser.ReadBuffer;
  336. var
  337.   Count: Integer;
  338. begin
  339.   Inc(FOrigin, FSourcePtr - FBuffer);
  340.   FSourceEnd[0] := FSaveChar;
  341.   Count := FBufPtr - FSourcePtr;
  342.   if Count <> 0 then Move(FSourcePtr[0], FBuffer[0], Count);
  343.   FBufPtr := FBuffer + Count;
  344.   Inc(FBufPtr, FStream.Read(FBufPtr[0], FBufEnd - FBufPtr));
  345.   FSourcePtr := FBuffer;
  346.   FSourceEnd := FBufPtr;
  347.   if FSourceEnd = FBufEnd then
  348.   begin
  349.     FSourceEnd := LineStart(FBuffer, FSourceEnd - 1);
  350.     if FSourceEnd = FBuffer then Error(SLineTooLong);
  351.   end;
  352.   FSaveChar := FSourceEnd[0];
  353.   FSourceEnd[0] := #0;
  354. end;
  355.  
  356. procedure TCopyParser.SkipBlanks(DoCopy: Boolean);
  357. var
  358.   Start: PChar;
  359. begin
  360.   Start := FSourcePtr;
  361.   while True do
  362.   begin
  363.     case FSourcePtr^ of
  364.       #0:
  365.         begin
  366.           if DoCopy then UpdateOutStream(Start);
  367.           ReadBuffer;
  368.           if FSourcePtr^ = #0 then Exit;
  369.           Start := FSourcePtr;
  370.           Continue;
  371.         end;
  372.       #10:
  373.         Inc(FSourceLine);
  374.       #33..#255:
  375.         Break;
  376.     end;
  377.     Inc(FSourcePtr);
  378.   end;
  379.   if DoCopy then UpdateOutStream(Start);
  380. end;
  381.  
  382. function TCopyParser.SourcePos: Longint;
  383. begin
  384.   Result := FOrigin + (FTokenPtr - FBuffer);
  385. end;
  386.  
  387. procedure TCopyParser.SkipEOL;
  388. begin
  389.   if Token = toEOL then
  390.   begin
  391.     while FTokenPtr^ in [#13, #10] do Inc(FTokenPtr);
  392.     FSourcePtr := FTokenPtr;
  393.     if FSourcePtr^ <> #0 then
  394.       NextToken
  395.     else FToken := #0;
  396.   end;
  397. end;
  398.  
  399. function TCopyParser.TokenFloat: Extended;
  400. begin
  401.   Result := StrToFloat(TokenString);
  402. end;
  403.  
  404. function TCopyParser.TokenInt: Longint;
  405. begin
  406.   Result := StrToInt(TokenString);
  407. end;
  408.  
  409. function TCopyParser.TokenString: string;
  410. var
  411.   L: Integer;
  412. begin
  413.   if FToken = toString then
  414.     L := FStringPtr - FTokenPtr else
  415.     L := FSourcePtr - FTokenPtr;
  416.   SetString(Result, FTokenPtr, L);
  417. end;
  418.  
  419. function TCopyParser.TokenSymbolIs(const S: string): Boolean;
  420. begin
  421.   Result := (Token = toSymbol) and (CompareText(S, TokenString) = 0);
  422. end;
  423.  
  424. function TCopyParser.TokenComponentIdent: String;
  425. var
  426.   P: PChar;
  427. begin
  428.   CheckToken(toSymbol);
  429.   P := FSourcePtr;
  430.   while P^ = '.' do
  431.   begin
  432.     Inc(P);
  433.     if not (P^ in ['A'..'Z', 'a'..'z', '_']) then
  434.       Error(SIdentifierExpected);
  435.     repeat
  436.       Inc(P)
  437.     until not (P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_']);
  438.   end;
  439.   FSourcePtr := P;
  440.   Result := TokenString;
  441. end;
  442.  
  443. procedure TCopyParser.UpdateOutStream(StartPos: PChar);
  444. begin
  445.   if FOutStream <> nil then
  446.     FOutStream.WriteBuffer(StartPos^, FSourcePtr - StartPos);
  447. end;
  448.  
  449. end.
  450.