package body Scanners is function Create (Input : in String; Delimiters : in String := Default_Delimiters; Return_Delims : in Boolean := False) return Scanner is begin return This : Scanner do This.Text := UB.To_Unbounded_String (Input); This.Delimiters := SM.To_Set (Delimiters); This.Return_Delims := Return_Delims; This.Reset; end return; end Create; function Has_More_Tokens (This : in Scanner) return Boolean is begin return This.Next_Start <= This.Next_Finish; end Has_More_Tokens; procedure Queue_Next (This : in out Scanner) is begin if This.Return_Delims and then SM.Is_In (UB.Element (This.Text, This.Position), Default_Delimiter_Set) then This.Next_Start := This.Position; This.Next_Finish := This.Position; else UB.Find_Token (This.Text, This.Delimiters, This.Position, Ada.Strings.Outside, This.Next_Start, This.Next_Finish); end if; This.Position := This.Next_Finish + 1; end Queue_Next; function Next_Token (This : in out Scanner) return String is Old_Start : Positive := This.Next_Start; Old_Finish : Natural := This.Next_Finish; begin if not This.Has_More_Tokens then return ""; end if; if This.Position > UB.Length (This.Text) then This.Next_Finish := This.Next_Start - 1; else This.Queue_Next; end if; return UB.Slice (This.Text, Old_Start, Old_Finish); end Next_Token; function Remaining_Token_Count (This : in Scanner) return Natural is -- Copying an entire Scanner like this is not efficient, -- but this function will never be efficient, so at the -- moment I am choosing to favour clearer code. Test_Scan : Scanner := This; Count : Natural := 0; begin while Test_Scan.Has_More_Tokens loop Count := Count + 1; exit when Test_Scan.Position > UB.Length (Test_Scan.Text); Test_Scan.Queue_Next; end loop; return Count; end Remaining_Token_Count; procedure Reset (This : in out Scanner) is begin This.Position := 1; if UB.Length (This.Text) > 0 then This.Queue_Next; else This.Next_Start := 1; This.Next_Finish := 0; end if; end Reset; end Scanners;