with String_Utilities;
separate (Structured_Comments_Solution)
procedure Parse (Comment_Lines : Lines.Lines_Type;
                 Block : in out Comment_Block) is

    type State is (Looking_For_Keyword, Found_Keyword);

    Lines_Iter : Lines.Line_Iterator := Lines.Initialize (Comment_Lines);

    Comment_Iter : Comment_List.Iterator;

    Current_Comment : Structured_Comment;

    Current_State : State;

    Parsed_Block : Comment_Block := Initialize;

    function Begins_With (Fragment : String; Line : String) return Boolean is
    begin
        if Fragment'Length > Line'Length then
            return False;
        else
            return String_Utilities.Equal
                      (Fragment, Line (Line'First ..
                                          Line'First + Fragment'Length - 1));
        end if;
    end Begins_With;
begin

    Comment_List.Init (Comment_Iter, Comment_List.List (Block));

    while not Comment_List.Done (Comment_Iter) loop

        Current_Comment := Comment_List.Value (Comment_Iter);

        Current_State := Looking_For_Keyword;

        if Lines.Done (Lines_Iter) then
            raise Illegal_Block_Format;  -- more comments in Block
        end if;

        -- state machine parse:
        loop
            declare

                Full_Line : constant String := Lines.Value (Lines_Iter);

                Stripped_Line : constant String :=
                   String_Utilities.Strip
                      (String_Utilities.Strip (Full_Line, '-'), ' ');
            begin
                if not Begins_With ("--", Full_Line) then
                    raise Illegal_Block_Format;
                end if;

                case Current_State is
                    when Looking_For_Keyword =>

                        if Stripped_Line = "" then
                            null;  -- ignore
                        elsif Begins_With
                                 (Bounded.Image (Current_Comment.Keyword) & ":",
                                  Stripped_Line)
                           -- begins with KEYWORD:

                            then

                            Current_State := Found_Keyword;

                            Lines.Add
                               (New_Line =>
                                   String_Utilities.Strip
                                      (Stripped_Line
                                          (Stripped_Line'First +
                                           Bounded.Length
                                              (Current_Comment.Keyword) + 1 ..
                                              Stripped_Line'Last)),
                                To => Current_Comment.Value);
                        else
                            raise Illegal_Block_Format;  -- not a keyword
                        end if;

                        Lines.Next (Lines_Iter);

                        if Lines.Done (Lines_Iter) then
                            raise Illegal_Block_Format;  -- no terminator
                        end if;

                    when Found_Keyword =>

                        if Stripped_Line = ""  -- comment terminator
                            then
                            Add_Structured_Comment
                               (Parsed_Block, Current_Comment);

                            Lines.Next (Lines_Iter);

                            exit;  -- go to the next comment
                        else
                            Lines.Add (New_Line => Stripped_Line,
                                       To => Current_Comment.Value);

                            Lines.Next (Lines_Iter);
                        end if;
                end case;
            end;

        end loop;

        Comment_List.Next (Comment_Iter);
    end loop;

    if not Lines.Done (Lines_Iter) then

        -- check to see that nothing but terminators follow

        declare
            Full_Line : constant String := Lines.Value (Lines_Iter);

            Stripped_Line : constant String :=
               String_Utilities.Strip
                  (String_Utilities.Strip (Full_Line, '-'), ' ');
        begin
            if not (Stripped_Line = "") then
                raise Illegal_Block_Format;
            end if;
        end;

        Lines.Next (Lines_Iter);
    end if;

    Block := Parsed_Block;

end Parse;