i21sys/Docu.Полезные сведения/О процедурах и модулях.odc

О процедурах и модулях


*Простейшаяпрограммадляшкольногоурока
Какаяпроцедураглавная?
Чтотакоемодуль
Экспортпроцедуризмодуля
*Простейшийспособвызовапроцедурпокомандепрограммиста
Импортпроцедур
Загрузкамодулей
Выгрузкамодулей
Каквызыватьпроцедурыспараметрами


Простейшая программа для школьного урока

Сначала покажем два простейших примера, эквивалентных обычным программам в Турбо Паскале: Program0 и Program1 (примеры открываются кликом по гиперссылкам). В учебных сборках Блэкбокса от проекта Информатика-21 предусмотрена горячая клавиша Ctrl+F9, при нажатии которой происходит компиляция и выполнение программы (только компиляция вызывается нажатием Ctrl+K, где K латинское). В большинстве школьных ситуаций больше ничего знать не надо; сообщения Блэкбокса в Рабочем журнале вроде старый модуль ... выгружен, появляющиеся при нажатии Ctrl+F9, можно просто игнорировать.

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


Какая процедура главная?

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

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

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

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

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


Что такое модуль

Итак, вместо главной процедуры появляется важное понятие модуля. 

Понятие модуля настолько важно, что непосредственный предшественник Оберона язык Модула-2 (см. историюэтихязыков) получил свое название из-за того, что среди всех его отличий от старого Паскаля именно модули были наиболее принципиальным новшеством.

Модуль  своего рода упаковка, контейнер для процедур, скрывающий от внешнего мира (в том числе от других модулей) как их внутреннее устройство, так и вспомогательные процедуры. 
Это выражают, говоря, что модуль  единица инкапсуляции. 

Обычно процедуры из одного модуля логически связаны. В этом смысле модуль похож на обычную библиотеку программ. Однако связь между процедурами из одного модуля может быть более тесной, чем в обычной библиотеке.

Именно модуль компилируют, т.е. модуль  единица компиляции.

Именно модуль загружают и выгружают из оперативной памяти (т.е. модуль  единица загрузки; о загрузке модулей см. ниже).

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

Сам Блэкбокс  не что иное, как совокупность модулей. Причем нет никакой принципиальной разницы между модулями самого Блэкбокса и модулями, написанными и скомпилированными пользователем. Например, если выполнить команду меню Инфо, Загруженные модули, то откроется список модулей, находящихся в памяти компьютера в активном состоянии, т.е. ждущих вызова своих процедур (о вызове процедур см. ниже). Например, модули с именами, начинающимися на Ole или Host, являются родными модулями Блэкбокса, т.е. были написани его авторами (компанией Oberon microsystems, Inc.). А, например, модули с именами на i21 написаны участниками проекта Информатика-21 и содержат дополнительные средства, удобные в учебном процессе.

Еще раз подчеркнем, что компилируются и загружаются модули в сущности независимо друг от друга, а их связь (возможность вызывать процедуры одного модуля из процедур другого) полностью определяется и контролируется программистом (см. ниже об экспорте-импорте процедур из модулей). 
Это позволяет полноценно реализовать при создании программных систем важнейший принцип проектирования РАЗДЕЛЯЙ И ВЛАСТВУЙ. 

Этот принцип был известен еще в античном мире (лат: divide et impera, англ: divide and rule). О нём обычно вспоминают в негативном политическом ключе (ср. другой английский вариант перевода divide and conquer, т.е. разделяй и завоёвывай). Однако принцип имеет универсальное значение при проектировании сложных систем. Подробнее о нём можно почитать, например, на сайте проекта Информатика-21.

Заметим, что ни в одной из широко распространенных систем программирования  начиная от старых фортрана, Паскаля, C/C++ и кончая новыми Java и C#  нет такого же четкого и полноценного средства, как модули в Обероне/Компонентном Паскале. Попытки обойтись без модулей ещё ни разу не увенчались полным успехом  всё равно приходится вводить дополнительные понятия вроде пространства имен (англ: namespace), и всё равно полноценной замены модулям не получается. 
Например, не имея привязки процедуры к конкретному модулю, в том же Турбо Паскале получаем настоящую головную боль, когда изучаем текст какой-то программы, видим там вызов процедуры и пытаемся найти, в каком именно файле эта процедура определена.
В Обероне/Компонентном Паскале вызов процедуры всегда сопровождается именем соответствующего модуля: ИмяМодуля.ИмяПроцедуры, и для открытия соответствующего исходника обычно достаточно выделить имя модуля двойным кликом и нажать Ctrl+0 (или Ctrl+Shift+D для открытия документации к модулю). 

Независимость модулей проявляется в том, что компилятор каждый раз перемалывает в машинные команды исходный текст единственного модуля, не обращаясь к исходникам других модулей. 
Исходный текст модуля является единой синтаксической конструкцией, которая подчиняется правилам, описанным в Сообщении о языке Компонентный Паскаль (см. меню Справка > Сообщение о языке ...). Это объясняет смысл утверждения, что модуль является единицей компиляции.

Все модули должны иметь разные имена. Обычно лучше каждый модуль хранить в отдельном документе (файле с расширением .odc  сокращение от Oberon DoCument). 

В Блэкбоксе принята определенная дисциплина организации модулей: они группируются в так называемые подсистемы. Эта дисциплина не задаётся языком программирования и не является обязательной, это просто удобно. Подробнее об этом написано отдельно.

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


Экспорт процедур из модуля

По умолчанию процедура, содержащаяся в модуле, невидима извне, т.е. не может быть выполнена по команде пользователя или из других модулей. 
Чтобы сделать ее видимой извне, она должна быть экспортирована из своего модуля  т.е. отмечена значком экспорта (звездочка *) после имени процедуры в ее заголовке. 

Экспортированы могут быть любые из процедур модуля, и любая из экспортированных процедур может быть вызвана для непосредственного исполнения  например, с помощью т.наз. коммандера (см. об этом чутьниже),  или использована в других модулях.

И наоборот: те процедуры, которые не отмечены специально значком экспорта, не видны за пределами данного модуля  они спрятаны: при компиляции других модулей компилятор их не видит и поэтому их невозможно вызвать из других модулей. Обычно это вспомогательные процедуры (подпрограммы).

 Внутри модуля все процедуры видят и могут вызывать друг друга. 
 Вне модуля видно только то, что его разработчик сделал видимым.
Это раскрывает смысл фразы о том, что модуль является единицей упрятывания информации.
Когда компилятор компилирует некоторый модуль, то он создает для него особый символьный файл, в котором записана вся информация о всех экспортированных и только экспортированных процедурах. Такой файл создается автоматически в двоичном формате, не предназначенном для модификации вручную. Такие файлы имеют расширение .osf от Oberon Symbol File. Почитать информацию из символьного файла можно, открыв его в Блэкбоксе. При компиляции других модулей компилятор обращается только к символьным файлам уже скомпилированных модулей.
Символьный файл создается компилятором автоматически и проверяется тоже автоматически. Этим символьные файлы отличаются от header-файлов языков C и C++, где их надо создавать и использовать вручную, причем компилятор не имеет средств контролировать корректность этих файлов. При создании больших систем неизбежные ошибки в определении и использовании header-файлов являются причиной колоссальной головной боли программистов. 
В языках семейства Оберон эта проблема исключена в принципе.

Важно, что по умолчанию процедура спрятана. Чтобы сделать ее видимой, нужно выполнить специальное действие  экспортировать ее. 
Это важный элемент защиты от случайных ошибок: только разработчик модуля имеет право определять, к каким процедурам допустить внешних клиентов: 
Во-первых, неконтролируемый доступ к вспомогательным процедурам чреват ошибками. 
Во-вторых, защищая вспомогательные процедуры от несанкционированного доступа, разработчик сохраняет возможность перелопатить внутренность модуля (например, если он придумает более быстрые алгоритмы)  и при этом не опасаться, что перестанут работать другие программы.

Поэтому не нужно приобретать дурную привычку ставить знак экспорта на все процедуры подряд.

Посмотреть, что экспортирует некоторый модуль, можно следующим образом: найти (или напечатать) в любом документе Блэкбокса имя модуля (например, StdLog); выделить его (например, двойным кликом мышки); с клавиатуры выполнить команду Ctrl+D. Откроется новое окошко, в котором будет представлена информация об объектах, экспортированных из данного модуля.


Простейший способ вызова процедур по команде программиста

Экспортированную процедуру (предполагается, что соответствующий модуль был успешно скомпилирован) можно вызывать извне, в частности, по команде программиста. Для этого прежде всего нужно уметь однозначно указать нужную процедуру. Это достигается с помощью полного (или квалифицированного) имени процедуры: оно составляется из имени модуля, в котором определена процедура, и имени процедуры внутри модуля, причем два имени должны быть разделены (или соединены, кому какое слово больше нравится) обычной точкой. Например, StdLog.Clear  полное имя процедуры Clear из модуля StdLog. Таким образом, имя модуля играет роль фамилии для членов одного семейства  процедур: две процедуры из двух разных модулей могут иметь одинаковые собственные имена, но т.к. имена разных модулей (фамилии) всегда различны, то полные имена процедур тоже различны.

Рассмотрим вызов процедур без параметров. С такими процедурами работать проще всего и значительная часть команд меню реализована именно такими процедурами. Для них в Блэкбоксе есть специальное название  команды. 
Покажем, как их вызывать с помощью т.наз. коммандера (commander).

В любом текстовом документе Блэкбокса (обычно в том же документе, где хранится текст модуля, после точки, заканчивающей модуль, на новой строке) нужно нажать Ctrl+Q  что приведет к появлению в месте курсора черного кружка   и затем сразу полное имя процедуры-команды (т.е. процедуры, не имеющей параметров). После этого клик мышкой по коммандеру вызывает процедуру. Разумеется, модуль должен быть уже откомпилирован.

Например, в Блэкбоксе есть откомпилированный модуль StdLog, в котором собраны процедуры, управляющие рабочим журналом. В частности, в нем есть процедура-команда Clear, очищающая рабочий журнал. Вот конструкция с коммандером, позволяющая выполнить эту процедуру:

StdLog.Clear

Простейший способ вызвать процедуру с параметрами  добавить в тот же модуль (например, в конце текста модуля, после всех других процедур) простую вспомогательную процедуру без параметров, в которой зашиты нужные фактические параметры для вызова желаемой процедуры, и вызывать эту вспомогательную процедуру уже с помощью коммандера. Коммандер тогда удобно ставить в том же документе, в котором хранится модуль, в любом месте после точки, закрывающей модуль.
 
Если нужно поменять параметры, то достаточно поменять их в тексте вспомогательной процедуры и перекомпилировать модуль, а затем вызвать вспомогательную процедуру с помощью коммандера, при этом одновременно с кликом мышки нужно нажимать клавишу Ctrl (это объясняется ниже).

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

О других способах вызывать процедуры с параметрами рассказано ниже.


Импорт процедур

Итак, экспорт позволяет сделать процедуру P видимой за пределами ее модуля M. Но чтобы использовать ее в процедурах другого модуля M2, этот другой модуль должен импортировать модуль M. Это делается с помощью оператора импорта, стоящего в самом начале модуля, что выглядит примерно так:

MODULE M2;
	IMPORT  M, Math, StdLog;
и далее следует остальной текст модуля M2.

(Об определении оператора импорта см. Сообщение о языке ... в меню Справка.)

Присутствие имени модуля M в списке импорта модуля M2 делает все экспортированные процедуры модуля M доступными для использования во всех процедурах внутри M2. 

В Модуле-2 каждую процедуру нужно было импортировать отдельно. Практика показала, что такое усложнение себя не оправдывает.

Говорят, что модуль M2 является клиентом модуля M (ведь M посредством своих процедур предоставляет некий сервис, которым и пользуется M2  поэтому о нем можно говорить как о клиенте).

Вся информация об импорте данного модуля тоже указывается в его символьном файле. Благодаря этому система имеет возможность определять, какие модули могут потребовать модификации, если изменить что-то в одном из модулей системы. Если в нашем примере изменится модуль M, то модуль M2 также может потребовать соответствующей модификации.

Может иметь место и косвенная связь между модулями: если модуль M3 импортирует M2, то он тоже может потребовать модификации при модификации M. Другими словами, M3 связан с M косвенно, через M2. В любом случае система может отследить все связи между модулями по экспорту-импорту.
Кстати, циклические связи по импорту в Блэкбоксе запрещены.

Обратно, если модуль M4 не связан с модулем M по экспорту-импорту ни прямо, ни косвенно, то изменения в M никак не затронут M4, что весьма приятно, т.к. в противном случае пришлось бы модифицировать все модули системы вообще  весь смысл разделения системы на независимые кубики-модули был бы потерян.


Загрузка модулей

Нужно отчетливо понимать следующие важные свойства модулей: 

1	Модуль  не программа, которую выполняют, а контейнер для процедур, который целиком загружается в оперативную память, прежде чем вызываются его процедуры.
2	Модуль M загружается в память автоматически при определенных условиях (например, при первом вызове одной из его процедур с помощью коммандера, как уже описывалось; полный алгоритм загрузки модулей дан ниже).
3	После загрузки модуль остается в памяти до выгрузки по явной команде программиста.
Впрочем, Блэкбокс устроен так, что всё, что можно сделать через меню и с помощью горячих клавиш, можно выполнить и из программы на Компонентном Паскале.
4	Если вызывается процедура из модуля, который уже находится в памяти, то повторной загрузки модуля не происходит  он уже загружен,  а просто вызывается нужная процедура.
5	Компиляция новой версии модуля вызывает замену откомпилированного модуля на диске  но не в оперативной памяти: там будет оставаться старая версия модуля, если она была загружена и еще не выгружена.

Отсюда следует, что нужно уметь выгружать модуль из памяти. К этому мы вернёмся ниже.

Здесь подробнее рассмотрим алгоритм загрузки модулей: 
1) Чтобы загрузить модуль M, система сначала проверяет, нет ли его уже в оперативной памяти. Если он там есть, то загрузка на этом и заканчивается.
2) В противном случае нужно сначала обеспечить, чтобы были загружены все модули, указанные в инструкции IMPORT/ПОДКЛЮЧИТЬ, стоящей в начале модуля M. С этой целью для каждого модуля в списке импорта выполняется загрузка по этому же алгоритму (процедура загрузки не может зациклиться, так как циклический импорт в Обероне/Компонентном Паскале запрещён, и выполнение этого требования проверяется ещё компилятором). 
В случае школьных программ из одного модуля все нужные модули чаще всего уже находятся в памяти, так что этот шаг сводится к проверке присутствия нужных модулей в памяти.
3) После того, как все модули из списка импорта M найдены/загружены в память, происходит собственно загрузка M. 
Именно в этот момент выполняется т.наз. связывание или редактирование внешних связей модуля M (linking). После этого процедуры модуля M знают реальные адреса в памяти всех процедур из других модулей, к которым они обращаются, так что вызов этих процедур из M не требует никаких накладных расходов по сравнению со старой схемой, применяемой в фортране, С и т.д. и известной как статическое связывание (static linking) в отличие от только что описанного и применяемого в обероноподобных системах динамического связывания (dynamic linking). 

Приведенный алгоритм загрузки активизируется при попытке вызвать процедуру из модуля M с помощью коммандера (как описывалось выше) или через меню Блэкбокса. Если такой вызов происходит из процедуры в уже загруженном модуле B, то M уже заведомо находится в памяти.


Выгрузка модулей

Выгрузить модуль из памяти означает, грубо говоря, стереть его из памяти так, чтобы место, которое он занимает, можно было использовать, например, для загрузки каких-то других модулей  или для загрузки новой, усовершенствованной версии этого же модуля.

Как мы уже говорили, модуль остается в памяти после того, как закончено выполнение процедур, ради которых он был загружен. Но при разработке нового модуля нужно уметь вызывать новые версии этого модуля взамен старых, уже находящися в памяти. Для этого надо уметь выгружать модуль из памяти.

Простейший случай. Мы уже рассматривали простейший случай, когда с самого начала работают с единственным модулем, а процедуры из него выполняют с помощью коммандера. В этом случае тонкостей загрузки и выгрузки знать не надо, а достаточно просто при клике по коммандеру нажимать клавишу Ctrl  это эквивалентно приказу системе выгрузить разрабатываемый модуль из памяти перед вызовом желаемой процедуры. Вот пример вызова некоторой процедуры из уже скомпилированного модуля (её смысл нам здесь не важен):

i21sysHello.Do

Если кликнуть по коммандеру, то в рабочем журнале будет что-то напечатано.
Если теперь кликнуть по коммандеру при нажатой клавише Ctrl, то в рабочем журнале сначала появится строка:

i21sysHello unloaded
или
i21sysHello выгружен

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

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

Причина: старая версия модуля не была выгружена из памяти.

Неправильное решение: сохранить модуль, закрыть Блэкбокс, снова запустить Блэкбокс, запустить процедуру из новой версии модуля.

Правильное решение: прижать клавишу Ctrl и, не отпуская её, кликнуть по коммандеру. Это вызовет предварительную выгрузку из памяти вызываемого модуля.


Однако если в дело вовлечено два и более модулей, связанных отношениям экспорта-импорта, то ситуация сложнее.

Сложные случаи.  Прежде всего нужно четко уяснить, что выгрузить можно только модуль, у которого нет клиентов в памяти. Напомним, что если модуль A импортирует модуль M, то A называется клиентом модуля M. 
Если M находится в памяти, то вовсе не обязательно, что A тоже находится в памяти. Если A нет в памяти, то модуль M выгрузить можно. Но если A загружен в память, то выгрузить M нельзя  предварительно нужно выгрузить модуль A.
В этом и заключается трудность, которую мы здесь обсуждаем.

Как проверить, какие модули находятся в памяти?
Для этого есть команда меню Инфо > Загруженные модули.
По этой команде открывается окошко, в котором дан список всех модулей в памяти, причем в третьей колонке указано количество находящихся в памяти клиентов данного модуля. 
В этот момент можно выгружать только те модули, у которых в третьей колонке стоит 0. 
Закрыть окошко (как и все окошки в Блэкбоксе) можно обычным способом  нажав на клавиатуре комбинацию двух клавиш Ctrl+F4.

Выгрузить группу модулей, связанных отношениями экспорта-импорта, можно несколькими способами. Один из самых удобных и простых для объяснения состоит в следующем.

Пусть мы работаем с двумя модулями  M и A, причем A является клиентом M (т.е. список импорта в A содержит M).
Например, M содержит процедуру сортировки, а модуль A содержит для нее тесты.
Пусть мы выполняли тесты, так что оба модуля находятся в памяти.
Предположим, что других клиентов у M в памяти нет.
Далее пусть мы обнаружили ошибку в M, исправили ее в исходном тексте модуля и скомпилировали модуль.
Чтобы выполнить новую версию, нужно выгрузить сначала A, потом M.

Простейший способ сделать это состоит в том, чтобы в любом документе Блэкбокса (можно в новом, а можно в том же, где хранится текст модуля A, после точки, закрывающей текст модуля) поставить следующую конструкцию:

DevDebug.UnloadThis A M

Здесь между двумя коммандерами стоят: полное имя некой специальной процедуры Блэкбокса, а затем через пробелы имена тех модулей, которые мы хотим выгрузить,  в правильном порядке. То есть если A импортирует M (M появляется в списке импорта A), то A стоит сначала.
Правый коммандер играет просто роль ограничителя  указывает конец списка выгружаемых модулей.
Клик мышкой по левому коммандеру вызовет выгрузку сначала A, потом M.

Следует внимательно просмотреть сообщения в рабочем журнале после выполнения выгрузки, чтобы удостовериться в успешном её выполнении.

Если работают более чем с двумя модулями и нужно их все выгрузить, то имена всех модулей следует вставить, разделяя пробелами, там же, где стоят A и M.
Важно только соблюдать порядок: если A  клиент модуля M, то A должен стоять левее, чем M. В остальном порядок произволен.


Обратим внимание еще на следующее.
В ситуациях, подобных описанной (модуль сортировки M и модуль с тестами A), после перекомпиляции M обычно нет нужды заново компилировать модуль-клиент A, если в нем ничего не менялось. Но если изменились оба модуля, то компилировать их нужно точно в обратном порядке по сравнению с выгрузкой: сначала M, потом его модуль-клиент A.

Вот полезная конструкция, аналогичная приведенной для выгрузки, которая позволяет одним кликом мышки перекомпилировать пару модулей:

DevCompiler.CompileThis M A 

Устроена она точно так же, но имена модулей стоят в обратном порядке.
Нужно только помнить, что процедура DevCompiler.CompileThis сумеет найти тексты модулей только в том случае, если они хранятся на диске в соответствии с правилами, принятыми в Блэкбоксе (см. здесь).


Как вызывать процедуры с параметрами

Во-первых, можно делать дополнительную интерфейсную процедуру без параметров, в которую зашиты фактические параметры для тех процедур, которые мы хотим выполнять. Например, можно включить такую процедуру в отдельный модуль, назовем его T. 
Такой отдельный модуль будет компилироваться очень быстро. 
Нужно только не забывать нажимать Ctrl при вызове процедур из T с помощью коммандера после изменения данных в T и его перекомпиляции (основной модуль ни перекомпилировать, ни выгружать не нужно  разумеется, если там не нужно исправлять ошибки).
Фактически модуль здесь играет роль диалоговой формы, в которую впечатываются значения параметров. Это возможно только благодаря быстроте компилятора и возможности динамической (пере)загрузки модулей.

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

С помощью коммандера можно вызывать процедуры, у которых:

	нет возвращаемого значения;
	всего не более четырех параметров, из них
	не более двух параметров типа ARRAY OF CHAR, передаваемых по значению или определенных с атрибутом IN, а также
	не более двух параметров типа INTEGER;
	причем параметры типа ARRAY OF CHAR должны идти до параметров типа INTEGER.

Все возможные комбинации параметров явно перечислены в документации к модулю StdInterpreter (двойной клик по имени модуля, правый клик, Документация).

В этом случае достаточно после коммандера в кавычках поставить вызов нужной процедуры с параметрами в скобках точно в таком виде, как в программе на Компонентном Паскале:

"StdLog.String('эта цепочка литер напечатается в рабочем журнале')"

Пример возможных проблем. В случае клика по следующему коммандеру:
"StdLog.Int(123)"
в рабочем журнале вместо целого числа 123 будет напечатано сообщение об ошибке. 
Причина: процедура StdLog.Int требует параметра типа LONGINТ, а коммандеры "умеют" вызывать только процедуры с параметрами типа INTEGER.
В тексте программы такая команда допустима, так как компилятор "умеет" обеспечивать вызовы любых процедур, допустимых в языке. 

Третий и самый гибкий способ  передать данные в программу непосредственно из текста, например, после коммандера  основан на использовании средств модуля In (или i21sysIn). 
По этому поводу см. здесь, а также документациюкмодулюi21sysIn.




________________
info21@inr.ac.ru
последние уточнения: 2012-10-22