Помощь - Поиск - Пользователи - Календарь
Полная версия: Настройка GPS (IDE для Ады)
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Ада и другие языки
Страницы: 1, 2
-TarasBer-
Скачал я себе ГНАТ (Gnat GPL(без исходников, поленился все ссылки тыкать) и Win32Ada.
Скопировал я для начала в редактор кода текст из Википедии:

with Ada.Text_IO;

procedure Hello is
use Ada.Text_IO;
begin
Put_Line("Hello, world!");
end Hello.


Нажимаю "проверка синтаксиса".
[2011-01-18 21:32:02] Could not determine the project for file: C:\ADA\projects\Test\test.gpr
[2011-01-18 21:32:02] Invalid context, cannot build

В общем, я так понял, я пока с какими-то настройками не разобрался, что делать?
Заметил, что можно копировать сообщения об ошибках в буфер обмена.
Ещё, что функцию можно свернуть. После каждого сворачивания/разворачивания в конец добавляется пустая строчка (баг, есть таблетка?).
В настройках цвета не нашёл отдельного цвета для символов. Мне нравится, когда скобочки и запятые коричневые, а не чёрные.
volvo
Цитата
Ещё, что функцию можно свернуть. После каждого сворачивания/разворачивания в конец добавляется пустая строчка
У меня на домашней GNAT GPL 2009 такого нет. На рабочей GNAT Pro 2010 - тоже не присутствует, но там не виндовая версия. Надо будет потом посмотреть на форуме поддержки, скорее всего там уже есть сообщение о баге (если это действительно баг), и решение.

Цитата
Скопировал я для начала в редактор кода текст из Википедии:
Для начала ... Хм. Ну, вот, смотри что получается (даже если ты это уже делал, может еще кто заинтересуется) :

Запускаем GPS. Выдается вот такой диалог:
Нажмите для просмотра прикрепленного файла

Выбираем в нем создать проект при помощи Визарда, и жмем ОК. Дальше Single Project + Forward. Выбираем папку и название проекта, и дальше Forward до тех пор, пока не придем в Objects. Тут надо выбрать для Build directory ту же папку, которую выбирали при создании проекта (это не обязательно, но при отладке мне, например, удобнее, чтобы объектники и EXE не валились на системный диск, а лежали в подпапке, рядом с исходниками). Дальше ничего интересного нет, можно пробежать Forward-ом до конца, а можно сразу Apply...

Теперь имеем вот такой пустой проект:
Нажмите для просмотра прикрепленного файла

Создаем новый файл (File->New или прямо самой левой кнопкой на тулбаре), туда вписываем текст программы и сохраняем файл в рабочую папку с расширением ADB (в твоем случае процедура называется Hello, значит, hello.adb). GPR файл не трогаем вообще - это для IDE.

А вот теперь жмем "Проверку синтаксиса" (будучи именно в окне ADB-файла) :
Нажмите для просмотра прикрепленного файла

Но собрать код пока не удастся, даже когда ошибку исправишь. Для этого надо назначить главный файл проекта: Project -> Edit project properties -> Main files -> Add + hello.adb.

Вот теперь можно и собирать код...

Цитата
В настройках цвета не нашёл отдельного цвета для символов.
Теоретически знаю, что это тоже настраивается через питон, надо задать регулярное выражение, описывающее то, что ты хочешь подсвечивать , и то, каким цветом это подсвечивать. Но практически я этого никогда не делал, так что чтоб ничего не нарушить - даже не буду говорить, куда надо лезть... Если найду в техподдержке тему - скопирую решение сюда.

Если еще будут вопросы по настройке GPS - тему разделю...
volvo
Аааа.... Вот это:
Цитата
Ещё, что функцию можно свернуть. После каждого сворачивания/разворачивания в конец добавляется пустая строчка
- фича такая. Если при разворачивании блока образуется новая строка - значит, блок завершается некорректным символом. Должен всегда завершаться точкой с запятой, у тебя - просто точка. Исправишь - пустые строки добавляться перестанут. Это стандартное поведение, только что проверил, и в 2009 версии оно есть. Просто я завершающую точку уже давно не ставлю, поэтому не попадаю на подобное поведение.
-TarasBer-
Мда, название, как оказалось, у языка очень неудобное - в гугле невозможно ничего найти, сплошная эзотерика да некромантия выдаётся.
Я ничего не нашёл, всё пока делаю наугад. Какой учебник посоветуете? Что-нибудь мощное и подробное, типа Фаронова?

Пока пытаюсь понять работу основных операторов.

with Ada.Text_IO;
use Ada.Text_IO;

procedure Test is
i: integer;

begin
i := -7;
Put_Line(integer'Image(i));
i := i / 2;
Put_Line(integer'Image(i));
end Test;


Выдал -7 и -3.
То есть / для целых чисел тоже сработало.
Судя по результату, деление (увы, как и во всех других языках) прошло по правилам не математической, а компьютерной арфиметики (по правилам математики частное округляется не в сторону нуля, а в сторону минус бесконености, это делает остаток периодичной функцией, что очень удобно).
Решив проверить этот момент с оператором / на безопасность, я решил воспроизвести известную крестопроблему (у них 1/3=0, тьфу, то есть не =, а ==) и сделать так:

with Ada.Text_IO;
use Ada.Text_IO;

procedure Test is
i: integer;
j: float;

begin
i := -7;
Put_Line(integer'Image(i));
j := i / 2;
Put_Line(float'Image(j));
end Test;


Не скомпилиловалось.
j := float(i) / float(2); прошло
Безопасность в порядке, насколько это будет мешать в написании сложных выражений - не знаю.

По поводу среды. Я пока не нашёл удобную последовательность кнопок для пересбоки проекта и запуска.
Пока что я пытаюсь нажимать кнопки ALT+B+P+B+B+B+B+(кто додумался два пункта в одном подменю на одну клавишу повесть)+ENTER+SHIFT+F2. Если просто запустить, то запустится старая версия программы, такого в дельфе не было - запустить неактуальную версию из среды было невозможно, и правильно, меньше непоняток.
Как это всё настроить?
Долго думал, почему после переноса строки добавляется пробел, догадался посмотреть и заменить автоотступы с 3 на привычные 2. Жирные ключевые слова хорошо обрамляют блок, большие отступы не нужны - это только в С-образных даже 4 отступов не хватает для различения блока (им наверное скобочки плохо видны), что опровергает довод о расползании кода Паскаля в ширину, перенаправляя его против Си.

Да, тему, пожалуй, стоит разделить.
volvo
Цитата
Мда, название, как оказалось, у языка очень неудобное - в гугле невозможно ничего найти, сплошная эзотерика да некромантия выдаётся.
Можно. Добавляй в запрос что-либо из ключевых слов языка. Скажем, я добавляю "with Ada.Text_IO", и вся эзотерика улетает туда где ей и место... Остается только то, что нужно.

Учебник... Ну, пожалуй, начать следует с Гаввы, "Адское" программирование. Ада-95. Компилятор GNAT. Больше вменяемой литературы на русском языке я не видел. Скачать можешь вот отсюда, я залил себе на сайт: ada_ru.pdf (2.5 Мб, PDF). Также желательно скачать Annotated Ada Reference Manual отсюда - это и есть Стандарт языка.

Цитата
Выдал -7 и -3.
То есть / для целых чисел тоже сработало.
Разумеется. Работает для любых одинаковых типов. Кстати, существует как минимум один язык, который округляет в сторону -бесконечности. Это Питон. По крайней мере любители Питона уверяют что это именно так.

Цитата
Я пока не нашёл удобную последовательность кнопок для пересбоки проекта и запуска.
Я себе повесил Build All на Ctrl+F9 (заходишь в меню Edit->Key Shortcuts, там разворачиваешь список Build, выделяешь Build All, жмешь внизу Grab и нажимаешь желаемую комбинацию клавиш. Не пугайся, секунды на 3, может чуть больше тебе покажется, что оно зависло, IDE должна проверить, не будет ли твоя настройка конфликтовать с другими, уже существующими). Потом закрываешь этот диалог и пользуешься нормальным <Ctrl+F9> + <Shift+F2>...
volvo
Цитата
Судя по результату, деление (увы, как и во всех других языках) прошло по правилам не математической, а компьютерной арифметики (по правилам математики частное округляется не в сторону нуля, а в сторону минус бесконечности, это делает остаток периодичной функцией, что очень удобно).
Вот знаешь, за что я люблю этот язык? smile.gif Понадобилось тебе в данной конкретной программе использовать округление к -inf вместо стандартного "к нулю" - берешь и переопределяешь операцию деления:


function "/" (Left, Right : Integer'Base) return Integer'Base is
type Add_Type is array (Boolean'Range) of Integer;
Add_Value : constant Add_Type := (False => 0, True => 1);
begin
return Standard."/" (Left, Right) - Add_Value ((Left rem Right) < 0);
end "/";

pragma Inline("/");
Вот этого тебе ни С++ ни Дельфи (FPC) не дадут возможности сделать, там надо чтоб хотя бы один из типов был пользовательским, у Ады такого ограничения нет. Причем простота записи этой перегрузки (это обычная функция) дают тебе возможность написать шаблонный пакет и инстанцировать его функцией деления (по умолчанию - сделать деление из Standard, если же пользователю захотелось другого округления - пускай пишет любую функцию и передает ее в пакет. Все деления будут выполняться, используя ту функцию, которой пакет инстанцирован).
TarasBer
> берешь и переопределяешь операцию деления:

Вот уж от кого, а от Ады не ожидал.
В Дельфе долго не хотели вводить, типа ради безопасности и надёжности, а тут-то...
volvo
Надежность ни разу не страдает. Скорее наоборот. Помнишь, я в начале той темы приводил пример с перепутанными временем и расстоянием? Как вариант решения проблемы приводилось решение:

Цитата
procedure Check_Speed(T : Time; D : Distance) is
S : Speed := Speed(Integer(D) / Integer(T)); -- явное приведение типов !!!
begin
if S < SAFETY_SPEED then
Increase_Speed(S); -- Ok
end if
end Check_Speed;


Для иллюстрации - пойдет. Но в реальном проекте с ума сойдешь, постоянно приводя типы "на месте". Проще в отдельном пакете перегрузить все возможные варианты использования операторов, и использовать их:

   function "/" (Left : Distance; Right : Time) return Speed is
begin
return Speed(Integer(Left) / Integer(Right));
end "/";

procedure Check_Speed(T : Time; D : Distance) is
S : Speed := D / T;
begin
if S < SAFETY_SPEED then
Increase_Speed(S); -- Ok
end if;
end Check_Speed;

Что, здесь безопасность пострадала? Нет, код стал читабельнее... Но совершить ошибку все равно не даст.
TarasBer
Кстати, а как обстоит дело с размером получаемых файлов?
400 кб на консольную программку - это перебор, например.
volvo
Ну, почему 400? Если переключить режим с Debug на Optimize, а потом зайти в Project -> Edit project properties -> Switches -> Ada linker, и там включить Strip symbols - то будет в три раза меньше. Опять же, UPX никто не отменял, после его прогона остается 60Кб.

А уже если зайти в Switches -> Binder и слинковать программу с GNAT-овским рантаймом, то простенькое консольное приложение получится вообще порядка 15-17Кб, безо всяких UPX-ов.
-TarasBer-
Возникли вопросы по использованию отладчика.
Если нажать Ф5 или Ф6, то выдаётся ошибка, типа приложение не было запущено, хотя я нажимал "отладка-инициализация".

Начал читать Гавву (порадовало, что можно писать аналог const e=exp(1), в дельфи компилятор не умел вызывать функции для констант (приходилось экспоненту писать руками, типа 2.71828итд), ещё что фиксированная запятая включена в стандарт), но ещё по поводу языка возник вопрос, как пользоваться сущностями неизвестной заранее длины.
Пока единственный способ корректно их определить, который я нашёл - это заводить свой блок каждой такой переменной и инициализировать при объявлении:

declare S: string := My_Cool_Func_Which_Returns_String_With_Unknown_Length;
begin
Do_Something_Cool_With_S;
end;


(а для 10 переменных - 10 вложенных блоков?)
Только так я смог определить строку, не указывая длину.
Попытки передать string(1..10) в качестве out-параметра привели к тому, что после вывода такой строки программа завершается без сообщений.
А типа заранее завести строку неизвестной длины, а потом её присвоить (и оно само аллоцируется), как я привык в Дельфи - нельзя?
Не знаю, насколько это ограничение мешает, как я привык, пользоваться динмассивами направо и налево, передавая их по всей программе, но подход уж очень непривычный.
volvo
Цитата
Только так я смог определить строку, не указывая длину.
У Гаввы не описываются строки переменной длины, почему - не знаю, они уже были в Стандарте 95 года.

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

function F return Unbounded_String is
begin
return To_Unbounded_String("test");
end F;

ubs : Unbounded_String;

-- ...

ubs := F;
-- работай с ubs дальше...


Цитата
Если нажать Ф5 или Ф6, то выдаётся ошибка, типа приложение не было запущено, хотя я нажимал "отладка-инициализация".
Запускаешь отладчик (Debug -> Initialize), ставишь точку останова (это как в Дельфи, щелчком по точке рядом с номером строки) и запускаешь собственно программу через F2 (можешь дополнительно диалоге при старте отметить "Остановиться при входе в основную программу" - доступно только если ты установил BreakPoint - тогда тебе отладчик покажет все инициализации переменных). А уж после этого - ходи по F6...
TarasBer
> У Гаввы не описываются строки переменной длины, почему - не знаю, они уже были в Стандарте 95 года.

А, я уж испугался, что для цикла

for i := 0 to 255 do s := s + char(i);

придётся писать функцию с рекурсией, как во всяких прикольных языках типа Хаскела.
А если эта неограниченная строка (представляет собой, я так понял, указатель) сама делает очистку, то получается, что копирование её ни к хорошему не приведёт - копия после удаления оригинала будет указывать на порченные данные. То есть для них запрещёно присваивание (я дочитал до места про эту директиву в описании типа) и есть спец. функция копирования?
volvo
Ты вот это имеешь в виду, что-ли:

procedure Main is
ubs2 : Unbounded_String;

procedure P is
s : Unbounded_String;
begin
s := To_Unbounded_String("just a test");
ubs2 := s;
Put_Line ("Inside : " & To_String(ubs2));
end P;

begin

P;
Put_Line ("Outside : " & To_String(ubs2));

end Main;

? Ну попробуй, запусти. К моменту вызова Put_Line основной процедуры, строки S уже не существует - это Controlled-type, при выходе из области видимости он удаляется. Однако, что будет напечатано?
TarasBer
Всё нормально отработало.
А в чём секрет фокуса?
Если бы я не прочитал, что переопределять := запрещено, то я бы всё понял - в присваивание зашили увеличение счётчика ссылок. Неужели разрешили?
Хранение данных произвольной длины без указателя?
Ничего не понимаю.
volvo
Для Controlled-типов есть процедура Adjust, с операцией присваивания ни разу не обязательно заморачиваться. Вот на нее и повешено увеличение счетчика ссылок.
TarasBer
> Для Controlled-типов есть процедура Adjust

И она неявно вызывается после присваивания (я ещё не дочитал до той главы)?

Кстати, а тут можно делать такой прикол, любимый сишниками, как рекурсивные шаблоны?
volvo
Да, она неявно вызывается, как только объект контролируемого типа появляется слева от знака присваивания:
Цитата(ARM (7.6))
In particular, the user can define, for a controlled type, an Initialize procedure which is invoked immediately after the normal default initialization of a controlled object, a Finalize procedure which is invoked immediately before finalization of any of the components of a controlled object, and an Adjust procedure which is invoked as the last step of an assignment to a (nonlimited) controlled object.
TarasBer
Ух ты, тут можно хранить автоматические объекты в вариантных полях! С++ обломе!111
(ну да, с таким жёстким контролем обращения к вариантым полям вполне понятно)
Насчёт шаблонов я немного не понял. Чтобы определить, например, шаблонную функцию сложения двух чисел, мне какое ограничение надо поставить на тип? Я думал, допустимость операций над типом определится при инициализации шаблона.
volvo
Цитата
Чтобы определить, например, шаблонную функцию сложения двух чисел, мне какое ограничение надо поставить на тип?
Хитрый, да? Хочешь чтоб и is (<>) и is delta <> и is digits <> ? А нельзя в одном шаблоне это совместить. И перегружать шаблоны нельзя. Замкнутый круг, да?

Почти. Только обходится очень просто: не надо ограничивать тип, просто задай функцию, которая будет использоваться при вычислении суммы. И укажи is <> в конце, то есть, "если есть стандартная функция с таким именем для переданного типа - использовать ее".
   generic
type Element is private;
with function "+" (Left, Right : Element) return Element is <>; -- Использовать стандартную для Element
function Sum(A, B : Element) return Element;

function Sum(A, B : Element) return Element is
begin
return A + B;
end Sum;

function MySum is new Sum(Integer); -- Здесь все нормально, у Integer-а есть "+"
function OtherSum is new Sum(Float); -- Здесь тоже нормально, "+" присутствует
function TryThisSum is new Sum(String); -- А вот тут - облом. Нет предопределенного "+"

Если ты определишь оператор "+" для строк - сможешь передать его вторым параметром в шаблон, тогда эта же функция будет складывать и строки...
TarasBer
> Хитрый, да?

Нет, просто со сложившимся мнением по другим (не будет показыать пальцем) языкам.

> Только обходится очень просто: не надо ограничивать тип, просто задай функцию, которая будет использоваться при вычислении суммы.

А, и эта функция будет находиться сама по имени, задавать её при инициализации шаблона не надо.
Тогда жить можно.
volvo
Я тебе больше скажу, можно даже сделать так:

  function StrSum is new Sum(Unbounded_String, "&");

, и тогда эта же функция будет работать с неограниченной строкой, используя "&" как "+" (в смысле, подставляя вместо "сложения" склеивание строк)... Кто бы мне из фанатов С++ показал, как это реализовать там...
TarasBer
То есть при инициализации шаблона можно не только использовать операции по умолчанию, но и вставлять свои?

В С++? Ну класс с нужной функцией в шаблон же пихать можно, вот например, так.
TarasBer
Среда ругается, когда видит в коде русские символы (даже если в комментариях), что делать?
Поковырял исходники строк переменной длины.
Заметил, что для удлинения строки буфер растёт по экспоненте (с базой 33/32), что хорошо. Не понял константу Standard'Maximum_Alignment (не нашёл описание).
Не понравилось, что для оператора & нет проверки, что левый аргумент и результат указывают на один объект (ну чтобы с нуля строку не копировать), но тут, я так понял, в языке нет способа проверить это.
Я не смог определить оператор ":=>[]" (ну захотелось красивый оператор завести), но это ладно, баловство.
Ещё не получилось сделать так:

generic
type KeyBase is (<>); -- любой дискретный тип
...
-- где-то тут определяется aNode, не суть;
...
type KeyArr is array (KeyBase) of aNode;


Пишет что тип не определён.
А очень хотелось бы, что делать?

Ещё я не понял, чем отличается access от access all (если честно, я даже забыл, на какой странице это написано).
volvo
Чтоб среда не ругалась на кириллицу, я себе переключил в настройках IDE Character Set в "Unicode UTF-8". Ну, или с кодировкой отдельно взятых файлов поиграйся (правой кнопкой мыши в редакторе -> Properties)

Цитата
Я не смог определить оператор ":=>[]"
А тут вообще ничего нельзя определить. Можно только переопределить. Это большая разница.

Цитата
Не понял константу Standard'Maximum_Alignment (не нашёл описание).
Странно. У Гаввы на 387 странице есть описание:
Цитата
Standard’Maximum_Alignment где Standard — единственно возможный префикс. Предоставляет максимальное пригодное значение выравнивания для целевой платформы. Это статическое значение которое может быть использовано для указания требуемого выравнивания объектов. При этом во всех случаях будет гарантироваться правильность выравнивания объектов Это может быть полезно при импортировании внешних объектов, когда требования для их выравнивания не известны.


Цитата
Ещё не получилось сделать так:
Где именно ты пытаешься описывать KeyArr? Внутри пакета? Или снаружи? Или это у тебя вообще не пакет?

Цитата
Ещё я не понял, чем отличается access от access all
Тип access позволяет тебе ссылаться только на объекты, размещенные в динамической памяти. Обратиться к статической переменной ты через него не сможешь. То есть, смотри:

procedure Main is
type Int_Ptr is access Integer;
type Int_Ref is access all Integer;

AI : aliased Integer; -- косвенно доступная переменная. Статическая !!!
P_Ptr : Int_Ptr;
P_Ref : Int_Ref;
begin
-- попробуем получить ссылку на AI через Int_Ptr
P_Ptr := AI'Access;
-- Облом: access - только для дин. переменных

-- А теперь ссылку на AI через access all ?
P_Ref := AI'Access;
-- Все нормально, ошибки нет...

-- ...
end Main;
TarasBer
> Где именно ты пытаешься описывать KeyArr? Внутри пакета? Или снаружи? Или это у тебя вообще не пакет?

Да, это пакет.
Да, внутри пакета.

При загрузке я выбрал "открыть существующий проект" и убрал галочку "показывать при каждом запуске", думая, что сохранится последний выбранный вариант. Вместо этого среда (при запуске) создаёт новый файл, диалог открытия показывает по умолчанию "мои документы" (директорию не запоминает), после долгого блуждания по папкам и открытия проекта при попытке компиляции выдаёт gnatmake -d -P C:\Documents\ and\ Settings\ТарасБ\default.gpr (и не находит его там, понятное дело), хотя файл был открыт в другой папке. Откуда привязка к "моим документам"?

Добавлено через 7 мин.
Так, про описание типа проехали, после подробного описания всего подряд компилятор таки съел массив с диапазоном неизвестного типа.
Осталась проблема с папками по умолчанию.
volvo
Открой GPR-файл своего проекта (можешь просто текстовым редактором, можешь - правой кнопкой мыши по корневому узлу дерева, там Project -> Edit sources file), и посмотри, что указано в use у Object_Dir. Если там указано "C:\Documents and Settings ..." - то просто зайди в свойства проекта и поменяй на вкладке Objects путь к папке, в которой проект будет собираться...
Гость
Покорение отладчика пока не удалось.
No symbol table is loaded. Use the "file" command.

Если при компиляции ошибка, то он не перекидывает сам на ошибку, приходится искать вкладку Locations, листать её вниз и среди всех сообщений искать те, что относятся к последней компиляции.

На мониторе 1024 на 600 меню занимает слишком много места (на код остаётся... треть высоты!). Окно с сообщениями тоже пестрит информацией, среди которой не найти нужную.

По поводу автотипов. Я так понял, слова Initialize, Adjust и Finalize зашиты в язык?

И почему-то ничего не выводит такой код:


-- auto.ads
package Auto is

type Auto is private;

private

with ADA.Finalization; use ADA.Finalization;

type Auto is new Controlled with record
null;
end record;

procedure Initialize(a: in out Auto);
procedure Finalize(a: in out Auto);

end package;

with ADA.Text_IO; use ADA.Text_IO;
with ADA.Finalization; use ADA.Finalization;

-- auto.adb
package body Auto is
procedure Initialize(a: in out Auto) is
begin
Put_Line("initialization");
end;

procedure Finalize(a: in out Auto) is
begin
Put_Line("finalization");
end;

end package;
-- test.adb
with Auto; use Auto;

procedure Test is
begin
declare
a: auto;
begin
null;
end;
end Test;


-TarasBer-
А, не, это опять что-то среда запускает только старый екзешник. То есть пытается.

[2011-01-26 11:44:22] Error while trying to execute C:\Program Files\ADA\projects\TEST\debug\test: not an executable

А сообщение не высветилось.

(для сравнения: так у меня настроена Д7, я и про размеры шрифта, полей, и про подсветку синтаксиса)

Нажмите для просмотра прикрепленного файла
TarasBer
И кстати, почему C:\Program Files\ADA\projects\TEST\debug\test
а не C:\Program Files\ADA\projects\TEST\test.exe
?

А то я в этих вкладках совсем запутался, к тому же там многие галочки друг друга дублируют.

Правка: перезапустил среду. Оказалось, что тот код не компилировался, но сообщения не выводились. Перекомпилил, наконец пошло.
volvo
Цитата
Покорение отладчика пока не удалось.
No symbol table is loaded. Use the "file" command.
Странно. Посмотрел сейчас на новом проекте. Если в настройках на закладке Switches установки вот такие:

Gnatmake -> (галка установлена)"Debug Information"
Ada -> (галка установлена)"Debug Information"
Ada Linker -> (галка установлена)"Debug Information" и (галка снята)"Strip Symbols"
, то дебаггер нормально запускается. В принципе, достаточно посмотреть в Messages, какая ком. строка выполняется при сборке программы. Если в вызове GCC присутствует ключ "-g", то сообщения "No symbol table is loaded" не будет.

Цитата
Если при компиляции ошибка, то он не перекидывает сам на ошибку
Это еще более странно. Не перебрасывать на Location и на первую из найденных ошибок в коде должно только в одном случае: у компилятора вообще нет претензий к программе. Но перед началом компиляции окно Locations должно очищаться. У тебя этого, по видимому, не происходит. А что вообще показывает окно Messages? Вот то, что я вижу у себя:
gnatmake -d -PF:\\Programs\\Ada\\forum\\forum.gpr main.adb --subdirs=debug -cargs -g -O0
gcc -c -g -gnatVn -gnat05 -gnata -g -g -O0 -I- -gnatA F:\Programs\Ada\forum\main.adb
main.adb:177:04: warning: variable "P_Ptr" is never read and never assigned
gcc -c -g -gnatVn -gnat05 -gnata -g -g -O0 -I- -gnatA F:\Programs\Ada\forum\myobj.adb
gcc -c -g -gnatVn -gnat05 -gnata -g -g -O0 -I- -gnatA F:\Programs\Ada\forum\mypck.ads
gnatbind -shared -I- -x F:\Programs\Ada\forum\debug\main.ali
gnatlink F:\Programs\Ada\forum\debug\main.ali -shared-libgcc -g -g -o F:\Programs\Ada\forum\debug\main.exe

[2011-01-26 12:04:32] process terminated successfully (elapsed time: 00.98s)

Более глобальный вопрос: путь к GNAT Studio в переменной PATH прописан? В каком состоянии галочка в Edit->Preferences->Jump to first Location?

Цитата
И почему-то ничего не выводит такой код:
Вот такой код не только ничего выводить не должен, он даже не откомпилируется. Вот так будет работать:
(auto.ads)
with Ada.Finalization; use Ada.Finalization;

package Auto is

type Auto is private;

private
type Auto is new Controlled with record
null;
end record;

procedure Initialize(a: in out Auto);
procedure Finalize(a: in out Auto);

end Auto;


(auto.adb)
with Ada.Text_IO; use Ada.Text_IO;

package body Auto is

procedure Initialize(a: in out Auto) is
begin
Put_Line("initialization");
end;

procedure Finalize(a: in out Auto) is
begin
Put_Line("finalization");
end;

end Auto;


(main.adb)
with auto; use auto;

procedure Main is
begin
declare
A : Auto.Auto;
begin
null;
end;
end main;



Вот чего выдало:
Нажмите для просмотра прикрепленного файла
(заодно, если что, размер окна - 1200*600. И что, меньше информации чем в Дельфи отображается?)
TarasBer
> Gnatmake -> (галка установлена)"Debug Information"
Ada -> (галка установлена)"Debug Information"
Ada Linker -> (галка установлена)"Debug Information" и (галка снята)"Strip Symbols"

Что-то много дублирующихся галочек.
Мне бы вообще в идеале хотелось два положения - полная отладка и полная оптимизация.

(посмотрел, у меня третья галочка, оказывается, не стояла, а первые две стояли).

> Это еще более странно. Не перебрасывать на Location и на первую из найденных ошибок в коде должно только в одном случае: у компилятора вообще нет претензий к программе.

У меня это бывает только после попыток запустить отладчик.

> Более глобальный вопрос: путь к GNAT Studio в переменной PATH прописан? В каком состоянии галочка в Edit->Preferences->Jump to first Location?

Галочка есть.

> Вот такой код не только ничего выводить не должен, он даже не откомпилируется.

Я это потом понял.

> Вот чего выдало:

А как ты убрал жирную панель с картинками? С остальным я, вроде, разобрался, убрав в отдельные вкладки.
volvo
Панель с картинками - это ToolBar, там есть комбобокс "Toolbar style", перекинь его в Hide_Toolbar, панель исчезнет.
TarasBer
(как-то комбобоксы странно выглядят).

Да, теперь места для кода стало достаточно.
Остался только вопрос - как же внутри реализован Controlled? Что у него за поля Prev и Next? И такие имена для процедур инициализации и финализации - это вшито в язык?
volvo
Цитата
Остался только вопрос - как же внутри реализован Controlled? Что у него за поля Prev и Next?
Это поля для типа Simple_List_Controller, который используется при организации списка контролируемых объектов. Открой файл \GNAT\{версия}\lib\gcc\i686-pc-mingw32\4.3.4\adainclude\a-filico.ads, и посмотри на описание этого типа.

Цитата
такие имена для процедур инициализации и финализации - это вшито в язык?
Да, это вшито. А что, хочется другие имена?
TarasBer
О, я сумел запустить отладчик.
Понравилось, что щелчок по адресу (в структуре с указателем) раскрывает его содержимое.
Но нельзя ли показ переменных сделать попроще?
А то нередко бывает список из 20 переменых.
Размещать их мышкой по полю не лучший вариант.

Да, ещё окно дизассемблера не хочет показывать код, но мне пока страшно туда смотреть - я хоть и понимаю, что все конструкции могут развернуться и скомпилироваться без лишнего, но их высокоуровневость пугает.

> Это поля для типа Simple_List_Controller, который используется при организации списка контролируемых объектов.

То есть мне это не нужно пока, я так понял.

> Да, это вшито. А что, хочется другие имена?

Нет, просто чтоб знать. Мало ли там какой-то хитрый хак используется в описании типа, тогда интересно, как его реализовали.
volvo
Цитата
Но нельзя ли показ переменных сделать попроще?
Вот чего нет - того нет. По крайней мере в GPL-версии. В GPS Pro с этим чуть лучше (там побольше скриптов на отладчик навешано), но она стоит столько, что лучше пользуйся GPL версией. Тем более, что расположение окон сохраняется между сессиями отладки. В большинстве случаев мне дома хватает "показать локальные переменные" и одну-две более глобальных.

Цитата
окно дизассемблера не хочет показывать код
Нормально оно показывает код
Нажмите для просмотра прикрепленного файла
(в настройках среды можно даже указать, сколько строк кода показывать).
TarasBer
Теперь мне понадобилось обойти излишне жёсткий контроль за процедурными типами.

один модуль

generic
type KeyBase is (<>);
type Value is private;

package Dictionaries is

type Dictionary is private;
type KeyArr is array (Positive range <>) of KeyBase;
type ItemFunc is access procedure(K: KeyArr; V: Value);

...

procedure EnumNodes(D: Dictionary; P: ItemFunc);
-- обойти словарь по алфавиту, для каждого узла применить P


основная программа

procedure Test is

package DCI is new Dictionaries(Character, Integer);
use DCI;

procedure OutPair(S: string; i: integer) is
begin
null;
end;

D: Dictionary;
begin
EnumNodes(D, OutPair'access);
end Test;


очевидно, что тип String совпадает с типом KeyArr, и что тип Integer совпадает с типом Value.
И я даже спокойно вызываю процедуры от KeyArr, передавая в них строковые константы (но неконстанты передавать не хочет почему-то).

Но тут выдало ошибку:

Нажмите для просмотра прикрепленного файла

Ещё нету ли в языке для каждого типа предопределённой константы, состоящей из нулей?
volvo
Ну, во-первых, Ада - это не Дельфи, для того чтоб описать переменную процедурного типа, передаваемую в другую процедуру, надо делать так:

   procedure EnumNodes(D: Dictionary;
P: access procedure(K: KeyArr; V: Value));


А во-вторых, пользуйся типом KeyArr из пакета, ты ж его определил.

   procedure OutPair(S: DCI.KeyArr; I: integer) is
begin
null;
end;


Цитата
Ещё нету ли в языке для каждого типа предопределённой константы, состоящей из нулей?
Нет. А зачем?
TarasBer
> procedure EnumNodes(D: Dictionary;
P: access procedure(K: KeyArr; V: Value));

Тут можно использовать анонимные процедурные типы в заголовке функции?!

> procedure OutPair(S: DCI.KeyArr; I: integer) is

Это проканало, только вместо Put(S) пришлось писать Put(String(S));

> Нет. А зачем?

Ну иногда в шаблоне надо инициализировать переменную неопределённого типа хоть чем-то. А FillChar типа не соответствует идеологии.

Ещё, по аналогии с Unbounded_String, нету ли в стандарте шаблонного Unbounded_Array для любого типа?

Также мне понадобились вещественные функции, умеющие работать с бесконечностями и не-числами без лишних проверок и исключений, я даже нашёл нужный модуль, но компилятор плюётся оранжевым и обещает страшные кары за его использование.

Ещё приходится извращаться с синонимами и сокращениями, чтобы не было совпадений в имени типа, имени пакета, имени переменной, константы перечислимого типа. Соглашения есть какие-нибудь, например, пакеты с буквы P, типы с буквы T (в Дельфи это удобно было), константы перечислимого типа - с заглавных букв названия типа, указатели на типа - с буквы A?


package pDemo is
type tDemo is (dDemo, dRelease, dTest);
type aDemo is access TDemo;
Demo: tDemo;

volvo
Цитата
иногда в шаблоне надо инициализировать переменную неопределённого типа хоть чем-то.
Пишется функция, возвращающая определенное значение для определенного типа, и передается в пакет при инстанцировании.

Цитата
Тут можно использовать анонимные процедурные типы в заголовке функции?!
Более того, только подобное описание будет работать при любом раскладе. Если ты предварительно опишешь тип, а потом будешь его использовать в заголовке (дельфийская практика), то даже если это и заработает где-то в одном случае, всегда остается вероятность, что в других случаях это работать не будет. Конкретный пример приводил C. Okasaki, но найти его сейчас у меня не получилось...

Цитата
Ещё, по аналогии с Unbounded_String, нету ли в стандарте шаблонного Unbounded_Array для любого типа?
Вообще-то в стандарте и Ada.Containers.Ordered_Maps и Ada.Containers.Hashed_Maps есть, это ж тебя не останавливает от написания своего Dictionary?

Есть Ada.Containers.Vectors, аналог std::vector из STL: http://www.martin.dowie.btinternet.co.uk/C...rs-vectors.html

Цитата
Соглашения есть какие-нибудь
И соглашения есть. Вот такие, например:
http://www.adaic.org/resources/add_content.../sec_3/toc.html
TarasBer
> Если ты предварительно опишешь тип, а потом будешь его использовать в заголовке (дельфийская практика), то даже если это и заработает где-то в одном случае, всегда остается вероятность, что в других случаях это работать не будет.

Тогда зачем вообще может понадобиться описывать такой тип?
Так, вспомнил.
При описании оконного класса (в задании оконной функции) проблем тут не будет?

> Вообще-то в стандарте и Ada.Containers.Ordered_Maps и Ada.Containers.Hashed_Maps есть, это ж тебя не останавливает от написания своего Dictionary?

Словарь я пишу свой, потому что:
1. Велосипеды полезны для общего развития и особенно для изучения языка.
2. Я пишу именно префиксное дерево (а не красно-чёрное дерево (Ordered_Maps) и не хеш-список (Hashed_Maps)) даже не для хранения данных по ключу (хотя у него очень высокая алгоритмическая эффективность), а для выделения самого длинного слова словаря, являющегося началом данной строки (или продолжением строки с определённой позиции).
То есть это именно словарь, а не карта.

В Дельфи меня парило, что этот словарь надо самому удалять, у меня даже были мысли делать его динмассивом, а вместо ссылок использловать номера потомков в массиве. Народ ещё рассказывал про хитрые приведения к интерфейсам (для автоудаления), я, правда, не знаю, насколько это обезопасит от мёртвых ссылок.
Ну и ещё (в Д7) я для универсальности (шаблонов-то нету) брал словарь строк из строк, а другие типы побайтово отображал в строку.

> Есть Ada.Containers.Vectors, аналог std::vector из STL: http://www.martin.dowie.btinternet.co.uk/C...rs-vectors.html

Спасибо.
volvo
Цитата
При описании оконного класса (в задании оконной функции) проблем тут не будет?
Нет, не будет. Вот это, кстати, тот случай, когда описание отдельного типа необходимо: смена соглашения о вызове. Для отдельно описанного типа Func_Type это делается
pragma Convention (Stdcall, Func_Type);

если имени типа нет, тогда как?
TarasBer
Ещё вопрос - есть ли тут аналог паскалевского with?
volvo
Нет, он здесь на фиг не нужен. При наличии возможности сделать
declare
R : SomeType renames Very_Long_Path_To_Rec;
begin
R.field1 := value;
-- ...
end;

паскалевский With теряет преимущества.
-TarasBer-
Посмотрел я Container.Vector.
Не нашёл двух функций (самых главных, наверное).
Array_To_Vector
и
Vector_To_Array
Поэлементно собирать неудобно.
И в доступе к элементу много проверок. Компилятор умеет ветки, состоящие только из выброса исключения, распознавать как проверки и выкидывать в неотладочной версии?

Разделено: Дискриминантные записи - GNAT + Отлов утечек памяти - GNAT
TarasBer
Новая проблема.
Я обнаружил утечку памяти у себя. Стал искать.
Нашёл.

Суть такая.
Есть процедура P(T: out aInteger);
Где-то внутри неё происходит T := new integer;
И где-то дальше (внутри неё) какая-то проверка на корректность выражения и выброс исключения.
Внешний код примерно такой:

PF.T := null;
P(PF.T);
что-то сделать с PF.T

И в деструкторе объекта PF прописано что-то типа if T /= null then Free(T);

Так вот, если внутри P кинуть исключение, то значение переменной PF.T, передаваемой внутрь процедуры, останется старым (как будто её не трогали)! И к объекту, созданному внутри, нет доступа и он повиснет в памяти - утечка.
То есть сопоставления внутренного out-параметра и внешней переменной как бы и нету, оно неявно копируется при корректном выходе из процедуры, а при некорректном внутренний объект висит.
Что делать?
volvo
Цитата
Так вот, если внутри P кинуть исключение, то значение переменной PF.T, передаваемой внутрь процедуры, останется старым
Во-первых, внутрь процедуры ничего не передается. out параметр - это ожидание, что процедура заполнит и передаст назад какое-то значение. Так что даже если ты инициализируешь чем-то PF.T перед тем, как вызвать процедуру, при выбросе исключения в PF.T все равно будет null. А во-вторых, такое поведение компилятора прописано в Стандарте языка:

Цитата(Ada RM 6.4.1)
After normal completion and leaving of a subprogram, for each in out or out parameter that is passed by copy, the value of the formal parameter is converted to the subtype of the variable given as the actual parameter and assigned to it. These conversions and assignments occur in an arbitrary order.
Согласно пункту 6.2 ссылочный тип - это тип, передающийся "by copy", а выброс исключения не может считаться "нормальным завершением программы"

Вывод: не передавать через out-параметры ссылочных (или любых других передающихся "by copy" типов), если подпрограмма может выбросить исключение. Как WorkAround (в твоем случае) - ловить в той же процедуре свое же исключение, освобождать память, и raise-ом отправлять дальше...

P.S. Отделил от темы кусок, связанный с поиском утечек, в отдельную тему...
-TarasBer-
Ну допустим, в моём случае, я разберусь как-то, что в случае исключения надо освободить память, как-то разберусь в этой вложенной рекурсивной структуре, где что надо освобождать в случае утечки. Но если мне дейтвительно снаружи нужно значение указателя (или целого) даже если выкинулось исключение? Есть ли оператор, который позволил бы прямо записать в наружные параметры результат? Аналогичный вопрос про return (и все языки, где он есть) - как одновременно выкинуть исключение и вернуть значение?

А вообще мысль с копированием переменной в стек хорошая - меньше неявных разыменований указателя, оптимизация...
volvo
По-моему, у кого-то неправильное понимание сущности исключений...

Цитата
Ada Model of Exceptions

<...>
To raise an exception is to abandon normal program execution thus drawing attention to the fact that the corresponding situation has arisen.

<...>
When an exception occurrence is raised by the execution of a given construct, the rest of the execution of that construct is abandoned; that is, any portions of the execution that have not yet taken place are not performed.
Поскольку возврат функцией результата - это завершающее действие (равно как и возврат out-параметров), и если ты хочешь исключение, ты должен его выбросить раньше, то ни функция ни процедура не завершат работу нормально, это будет исключительная ситуация, и текущая конструкция не выполнится. То есть, в Аде это технически невозможно. Не пользуются исключениями одновременно с возвратом значения. Либо одно, либо другое.

Максимум, что можно предложить - это в случае исключения забрасывать результат в глобальную переменную... Но это неверный дизайн.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.