unit dpgrtl.inputbuffer; interface uses dpgrtl.types; type TInputBuffer = class( TInterfacedObject, IInputBuffer) protected fMarkerCount : integer; fMarkerOffset : integer; fNumToConsume : integer; protected procedure Remove( Num: integer); virtual; abstract; procedure SyncConsume; inline; protected function GetMarked: boolean; inline; procedure Consume; inline; procedure Commit; inline; function Mark: integer; procedure Rewind( Value: integer); end; implementation { TInputBuffer } // @@@: IInputBuffer implementation +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // IInputBuffer implementation // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ================================================================================================ // Mark // // Returns an integer marker theh can be used to rewind the buffer to its current state. // ================================================================================================ function TInputBuffer.Mark: integer; begin SyncConsume; INC( fMarkerCount); result := fMarkerOffset end; // ================================================================================================ // Consume // // Mark another input item for deferred consumption. // ================================================================================================ procedure TInputBuffer.Consume; begin INC( fNumToConsume); end; // ================================================================================================ // Commit // // This method updates the state of the input buffer so that the text matched since the most // recent Mark() is no longer held by the buffer. So, you either do a mark/rewind for failed // predicate or mark/commit to keep on parsing without rewinding the input. // ================================================================================================ procedure TInputBuffer.Commit; begin if fMarkerCount > 0 then DEC( fMarkerCount) end; // ================================================================================================ // Rewind // // Rewind the character buffer to a marker. 'Value' marker returned previously from mark. // ================================================================================================ procedure TInputBuffer.Rewind(Value: integer); begin SyncConsume; fMarkerOffset := Value; DEC( fMarkerCount) end; // ================================================================================================ // GetMarked // ================================================================================================ function TInputBuffer.GetMarked: boolean; begin result := fMarkerCount <> 0 end; // @@@: Internals +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Internals // // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ================================================================================================ // Sync Consume // ================================================================================================ procedure TInputBuffer.SyncConsume; begin if fNumToConsume > 0 then begin if fMarkerCount > 0 then INC( fMarkerOffset, fNumToConsume) else Remove( fNumToConsume); fNumToConsume := 0 end end; end.