Я поставил пакет win32ada, он создал папку include\win32ada
Если написать первой строкой test.gpr with "win32ada", то среда ругается при открытии пакета:
[2011-02-08 16:25:57] C:\Program Files\ADA\projects\TEST\test.gpr:1:06: unknown project file: "win32ada"
[2011-02-08 16:25:57] Error while loading project 'C:\Program Files\ADA\projects\TEST\test.gpr'. Loading the default project.
Ну я это убрал.
Добавил в test.gpr строчку
for Source_Dirs use ("..\..\include\win32ada\**");
Пишу в test.adb with win32.winuser (вроде все основные функции, типа окно нарисовать итд, там).
Компилирую.
gnatlink "C:\Program Files\ADA\projects\TEST\test.ali" -shared-libgcc -g -g -fprofile-generate -o "C:\Program Files\ADA\projects\TEST\test.exe"
c:/program files/ada/bin/../libexec/gcc/i686-pc-mingw32/4.3.6/ld.exe: cannot find -lwin32ada
collect2: ld returned 1 exit status
gnatlink: error when calling C:\Program Files\ADA\bin\gcc.exe
gnatmake: *** link failed.
[2011-02-08 16:28:19] process exited with status 4 (elapsed time: 06.26s)
Что делать?
with "win32ada";
project Test is
for Source_Dirs use (".");
for Main use ("first.adb");
package Builder is
for Default_Switches ("ada") use ("-O2");
end Builder;
package Compiler is
for Default_Switches ("ada") use ("-O3");
end Compiler;
package Linker is
for Default_Switches ("ada") use ("-s");
end Linker;
end Test;
project Win32Ada is
for Languages use ("ada");
for Source_Dirs use ("../../include/win32ada");
for Library_Dir use "../../lib/win32ada";
for Library_Name use "win32ada";
for Externally_Built use "true";
end Win32Ada;
> У тебя что, нет этого файла?
Файл есть.
Если написать
with "..\..\lib\gnat\win32ada.gpr";
то при открытии выдаётся простыня ошибок на много страниц.
Но файл типа обнаружен, наверное.
А на просто with "win32ada"; он просто говорит, что не может найти.
В среде галочек и папок никаких выставить не надо?
Попробуй создать новый проект, и когда он будет создан - правой кнопкой мыши щелкнуть на корневом узле в Project View (название твоего проекта), и в меню выбрать Project -> Dependencies. Откроется окошко, в котором никаких зависимостей не будет (ну, понятно, проект-то новый). Жмешь кнопку "Add from known projects". Если в появившемся списке известных проектов тоже нет Win32Ada - значит, установка не завершилась корректно, где-то что-то недопрописано в настройках. Если есть - просто отмечай его галочкой и IDE сделает все остальное сама...
> Если в появившемся списке известных проектов тоже нет Win32Ada - значит, установка не завершилась корректно, где-то что-то недопрописано в настройках.
А там нету.
Странно, вроде винада запустилась, что-то в консольном окне с процентами долго показывала...
Снес ГНАТ, переставил всё.
Если прямо из среды дописать with "win32ada", то пересобирается нормально, но потом при открытии опять ругается. Да, в том списке зависимостей опять пусто.
Хм... Как вариант попробуй в зависимостях добавить через "Add from file" (у тебя ж Win32Ada.gpr есть, ты говоришь) вот этот самый файл: GNAT\2010\lib\gnat\win32ada.gpr ... И сразу после того, как это сделал (и прогрессбар исчез) - жми Project -> Save All... Только что попробовал - тоже отработало. А потом попробуй закрыть среду, и посмотреть что записано в первой строке твоего GPR-файла.
И, если опять будет ругаться при переоткрытии проекта - сделай скриншот, чтоб было видно полный текст ошибки, и содержимое Project View...
> А потом попробуй закрыть среду, и посмотреть что записано в первой строке твоего GPR-файла.
with "..\..\lib\gnat\win32ada.gpr";
> И, если опять будет ругаться при переоткрытии проекта
Не, теперь нормально открылось.
Всё, наконец-то я могу перейти к окнам.
> - сделай скриншот
Если бы я в прошлый раз, когда добавил полный путь к файлу, сделал снимок экрана, то на нём бы самой интересной деталью был выродившийся ползунок в списке ошибок (там строчек за 1000 было).
> А по проводу ошибки линкера - в проектах, использующих WinAPI - вот здесь есть пример минимального Win32-приложения: http://users.ncrvnet.nl/gmvdijk/w32first.zip , скачай его, и вот с таким GPR-файлом у меня только что откомпилировалось и заработало:
У меня не компилируется (ругается на слово "or").
Эскизы прикрепленных изображений
Странно. Значит, я не оттуда брал тот тестовый пример, которым пользовался (скачан он был давно). Или компилировал другой файл...
В любом случае - ничего страшного. Строкой ниже указано, что делать. Смотришь, с каким типом у компилятора вышла заминка (в данном случае это Interfaces.C.unsigned), и добавляешь либо локально в этой функции, либо глобально для всего пакета, если подобная ошибка встречается несколько раз
use type Interfaces.C.unsigned;
Программу я скомпилировал.
Но окно белое.
Новый вопрос: что надо написать, чтобы скомпилировалось
Wnd_Class.hbrBackground := Win32.WinUser.Color_BtnFace + 1;
?
function To_HBRUSH is new Ada.Unchecked_Conversion
(Integer, Win32.Windef.HBRUSH);
-- ...
Wnd_Class.hbrBackground := To_HBRUSH (Win32.WinUser.Color_BtnFace + 1);
Вопрос: в каком модуле описаны константы wmsz_TopLeft итд?
Я ещё много вопросов буду задавать вида "в каком модуле описано что-то там". Вообще взаимодействие с виндой сделано очень неудобно, на каждый чих свой тип, всех их надо приводить, а то и конвертировать, на каждый чих компилятора долго подбирать какой тип в какой надо преобразовать, чтобы это скомпилировалось, кошмар.
Да ещё и куча функций, требующих параметр по ссылке, а давать ссылку на локальную переменную нельзя, приходится портить код и заводить глобальные переменные для того, чтобы применить их в локальной процедуре и передать ссылку на них, либо заводить указатель и выделять память при входе в процедуру, короче, одни костыли кругом. И это всё из-за того, что нет out -параметров для функций, почему их раньше не ввели?
WM_SIZING тоже куда дели?
WMSZ_TOPLEFT : constant := 4;
WMSZ_TOPRIGHT : constant := 5;
-- и так далее ...
function Window_Proc (hwnd : Win32.Windef.HWND;(пример из совершенно рабочей программы, валялся у меня на флешке). Что я не так делаю?
message : Win32.UINT;
wParam : Win32.WPARAM;
lParam : Win32.LPARAM) return Win32.LRESULT is
use Interfaces.C;
-- ...
My_DC : Win32.Windef.HDC;
bResult : Win32.BOOL;
Paint_Record : aliased Win32.Winuser.PAINTSTRUCT;
begin
case message is
-- ...
when Win32.Winuser.WM_PAINT =>
My_DC := Win32.Winuser.BeginPaint (hwnd, Paint_Record'Access);
-- ... Рисуем на My_DC ...
bResult := Win32.Winuser.EndPaint (hwnd, Paint_Record'Access);
when others => return
Win32.Winuser.DefWindowProc (hwnd, message, wParam, lParam);
end case;
return 0;
end Window_Proc;
> Не описаны они вообще. Кому надо - тот открывает MSDN -> WM_SIZING Message, смотрит там на значения констант, и пишет себе в пакет:
Ну сегодня константы описаны так, а в другой системе иначе. И перекомпилированная программа неверно работает. Ну в МСДН-то посмотреть я догадался, но как-то это неправильно, по-моему.
> То, что в WinAPI куча дублирующих друг друга типов - это только проблемы WinAPI.
Ну при переводе заголовков-то можно было все нужные типы к одному свести?
> Пример костылей можно посмотреть?
Например, в том примере:
msg : Win32.Winuser.LPMSG := new Win32.Winuser.MSG;
Result := TranslateMessage(ac_Msg_T(msg));
А потому, что если просто написать
message: aliased Msg; // локально
Result := TranslateMessage(message'access);
то компилятор выдаёт "non-local pointer cannot point to local object".
А просто ради интереса проверь, вот такое будет компилироваться (и работать, разумеется, понятно что просто компиляция никому на фиг не сдалась) :
Message: aliased Msg; -- локально
Message_Ptr: Win32.Winuser.ac_MSG_t := Message'Unchecked_Access;
Result := win32.Winuser.TranslateMessage(Win32.WinUser.ac_Msg_t(Message_Ptr));
Unchecked_Access скомпилировался и заработал, спасибо (я сразу передавал в процедуру Message'Unchecked_Access, без промежуточной переменной Message_Ptr).
Я таки не понял, что происходит с исключениями внутри оконной функции?
Я зашил содержимое главного оконного цикла (while getmessage(...)) в блок begin-except-end, а в оконной функции на нажатие ЛКМ сделал деление на ноль. При нажатии ЛКМ прога вылетела.
Хм. Извини, а с каких пор исключение может покидать пределы оконных функций и Callback-ов? Этого никогда нельзя было делать, насколько я помню. То, что где-то это работало - не повод думать, что оно должно было там работать.
Исключение должно быть обработано до выхода из оконной функции, и не должно передаваться дальше. Иначе система возьмет на себя его обработку. К чему это приводит - ты уже видел...
> Хм. Извини, а с каких пор исключение может покидать пределы оконных функций и Callback-ов?
Впервые слышу про такое.
В Д7 это работало, да.
А с чего это не должно работать?
> Иначе система возьмет на себя его обработку.
Система разве не передаёт его выше (то есть в мой обработчик в итоге)?
Значит, смотри. Пользуемся возможностями Ады:
Пакет Err
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Task_Termination; use Ada.Task_Termination;
with Ada.Task_Identification; use Ada.Task_Identification;
package Err is
protected End_Of is
procedure World(C : Cause_Of_Termination;
T : Task_ID; X : Exception_Occurrence);
end End_Of;
end Err;
with Ada.Exceptions;(Исправил на вывод в файл, иначе могут быть проблемы с запуском вне среды)... Что это дает?
with Ada.Text_IO;
package body Err is
protected body End_Of is
procedure World(C : Cause_Of_Termination;
T : Task_ID; X : Exception_Occurrence) is
My_File : ada.Text_IO.File_Type;
begin
case C is
when Normal => null;
when Abnormal =>
Ada.Text_IO.Put_Line ("Abnormal termination of Task" & Image(T));
when Unhandled_Exception =>
Ada.Text_IO.Create(My_File, Ada.Text_IO.Out_File, "My.txt");
Ada.Text_IO.Put_Line (My_File, "Unhandled exception in Task : " & Image(T));
Ada.Text_IO.Put_Line (My_File, Exception_Information(X));
Ada.Text_IO.Put_Line (My_File, "End logging");
Ada.Text_IO.Close (My_File);
end case;
end World;
end End_Of;
end Err;
with Err; use Err;Вот сейчас специально нашел машину с Windows XP, запустил там программу, которая из WndProc бросает исключение (то самое деление на 0). Вот чего показывает:
with Ada.Task_Termination;
procedure Main is
-- ...
begin
Ada.Task_Termination.Set_Dependents_Fallback_Handler(End_Of.World'Access);
-- ...
N:\Just_Test\debug\main
Unhandled exception in Task : main_task_003E4008
Exception name: CONSTRAINT_ERROR
Message: wndproc.adb:59 divide by zero
Call stack traceback locations:
0x401e99 0x401f08 0x7e418732 0x7e418814 0x7e4189cb
0x7e4196c5 0x401e1d 0x4017a6 0x401235 0x4012a6 0x7c817075
End logging
В общем я тут сделал первую оконную программу на Аде.
wintest.rar ( 24.2 килобайт )
Кол-во скачиваний: 337
Ну и куча вопросов накопилась.
1. Зачем помимо INT ввели тип LONG, который от -2**31 до 2**31-1? В чём прикол?
2. У меня, например, есть функция. Принимает массив, который может быть ооочень длинным. Массив может быть передан в функцию либо сразу, как переменная, либо как результат вычисления выражения, либо как агрегат, то есть нужен именно in-параметр. Внутри функции над массивом производятся какие-то операции. Над самим параметром операции запрещены, поэтому первой строчкой функции стоит копирование
copy_a: arr := a;
Понятно, что если массив передаётся из переменной, то тут явно происходит то, что в Паскале делалось неявно. Но если массив передаётся как результат вычислений, то он изначально сидит на стеке, и если внутри функции все операции делаются с copy_a (а изначальное a даже не упоминается), то делать копирование из стека в стек просто бессмысленно. Умеет ли компилятор убирать копирование в таких случаях?
3. Агрегат при передаче в функцию не работает, если внутри только 1 параметр. f((a)) - это вызов функции от числа (a) или от массива (a)? Вот компилятор и запрещает так передавать 1-элементные массивы.
Но если у разработчиков языка явно была клавиатура только с одним типом скобочек, то сейчас у всех есть [ и ], которые можно разрешить применять для агрегатов. f(a) - передача числа, f([a]) - передача 1-элементного массива, f((a)) - неопределённость, запретить, не нужна.
4. Подобно очень опасной описке в С между == и =, в Аде есть очень опасная возмжность написать and вместо and then, "благодаря" которой будет выполняться то, что выполняться не должно. Это серьёзный изъян языка. Зачем для операции, которая нафиг не нужна в большей части случаев (вычисление выражения по полной схеме), оставили привычную запись, а для реально нужной операции сделали непривычную и длиную запись? Почему бы не оставили and и or для неполного вычисления, а для полного сделали бы, например, and necessarily и or necessarily?
5. Тот код из архива занимает 100 кб, но компилируется в мегабайт. В этом мегабайте последние 2/3 - это чистый текст. Как его скомпилировать в более приемлемый размер?
type T is array (Positive range <>) of integer;
procedure Foo (arr : T) is
begin
for i in arr'Range loop
Ada.Text_IO.Put_Line (Integer'Image (arr (i)));
end loop;
end Foo;
-- ...
Foo (arr => (1 => 1)); -- Что-то не так?
> С точки зрения англоязычного программиста как раз запись
if A > 0 and then Arr (A) = Value then
является более наглядной. "Выполнять второе действие только тогда, когда первое выполнилось". Аналогично и с or else.
А запись if (f(A) > 0) and necessarily (g(A) > 0) тоже тогда наглядна - вычислять второе условие обязательно.
> А то, что другой язык программирования приучил программиста писать and везде - это опять же не проблемы Ады.
Опасность в том, что можно случайно забыть одно слово и получить некорректный код (полный аналог "случайно забыть один символ и..."). Да, в варианте с necessarily тоже опасность есть, что забудешь слово, и что-то не будет выполняться, но проявляться она будет намного реже, поскольку схема полного вычисления выражения нужна крайне редко (мне вообще никогда не пригождалась). Логично же для более частого случая применять более короткую запись, чтобы случайно не написать экзотический вариант.
gnatlink F:\Programs\Ada\wintest\wintest\opt\wintest.ali -shared-libgcc -g -fprofile-generate -s
-LD:\GNAT\2009\lib\win32ada\ -lwin32ada -o F:\Programs\Ada\wintest\wintest\opt\wintest.exe
> Кстати, откомпилировал твой проект со всеми Warning-ами
Так там по умолчанию не все включены?
> (в свойствах - кнопка Warnings, и щелкнуть на Activate every optional warning)
Блин, точно, есть такое подменю в том подменю.
> Там и предупреждения о лишних with/use, и о том, что типы не надо подключать, они уже подключены и ты делаешь двойную работу, и то, что неизменно в ходе процедуры/функции и можно его описать как constant...
Ну это да, надо исправить.
> , от размера осталась едва ли треть (275К).
Всё равно много.
Посмотрю, что можно еще сделать...
В общем, включил я ВСЕ предупреждения.
И выключил.
"Внимание: к формальному параметру нет обращения".
То есть он какбэ предлагает мне убрать параметр из заголовка функции.
Куда я его уберу, это функция для подстановки в качестве параметра функционального типа.
"Осторожно, к переменной после присваивания нет обращений".
А шо робыть, если эта функция зачем-то возвращает не нужное мне значение, которое надо непременно куда-то записать.
Всё-таки, какие предупреждения надо поставить, а какие не надо?
Ещё вопрос: в модуле Parser.ads как функцию Val_Number (ну которая используется в Do_Function и Do_Func_List) перенести в параметры шаблона? А то она принимает Key_Arr, а он задан как тип, производный от того, что идёт в параметрах шаблона, то есть описать его до функции Val_Number нельзя.
pragma Warnings (Off, "formal parameter ""lParam"" is not referenced");
pragma Warnings (Off, "formal parameter ""wParam"" is not referenced");
procedure Block( hWnd : in out Win32.Windef.HWND;
Msg : in out Win32.UINT;
wParam : in out Win32.WPARAM;
lParam : in out Win32.LPARAM;
Result : out Win32.LRESULT;
Continue : out boolean) is
pragma Warnings (On, "formal parameter ""lParam"" is not referenced");
pragma Warnings (On, "formal parameter ""wParam"" is not referenced");
begin
Result := 0;
Continue := False;
end;
function Graph(Func: Parsed_Function) return boolean is
procedure SetPixelProc
(hDC : Win32.Windef.HDC;
X : Win32.INT;
Y : Win32.INT;
crColor: Win32.Windef.COLORREF);
pragma Import (StdCall, SetPixelProc, "SetPixel");
-- ... Дальше всё как было, но вместо обращения к функции SetPixel
-- будет обращение к процедуре SetPixelProc - переменная С уже не нужна.
function Graph(Func: Parsed_Function) return boolean is
c : COLORREF; Unreferenced ©; -- Компилятор тут же перестанет паниковать
> Нет, он предлагает тебе либо убрать параметр из заголовка, либо отключить выдачу предупреждения:
> ...
> c : COLORREF; Unreferenced ©;
Ладно, понял.
Ещё такой момент: если включить галочки в Validiting Checking Mode, то программа падает при запуске на строчке
NAN: constant f80 := Get_NAN;
Но мне действительно нужна такая константа, чтобы показать, что в этой точке график рисовать не надо.
Дальше, проверка стиля.
Ругается на то, что я выравниваю двоеточия табами.
Как надо? Пробелы мне не нравятся.
"слишком длинная линия"
Это он про комментарий из 70 русских букв, который он посчитал за 140.
"тело подпрограммы не имеет предварительного описания"
Чисто внутренняя подпрограмма же, зачем мне её описывать
"надо написать and then вместо просто and"
За это спасибо.
Трудно нигде не ошибиться в этом.
Ещё несколько предупреждений внутри стандартного (не моего) пакета. Что делать?
"неявное разыменование"
В смысле?
Form.ID := To_HMENU(integer(LastID));
Form.all.ID := To_HMENU(integer(LastID));
> Проблема не в этом. Проблема - в том, что тебе для того, чтобы получить тип Key_Arr, надо инстанцировать другой шаблонный модуль. Это невозможно сделать при описании параметров настройки.
А как выкручиваться-то?
Ещё компилятор выдаёт предупреждение, если Initialize-Finalize-Adjust находятся в private -части ads файла.
Что определение этой процедуры перекрывает определение на линии, где я объявил тип.
package Pack2 isТеперь в зависимости от того, где будет вызываться T2.Op (в смысле, видима ли там приватная часть модуля Pack2 или нет) под P2.Op может подразумеваться разная функциональность. Где-то унаследованная от T1.Op, где-то - переопределенная.
type T2 is new Pack1.T; -- для типа описана операция/процедура Op
-- Естественно, T2 наследует Op
private
overriding procedure Op (X : T2);
end Pack2;
> Ты ж выкрутился.
Круто, теперь у моего разборщика выражений есть новый функционал: я могу в один и тот же разборщик подсовывать разные функции преобразования строки в число! (ирония)
> Вот просто пример приведи, неважно, пускай некомпилируемый, как ты хочешь чтоб это работало...
generic
type Key_Base is (<>);
type Number is private;
type Key_Arr will be declared; -- как-то так
with function Val_Number(Expression: Key_Arr; Position: access integer; V: access Number) return boolean;
package Parser is
...
generic
type Key_Base is (<>);
type Key_Arr is array (Positive range <>) of Key_Base;
type Number is private;
with function Val_Number(Expression: Key_Arr; Position: access integer; V: access Number) return boolean;
package Parser is
-- ...
type Char_Arr is array (Positive range <>) of Character;
function My_Func (Expression : Char_Arr; Position : access Integer; V : access f80) return Boolean is
begin
-- ...
end My_Func;
package f80_Parser is new Parser(Character, Char_Arr, f80, My_Func);
use f80_Parser;
with Parser; pragma Elaborate_All (Parser);(файл func_lib.ads)
with Func_Lib; pragma Elaborate_All (Func_Lib);(файл wintestmain.adb)
use Func_Lib;
with WinAPI.Bitmaps; pragma Elaborate_All (WinAPI.Bitmaps);
use WinAPI.Bitmaps;
1. От предупреждений я, вроде как, избавился. Правда, при включённой оптимизации ругается на конверсию LPARAM в PRECT. Что делать?
2. Стандартные вектора мне не понравились тем, что в них почему-то нет именно тех операций, которые мне нужны. Простейшие действия превращаются в пляски с бубном. Короче, я забил и свелосипедил.
3. В среде вкладочка Project View полезна, но как сделать так, чтобы она не показывала локальные подпрограммы в одном списке с глобальными, чтобы она иерархию подпрограмм показывала в виде дерева?
4. Если код имеет ошибки, то я вообще не понял, по какому принципу выбирается место, где они показываются, по-моему, по абсолютно случайному. Я ошибся в модуле A, компилятор показывает на ошибку в модуле B, использующем модуль A. Я поначалу долго думал, потом понял, что надо сразу свернуть все ошибки, найденный в модуле B и сразу смотреть на модуль A.
5. Напрягает, что навигация по модулям работает только после корректной компиляции проекта. А если я хочу залезть внутрь того модуля именно для того, чтобы дописать в него кое-что, что сделает проект компилирующимся? Что делать? Ааа, файл-открыть-папка вверх-папка с проектами-ещё одна папка-ой не туда, где же этот модуль-а, другая папка-о, наконец-то открыл.
6. Я так и не понял, как подружить отладочные пулы с объектами, живущими в глобальной области видимости. Ведь они умирают только при закрытии приограммы, а вывод утечек происходит до этого. Поэтому опять пришлось совершать извращение.
7. Стиль кода я не правил вообще. И делать это вручную не собираюсь. Есть автоматика для этого?
8. Как сделать программе иконку?
Пока что вышло вот это:
(правда, такие приколы уж очень медленно считаются).
Func_Graph_Test.rar ( 28.92 килобайт )
Кол-во скачиваний: 314
> Так что тебе надо либо включать pragma No_Strict_Aliasing для типа PRECT, либо в список ключей компиляции добавить -fno-strict-aliasing (я выбираю именно этот вариант), если выбрана оптимизация второго уровня и выше:
Тогда данный вид оптимизации угробится во всём проекте?
Включить прагму для одного типа я не могу, так как он определён в не моём модуле.
Может определить свой тип, логически равный PRECT, и прагму для него включить? А в обработчике WM_SIZING работать именно с ним (а конверсия эта мне нужна именно для WM_SIZING).
> Это то есть как?
Я имею в виду, прямо в коде ткнуть правой кнопкой по названию модуля, переменной, функции и выбрать "перейти к описанию/реализации".
type P_RECT is access all RECT;
pragma No_Strict_Aliasing (P_RECT);
-- Эту функцию не забудь убрать из WinApi.Conversions
function To_PRECT is new Ada.Unchecked_Conversion(LPARAM, P_RECT);
-- ...
R: constant P_RECT := To_PRECT(lp);
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>rc -r -dWin32 -fo bf.res bf.rc
тут бла-бла-бла, скомпилировал в RES
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>cvtres /machine:x86 /out:bf.rbj bf.res
бла-бла-бла, преобразовал в RBJ
pragma Linker_Options ("{полный_путь_к_полученному_RBJ_файлу}\bf.rbj");
М | Вопрос об исключениях перенесен: http://forum.pascalnet.ru/index.php?showtopic=28172 |
есть кто умеет писать на Аде?!! помогите, нужно найти произведение элементов одномерной матрицы
Задание нормально поставь. Какой тип элементов массива (одномерный - это массив а не матрица)? Размер? Как задается массив (ввод от пользователя, генератор случайных чисел, константа)?
В простейшем случае будет так:
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
type Vector is array(Positive range <>) of Long_Integer;
Size : constant := 10;
Arr : Vector(1 .. Size) := (2, 3, 4, others => 5);
p : Long_Integer := 1;
begin
for i in Arr'Range loop
p := p * Arr(i);
end loop;
Put_Line ("P = " & Long_Integer'Image(p));
end Main;