soft :: субд

СУБД Cache. Программы


СУБД Cache. Программы Продолжим наше повествование о СУБД Cache. В меню Cache-куба есть пункт Терминал. Это приложение, организующее работу с базой данных в текстовом режиме, является эмулятором консоли и служит, как правило, для тестирования и отладки программ. При запуске Терминала появляется простое текстовое окно с приглашением для работы на языке Cache Object Script. Само приглашение указывает, в какой области на данный момент идет работа. Пример рабочего окна с командой вывести текущую версию Cache Objects и результатом ее выполнения показан на рис. 1.

Работая в командной строке Терминала Cache, вы получаете доступ к работе с утилитой ^%apiOBJ и специального объекта %System, предоставляющих разработчику различные API-вызовы программного окружения Cache Objects.
Рассмотрим вопрос загрузки и компиляции классов из CDL-файлов. Практически все команды в Терминале интуитивно понятны знающему английский язык человеку. Так, например, эти две строки загружают файл с определением класса:
Set status=$System.OBJ.LoadFile (_filename,_flag)
Do LoadFile^aipOBJ(_filename, _flags,_errlog).
Следующий вариант более общий — он загружает все файлы, содержащиеся в определенной директории:
Set status=$System.OBJ.LoadDir (_dir,_flags)
Do LoadDir^aipOBJ(_dir,_flags, _errlog).
Отдельно стоит остановиться на передаваемых параметрах _filename, _flags и _errlog. И если с первым параметром все ясно — он содержит путь к необходимому CDL-файлу, то второй определяет режимы компиляции классов, которых всего восемь. Приведу некоторые из них.
Флаг "а" — в этом режиме компилируются только прикладные классы, то есть те, у которых не задан параметр System. Действует по умолчанию, если не указано иное.
Флаг "u" — компиляция проводится только для тех классов, которые в этом нуждаются, то есть редактированные с момента последней компиляции.
Флаг "d" — выводить информацию о ходе процесса загрузки, компиляции или экспорта на экран. Действует по умолчанию. Третий аргумент errlog представляет разработчику инструмент для обработки ошибок, обнаруженных вызовами API. При работе с API-вызовами необходимо снабжать их параметром errorlog. После выполнения переменная errorlog (параметр передается по ссылке: .errorlog) содержит информацию о количестве ошибок и отдельные сообщения в формате типа errorlog(индекс)=сообщение, очень похожем на тот, что выдается компиляторами от Борланд или MSVS. В случае, если сообщения об ошибках нет необходимости выводить на экран, а лишь возвращать в локальной переменной, необходимо отключить флаг "d". Простейший пример показан на рисунке 2.
Собственно, переменная error нам все и сообщила — код ошибки, сообщение об ошибке, количество параметров и сам параметр.
Но это далеко не полный список возможных операций в Терминале Cache. Кроме создания и компиляции классов, так сказать, input`a, предусмотрен еще и output. Существует несколько способов удаления одного класса или всех классов из конкретной области. Удаление одного класса осуществляется так: Do Delete^%apiOBJ (_classname, flags, errorlog). Удаление классов, входящих в определенный пакет package, происходит так: Do DeletePackage^%apiOBJ(classname, flags). Если нужно удалить все классы, в том числе и их сгенерированные программы, используйте Do DeleteAll^%apiOBJ(). Кстати, для всех приведенных выше примеров удаления классов удаление сгенерированных программ будет также верно.
Ко всему вышесказанному необходимо добавить пару слов о косвенных вызовах. Коль скоро пошел разговор об отладке программ в Терминале Cache, для тестирования можно использовать и косвенный вызов метода объекта. Осуществляется это через указание класса class, экземпляра класса objref и вызываемого метода method с использованием параметров param1, param2 и т.д.: Do Method^%apiObj(class, objref,method,param1,param2,...).
До этого момента все, что было использовано нами, представляло собой просто отрывки кода, тестовые конструкции, направленные все лишь на визуальное подтверждение написанного словами. Однако, рано или поздно необходимо переходить от простого к сложному. Обратимся к Cache Studio, среде разработки программ, и для начала рассмотрим типы программ в Cache, так как тут их несколько.
В программах СУБД различают макрокод (*.MAC — текст, который может содержать Cache Object Script, макросы, макродирективы, встроенный SQL и даже HTML). Компилируется в промежуточный код, а тот потом — в объектный). Включаемые макропрограммы (*.INC — также разрешен любой код, доступный в MAC-программах). Применяются для построения библиотек, которые потом могут быть использованы в макропрограммах. Промежуточный код (*.INT — рабочий код Cache ObjectScript). Макросы и встроенный SQL из предыдущих двух типов программ сначала преобразуются в такой промежуточный код. Прежде чем выполнить промежуточный код, необходимо его откомпилировать в объектный код. Это происходит автоматически при сохранении отредактированной программы. Во время выполнения используется только объектный код, так как фирмы-производители программного обеспечения, как правило, тиражируют свои приложения именно в объектном коде.
Для написания и запуска программ в СУБД Cache предусмотрена еще одна оболочка, немного интерактивнее, чем Терминал. Впрочем, ее внешний вид явно "позаимствован" у MS Visual C++, да еще и страшно урезан. Такой строгий, без капли лишнего, интерфейс Cache Studio называется разработчиками графическим редактором, позволяющим комфортно создавать макропрограммы, включаемые макропрограммы и программы в промежуточном коде, а также компилировать их в исполняемые объектные коды. В частности, на рисунке 3 показано окно Cache Studio с открытым в ней файлом из стандартной поставки этой СУБД.
Основной структурой в программе в Cache являются индивидуальные блоки кода. Они создаются и редактируются как исходный код и при сохранении автоматически компилируются в особую объектную форму, не являющуюся машинным кодом и независимую от платформы. Стоит заметить, что тут четко прослеживается аналог с MS Visual C++. Не только в плане визуальной среды разработки, но и в плане функционирования всей системы программ. Структура программы довольна проста. Программный код отделяется от комментариев точкой с запятой или двумя, есть С-совместимые комментарии. Допускается наличие пустых строк, за исключением первой строки программы. Так же, как и в развитых языках программирования, команда может быть расположена или в нескольких строках программы, если она достаточно громоздка, или в одной. Ограничение на длину сроки — 4К (интересно, такие вообще у кого-либо получались при создании программ?).
Индивидуальные блоки кода, как уже говорились выше, — основа программ в Cache Studio. Различают точечные блоки, вызываемые при помощи команды Do без аргументов; процедурные блоки, которые представляют собой несколько строк кода, заключенных в фигурные скобки; командные конструкции условного выполнения программы, основанные на языковых элементах, эквивалентных применяемым в Java, C, C++. Что-то сродни процедурному структурированию, но об этом будет рассказано позже. Пока же достаточно считать, что командные конструкции — это обыкновенные логические операторы и процедуры.
Точечные блоки называются так потому, что после команды Do без аргументов строки должны начинаться с одной или нескольких точек и со следующей за командой Do строки. Точечные блоки как бы расширяют область действия программной строки. Инициализация такого блока происходит посредством команды Do, при этом счетчик вложенности (так называемый Do-стек) увеличивается на единицу. Далее идет перечисление команд в строках, начинающихся с символа "." — точка. В случае наличия еще одной безаргументной строки Do, то есть необходимости выделить в отдельный блок некое количество строк внутри уже существующего блока, все следующие за вторым Do строки должны начинаться с "..". Проще говоря, какой степени у вас вложенный блок безаргументного Do, столько точек перед строкой и ставьте. Однако не забывайте, что при введении в текст программы комментариев они должны начинаться с того же количества точек, что и строка программного кода, к которой комментарий относится, иначе может быть вызвано автоматическое завершение блока. Кроме того, в каждом блоке служебные переменные независимы — переменные $Test из первого блока недоступны из второго и наоборот, то есть их значения не передаются наружу.
Пример ниже иллюстрирует также неявное завершение вложенного безаргументного Do второго уровня:
<code>
Do
.
.<Code> //делаем тут что-то, что нам нужно
.
.Do
..
.. <Code> //тут — второй уровень вложенности
..
. //неявное завершение предыдущего Do второго уровня — количество точек изменилось
.
//отсутствие точки — основной блок программы
Quit

Следующий тип блоков — процедурный. Работа с процедурами немыслима без локальных переменных. Не буду вдаваться в подробности концепции области видимости переменных. Схема доступа к переменным внутри процедур и вне их такая же, как и в любом объектном языке программирования. Синтаксис процедуры следующий:
<procedure name> (<formal param list> ) [<public param list> ] <access>
(
code here ...
)
Интерес, пожалуй, может вызвать только наличие общего списка переменных и ключевое слово <access> , отвечающее за то, можно ли вызвать процедуру из других программ или нет. Процедура, объявленная как public, может быть вызвана из других программ. Но по умолчанию, если не указано иначе, процедура объявляется как private.
В самой процедуре переменные также могут быть общедоступными или внутренними. Переменные, описанные в <public param list> , являются общедоступными. Все остальные локальные переменные, использованные в процедуре, считаются по умолчанию внутренними. Даже если <public param list> пуст и его можно опустить, предыдущее предложение остается верным. В дополнение ко всему этому внутренние переменные при входе в процедуру не определены, а при выходе из нее автоматически уничтожаются.
В качестве описания управляющих конструкций приведу основные правила для блоков кода. Существует несколько правил, которым подчиняются все блоки кода внутри управляющих конструкций. Вход в управляющую конструкцию может осуществляться только в ее начале, но не на метку внутри ее; аналогично, вход в блок кода должен выполняться только в начало "{". Использование Goto внутри блока допустимо, только если переход осуществляется: внутри того же блока; в блок кода, внутрь которого вложен текущий блок; на строку вне всех блоков кода.
Конечно, все нюансы и особенности написания программ, правила обработки информации нельзя перечислить в одной статье. Лучше сейчас заняться практикой — попробовать создать небольшое приложение, написать немного исходных кодов, тем самым подытожив обе статьи и получив маленький практический опыт.
Начнем, пожалуй, с самого простого примера — "Hello, world!". Сразу усложним задачу, чтобы получить не просто приветствие, а приветствие с упоминанием имени сидящего за компьютером.
Ниже приведен код программы с пояснениями для каждой строки:
hello; процедура вывода приветствия с использованием
; только что введенного имени
read "Введите ваше имя:", name
write!, "Привет, ", name, ", как твои дела?"
end quit; завершение работы программы
Первое слово "hello" обозначает метку (имя) программы. Как уже говорилось, однострочные комментарии отделяются от кода программы точкой с запятой. Далее идет набор простейших команд — "read", выводящая сначала приглашение и считывающая введенное пользователем имя в переменную "name". Затем исполняется вывод комбинированной строки с использованием только что введенного имени. Восклицательный знак означает, что вывод необходимо начать с новой строки. Перечисленные через запятую строковые константы и переменные выводятся командой "write" последовательно в одну строку. Далее, программа завершается оператором "quit", после которого должно стоять обязательно два пробела, так как эта команда передается баз параметров. В этой же сроке присутствует метка "end", которая говорит о завершении программы. Для выполнения программы необходимо в Cache Studio нажать Ctrl+F7 для компилирования программы, а потом сохранить файл в области USER, впоследствии именно оттуда мы будем его запускать на выполнение. Пример выполнения программы можно увидеть на рис. 4.
После компиляции программы и сохранения ее в файле с именем hello01.MAC автоматически создается файл с расширением INT, который и используется при исполнении программы. На рисунке 4 показан результат работы программы в окне Cache Terminal. Сначала командой "Do" мы вызываем соответствующую программу, потом в ответ на ее предложение вводим имя и получаем строку приветствия. Экскурс в самый простейший пример закончен.
Вышеописанная программа, конечно, работала, но совершенно не использовала никаких логических конструкций языка программирования. В реальной жизни, к сожалению, это не совсем так. Следующая программа предлагает пользователю сыграть в маленькую занимательную игру — угадывание числа из заранее определенного промежутка от 10 до 99. Для начала она "загадывает" число, потом просит игрока ввести свой вариант. В случае "попадания" — игрок выиграл, иначе интервал отсекается по числу игрока и границе промежутка так, чтобы "загаданное" программой число осталось внутри этого промежутка.
Разберем эту программу построчно:
guessnum; программа угадывания числа, загаданного компьютером
write "Добро пожаловать! Сейчас программа загадает число и начнет с Вами играть."
set usernum = -1
set guessflag = 0
set left = 10
set right = 99
set compnum = $Random(89) + 10
Вышеописанные строки — начальные данные программы. По порядку это: номер, который выбрал игрок, флаг отметки об угадывании пользователем номера компьютера, левая и правая границы и, наконец, загаданное компьютером число. Функция $Random является системной (встроенной), поэтому перед ее именем употребляется знак "$". Полный список системных функций можно найти в Cache ObjectScript Language Reference.
while (guessflag = 0)
{
read!, "Пожалуйста, введите Ваш вариант числа:", usernum
До тех пор, пока пользователь не угадал номер, продолжать спрашивать число у игрока.
If (usernum '= compnum)
{
if (usernum < left) || (usernum > right)
{write!!,"Вы пытаетесь обмануть программу! Я больше не хочу с Вами играть!"
quit;выход, если игрок пытался завалить программу}
Обязательная защита от "дурака". В том случае, если пользователь попробует подсунуть игре значение, выходящее за рамки установленного интервала, программа скажет о нежелании больше играть и завершит работу.
if (usernum > left) && (usernum < compnum) {set left = usernum}
Рассмотрим вариант, когда указанное игроком число меньше загаданного. Тогда необходимо сократить интервал слева.
if (usernum < right) && (usernum > compnum) {set right = usernum}
В ином случае — сократить интервал справа.
write!, "Вы не угадали, но промежуток сократился: ", left, "..", right}
Вежливая просьба продолжить игру с указанием диапазона чисел для тех, кто закрылся в системном блоке.
else
{ write!!!,"Вы победили! Вы угадали число ", compnum
set guessflag = 1}
Программа рукоплещет счастливому победителю и освобождает его от обязанности дальше угадывать числа путем завершения своей работы.
}
end quit; завершение работы программы
Моя игра в качестве примера представлена на рисунке 5. На нем видна вся последовательность моих действий. Тактика тут проста: пока промежуток достаточно большой, лучше выбирать всегда середину интервала; когда же останется буквально несколько чисел — тут уж вам угадывать и решать. Но я отвлекся от главной темы — СУБД Cache, о которой и шел разговор.
Далее, думаю, стоит рассказать немного об обработке ошибок. При работе с любым языком программирования они возникают неизменно. Ведь, как известно, если программа работает без ошибок, значит она коренным образом неправильно написана.
Понятие "обработка ошибок" довольно широкое, и это подтверждает приличное количество терминов, обозначающих одно и то же: Error handling, Error processing, Error trapping, Exception handling. Вообще же говоря, все эти термины обозначают ряд мер, принимаемых разработчиком в программе на случай возникновения какой-либо ошибки, которая может привести к аварийному завершению работы программы. Нет известнее примера, чем деление на 0. Думаю, каждый программист хоть раз, но сталкивался с такими ошибками. Даже очень известные и "правильные" программы при определенных условиях могут аварийно завершаться.
В СУБД Cache поддерживается так называемая методика непосредственного режима отладки. Она реализована с помощью команды Break, которая позволяет перейти в режим программиста или отладчика.
Конечно, отладка невозможна на компьютере клиента. Более того, в таких системах лучше всего сохранить как можно больше информации о контексте, в котором возникла ошибка, и продолжить выполнение программы далее с определенной точки. Cache предоставляет разработчику возможность написать какой угодно код для выполнения в случае ошибки. Как правило, это специальная подпрограмма обработки ошибок, которая может сохранять условия, место возникновения ошибки и полную информацию о текущем состоянии процессов.
Как это работает? При возникновении ошибки СУБД помещает их в специально для этого зарезервированные переменные $Ecode и $ZЕrror. Программа обработки ошибок может использовать содержимое этих переменных в целях принятия решений. В переменную $Zеrror помещается строка, содержащая наименование ошибки и ее местоположение — метку и имя программы. $Ecode, напротив, содержит стандартизированный по ANSI код ошибки. Кроме того, существуют еще специфические коды ошибок, свойственные Cache, которые начинаются с "Z", плюс к этому программист может определять свои коды ошибок, которые должны начинаться с "U". Инициализировать обработчик ошибок можно через любую из двух специальных переменных, $ETrap и $ZTrap, которые отличаются друг от друга. Первая содержит полную команду, выполняемую в случае ошибки, а вторая держит адрес, по которому происходит переход в случае ошибки. В случае спорного варианта использования переменных в программе преимущество имеет вторая, то есть $ZTrap.
С использованием этих переменных можно моделировать возникновение ошибки, проверяя правильность обработки особой ситуации, перехватывать ошибки (с помощью $ETrap), сохранять контекст ошибки с помощью $Stack (также системной переменной, которая дает информацию о действиях, которые привели программу к ошибке).
Вот, пожалуй, и все, что я кратко хотел рассказать о программах в Cache. Если вдруг у кого появится желание более подробно узнать о программировании в этой СУБД, попробуйте обратиться к справочной системе Cache ObjectScript Language Reference. Или пишите, хотя я не являюсь достаточно опытным пользователем Cache, чтобы "с куста" разбираться во всех вопросах, но чем смогу — тем помогу.

Денис "Denver" Мигачев dtm@tut.by



© компьютерная газета