Глава 3. Операторы.

Глава посвящена описанию конкретных операторов KLisp, но вначале следует отметить, что этот язык построен как открытая система,то есть количество и функциональное содержание операторов может быть изменено в зависимости от условий использования и решаемых задач. Как это дос- тигается ? Интерпретатор строится на основании базового класса С++ - Serv_KL, который осуществляет: - интерпретацию программного кода KLisp; - доступ к данным; - взаимодействие подпрограмм; - вызов операторных функций и передачу им параметров; - исполнение основных системонезависимых операторных функций. Внутренние операторы Serv_KL выполняют действия, определяющие специфику языка KLisp. Они разбиты на несколько групп: 1. Операторы внутрипрограммных переходов: (if ...) - Оператор условного выполнения. (cond ....) - Оператор условного переключателя. (while ...) - Оператор цикла. (break) - Оператор прерывания цикла. (continue) - Оператор перехода к проверке условия цикла. (metka Name) - Оператор установки метки в программе. (goto Name) - Оператор перехода на метку. 2. Операторы взаимодействия подпрограмм. (call ...) - Вызов подпрограммы. (gofunc ...) - Переход к подпрограмме. (return ...) - Выход из подпрограммы. 3. Группа операторов работы с указателями. (Adr ...) - Инициализация указателя адресом переменной. (Con ...) - Возврат содержимого указателя. (# ...) - Возврат адреса переменной. (>< ...) - Смещение указателя к элементу массива. (++ ...) - Смещение указателя по массиву вправо. (-- ...) - Смещение указателя по массиву влево. (Sm ...) - Значение смещения указателя по массиву. (## ...) - Инициализация указателя смещением в байтном массиве. (-> ...) - Смещение указателя по типам данных. 4. Группа операторов межпроцессорного взаимодействия (run ...) - запустить функцию в работу (wait ...) - установить режим ожидания процесса. (exit ...) - выход из процесса. Последнюю группу операторов мы рассмотрим в самом конце описания, так как ее значение требует очень глубокого анализа и этому посвящена специально выделенная глава. Класс Serv_KL содержит чисто ассемблерный код, то есть не требует наличия какой-либо операционной системы. Поэтому может быть использо- ван как базовый для построения иерархии порождаемых классов и встроен в любую исполнительную среду. В порождаемых классах пользователи име- ют возможность определить новые системозависимые операторные функции и с их помощью вести самостоятельную обработку данных,передаваемых из Serv_KL. В качестве примера был построен DOS ориентированный потомок class DOS_KL:public Serv_KL, который содержит набор операторных функ- ций работающих в операционной среде DOS. Эти операторы также разбиты на несколько групп по функциональному признаку. Вначале, условимся о форме описания операторов. Выглядит она так: (char)(оп1 (char Arg1) ...) --1-- -2- ----3---- ----4---- -5- в поле 1 - описывается тип переменной, возвращаемой оператором. Если оператор ничего не возвращает - пишется (non); в поле 2 - имя оператора, по которому его распознает транслятор; в поле 3 - аргументы, передаваемые оператору, если они есть,и их тип. Если для данного аргумента имеется умолчание и его можно не указывать, он пишется в скобках "< >" - поле 4; поле 5 - означает что переменных может быть произвольное количество и все они считаются значимыми. В случае возникновения каких-либо ошибок при выполнении оператора могущих повлечь ошибки при дальнейшем выполнении программы интерпре- татор устанавливает флаг Глобальной ошибки - ERR_KL, останавливает выполнение программы и, в зависимости от Вашей реакции, может аварий- но завершить процесс. При описании каждого оператора будет указано, какие ошибки считаются глобальными.

3.1. Операторы внутрипрограммных переходов.

Группа условных операторов if, while, cond имеет свою особенность написания. Это вытекает из их функционального назначения - разделять исполняемые блоки программы. Операторы if и while разделяют программу на два блока: Блок вычисления <условия исполнения> и блок < исполняе- мого тела>, поэтому перед этими операторами ставятся две левые скоб- ки и с учетом их закрытия определяются границы указанных программных блоков. Оператор условного переключателя cond разделяет программу на три и более блоков, поэтому он требует еще более сложной конструкции скобок. Итак, приступим к описанию операторов. Оператор условного выполнения (if ). Конструкция: ((if <условие исполнения>) <исполняемое тело> ) <условие исполнения> - Аргументы оператора if. Значащим является только первый аргумент, остальные игнорируются. Как отмечалось выше, аргументом оператора может быть любая переменная или произвольная языковая конструкция возвращающая значение, главное, чтобы внутри оператора соблюдалась парность закрытия скобок. Оператор if в качес- тве аргумента принимает переменную произвольного типа,кроме структур. Если это значение соответствует 0, то <исполняемое тело> обходится, то есть управление передается за вторую правую скобку оператора if. Обычно, в качестве <условия исполнения> используют конструкцию из логических операторов. <исполняемое тело> - Произвольная языковая конструкция. Оператор ничего не возвращает. Глобальные ошибки: Нет. Оператор условного переключателя (cond ). Конструкция: ( ((cond <условие исполнения 1>) <исполняемое тело 1> ) ((cond <условие исполнения 2>) <исполняемое тело 2> ) <безусловное исполняемое тело> ) Оператор расширяет функциональные возможности оператора (if ...), позволяя сделать выбор исполняемой части по нескольким условиям. Если <условие исполнения> истинно, то управление передается операторам его <исполняемого тела>, а затем происходит выход на конец конструкции. Если ни одно из условий переключателя не удовлетворено, исполняется <безусловное тело> в конце конструкции.Количество условий cond в этой конструкции не ограниченно. Оператор ничего не возвращает. Глобальные ошибки: Нет. Оператор цикла (while ). Конструкция: ((while <условие исполнения>) <исполняемое тело> ) Цикл позволяет повторять исполнение внутренних операторов до тех пор, пока будет истинно <условие исполнения>. Все что касается аргу- ментов оператора if, в полной мере относится и к while. В случае от- сутствия аргументов в операторе Конструкция: ((while) <исполняемое тело> ) мы получаем бесконечный цикл, который может быть завершен только опе- раторами break, goto или return. Оператор ничего не возвращает. Глобальные ошибки: Нет. Оператор прерывания цикла. (non)(break) ------------ Оператор прерывает интерпретацию операторов < исполняемого тела > цикла и осуществляет переход в конец его конструкции за вторую правую скобку оператора while. При использовании вложенных циклов, прерыва- ется только внутренний цикл. Запрещена вложенность внутри оператора. Оператор ничего не возвращает. Глобальные ошибки: Нет. Оператор перехода к проверке условия цикла. (non)(continue) --------------- Оператор прерывает интерпретацию операторов <исполняемого тела> и осуществляет переход к проверке <условия исполнения> цикла за вторую левую скобку оператора while. Запрещена вложенность внутри оператора. Оператор ничего не возвращает. Глобальные ошибки: Нет. Оператор установки метки в программе. (non)(metka Name) ----------------- Name - это не переменная, а имя метки, к которому будет ссылаться оператор (goto ...), поэтому оно не конфликтует с именами переменных. Нельзя устанавливать в пределах одной подпрограммы две метки с одина- ковыми именами. Метка может устанавливаться в любом месте операторной конструкции, но не вместо имени оператора. При передаче управления на метку, вычисления начинаются с того оператора чья правая скобка зак- роется первой. Запрещена вложенность внутри оператора. Оператор ничего не возвращает. Глобальные ошибки: Нет. Оператор перехода на метку. (non)(goto Name) ---------------- Name - имя метки. Передает управление той части программы, где установлена соответ- ствующая метка независимо от уровня вложенности. Запрещена вложенность внутри оператора. Оператор ничего не возвращает. Глобальные ошибки: Нет.

3.2. Операторы взаимодействия подпрограмм.

Организация исполняемой памяти KLisp - процесса коренным образом отличается от принятой в других языках программирования. При трансля- ции исходного текста, каждая программа формируется в виде единого блока содержащего и код и данные. При загрузке они размещаются после- довательно друг за другом сначала блока памяти процесса. Перед каждой подпрограммой располагается служебная KLisp-структура: ((struct progr) (char Nam[10]) (int DN[7])) где, в Nam[] - размещается имя подпрограммы; DN[] - служебная информация о программе. Все эти структуры объединяются в список, так что всегда имеется возможность определить, какие подпрограммы загружены в процесс. Коли- чество подпрограмм в процессе не ограниченно. Ограничен только размер памяти, выделенной KLisp-процессу. Из сказанного становиться понятен механизм инициализации переменной типа func: (func Fn) (setq Fn "aaa") в Fn помещается адрес экземпляра (struct progr) для подпрограммы "aaa", поэтому при обращении к ней поиск идет не по всему списку под- программ, а конкретно по адресу. С помощью служебных функций класса Serv_KL можно загружать и выг- ружать подпрограммы в процессе работы. Для этого в DOS_KL предусмот- рены операторы load и dload. Эта возможность значительно увеличивает возможности системы при построении крупных многопрофильных программ, поскольку нет необходимости сразу загружать всю программу в память. Следует отметить, что этот механизм значительно проще системы оверле- ев в Си, так как не требуется специальная трансляция подпрограмм. Лю- бая оттранслированная подпрограмма может быть загружена в процесс и выгружена когда угодно по желанию программиста. В конце блока памяти KLisp-процесса располагается стек програм- мных вызовов. При каждом обращении к оператору call этот стек увели- чивается сохраняя информацию о месте вызова подпрограммы.При возврате он уменьшается. Размер стека ограничивается концом последней загру- женной в процесс подпрограммы. Оператор gofunc не сохраняет информа- цию о месте вызова подпрограммы, поэтому не увеличивает стек прог- раммных вызовов. Все параметры процесса: - адрес конца программного кода; - размер свободного пространства; и другие данные доступны программисту через оператор info. Приступим к описанию операторов. Оператор вызова подпрограммы. (ssyl Ret)(call (char[]/func Nam) ) -------------------------------------------- Оператор перехода к подпрограмме. (non )(gofunc (char[]/func Nam) ) ------------------------------------------ Параметр Nam может быть двух типов либо (char []), либо (func) (char Nam[]) - имя подпрограммы в виде текстовой строки не более 9 знаков. Поиск идет по списку подпрограмм процесса. (func Nam) - инициализированный идентификатор подпрограммы. Вызов по идентификатору происходит быстрее, чем по имени. ( Arg) - аргументы, передаваемые подпрограмме. Их количество и тип определяются вызываемой подпрограммой. ( Ret) - ссылка на переменную произвольного типа,возвращаемая из подпрограммы оператором (return). Поскольку опе- ратор (gofunc) не возвращается к вызвавшей его прог- рамме, то и возврата параметров из него нет. Тип аргументов должен соответствовать типу аргументов подпрог- раммы. Нельзя передавать в качестве аргумента переменную типа струк- туры или массив, кроме как по указателю. Значения аргументов копиру- ются во входные параметры подпрограммы. Число аргументов может не совпадать с их количеством в подпрограмме: лишние будут игнорировать- ся, недостающие сохранят предыдущее значение. Изменение значения входных параметров в подпрограмме не изменяет значения аргументов в вызвавшей ее программе, но, передавая указатель на переменную, вы имеете возможность из вызванной подпрограммы изменять значения этой переменной. Оператор (call ) передает управление подпрограмме, загруженной в память, сохраняя информацию о месте вызова в стеке подпрограммных переходов. Оператор (gofunc) прекращает исполнение данной подпрограммы и пе- редает управление другой подпрограмме без сохранения информации о месте вызова. Оператор может быть использован для построения цепочеч- ных программ и реализован только благодаря безстековой организации языка. Hи один из существующих языков программирования высокого уров- ня не содержит подобных операторов. Глобальные ошибки: - нарушение типа Nam; - отсутствие в памяти подпрограммы с данным именем; - несоответствие типов аргументов; - переполнение стека подпрограммных переходов (для (call)). Оператор выхода из подпрограммы. (non)(return ) ------------------- ( Arg) - переменная произвольного типа, передаваемая опера- тору (call ) по ссылке. Если она отсутствует, то возврат (call) пуст. Оператор прекращает исполнение данной подпрограммы и передает уп- равление другой подпрограмме информация о которой находится в вершине стека подпрограммных переходов. Если стек пуст, то процесс исполнения кода завершается. Если в тексте подпрограммы отсутствует данный опе- ратор, то он автоматически выполняется за последним исполнимым опера- тором. В этом случае Arg отсутствует. При возврате в подпрограмму указатель вершины стека смещается к следующему переходу.Возврат может быть произведен не к той программе,из которой ей было передано управ- ление, если для перехода к ней использовался оператор (gofunc), а к последней программе использовавшей вызов (call). Глобальные ошибки: - возврат в несуществующую программу.

3.3 Операторы работы с указателями.

Операторы работы с указателями в KLisp схожи с операторами в Си, но специфика организации данных и указателей в KLisp, о которой гово- рилось в п 1.3. приводит к некоторому изменению их функционального значения. Инициализация указателя адресом переменной. (ssyl Uk)(Adr (addr Uk) Arg) ---------------------------- (addr Uk) - инициализируемый указатель; ( Arg) - инициализирующая переменная произвольного типа. Оператор производит установку указателя на адрес и элемент масси- ва данной переменной. Возвращает ссылку на указатель. Глобальные ошибки: - Нарушение типа переменных. Возврат ссылки на содержимое указателя. (ssyl Arg)(Con (addr Uk) ) -------------------------------------- (addr Uk) - инициализированный указатель; (ssyl Arg) - ссылка на переменную инициализирующую указатель; (char) или (int) Dim - смещение в массиве переменной относитель- но указанного Uk. По умолчанию - 0, без смещения. Оператор возвращает ссылку на переменную, на которую установлен указатель, возможно со смещением по массиву переменной. Глобальные ошибки: - Нарушение типа переменных. Оператор формирования адреса переменной. (addr)(# ( Arg)) ------------- ( Arg) - переменная произвольного типа. Оператор возвращает указатель на переменную. Обычно используется для передачи в подпрограмму адресов структур или массивов, а также возврата их из подпрограмм. Hапример, чисто для визуального понимания сути оператора: ((char) (Str[] "*****")) (call cmpstr (# Str) (# "++++")) В подпрограмму сравнения строк будут переданы два аргумента типа (addr). Глобальные ошибки: - нет переменной Arg. Смещение указателя к элементу указанного массива. (ssyl Uk)(>< (addr Uk) ) ------------------------------------ (addr Uk) - инициализированный указатель; (ch/int) Dim - номер элемента массива переменной. По умолча- нию 0. Оператор изменяет значение указателя только по статье - "элемент массива", адрес указанной переменной не изменяется. Усвойте разницу: Uk.[2] и (>< Uk 2) в первом случае значение Uk не изменяется, а элемент массива выбира- ется относительно установленного в Uk, во втором случае Uk изменяет- ся и указывает на второй элемент массива относительно начала. Возвращает ссылку на сам указатель. Глобальные ошибки: - Нарушение типа переменных. Смещение указателя по массиву вправо. (ssyl Uk)(++ (addr Uk) ) ------------------------------------ Смещение указателя по массиву влево. (ssyl Uk)(-- (addr Uk) ) ------------------------------------ (addr Uk) - инициализированный указатель; (char)/(int) Dim - значение смещения. По умолчанию 1. Оператор изменяет значение указателя только по статье - "элемент массива". Переменная Dim может принимать и отрицательные значения. Операторы (>< ) (++ ) (-- ) контролируют размер массива указанной пе- ременной и не могут выйти за его пределы. То есть при достижении опе- ратором (++ ) последнего элемента, он устанавливает указатель на ну- левой элемент массива. То же и (-- ) при достижении нулевого элемента переходит к последнему. Это свойство можно использовать для обработки массивов по кругу. Возвращает ссылку на указатель. Глобальные ошибки: - Нарушение типа переменных. Значение смещения указателя по массиву. (int)(Sm (addr Uk)) ------------------- (addr Uk) - инициализированный указатель; Возвращает значение, на какой элемент массива установлен указа- тель. Оператор обычно используется для определения свободного хвоста массива: (char Str[10] N) (addr Uk) (Adr Uk Str[5]) (- (= N (Sm (# Str[10]))) (Sm Uk)) в результате N=4. Глобальные ошибки: - Нарушение типа переменных. Инициализация указателя смещением в байтном массиве (ssyl Uk)(## (addr Uk) (char Buf[])) ------------------------------------- (addr Uk) - инициализируемый указатель; (char Buf[]) - байтный массив где располагается переменная. Возвращает ссылку на указатель. Оператор аналогичен, например, конструкции в языке Си: *(long *)&str[2] обычно используется для записи и чтения данных в файле, поскольку там пишутся только байтные массивы. Глобальные ошибки: - Нарушение типа переменных. - Переменная в байтном массиве неизвестного типа. Смещение указателя по переменным вправо. (ssyl Uk)(-> (addr Uk) ) ------------------------------------- (addr Uk) - инициализированный указатель; (char) (int) Dim - количество переменных для смещения. По умолчанию 1. Оператор изменяет значение указателя таким образом, чтобы он ука- зывал на переменную следующую за текущей в блоке памяти. Размер мас- сива переменной при этом не имеет значения. Если указатель установлен на переменную типа структура, то оператор смещает его к первому чле- ну этой структуры. Аналогов этому оператору в Си нет. Его реализация оказалась возможна только при организации данных принятой в KLisp. Оператор используется для упрощения доступа к данным структур: ((struct W) (char Str[10] N) (int DN[8])) ((struct W) W)(addr Uk) (Adr Uk W) (-> Uk 3) в результате Uk будет указывать на W.DN[0] Возвращает ссылку на указатель. Глобальные ошибки: - Нарушение типа переменных. - Переменная неизвестного типа.

3.4. Арифметико-логические операторы.

Арифметико-логические операторы входят в набор операторов, вклю- ченных в порождаемый класс DOS_KL, хотя, строго говоря, они не явля- ются системозависимыми. Это сделано для повышения открытости и гибко- сти системы. Арифметические операторы. (ssyl Res)(+ Res Arg ... ) - сложение. (ssyl Res)(- Res Arg ... ) - вычитание. (ssyl Res)(* Res Arg ... ) - умножение. (ssyl Res)(/ Res Arg ... ) - деление. (ssyl Res)(= Res Arg ) - приравнивание. (Res ) - результирующая переменная. (Arg ) - аргументы. Оператор производит действия над переменной Res. Переменные Res и Arg должны быть либо одного типа, либо приводимые. В арифметических операторах допускается использование произвольного количества аргу- ментов следующих типов: - (char), (int), (long), (float). Приводимыми друг к другу являются типы: - (char), (int), (long). В операторе приравнивания значимыми являются только первые два аргумента, а кроме численных можно использовать типы: - (func) и (addr), но (addr ) только по указателю. Поскольку операторы работают с произвольными типами данных, они возвращает ссылку на результат операции, первый аргумент, поэтому тип возвращаемой переменной определяется им. Глобальные ошибки: - Нарушение типа переменных. Логические операторы всегда возвращают (char) и, обычно, использу- ются в операторах if, while, cond в качестве условия исполнения. Операторы сравнения. (char)(> Res Arg) - больше. (char)(< Res Arg) - меньше. (char)(>= Res Arg) - больше или равно. (char)(<= Res Arg) - меньше или равно. (char)(== Res Arg) - равно. (char)(!= Res Arg) - не равно. Операторы производят сравнение переменных Res и Arg. Они должны быть одного типа или приводимыми. Допускается сравнение всех типов кроме структур. Операторы возвращают "истину" - (1), если выражение верно, в противном случае возвращается "ложь" - (0). Глобальные ошибки: - Нарушение типа переменных. Логические операторы. (char)(! Arg) - логическое "НЕ". Один аргумент. (char)(&& Arg ... ) - логическое "И". (char)(|| Arg ... ) - логическое "ИЛИ". Произвольное количество аргументов. Операторы производят логическое объединение аргументов. Возвраща- ют, в зависимости от результата, "истину" - 1, или "ложь" - 0. В ка- честве аргументов допускаются любые типы переменных, кроме структур, независимо от их приводимости. Глобальные ошибки: - структура или неизвестный тип.

3.5. Экранные операторы.

Поскольку предлагаемый вариант класса DOS_KL является демонстра- ционным он предоставляет упрощенный набор экранных операторов ориен- тированных на текстовый режим DOS. Этот набор может быть произвольным образом изменен в зависимости от задачи, которую требуется решить с помощью языка KLisp. Вывод знаков на экран. (non)(msg (char Arg) ....) -------------------------- Arg - набор строковых переменных и отдельных знаков. Оператор выводит на экран последовательно все указанные аргумен- ты. Если переменная строка, то она выводится до 0 или до конца мас- сива. Возврата нет. Глобальные ошибки: - Нарушение типа переменных. Позиционирование курсора. (non)(gotoxy (char\int X Y)) ---------------------------- X Y - номер колонки (от 1 до 80) и строки на экране (от 1 до 25). Возврата нет. Глобальные ошибки: - Нарушение типа переменных. Определение текущего положения курсора на экране. (char)(whx) (char)(why) ----------- Возвращают текущий номер строки и колонки на экране. Глобальные ошибки: Нет. (void)(clrscr) - Очистка экрана. (void)(clreol) - Очистка до конца строки. -------------- Возврата нет. Глобальные ошибки: Нет. Установка текущего атрибута вывода текста (non)(textattr (char\int Atr)) ------------------------------- Atr - значение атрибута. Возврата нет. Глобальные ошибки: - Нарушение типа переменных. Читать информацию с экрана в буфер. (non)(gettext X1 Y1 X2 Y2 (char Buf[])) --------------------------------------- (int) или (char) X1 Y1 X2 Y2 - параметры окна; (char Buf[]) - массив для приема информации. Оператор производит считывание информации с экрана в буфер вместе с их атрибутами. Hа каждый знак отводится два байта: младший - код знака; старший - атрибут знака. Возврата нет. Глобальные ошибки: - Нарушение типа переменных. - Hарушение параметров окна. Вывод информации из буфера на экран. (non)(puttext X1 Y1 X2 Y2 (char Buf[])) --------------------------------------- (int) или (char) X1 Y1 X2 Y2 - параметры окна; (char Buf[]) - массив вывода информации. Как и в предыдущем операторе на знак в массиве отводится два бай- та: младший - код знака; старший - атрибут знака. Возврата нет. Глобальные ошибки: - Нарушение типа переменных. - Hарушение параметров окна. Смещение информации на экране. (void)(movtext X1 Y1 X2 Y2 NewX1 NewY1) --------------------------------------- (int) или (char) X1 Y1 X2 Y2 - параметры окна; (int) или (char) NewX1 NewY1 - новые координаты верхнего левого угла окна. Оператор производит смещение информации окна экрана в новую пози- цию. Возврата нет. Глобальные ошибки: - Нарушение типа переменных. - Hарушение параметров окна. Читать код нажатой клавиши. (ssyl Key)(inkey ) -------------------------------- (char Key) или (int Key) - Приемник кода. Оператор читает код из буфера клавиатурного ввода,а если он пуст, то ждет ввода с клавиатуры. Код клавиши всегда имеет тип (int ), ис- пользование (char ) приводит к игнорированию старшего байта. Пустой оператор приостанавливает исполнение программы до нажатия любой кла- виши. Оператор возвращает ссылку на Key. Глобальные ошибки: - Нарушение типа переменных. Форматирование вывода на экран и в строку. (non) (print Fmt Arg ...) (ssyl Str)(sprint Str Fmt Arg ....) ----------------------------------- (char Str[]) - приемник форматного вывода; (char Fmt[]) - описатель форматного вывода (не более 80 знаков); ( Arg) - аргументы вывода. Операторы осуществляют вывод переменных в строку или на экран в виде форматированной строки. Порядок вывода определяет переменная Fmt которая может содержать текстовую информацию и специальные знаки, оп- ределяющие формат вывода переменных. Они располагаются между двух знаков - '%' (длина не более 8 знаков): % [flags] [width] [.prec] [l] type % type - тип форматного вывода: ------------------------------ (тип аргумента (char)(int)(float)) d знаковое десятичное целое; i знаковое десятичное целое; o беззнаковое восьмеричное целое; u беззнаковое десятичное целое; x беззнаковое шестнадцатиричное целое, нижний регистр; X беззнаковое шестнадцатиричное целое, верхний регистр; (тип аргумента (float)) f число с плавающей точкой [-]dddd.ddd; e число с плавающей точкой [-]d.ddd e [+/-]ddd; g формат e или f в зависимости от точности; E тоже что и e, но с буквой E; G тоже что и g, но с буквой E; c один знак (тип аргумента (char)(int)); s печать строки до '\0' или [.prec] (тип аргумента (char [])); % (двойной процент) - знак '%'. [flag] - флаг вывода: --------------------- (none) правостороннее выравнивание, слева 0 или пробелы; - левостороннее выравнивание, справа пробелы; + начать вывод с + или - ; blank печатать знак только для отрицательной переменной [width] - длина выводного формата: --------------------------------- n n знаков с лидирующими пробелами; 0n n знаков с лидирующими нулями. [.prec] - длина выводного формата: --------------------------------- none длина по умолчанию; .0 (d,i,o,u,x) длина по умолчанию; (e,E,f) без десятичной точки; .n не более n знаков. [l] ---- l (d,i,o,u,x,X) аргумент длинное целое (long). Оператор производит последовательную выборку аргументов по мере обнаружения структуры спецзнаков. Форматированного вывода переменной не производится, если ее тип не совпадает с указанным флагом - type. В операторе (sprint ) вывод ограничен длиной строки Str. Операторы обычно используются для визуализации данных, получаемых в процессе работы программы. Hапример, (print "\r\n Nam=%d%, Dim=%d%" Nam Dim) (print ) - ничего не возвращает; (sprint) - возвращает адрес строки Str. Глобальные ошибки: - Нарушение типа переменных Str или Fmt; - Ошибка преобразования переменной.

3.6. Операторы работы с файлами.

Как и в предыдущем разделе представленный класс DOS_KL имеет уп- рощенный набор операторов для работы с файловой системой DOS. Доста- точный для организации взаимодействия интерпретатора KLisp с другими программами операционной системы. (non )(unlink (char[] Name)) - Удалить файл. (char Ок)(access (char[] Name)) - Существование файла. ------------------------------- (char[] Name) - Строка имени файла. Глобальные ошибки: - Ошибка типа Name. Открыть файл: (char ERR)(open (char ID) (char[] Name) (char[] Rev)) ----------------------------------------------------- (char ID) - идентификатор файла (char[] Name) - Строка имени файла. (char[] Rev)) - Режим открытия: "r","rb" - для чтения (текст, байты), "w","wb" - для записи (текст, байты). ID - инициализируется идентификатором файла. Возвращает 0 при успешном завершении или код ошибки: 1 - не может открыть файл Name. 2 - ошибка в данных. 3 - нет свободных блоков FILE. (char ERR)(close (char ID)) - Закрыть файл. --------------------------- (char ID) - Идентификатор файла. Возвращает 0 при успешном завершении или код ошибки: 1 - если идентификатор ID не инициализирован. 2 - ошибка в данных. Читать блок из файла: (char ERR)(read (char ID) (char[] Buf) (ch\in Len)) --------------------------------------------------- Писать блок в файл: (char ERR)(write (char ID) (char[] Buf) (ch\in Len)) --------------------------------------------------- (char ID) - Идентификатор файла; (char[] Buf) - Выделенный для обмена буфер памяти. (ch\in Len) - Количество байт для обмена. Если Len превышает размер Buf, количество байт обмена уменьшается. Возвращает 0 при успешном завершении или код ошибки: 1 - если идентификатор ID не инициализирован. 2 - ошибка в данных. (char ERR)(gets (char ID) (char[] Str)) - читать строку из файла. --------------------------------------- (char ERR)(puts (char ID) (char[] Str)) - писать строку в файл. --------------------------------------- (char ID) - Идентификатор файла. (char[] Str) - Строка обмена. Возвращает 0 при успешном завершении или код ошибки: 1 - если идентификатор ID не инициализирован. 2 - ошибка в данных. 3 - ошибка обмена с файлом.

3.7. Служебные операторы.

Служебные операторы также вынесены в класс DOS_KL, хотя не явля- ются системозависимыми и явно отражают особенности языка KLisp. Это сделано для того чтобы увеличить прозрачность языка и дать возмож- ность дополнять набор типов данных. К этой группе относятся два опе- ратора: оператор (type ) для исследования данных в памяти и оператор (setq ) для преобразования строковой переменной в переменную опреде- ленного типа. Оператор исследования данных: (char Typ)(type (... Arg) ) ------------------------------------------------- (... Arg) - Исследуемая переменная. - Инициализируется размером массива исследуемой переменной или 1, если это не массив. ) - Инициализируется количеством байт отведенных в переменной для данных без учета служебных полей KLisp. Возвращает признак типа исследуемого аргумента: char = '*' (42); int = '&' (38); long = '%' (37); float= '$' (36); addr = '[' (91); func = ']' (93); struct = '.' (46); или - 0, если тип неизвестен. Значение произведения (* DIM LenArg) будет указывать на количес- тво байт отведенных на весь массив переменной. Стандартно, как и в других языках, KLisp выделяет на char 1 байт, на int - 2 байта и т.д. поэтому больший интерес представляет исследование с помощью этого оператора новых типов данных и структур. При исследовании этим опера- тором структуры данных LenArg инициализируется количеством байт отве- денных на один экземпляр указанной структуры независимо от входящих в нее типов данных. Глобальные ошибки: - Ошибка типа аргументов DIM и LenArg. (ssyl Arg)(setq (... Arg) (char[] Str)) --------------------------------------- Преобразование строковой переменной в переменную определенного типа. Оператор исследует тип Arg и в зависимости от этого интерпрети- рует строковую переменную. Затем инициализирует Arg полученным значе- нием. Возвращает ссылку на инициализируемую переменную. Глобальные ошибки: - Ошибка типа аргументов или не инициализируемый тип. В завершении главы описания операторов, хочется еще раз напомнить пользователю об основной задаче, поставленной при разработке языка, с тем, чтобы не сложилась ситуация: "За деревьями леса не видно". Суть языка не в наборе операторов,а в предоставлении им (языком) механизма объединения любых операторов в исполняемую конструкцию, в возможности организации сложноструктурированных данных и упрощении доступа к этим данным с целью передачи их операторам в качестве аргументов.