global Init_Id_Chars, Id_Chars

procedure Init_Char_Sets ()
   Init_Id_Chars := &letters ++ '_'
   Id_Chars := Init_Id_Chars ++ &digits  
end

procedure Find_Chunks (Ident)
   local i, j
   i := 1
   while i < * Ident do
      if any (&lcase, Ident [i]) then {
         j := many (&lcase, Ident, i)
         suspend Ident [i : j]
         i := j
      } else if Ident [i] == '_' then i +:= 1
      else if any (&ucase, Ident [i]) then {
         if j := many (&ucase, Ident, i + 1) then {
            any (&lcase, Ident, j) & j -:= 1
             # "CreateDIBSection" -> "Create", "DIB", "Section"
             # Второй результат "DIB", а не "DIBS"
            suspend Ident [i : j]
            i := j
         } else {
            j := i + 1; j := many (&lcase, Ident, i + 1)
            suspend Ident [i : j]
            i := j
         }
      } else if any (&digits, Ident [i]) then {
         j := many (&digits, Ident, i)
         suspend Ident [i : j]
         i := j
      } else fail
end

procedure Chunk_To_Ada (Chunk)
  return map (Chunk [1], &lcase, &ucase) || map (Chunk [2 : 0], &ucase, &lcase)
end

procedure Identifier_To_Ada (Ident)
   local Chunk, Result
   Result := ""
   every Chunk := Find_Chunks (Ident) do {
      * Result > 0 & Result ||:= '_';
      Result ||:= Chunk_To_Ada (Chunk)
   }
   return Result
end

procedure main ()
   local input, output
   local s, i, j, initIdChars, idChars
   Init_Char_Sets ()

   input := open ("test.txt","r") & output := open ("output.txt", "w") &
   {
      while s := read(input) do
      {
         i := 1
         while (j := upto(Init_Id_Chars, s, i),
                not any (Id_Chars, s[j - 1]),
                k := many (Id_Chars, s, j)) do {
              write(output, Identifier_To_Ada (s[j : k]))
              i := k
           }
      }
   }
end
