Следующие команды позволяют загрузить и сохранить вновь установленную конфигурацию. Load Options / Window / Setup (Загрузить параметры / Окно / Установка). Нажмите L для загрузки файла типа .TB из справочника Turbo и переустановки системы в соответствии с содержащимися в нем параметрами. Save Options / Window / Setup (Сохранить параметры / Окно / Установка). Нажав S вы сохраните текущие значения параметров системы в файле типа .TB в справочнике Turbo. Данной конфигурации системы можно дать любое имя, но при первом запуске Turbo Basic автоматически используется файл по умолчанию (TBCONFIG.TB). Можно также сохранить справочник конфигураций в файле TB.EXE. Однако, если вы сделаете это, то выводится запрос: действительно ли вы хотите изменить первоначальный файл TB.EXE. Команда Window (окно). Как было сказано в разделе, посвященном главному меню, вы можете изменять размеры и перемещать любое активное окно, нажимая Scroll Lock, а затем при нажатой клавише Shift использовать клавиши-стрелки для перемещения окна в желаемом направлении. По умолчанию, все окна являются активными, пока вы их не закроете. Нажмите W, чтобы получить просматриваемое меню команды Window, показанноe на рис.3-9. Open (открыть). Нажмите O и выберите Edit (редактирование), Run (исполнение), Message (сообщение) или Trace (трассировка) из вложенного меню. Команда Open (открыть) делает выбранное окно "активным". Это означает, что, если окно было перед этим закрыто, оно создается и, в любом случае, "открытое" окно переносится наверх экрана. Все остальные команды этой группы воздействуют теперь только на активное окно. Close (закрыть). Отменяет вывод на экран выбранного окна, однако, в него по-прежнему может записываться информация. Next (следующий). Команда Next позволяет сделать активным другое окно, не прибегая для этого к команде Open. Многократное нажатие Next приводит к циклическим переходам между окнами. Если вы находитесь в главном меню или меню окна, клавиша F6 выполняет те же функции, что и команда Next. Goto (перейти). После открытия окна используйте команду Goto для входа в это окно без обращения к главному меню. Tile (разделить на равные части). Нажмите T для выделения под каждое активное окно равной части экрана. Клавиша F6 переключает активное окно. Stack (штабелировать). Используйте команду Stack, чтобы расположить друг над другом (в виде штабеля) все открытые окна при максимально возможном их размере. Нажмите F6 для перенесения последнего окна из штабеля наверх, т. е. на экран. Zoom (изменить масштаб изображения). Ввод команды Zoom (или F5) увеличивает выбранное окно до полного размера экрана; однако, эта команда работает только с окнами редактора и исполнения. Для возврата к первоначальной установке экрана снова введите команду Zoom. Команда Debug (отладка). По команде Debug ван предоставляется на выбор одна из двух команд в ее вложенном меню: Trace (трассировка) и Run-time error (ошибка периода выполнения). Trace (трассировка). Команда-ключ Trace позволяет задать глобальную трассировку программы. Действие этого ключа может быть изменено операторами TRON и TROFF, вставленными в программу. При трассировке на экран в соответствующее окно выводятся метки операторов, номера строк и имена процедур и функций. При запуске программы в режиме трассировки используйте Alt-F9 для переключения между трассировкой и выполнением вашей программы. При нажатие Alt-F10 программа выполняется в пошаговом режиме; при этом шаг может определяться следующим номером строки, меткой и т.д. Run-time error (ошибка периода выполнения). Эта команда используется в основном для нахождения ошибок, которые встречаются в файлах типа .EXE и .TBC (автономных программах); никакие сообщения при этом не выдаются. При запуске программы в системе Turbo Basic все нижеперечисленные делается автоматически. Введите эту команду, нажав R или Enter. После этого выводится запрос на ввод значения счетчика команд. Turbo Basic определяет соответствующую точку в исходной программе и помещает курсор на оператор, вызвавший ошибку. При возникновении ошибки в период выполнения программы, Turbo Basic сообщает вам тип ошибки (всегда в числовом виде, и в виде текста, если программа запущена из Turbo Basic), а также значение счетчика команд процессора в момент обнаружения ошибки. Осуществляя рекомпиляцию, Turbo Basic может вычислить точку в исходной программе, соответствующую адресу ошибочной команды в объектной программе. Например, рассмотрим программу TEST.BAS: x = 256 PRINT CHR$(x) Хотя эта программа синтаксически корректная и, следовательно, компиляция пройдет успешно, но в перид выполнения будет зафиксирована ошибка, когда система попробует напечатать символ со значением кода ASCII 256: Error 5 Illegal function call at pgm-ctr: 29 Команда Run-time error использует это значение счетчика команд для поиска оператора, вызвавшего ошибку. Примечание: Если задать неправильное значение счетчика, то генерируется сообщение об ошибке Run-time Error Not Found (ошибка периода выполнения не найдена). Глава 4 Turbo Basic: Описание языка. Структура программы. Программы на языке Turbo Basic состоят из одной или более строк исходного текста, каждая из которых имеет следующий формат: [номер строки]оператор[:оператор]...['комментарий] или: метка: или: $метаоператор "Номер строки" представляет собой целое число в диапазоне от 0 до 65535, которое может дополнительно идентифицировать строки программы. Turbo Basic осуществляет привязку к номерам строк. Они могут свободно взаимозаменяться с метками и использоваться в некоторых частях программы, но не в других программах. В действительности они не обязательно должны следовать в порадке строгой числовой последовательности; при этом никакие две строки не могут иметь один и тот же номер, и ни одна строка не может иметь как метку, так и номер. Номера строк по существу являются метками. "Операторы" являются теми "кирпичиками", из которых строится программа. В языке Turbo Basic имеется около 100 типов операторов (полный перечень операторов приведен в главе 5 "Справочника по языку Turbo Basic"). В строке может быть ни одного, один или несколько операторов, разделенных двоеточиями. В следующих примерах показаны допустимые строки языка Turbo Basic: Start: 'только метка 10 'только номер строки $INCLUDE "CONST.TBS" 'метаоператор 20 a=a+1 'номер строки и оператор a=a+1 : b=b+1 'два оператора 30 a=a+1 : b=b+1 : c=c+1 'номер строки и три оператора Количество операторов в одной строке ограничивается только шириной строки Turbo Basic, равной 249 колонкам. Однако, некоторые школы программирования рекомендуют помещать в строке не более одного оператора, хотя некоторые синтаксические структуры требуют обратного (например, IF/THEN/ELSE). В отличие от языка интерпретирующий Basic, Turbo Basic не фиксирует ошибок в случае наличия в программе символов пробела и комментариев - пробелы, комментарии и пустые строки игнорируются компилятором. Все школы программирования считают "плохим тоном" писать строки программы шире, чем 80-символьная ширина окна редактора (несмотря на способность редактора горизонтального прокручивания более широких строк). Если ваша строка будет шире 80 колонок, то вы не сможете увидеть ее на экране целиком. Кроме того, при печати она будет выглядеть не очень красиво. В тех ситуациях, когда требования синтаксиса заставляют вас создавать строку длиннее 80 символов (примером этого является оператор FIELD), используйте символ подчеркивания (_) в конце строки. Это заставит транслятор с Turbo Basic рассматривать следующую строку как продолжение предыдущей. Эта строка, в свою очередь, также может быть продолжена. Например: FIELD #1, 30 AS name$, 30 AS address1$, 30 as address2$,_ 15 AS city$, 2 AS state$, 5 AS zip$,_ 30 AS comments$ Что касается компилятора, то он рассматривает все это как одну строку, начинающуюся с FIELD и заканчивающуюся comments$, без промежуточных символов подчеркивания. "Комментарий" может быть любым текстом, помещенным в конце строки и отделенным от основной программы символом одиночной кавычки (апострофом) ('). Одиночная кавычка (') может использоваться вместо оператора REM для отделения в строке комментария от оператора, если только это не делается в конце строки оператора DATA (оператор DATA рассматривает одиночную кавычку и все следующие за ней символы как часть строки). В отличие от оператора REM, нет необходимости отделять комментарий, следующий за одиночной кавычкой, от основного оператора с помощью двоеточия. Например, следующие строки являются для компьютера эквивалентными: area = radius^2 * 3.14159 'вычисление площади area = radius^2 * 3.14159 :REM вычисление площади "Метка" должна появляться на строке одна (хотя комментарий в такой строке допустим). Она служит для идентификации оператора, следующего непосредственно за ней. Метка должна начинаться с буквы и может состоять из любого количества букв и цифр. Регистр, на котором набита буква, не имеет значения: метки THISLABEL и ThisLabel - эквивалентны. За меткой должно следовать двоеточие; однако, в операторах, ссылающихся на метку, (например, GOSUB) двоеточие не указывается. Примеры: SORTSUBROUTINE: ExitPoint: a = a+1 'недопустимо; в строке с меткой 'больше ничего не должно быть SortInvoices: GOSUB SortInvoices 'ссылка на метку "$метаоператоры" представляют собой операторы, которые выполняются на другом, по сравнению с обычными операторами, уровне. Они называются также директивами компилятора и всегда начинаются с символа доллара ($). Стандартные операторы управляют работой компьютера в период выполнения программы; метаоператоры, как и выбор альтернатив в меню дополнительных возможностей, управляют работой компьютера в период компиляции. Примером является метаоператор $INCLUDE, который заставляет компилятор включить содержимое другого файла на место, указанное в текущем файле. Заметим, что метаоператоры Turbo Basic не могут появляться в операторах REM, в отличие от других компиляторов Basic, в которых это допускается. В одной строке может быть только один метаоператор. Набор символов, используемых в языке Turbo Basic. Turbo Basic представляет собой что-то вроде конструктора для построения программ. Он обеспечивает вас набором основных элементов языка (зарезервированные слова и символы), которые могут быть соединены между собой бесконечным числом способов для создания любого программного обеспечения. Буквы от A до Z, или от a до z, и цифры от 0 до 9 могут быть использованы для построения идентификаторов (наименований меток, переменных, процедур и функций). Цифры от 0 до 9, символы ., + и -, и буквы E, e, D и d могут быть использованы при построении числовых констант. Следующие символы имеют в языке Turbo Basic специальные значения: ________________________________________________________ Символ Описание/Функция ________________________________________________________ = Знак равенства (в операторе присваивания, в операторе отношения) + Знак плюс (операторы сложения и конкатенации строк) - Знак минус (операторы вычитания и отрицания) * Звездочка (оператор умножения) / Косая черта (оператор деления) \ Обратная косая черта (оператор целочисленного деления) ^ Стрелка вверх (оператор возведения в степень) % Знак процента (символ объявления данных целого типа) & Амперсенд (символ объявляния данных целого типа двойной длины и оператор описания недесятичной системы счисления) ! Восклицательный знак (символ объявления данных обычной точности) # Символ номера (Символ объявляния данных двойной точности) $ Знак доллара (символ объявления данных типа символьной строки, префикс метаоператора) () Круглые скобки (аргументы функций и процедур, массивы, установление приоритетов при вычислении выражений) [] Квадратные скобки (используются только при обрашении к элементам массивов) Пробел (разделитель) , Запятая (универсальный разделитель) . Точка (десятичная точка, разделитель имени и расширения файла) ' Одиночная кавычка (разделитель поля комментария) ; Точка с запятой (универсальный разделитель) : Двоеточие (разделитель операторов) ? Вопросительный знак (заменитель оператора PRINT) < Знак "Меньше, чем" (оператор отношения) > Знак "Больше, чем" (оператор отношения) " Двойная кавычка (разделитель символьных строк) _ Подчеркивание (символ, обозначающий строку продолжения) ________________________________________________________ Зарезервированные слова. В Turbo Basic зарезервировано использование некоторых слов с целью реализации некоторых заранее определенных синтаксических потребностей. Такие зарезервированные слова не могут быть использованы в качестве меток, имен переменных, именованных констант, имен процедур или функций, хотя ваши идентификаторы могут содержать их внутри себя (см. табл.4-1). Например, END является недопустимым именем для переменной, поскольку имеется зарезервированное слово END. Однако, имена ENDHERE и FRIEND допустимы. Кроме того, идентификатор не должен начинаться с сочетания букв FN, т.к. такое сочетание обозначает функцию, определенную пользователем. Попытка использования зарезервированных слов в качестве идентификаторов вызовет фиксацию ошибки во время компиляции. Таблица 4-1. Зарезервированные слова Turbo Basic. _____________________________________________________________ $COM1 CLOSE ERR LOC POKE STRING$ $COM2 CLS ERROR LOCAL POS SUB $DEBUG COLOR EXIT LOCATE PRESET SWAP $DYNAMIC COM EXP LOF PRINT SYSTEM $ELSE COMMAND$ EXP10 LOG PRINT# TAB $ENDIF COMMON EXP2 LOG10 PSET TAN $EVENT COS FIELD LOG2 PUT THEN $IF CSNG FILES LOOP PUT$ TIMES$ $INCLUDE CSRLIN FIX LPOS RANDOM TIMER $INLINE CVD FN LPRINT RANDOMIZE TO $LIST CVI FOR LPRINT# READ TROFF $OPTION CVL FRE LSET REG TRON $SEGMENT CVMD GET MEMSET REM UBOUND $SOUND CVMS GET$ MID$ RESET UCASE$ $STACK CVS GOSUB MKDIR RESTORE UNTIL $STATIC DATA GOTO MKD$ RESUME USING ABS DATE$ HEX$ MKI$ RETURN USR ABSOLUTE DECR IF MKL$ RIGHT$ USR0 AND DEF IMP MKMD$ RMDIR USR1 APPEND DEFDBL INCR MKMS$ RND USR2 AS DEFINT INKEY$ MKS$ RSET USR3 ASC DEFLNG INLINE MOD RUN USR4 AT DEFSNG INP MTIMER SAVE USR5 ATN DEFSTR INPUT NAME SCREEN USR6 BASE DELAY INPUT# NEXT SEEK USR7 BEEP DIM INPUT$ NOT SEG USR8 BIN$ DO INSTAT OCT$ SELECT USR9 BINARY DRAM INSTR OFF SERVICE VAL BLOAD DYNAMIC INT ON SGN VARPTR BSAVE ELSE INTERRUPT OPEN SHARED VARPTR$ CALL ELSEIF IOCTL OPTION SHELL VARSEG CASE END IOCTL$ OR SIN VIEW CDBL ENDMEM KEY OUT SOUND WAIT CEIL ENVIRON KILL OUTPUT SPACE$ WEND CHAIN ENVIRON$ LBOUND PAINT SPC WHILE CHDIR EOF LCASE$ PALETTE SQR WIDTH CHR$ EQV LEFT$ PALETTE USING STATIC WINDOW CINT ERADR LEN PEEK STEP WRITE CIRCLE ERASE LET PEN STICK WRITE# CLEAR ERDEV LINE PLAY STOP XOR CLNG ERDEV$ LIST PMAP STR$ ERL POINT STRIG _____________________________________________________________ Числа в языке Turbo Basic. Типы чисел и их методы их формирования составляют важную часть любого языка программирования. Turbo Basic разработан в соответствии с традициями языка Basic таким образом, чтобы позволить вам не вдаваться в технические подробности, касающиеся внутреннего представления чисел. Если вы никогда не будете задумываться о таких вещах, как скорость вычислений, точность и требования к памяти, то ваши программы все-же будут иметь возможность работать точно. Однако, понимание отмеченных в данном руководстве моментов поможет вам писать программы более быстродействующие, точные и требующие меньше памяти. В целях повышения эффективности, Turbo Basic хранит и обрабат тывает данные, представленные в четырех различных формах; т.е. он поддерживает четыре типа данных: целые, длинные целые, с плавающей запятой обычной точности и двойной точности. Целые числа. Самыми простыми и допускающими наиболее быструю обработку числами в Turbo Basic являются целые числа. В Turbo Basic целым является число без десятичной точки (т.е. число, называемое в математике целым) в диапазоне от -32768 до 32767. Это ограничение имеет место из-за представления целых чисел 16-разрядным двоичным числом: 32768 равно 2^15. Хотя этот диапазон ограничивает область применения целых чисел, но почти все переменные в тех программах, которые вы будете писать (например, счетчики в циклах FOR/NEXT), не выйдут за указанные пределы. Если эти пределы вас удовлетворяют, то использование целых чисел позволит получить чрезвычайно быстродействующую и компактную программу. Ваш компьютер наилучшим образом приспособлен для реализации арифметических операций над целыми числами (например, он реализует их быстро), и для хранения каждого числа требуется только 2 байта памяти. Ключ отладки Overflow (Переполнение) в меню дополнительных возможностей позволяет вам создавать программы, которые автоматически проверяют и указывают на ошибки, связанные с переполнением переменных целого типа. Длинные целые числа. Существенным расширением возможностей Turbo Basic по сравнению с интерпретирующим Basic является введение типа чисел, называемых длинными целыми. Позволяя избежать ошибок переполнения, длинные целые числа являются наиболее совершенным типом данных для финансовых приложений. Подобно обычным целым, длинные целые числа не дол- жны содержать десятичную точку. Однако, в отличие от простых целых они изменяются в значительно большем диапазоне: от -2147483648 до +2147483647 (от -2^31 до 2^31, или от -2 миллиардов до +2 миллиардов). Следствием такого расширенного диапазона является то, что для хранения длинного целого требуется 4 байта памяти, а выполнение арифметических операций над ними требует больше времени, чем над простыми целыми. Применение длинных целых является относительно эффективным, особенно на компьютерах, не имеющих арифметического сопроцессора 8087. В зависимости от ваших потребностей, наличие десятичной точк ки может оказаться менее важным, чем кажется на первый взгляд. Например, вы можете измерять количество денег в пенни, а для вывода на экран суммы в долларах - делить его на 100. Таким способом могут быть выражены величины до 20 миллионов долларов. Числа с плавающей запятой обычной точности. Числа с плавающей запятой обычной точности (или просто числа обычной точности) являются, пожалуй, наиболее гибким типом чисел в Turbo Basic. Числа обычной точности могут содержать десятичную точку и имеют огромный диапазон: от 10^-38 (число очень близкое к нулю - 0.00000000000000000000000000000000000001) до 10^38 (гигантское число - 100000000000000000000000000000000000000), как в области положительных, так и отрицательных чисел. Вам придется сильно потрудится, чтобы придумать необходимость в числе, которое бы не могло быть выражено числом обычной точности. Скорость вычислений является неплохой, хотя и не такой быстрой, как для длинных целых чисел. Для хранения числа обычной точности требуется 4 байта памяти. Недостатком чисел обычной точности является то, что хотя они и могут представлять как очень большие, так и микроскопические числа, они не позволяют производить вычисления с точностью, превышающей шесть цифр. Другими словами, использование чисел обычной точности позволяет правильно оперировать с такими числами, как $451.24 и $6411.92, но число $671421.22 не может быть точно представлено, так как оно содержит слишком много цифр. Не могут быть точно представлены ни 234.56789, ни 0.00123456789; число обычной точности можно использовать, когда представляемое им число может быть выражено не более, чем шестью значащими цифрами: $671421, или 0.00123457. В зависимости от вашей области интересов, такое округление может привести как к не очень важным, так и к катастрофическим последствиям. Числа с плавающей запятой двойной точности. Числа двойной точности соотносятся с числами обычной точности, как длинные целые с обычными целыми. Они занимают в два раза больше памяти (8 байтов вместо 4 байтов), и, следовательно, требуется больше времени для выполнения вычислений, они имеют больший диапазон (10^308) и большую точность (16 цифр вместо 6 цифр у чисел обычной точности). Повышенные требования к памяти для чисел двойной точности становятся особенно существенными, если вы работаете с массивами. Массив из 5000 чисел двойной точности требует 40000 байтов памяти. Массив из такого же количества целых чисел занимает только 10000 байтов. Примечание: в Turbo Basic для представления чисел с плавающей запятой используется стандарт IEEE, а не формат фирмы "Microsoft", который используется в интерпретирующем Basic. Поэтому необходимо использовать специальные функции перевода (CVMS, CVMD, MKMS$ и MKMD$), чтобы читать и записывать данные в формате чисел с плавающей запятой, хранящеися в файлах с произвольным доступом, созданных в интерпретирующем Basic. (Более подробная информация приведена далее в этой главе в разделе "Файлы с произвольным доступом"). Если вы не уверены, какой тип чисел с плавающей запятой следует использовать, мы предлагаем использовать числа двойной точности. Организация вычислений в Turbo Basic такова, что они выполняются более эффективно для чисел двойной точности. Трансцендентные функции Turbo Basic, такие как COS и LOG, возвращают значения двойной точности. Использование чисел обычной точности может оказаться предпочтительнее при работе с большими массивами, когда становится ощутимым преимущество их меньшего размера. Организация вычислений и сопроцессор 8087. Сопроцессор 8087 (или 80287 для компьютеров типа AT) существенно сокращает разницу в скорости вычислений для чисел различных типов. Поскольку сопроцессор 8087 выполняет все вычисления с двойной точностью, независимо от типов операндов, то это делает еще более привлекательным использование чисел двойной точности. В отличие от интерпретирующего Basic, Turbo Basic не всегда округляет в большую сторону дробную часть числа. Turbo Basic особым образом обрабатывает числа, дробная часть которых оканчивается на цифру 5: число округляется до ближайшего четного числа. Например, число 0.5 будет округлено до 0, ближайшего к нему четного числа. А число 9.005 будет округлено также до ближайшего четного числа, которым в данном случае будет 9.000. Поскольку наиболее типичным методом округления чисел является их округление до большего значения, то метод, используемый в Turbo Basic, обеспечивает более четное распределение. Константы. Программы на языке Turbo Basic обрабатывают два типа данных: константы и переменные (они будут рассмотрены в следующем разделе). Переменные могут изменять свое значение в течение выполнения программы. Значение константы фиксируется в период компиляции и не может быть изменено при выполнении программы. Turbo Basic поддерживает три типа констант: символьные константы (строки), числовые константы и специальный вид целых констант - именованные константы, которых нет в интерпретирующем Basic. Символьные константы. Символьные константы представляют собой просто группы символов, заключенные в двойные кавычки, например: "This is a string" "3.14159" "Tim Jones, Attorney at Law" Если символьная константа стоит в конце строки, то закрывающая двойная кавычка не является обязательной: PRINT "This is sloppy but legal. Числовые константы. Числовые константы представляют числовые значения и могут включать цифры от 0 до 9 и десятичную точку. Перед отрицательными константами должен стоять знак минус (-); знак плюс (+) перед положительными константами не является обязательным. Количество значащих цифр, которое вы задали для числовой константы, определяет ее внутреннее представление (целое, длинное целое, обачной точности или двойной точности), которое будет использовать Turbo Basic при обработке этой константы. Если заданная величина не содержит десятичной точки и находится в диапазоне от -32768 до 32767, то Turbo Basic использует целый тип. Если заданная величина является целым числом в диапазоне от -2^31 до 2^31-1, включительно (примерно от -2 миллиардов до +2 миллиардов), но вне диапазона констант целого типа, то Turbo Basic использует для ее представления тип длинного целого. (Примечание: тип длинного целого не может быть использован в интерпретирующем Basic). Если заданная величина содержит десятичную точку и имеет до шести значащих цифр, то Turbo Basic использует тип числа с плавающей запятой обычной точности. Числовые константы с десятичной точкой и болеее, чем шестью значащими цифрами, или целые числа, слишком большие даже для представления в виде длинных целых, представляются в формате чисел с плавающей запятой двойной точности. Например: 345.1 обычная точность 1.10321 обычная точность 1.103213 двойная точность 3453212.1234 двойная точность Задание целых констант в других системах счисления. Иногда бывает удобно выражать целые константы в системах счисления, отличных от десятичной. Это, в частности, имеет место при отображении информации, двоичной по своей сути, например, адресов в памяти компьютера. Turbo Basic позволяет задавать данные целого типа в шестнадцатеричной (основание 16), восьмеричной (основание 8) и двоичной (основание 2) форме. Заметим, что длинные целые не могут быть представлены в другой системе счисления. Шестнадцатеричные константы могут содержать до четырех шестнадцатеричных цифр, каждая из которых может быть представлена цифрами от 0 до 9 и буквами от A до F. Перед шестнадцатеричной константой должны стоять символы &H. Восьмеричные константы могут содержать только цифры от 0 до 7, количество которых не должно превышать 6. Перед восьмеричной константой должны стоять символы &O (или &Q, или просто &). Двоичные константы состоят только из нулей и единиц, которых в одном числе может быть до 16. Перед двоичной константой должны стоять символы &B. Каждая из следующих констант представляет целое число, десятичное значение которого равно 256: 256 &H100 &O400 &400 &B100000000 Именованные константы Turbo Basic позволяет ссылаться на целые константы по имени. Это является расширением интерпретирующего Basic, в чем-то напоминающим конструкцию CONST языка Pascal. Именованными могут быть только константы целого типа. Чтобы присвоить имя целой константе, надо поставить перед ее идентификатором знак процента (%) и присвоить ему некоторое целое значение. В отличие от переменных, вы можете использовать именованную константу в левой части оператора присваивания только один раз, и ей может быть присвоено только целое значение (не переменная и не выражение). Например: %debug = -1 'именованная константа со 'значением -1 debug% =12409 'целая переменная PRINT %debug,debug% 'это разные элементы... Используйте именованные константы для флагов условной компиляции (см. описание метаоператоров в Главе 5) и для повышения надежности программ. (Вы можете также использовать именованные константы для уменьшения неясности ваших программ из-за "магических чисел". Магические числа - это мистические величины, которые означают для вас что-то, когда вы первоначально пишете программу, но ничего не говорят вам, когда вы к ней возвращаетесь спустя шесть месяцев.) Переменные. Переменная обозначается идентификатором, который представляет числовую или символьную величину. В отличие от константы, значение переменной может изменяться в процессе выполнения программы. Подобно меткам, имена переменных должны начинаться с буквы и могут содержать любое количество букв и цифр. Старайтесь выбирать значащие идентификаторы при именовании важных переменных. В отличие от интерпретирующего Basic, в Turbo Basic длинные имена переменных не занимают лишнюю память, используемую программой при выполнении. Для переменных с именами EndOfMonthTotals и emt требуется ровно по 4 байта памяти, отведенной под выполняемую программу. Turbo Basic поддерживает пять типов переменных: символьные, целые, длинные целые, обычной точности и двойной точности. Имя переменной определяет ее тип. Обычно ввод переменной сопровождается добавлением к ее имени символа, определяющего ее тип. Символьные переменные оканчиваются знаком доллара ($): a$ = "Turbo Basic" Для обозначения переменных целого типа используется знак процента (%): a% = 15 У длинных целых для обозначения типа используется амперсенд (&): a& = 7000 Для обозначения переменных с плавающей запятой обычной точности используется восклицательный знак (!): a! = 1.1 Переменные с плавающей запятой двойной точности оканчиваются знаком номера (#): a# = 1.031 Если вы не включили в имя переменной символ объявления типа, то Turbo Basic использует тип числа с плавающей запятой обычной точности, принятый по умолчанию. Чтобы назначить использование по умолчанию другого типа, применяется оператор DEFтип. Например: a# = 1.031 'a# - переменная двойной точности b = 16.5 'b - обычной точности a% = 3 'a% - целая переменная; a# - это 'другая переменная DEFINT m 'типом по умолчанию для переменных, 'начинающихся с m, является теперь 'целый m = 16 'm - целая переменная... Заметим, что a%, a#, a&, a$ и a! являются пятью разными переменными. Массивы. Массив - это группа символьных или числовых данных, объединенная общим именем переменной. Отдельные величины, образующие массив, называются элементами. Элемент массива может быть использован в операторе или в выражении в любом месте, где бы вы использовали символьную или числовую переменную. Другими словами, каждый элемент массива сам является переменной. Перед запуском программы все элементы всех числовых массивов устанавливаются равными нулю. Элементам символьных массивов присваивается значение пустой строки (""). При задании размера динамического массива также очищаются все его элементы. Если программа позднее снова запускается оператором RUN, то описанная инициализация повторяется снова. Объявление имени и типа массива, а также количества и организации его элементов, осуществляется оператором DIM (размерность). Например, оператор: DIM payments(55) создает массив с именем payments, состоящий из 56 элементов обычной точности, пронумерованных от 0 до 55. Массив payments и переменная обычной точности с таким же именем являются различными переменными. Индексы. Обращение к отдельным элементам массива осуществляется посредством индексов, т.е. выражений целого типа, заключенных в круглые скобки и стоящих справа от имени массива. Например, payments (3) и payments(44) - два из 56 элементов массива payments. Обычно, первый элемент массива имеет индекс 0, хотя это может быть изменено оператором DIM, либо оператором OPTION BASE. Например: 'Данный оператор DIM объявляет массив из 56 элементов 'с границами индексов от 0 до 55. DIM payments(55) ----------------------- OPTION BASE 1 'Следующий оператор DIM объявляет массив из 55 элементов 'с границами индексов от 1 до 55, что определяется 'оператором OPTION BASE DIM payments(55) Если вы используете в программе массив без объявления его оператором DIM, то Turbo Basic обрабатывает его так, как если бы вы объявили массив из 11 элементов (со значениями индексов от 0 до 10). Однако, мы убедительно рекомендуем, чтобы вы в явном виде объявляли размерности массивов, используемых в вашей программе. В дополнение к обработке массивов, осуществляемой в интерпретирующем Basic, Turbo Basic позволяет определять диапазон значений индексов, а не только его верхнюю границу. Например, оператор DIM: DIM b(50:60) создает массив b, состоящий из 11 элементов обычной точности, пронумерованных от 50 до 60. Оператор: DIM c(50:60,25:45) создает двумерный массив c, содержащий 231 (11 х 21) элемент. Возможности Turbo Basic по объявлению диапазона значений индексов позволяют более точно моделировать задачу в структуре данных программы. Например, рассмотрим программу, отслеживающую статистику рождений в 19 веке. Центральной структурой данных программы является массив из 100 элементов обычной точности, содержащий количество детей, родившихся в каждый год прошлого столетия. В идеале вы могли бы создать массив, который бы использовал значения индексов, равные годам, в которых отмечались рождения (например, births(1851) представляет количество детей, родившихся в 1851 году), с тем, чтобы фрагмент программы: DIM births(1899) . . . FOR n = 1800 TO 1899 PRINT "There were" births(n) "births in" n NEXT n был бы как можно более наглядным. К сожалению, оператор DIM births (1899) создает массив из 1900 элементов, из которых первые 1800 являются ненужными. Обычно, программисты, программирующие на языке Basic, решают эту проблему, объявляя этот массив следующим образом: DIM births(99) и осуществляя различные манипуляции с индексами: FOR n = 1800 TO 1899 PRINT "There were" births(n-1800) "births in" n NEXT n Если решать проблему таким образом, то это усложняет программу и делает ее более медленной, т.к. теперь появились лишние 100 операций вычитания. Оператор OPTION BASE также может быть использован для задания нижнего индекса массива, хотя механизм задания диапазона индексов является более мощным и предпочтительным. Символьные массивы. Элементы символьных массивов вместо чисел содержат строки. Каждая строка может быть различной длины от 0 до 32767 символов. Общее пространство, отводимое под символьные строки и символьные массивы, равно 64К. Например, оператор: DIM a$(50) создает последовательность из 51 независимой символьной переменной: a$(0) = "A medium length string" 'строка из 21 символа a$(1) = "" 'пустая строка (по умолчанию) a$(2) = SPACE$(20000) 'строка из 20000 символов . . . a$(50) = "The last one" Многомерные массивы. Массивы могут быть одно- или более мерными. Максимальная разм мерность массива - 8. Одномерный массив, как рассмотренный выше массив payments, является простым списком значений. Двумерный массив представляет собой таблицу чисел, разделенную на ряды и колонки. Многомерные массивы не имеют аналога в обычной среде, но их использование также возможно. DIM a(15) (одномерный список) DIM b(15,20) (двумерная таблица) DIM c(5,5,10,20,3) (пятимерный массив) Максимальное количество элементов по каждому измерению равно 32768. Проверка границ массивов. В Turbo Basic делается все возможное, чтобы помочь вам избежать ошибок при задании индексов массивов (т.е. индексов, которые являются слишком большими, или слишком маленькими для данного массива). Компилятор сообщает вам о неправильном использовании индексов в виде констант: DIM a(50) a(51) = 33 Эта программа не будет скомпилирована, т.к. Turbo Basic не будет генерировать программу, которая пытается обратиться к 52-му элементу массива, имеющего всего 51 элемент. Однако, если вы в качестве индексов используете переменные, то компилятор не сможет обнаружить ошибку: DIM a(50) n = 51 a(n) = 33 Даже если эта программа скомпилируется без ошибки, вы все же можете определить выход индекса в строке 3 за заданные пределы во время выполнения программы, скомпилировав программу с ключем отладки Bounds (границы). (Более подробная информация о проверке индексов массивов приведена в разделе "Дополнительные команды" в Главе 3. Требования к памяти, отводимой под массивы. По техническим причинам, связанным с эффективностью программы по быстродействию и объему занимаемой памяти, Turbo Basic ограничивает размер одного массива 64К байтами памяти, хотя программа может иметь столько массивов по 64К байт, сколько позволяет объем имеющейся памяти. Максимальное количество элементов, которое может содержать массив, зависит от его типа и определяется следующим образом: _____________________________________________________________ Тип Требования к памяти _____________________________________________________________ Целый 2 байта на элемент (32768 элементов в 64К) Длинный целый 4 байта на элемент (16384 элемента в 64К) Обычная точность 4 байта на элемент (16384 элемента в 64К) Двойная точность 8 байтов на элемент (8192 элемента в 64К) Символьный 4 байта на элемент (16384 элемента в 64К) _____________________________________________________________ Примечание: В элементе символьного массива содержится только указатель и длина строки. Сама строка данных хранится в пространстве памяти, отведенном под символьные строки, и занимает столько байтов, сколько в строке имеется символов. Пространство символьных строк максимально может содержать 64К символов. Динамическое распределение памяти. Turbo Basic поддерживает динамическое распределение памяти. Динамическое распределение означает создание массивов переменного размера в период выполнения программы, вместо создания структур постоянного размера (или статических) в период компиляции. Это позволяет создавать массивы в точности того размера, который требуется для хранения данных, генерируемых программой во время своего исполнения. После завершения выполнения какой-либо функции, отведенная под динамические массивы память может быть возвращена и снова использована. Чтобы создать динамический массив, надо просто использовать в операторе DIM аргументы в виде переменных; если свободная память имеется в наличии, то массив будет создан. Когда ваша программа завершит использование этого массива, используйте оператор ERASE для его очистки с тем, чтобы память могла быть снова использована для других целей. Например: 'в примере сначала определяется количество записей в файле, 'затем задаются размерности динамических массивов и они 'загружаются OPEN "PARTS.DTA" AS #1 LEN=56 count = LOF(1)/56 DIM partNo(count),desk$(count),quan(count),cost(count) GOSUB LoadArrays 'загрузка массивов GOSUB UseArrays 'использование массивов ERASE partNo,desc$,quan,cost Чтобы воспользоваться преимуществом наличия динамических масcивов в Turbo Basic, вам необходимо только определиться с каждым массивом программы: статический он, или динамический? Является ли его размер фиксированным, в соответствии со структурой программы, или он зависит от некоторого параметра, значение которого неизвестно до начала выполнения программы? Например, массив births из приведенного ранее примера лучше создать как статический, т.к. он всегда содержит ровно 100 элементов. Недостатком динамических массивов является то, что вы можете попытаться задать большую размерность массива и получите отказ, т.к. в момент выполнения вашей программы может не оказаться достаточной свободной памяти для удовлетворения вашего запроса. Если программа содержит только статические массивы и имеется достаточно памяти, чтобы начать ее выполнение, то она не прервется из-за недостатка памяти, поскольку ее массивы созданы заранее, до начала ее выполнения. Поэтому программа, использующая динамические массивы, должна учитывать, что возможна ситуация, когда во время ее выполнения не окажется достаточно памяти для создания всех массивов, которые она объявляет. Прежде, чем задать размерность динамического массива, используйте функцию FRE(-1), чтобы убедится в наличии достаточного пространства для этого массива. Объявление статических или динамических массивов. Метаоператоры $DYNAMIC и $STATIC задают используемый в программе по умолчанию тип массивов. Обычно программа содержит один из этих метаоператоров. По умолчанию, компилятор предполагает заданным метаоператор $STATIC. Массивы считаются динамическими в следующих случаях: - Если они объявляются после метаоператора $DYNAMIC, например: 10 $DYNAMIC 20 DIM A(10) - Если они объявляются динамическими в явном виде: 10 DIM DYNAMIC A(10) - Если в операторе DIM используется переменная для задания границы индекса, например: 10 X%=10 20 DIM A(X%) - Если массив включен в оператор COMMON, например: 10 DIM A(10) 20 COMMON A(1) - Если один и тот же идентификатор массива встречается в двух или более операторах DIM, например: 10 DIM A(10) 20 A(0)=10 30 DIM A(10) - Если массив объявлен локальным в процедуре или в функции, например: DEF FNTest% LOCAL A() DIM A(10) FNTest% = A(0) END DEF Тип массива может быть также задан атрибутом STATIC или DYNAMIC в операторе DIM. Кроме того, массив всегда будет динамическим, если в связанном с ним операторе DIM используется выражение. Например: $STATIC 'с этого момента все массивы будут статическими DIM a(40),b(20,20) 'поэтому a и b - статические массивы DIM DYNAMIC c(20) 'атрибут DYNAMIC отменяет действие 'метаоператора $STATIC DIM d(n) 'использование переменной в операторе 'DIM также делает массив динамическим $DYNAMIC 'с этого момента компилятор полагает, 'что все массивы динамические DIM e(5) 'поэтому e - динамический массив Очищайте динамические массивы оператором ERASE. Стирание оператором ERASE статического массива не увеличивает объем доступной памяти, но устанавливает значения всех его элементов равными нулю (для символьных массивов - пустой строке). Выражения. Выражение состоит из операторов и операндов, которые выполняют некоторые действия при вычислении выражения. В Turbo Basic имеется два основных типа выражений: символьные и числовые. Символьное выражение состоит из символьных констант, символьных переменных и символьных функций (т.е. тех, которые оканчиваются на знак "$"). Кроме того, оно может быть дополнено оператором конкатенации - знаком плюс (+). Значением символьного выражения является строка, т.е. последовательность символов ASCII известной длины. Примеры символьных выражений: "Cats and dogs" a$ a$ + z$ LEFT$(a$ + z$) a$ + MID$("Cats and dogs",5,3) RIGHT$(MID$(a$ + z$,1,6),3) Числовые выражения состоят из числовых констант, переменных и функций, которые могут быть разделены числовыми операторами. Числовые выражения всегда сводятся к значению, имеющему один из четырех числовых типов (целое, длинное целое, обычной точности, двойной точности). Примерами числовых выражений являются: 37 37/15 a 37/a SQR(37/a) SQR((c + d)/a) * SIN(37/a) При формировании числовых выражений вы должны учитывать, что некоторые операторы будут выполняться первыми. Ниже приведен список числовых операторов в порядке уменьшения их приоритетов. Наивысший приоритет имеет оператор возведения в степень; самый низший - IMP: - Возведение в степень (^). - Отрицание (-). - Умножение и деление с плавающей запятой (*,/). - Целочисленное деление (\). - Вычисление по модулю (MOD). - Сложение и вычитание (+,-). - Операторы отношений (<,<=,=,>=,>,<>). - NOT (логическое отрицание). - AND (логическое И). - OR, XOR (логическое ИЛИ, исключающее ИЛИ). - EQV (эквивалентность). - IMP (импликация). Например, значением выражения 3+6/3 будет 5, а не 3. Поскольку операция деления имеет более высокий приоритет, чем сложение, то выражение (6/3) будет вычислено первым. Обработку операций одинакового приоритета Turbo Basic осуществляет слева направо. Например, в выражении 4-3+6 сначала выполняется вычитание (4-3), а не сложение (3+6), что даст промежуточное выражение 1+6. Операции, заключенные в круглые скобки, имеют наивысший приоритет и всегда выполняются первыми; внутри круглых скобок действует обычная система приоритетов. Операторы. Числовые операторы делятся на три основные группы: арифметические, отношений и логические. Арифметические операторы. Арифметические операторы задают выполнение обычных математических операций. В таблице 4-2 приведены арифметические операторы в порядке уменьшения их приоритетов. Таблица 4-2. Арифметические операторы. _____________________________________________________________ Оператор Действие Пример _____________________________________________________________ ^ Возведение в степень 10^4 - Отрицание -16 *,/ Умножение, деление с плавающей 45*19 запятой 45/19 \ Целочисленное деление 45\19 MOD Вычисление по модулю 45 MOD 19 +,- Сложение, вычитание 45+19,45-19 _____________________________________________________________ Два из этих операторов требуют пояснения. Обратная косая черта (\) обозначает целочисленное деление. Целочисленное деление округляет операнды до целых значений и выдает усеченный результат. Например: 5\2 дает результат 2, а 9\10 дает 0. Остаток целочисленного деления может выть получен оператором MOD (вычисление по модулю). (Заметим, что оператор MOD может быть применен только к коротким целым числам.) Оператор MOD подобен оператору целочисленного деления за исключением того, что он возвращает остаток от деления, а не частное. Например, 5 MOD 2 равно 1, 9 MOD 10 равно 9. Операторы отношений. Операторы отношений позволяют сравнивать значения двух строк или двух чисел (но не одно с другим) с целью получения логического результата ИСТИНА или ЛОЖЬ. Результатом сравнения является целое число -1, если результат был ИСТИНА, и 0, если результат был ЛОЖЬ. Например: PRINT 5>6,5<6,(5<6)*15 При этом будут напечатаны 0, -1, -15. Хотя числовые результаты, возвращаемые операторами отношений, и могут быть использованы в числовых выражениях (например, a=(b>c)/13), все же обычно они используются в операторе IF, или в другом операторе принятия решения, с целью выбора нужного пути передачи управления в программе. В таблице 4-3 перечислены операторы отношений. Таблица 4-3. Операторы отношений. _____________________________________________________________ Оператор Отношение Пример _____________________________________________________________ = Равенство x=y <> Неравенство x<>y < Меньше чем x Больше чем x>y <= Меньше или равно x<=y >= Больше или равно x>=y _____________________________________________________________ Когда арифметические операторы и операторы отношений объединяются в одном выражении, то арифметческие операторы имеют более высокий приоритет. Например, значением выражения 4+5<4*3 является -1 (ИСТИНА), т.к. арифметические операторы выполняются до оператора отношения, который проверяет истинность выражения 9<12. Логические операторы. Логические операторы выполняют логические (булевы) операции над целыми числами. При использовании совместно с операторами отношений, они позволяют выполнять сложные проверки, подобные следующей: IF day>29 AND month=2 THEN PRINT "Error in date" В этой строке выполняется операция логического И над результатами целого типа, возвращаемыми двумя операторами отношений. (Оператор AND имеет более низкий приоритет, чем операторы отношений ">" и "=", поэтому круглые скобки здесь не нужны.) Например, если day=30 и month=2, то оба оператора отношений дадут результат ИСТИНА (-1). Если рассматривать двоичное представление целых чисел, то -1 имеет двоичное значение &HFFFF (все разряды взведены), а 0 - &H0000 (все разряды сброшены). Затем оператор AND выполнит операцию логического И над этими двумя результатами, имеющими значение ИСТИНА: 1111 1111 1111 1111 (-1) AND 1111 1111 1111 1111 (-1) _____________________________ 1111 1111 1111 1111 (-1) В результате получилось значение ИСТИНА (не нуль). Оператор OR (иногда называемый включающее ИЛИ) вщзвращает значение ИСТИНА, если один или оба его аргумента имеют значение ИСТИНА, и возвращает значение ЛОЖЬ только в том случае, если оба аргумента имеют значение ЛОЖЬ. Например: -1 OR 0 дает ИСТИНА 0 OR 0 дает ЛОЖЬ 5>6 OR 6<7 дает ИСТИНА Оператор XOR (исключающее ИЛИ) возвращает результат ИСТИНА, если проверяемые величины имеют разные значения, и возвращает результат ЛОЖЬ, если они имеют одинаковые значения. Например: -1 XOR 0 дает ИСТИНА -1 XOR -1 дает ЛОЖЬ 5>6 XOR 6<7 дает ИСТИНА Функция EQV (эквивалентность) противоположна оператору XOR. Она возвращает результат ИСТИНА, если две проверяемые логические величины имеют одинаковые значения, и возвращает результат ЛОЖЬ, если их значения различны: -1 EQV 0 дает ЛОЖЬ -1 EQV -1 дает ИСТИНА 5>6 EQV 1<99 дает ИСТИНА Оператор IMP (импликация) возвращает результат ЛОЖЬ только в том случае, если первый операнд имеет значение ИСТИНА, а второй - ЛОЖЬ: -1 IMP -1 дает ИСТИНА 0 IMP -1 дает ИСТИНА 0 IMP 0 дает ИСТИНА -1 IMP 0 дает ЛОЖЬ Заметим, что логические операторы выполняют действия над целыми числами, а не над длинными целыми, или числами с плавающей запятой. Если операнды, входящие в логическое выражение, не могут быть преобразованы в целые числа, то возникает ошибка переполнения: x=500000 IF x OR y THEN GOTO Exit Этот оператор IF даст ошибку переполнения, т.к. данное значение x не может быть преобразовано в целое число. Манипуляции с разрядами. Помимо создания сложных проверок, логические операторы позволяют осуществлять операции над двоичными образами своих операндов. Наиболее употребимыми являются операции маскирования AND, OR и XOR (исключающее ИЛИ). Операция AND используется для очистки выбранных разрядов целого числа без воздействия на его остальные разряды. Например, чтобы очистить старшие два разряда в целом числе &H9700, надо использовать операцию AND с маской &3FFF; т.е. маска содержит все единицы за исключением двух старших разрядов, которые вы хотите сделать равными нулю: 1001 0111 0000 0000 &H9700 AND 0011 1111 1111 1111 &H3FFF (маска) ________________________________ 0001 0111 0000 0000 &H1700 (результат) Операция OR взводит выбранные разряды целого числа, не влияя на остальные его разряды. Чтобы взвести старшие 2 разряда в числе &H9700, надо использовать операцию OR с маской &HC000; т.е. маска содержит нули во всех разрядах, кроме тех разрядов, которые вы хотите сделать равными единице: 1001 0111 0000 0000 &H9700 OR 1100 0000 0000 0000 &HC000 (маска) _______________________________ 1101 0111 0000 0000 &HD700 (результат) Операция XOR инвертирует (создает дополнение) выбранные разряды целого числа, не влияя на его остальные разряды. Например, чтобы инвертировать старшие два разряда числа &H9700, надо использовать операцию XOR с маской &HC000; т.е. маска содержит нули во всех разрядах, кроме тех, которые вы хотите инвертировать: 1001 0111 0000 0000 &H9700 XOR 1100 0000 0000 0000 &HC000 (маска) ________________________________ 0101 0111 0000 0000 &H5700 (результат) Операция XOR часто используется в графике, т.к. она позволяет перемещать объект, не разрушая его, на сложном фоне. Выполнив однажды операцию XOR над объектом, чтобы нарисовать его на заданном фоне, можно затем повторно выполнить операцию XOR на том же месте, чтобы стереть изображение объекта и восстановить исходный вид фона. Операторы отношений и строки. Turbo Basic позволяет сравнивать символьные данные, представленные в виде строк. Символьные выражения могут быть проверены на равенство, или на "больше чем" и "меньше чем" в смысле алфавитного упорядочения. Два символьных выражения равны тогда и только тогда, когда они содержат одни и те же символы в одном и том же порядке. Например: a$ = "CAT" PRINT a$ = "CAT", a$ = "CATS", a$ = "cat" Сравнение символьных строк основано на следующих двух критериях, используемых в указанном порядке: (1) значения символов, входящих в эти строки, в коде ASCII; (2) длина строк. Например: A меньше B, т.к. код ASCII для A равен 65 и он меньше, чем код B, равный 66. Заметим, однако, что B меньше, чем a, т.к. коды строчных букв больше кодов соответствующих прописных букв (ровно на 32). При сортировке информации, содержащей как строчные, так и прописные буквы, вы можете использовать функции UCASE$ или LCASE$, чтобы разница в регистре, на котором набрана буква, не влияла на результат сортировки. Длина строк учитывается только тогда, когда они оказались идентичными вплоть до последнего символа более короткой строки. При этом считается, что более короткая строка меньше более длинной; например, "CAT" меньше, чем "CATS". Подпрограммы, функции и процедуры. Структура программы на Turbo Basic мщжет быть упрощена, если использовать подпрограммы, процедуры и функции. Подпрограммой называется помеченный набор операторов, который выполняется, если встречается оператор GOSUB. Процедура подобна небольшой программе (которая также является подпрограммой), которая выполняет некоторую частную функцию в вашей основной программе. Функцией называется набор программ, который возвращает символьный или числовой ре- зультат, обычно связанный с параметрами, передаваемыми функции. Помещая сложные и/или часто используемые части программ в эти структуры, вы упростите и укоротите ваши программы. Процедуры Turbo Basic и функции, определенные пользователем, являются развитием простых структур, обеспечиваемых подпрограммами. Хотя миллионы программ на языке Basic были написаны с использованием его первоначальной организационной структуры на основе операторов GOSUB/RETURN, мы рекомендуем вам использовать эти более совершенные структуры. Процедуры и функции в Turbo Basic обеспечивают истинную рекурсию, передачу параметров и доступ к локальным, статическим и глобальным переменным. Если у вас не было раньше возможности убедиться в удобстве использования передачи параметров, локальных переменных и рекурсии, то вам следует постараться сделать это. Процедуры и функции имеют больше общих черт, чем различий. Наиболее существенным различием между ними является то, что функции возвращают значения, и поэтому могут непосредственно включаться в выражения (с буквами "FN", стоящими перед именем функции). Процедуры значений не возвращают, и поэтому обращение к ним должно осуществляться в явном виде с помощью оператора CALL. Например: a = b + FNCubeRoot(c) 'вызов функции CALL OutChar(a) 'вызов процедуры Подпрограммы. Использование подпрограмм является традиционным методом разделения на части программ, написанных на языке Basic. Подпрограмма представляет собой помеченную группу операторов, завершающуюся оператором RETURN. Чтобы выполнить подпрограмму, вы можете использовать оператор GOSUB, в котором указывается метка, связанная с первым оператором подпрограммы. Когда встречается оператор RETURN, управление возвращается на оператор, следующий непосредственно за GOSUB. Например: GOSUB AddMonths PRINT total END AddMonths: total = 0 FOR i = 1 TO 12 total = total + month(i) NEXT i RETURN Функции. Существуют два типа функций: заранее определенные функции (такие, как COS и LEFT$), которые определены в языке, и функции, определенные пользователем, которые могут состоять из одной или нескольких строк. (Более подробная информация о заранее определенных функциях приведена в специальных параграфах Главы 5 "Справочного руководства по Turbo Basic".) Синтаксис для определения функции, состоящей из одной строки: DEF FNидентификатор[(список параметров)]=выражение где "идентификатор" - это имя, назначенное пользователем данному выражению; "список параметров" - это факультативная последовательность из одного или более идентификаторов, разделенных запятыми, которые представляют данные, которые должны быть переданы функции при обращении к ней (количество параметров, передаваемых любой функции, должно быть не более 16); "выражение" определяет действия, которые выполняются с целью получения значения, возвращаемого функцией. Например, рассмотрим метеорологическую программу, которая должна постоянно перводить градусы Цельсия (которые используются внутри программы) в градусы Фаренгейта (которые выводятся на экран и вводятся с клавиатуры) и наоборот. Однострочные функции наилучшим образом подходят для такой программы: DEF FNCtoF(degreesC) = (1.8 * degreesC) + 32 DEF FNFtoC(degreesF) = (degreesF - 32) * .555555 Чтобы вывести на экран колебания температуры, которые по соглашению всегда хранятся в градусах Цельсия, используйте функцию FNCtoF (читается как "Функция C в F") в любом операторе, который может принимать числовое выражение; например, PRINT: temp = 100 PRINT FNCtoF(temp) Чтобы преобразовывать значения из градусов Фаренгейта в градусы Цельсия, используйте функцию FNFtoC: INPUT "Enter today's high: ", th temp = FNFtoC(th) Многострочные функции Turbo Basic играют более существенную роль, чем простые однострочные функции интерпретирующего Basic. Turbo Basic позволяет функции содеражть много программных строк и использовать ее подобно подпрограмме, которая также иногда возвращает значение. Формальный синтаксис для объявления многострочной функции: DEF FNидентификатор[(список параметров)] [объявление переменных] . . операторы . [EXIT DEF] [FNимя функции = выражение] END DEF где "идентификатор" задает имя функции, "список параметров" является факультативным перечнем формальных параметров, разделенных запятыми, которые определяют переменные, передаваемые функции при ее вызове. Для иллюстрации рассмотрим многострочную функцию Factorial, которая часто используется в статистике. (Вы, наверно, помните со школьной скамьи, что факториалом положительного целого числа n (записывается как n!) является произведение всех целых чисел, меньших или равных n. Например, 6! = 6*5*4*3*2*1 = 720.) Факториал не включен в набор встроенных математических операторов Turbo Basic, но многострочная функция может восполнить этот пробел: 100 DEF FNFactorial#(x%) 110 LOCAL i%,total# 120 IF x%<0 OR x%>170 THEN FNFactorial#=-1 : EXIT DEF 130 total# = 1 140 FOR i%=x% TO 2 STEP -1 'можно также сделать 150 total# = total# * i% 'умножение и в порядке 160 NEXT i% 'возрастания чисел 170 FNFactorial# = total# 180 END DEF FNFFactorial демонстрирует структуру многострочной функции (номера строк здесь приведены для того, чтобы на них можно было ссылаться в тексте, а вообще они, конечно, необязательны). Определение функции ограничивается операторами DEF FN и END DEF. Отделение всех входящих в нее операторов двумя пробелами от начала строки делает текст более наглядным. В строке 100 задается имя функции и, следовательно, ее тип (# означает двойную точность). FNFactorial имеет единственный формальный параметр целого типа - x%. В строке 110 объявляется пара локальных переменных - i% и total#. Локальные переменные - это временные структуры, доступные и видимые только внутри определения функции или процедцры (они будут подробнее обсуждены в следующем параграфе "Локальные переменные"). В строке 120 осуществляется контроль аргумента, передаваемого функции FNFactorial. Не должно быть попыток вычислить факториал отрицательного числа (такого нет в природе), или факториал такого большого числа, что результат выйдет из диапазона 10^38, обеспечиваемого арифметикой двойной точности (факториал становится таким большим для числа 170!, и равен 7.26Е+308). В этих случаях значение, возвращаемое функцией, задается равным -1 и выполняется оператор EXIT DEF. Программа, использующая функцию FNFactorial, должна знать, что значение -1, возвращенное этой функцией, соответствует ошибочному обращению, и действовать соответствующим образом. (К сожалению, значением 0! является 1.) Оператор EXIT DEF для функций является тем же, что и оператор RETURN для подпрограмм. Он передает управление на оператор, который вызвал функцию. Кажется, что для этой цели можно использовать оператор RETURN, но это не так. Заметим, что EXIT DEF не является обязательным, если вам не требуется делать выход из функции до ее завершения. В строках со 130 по 160 запрограммирован алгоритм вычисления факториала. Эта часть многострочной функции ("тело") может быть люьой необходимой длины. В строке 170 определяется значение, которое возвращает FNFactorial, присваивая его имени функции. Удивительно, но такое присваивание не является синтаксическим требованием к определению функции. Если вы не сделаете присваивания значения имени функции, то возвращаемое значение будет произвольным. Определение функции FNFactorial заканчивается оператором END DEF в строке 180. Подобно EXIT DEF, END DEF возвращает управление оператору, вызвавшему данную функцию. (Оператор END реализует завершение чего-либо в синтаксисе, принятом в Turbo Basic, - он используется в целом ряде структур.) Если вас интересует, сколько существует возможных комбинаций карт в колоде, то функция FNFactorial даст ответ: PRINT FNFactorial#(52) Результатом будет 8.065817517094388Е069. Поскольку функция FNFactorial определена, как имеющая формальный параметр целого типа, то аргументы, заданные в формате с плавающей запятой, будут округляться до целых прежде, чем окажутся переданными этой функции; например, FNFFactorial(2.7) это то же самое, что и FNFactorial(3). Если вы вызовете FNFactorial с параметром большим, чем может обработать подпрограмма преобразования в целый формат (т.е. больше, чем 32767, или меньше, чем -32768), то на этапе выполнения программы будет зафиксирована ошибка 6 - Overflow (Переполнение). Такая же обработка осуществляется и для аргументов, передаваемых встроенным функциям Turbo Basic, которым нужны аргументы целого типа; например, LOCATE 2.7,1 поместит курсор на строку 3. Формальные и фактические параметры. Переменные, которые указываются в списке параметров в определении функции, называются формальными параметрами. Они служат только для определения функции и существенно отличаются от других переменных в программе, имеющих такое же имя. Чтобы проиллюстрировать это, рассмотрим короткую программу: 100 DEF FNArea(x,y) = x*y 110 x = 56 120 PRINT x,FNArea(2,3),x Переменная x в строках 110 и 120 этой программы никак не связана с параметром x, который определен в функции Area. При использовании этой программы, переменная x сохраняет одно и то же значение до и после обращения к функции FNFArea: будет напечатано оба раза число 56. Значения, передаваемые функции при ее вызове на этапе выполнения программы, иногда называются фактическими параметрами. В последнем примере числовые константы 2 и 3 являлись фактическими параметрами, передаваемыми функции FNFArea. Фактические параметры также могут быть переменными: a = 2 : b = 3 PRINT FNArea(a,b) Типы функций. Функции могут возвращать значение любого из четырех числовых типов (целое, длинное целое, с плавающей запятой обычной и двойной точности), а также символьное значение типа строки. Тип функции, как и переменной определяется ее именем. При этом используются символы объявления типа и оператор DEFtype; например: DEF FNIntSquareRoot%(x) = INT(SQR(x)) PRINT FNIntSquareRoot%(2) и DEF FNRepeatFirst$(a$) = LEFT$(a$,1) + a$ PRINT FNRepeatFirst$("Hello") Попытка сделать присвоение числовой переменной значения, возвращаемого функцией символьного типа, или символьной переменной значения, возвращаемого функцией числового типа, приведет к фиксации ошибки 13 - Type Mismatch (Несоответствие типа). Процедуры. Процедурами называются части программы, ограниченные операторами SUB и END SUB. Существует следующий формальный синтаксис объявления процедуры: SUB имя процедуры[(список параметров)][INLINE] [объявление переменных] . . операторы . [EXIT SUB] END SUB Параметр "имя процедуры" задает имя процедуры, которое может иметь длину до 31 символа, но которое не может содержаться больше ни в одном операторе SUB данной программы. "Список параметров" является факультативным элементом, состоящим из списка формальных параметров, разделенных запятыми, которые определяют переменные, передаваемые процедуре при ее вызове. (Любой процедуре может быть передано не более 16 параметров.) Параметр INLINE определяет, что процедура имеет переменное число неуказанных параметров, и что она будет содержать встроенный ассемблерный код (см. Приложение C "Интерфейс с языком ассемблера"). Как было указано ранее, наиболее очевидным различием между функциями и процедурами является то, что процедуры не возвращают никакого значения; однако, они, кроме того, не могут быть вызваны внутри выражений, не имеют типа, и не содержат присваивания значения имени процедуры. Обращение к процедурам осуществляется с помощью оператора CALL, во многом сходного с оператором обращения к подпрограммам GOSUB. Рассмотрим программу, которая определяет и вызывает процедуру PrintTotal: SUB PrintTotal(a,b,c,d) LOCAL total total = a+b+c+d PRINT total END SUB w=1 : x=2 : y=0 : z=3 CALL PrintTotal(w,x,y,z) Передача процедурам массивов. В отличие от функций, процедуры позволяют передавать в качестве аргументов целые массивы. В описании процедуры должно быть объявлено,что она ожидает аргумента в виде массива, включением соответствующего элемента в список формальных параметров. То, что аргумент является массивом, показывается добавлением к идентификатору параметра круглых скобок, в которых заключена числовая константа. Значение этой константы указывает на размерность массива, но не на его размер. Проиллюстрируем это: SUB ContZeros(a(1),size,count) 'Переменная count возвращает количество нулевых элементов 'в одномерном массиве чисел с обычной точностью, который 'содержит size+1 элемент LOCAL i count = 0 FOR i=0 TO size IF a(i)=0 THEN count=count+1 NEXT i END SUB Наличие a(1) в списке параметров определяет первый аргумент процедуры CountZeros как одномерный массив. При этом ничего не сообщается о величине этого массива. Эта задача возлагается на второй аргумент - size. Аргумент count используется для того, чтобы передать количество нулевых элементов, найденных в массиве a. Вызов процедуры CountZeros ocуществляется следующим образом: size = 100 : DIM Primes(size) GOSUB StrikePrimes 'все непростые числа получают 'ненулевое значение CALL CountZeros(Primes(),size,primesCount) PRINT "There are" primesCount "primenumbers <=" size END Определение процедур и функций и порядок выполнения программы. Расположение определений процедур и функций в программе не является чем-то существенным. Функция может быть определена в строке 1 или в строке 1000 программы независимо от того, где она используется. И вам не нужно направлять порядок выполнения программы таким образом,чтобы определения процедур и функций были бы исполнены на этапе инициализации программы (что, однако, вы должны сделать для однострочных функций в интерпретирующем Basic). Компилятор увидит все ваши определения, где бы они ни располагались. Кроме того, в отличие от подпрограмм, программа в процессе выполнения не может случайно "попасть" в область, занимаемую процедурой или функцией. Что касается пути, по которому идет выполнение программы, то определения процедур и функций являются для нее просто невидимыми. Например, когда выполняется следующая программа из четырех строк: CALL PrintSomething SUB PrintSomething PRINT "Printed from within PrintSomething" END SUB то сообщение будет напечатано только один раз. Примечание: Вы должны рассматривать определения ваших процедур и функций как изолированные части программы. Не входите и не выходите из них с помощью операторов GOTO, GOSUB или RETURN, т.к. вы получите при этом непредсказуемые и/или катастрофические результаты. Заметим, что определения ни процедур, ни функций не могут быть вложенными; т.е. вы не можете определить другую процедуру или функцию в определении процедуры или функции (хотя процедура или функция может содержать вызовы других процедур и функций). Контроль аргументов. В отличие от других компиляторов Basic, Turbo Basic осуществляет контроль числа и типов аргументов в вызовах процедур и функций в программе на соответствие их числу и типу формальных параметров в соответствующих определениях. Например, попытка скомпилировать программу: DEF FNDummy(a,b) END DEF t = FNDummy(3) приведет к тому, что в строке 3 будет зафиксирована ошибка Parameter Mismatch (Несоответствие параметров), т.к. для функции FNDummy требуются два аргумента. Дополнительные вопросы, связанные с процедурами и функциями. Передача параметров по значению или по ссылке. Имеется несколько небольших, но существенных различий между процедурами и функциями. Для понимания этих различий требуется разобраться в том, как Turbo Basic обрабатывает вызовы процедур и функций в процессе выполнения программы (см. табл.4-4). Таблица 4-4. Различия между процедурами и функциями. _____________________________________________________________ Действие Функции Процедуры _____________________________________________________________ Возврат значения Да Нет Метод вызова Вызов в выражениях Использование оператора CALL Передача параметров Передача по значению Передача по ссылке и по значению Тип переменных по умолчанию SHARED (общие) STATIC(статические) Аргументы в виде массивов Нет Да _____________________________________________________________ Прежде всего рассмотрим небольшую программу, в которой определяется и вызывается функция CylVol: DEF FNCylVol(radius,height) STATIC FNCylVol = radius * radius * 3.14159 * height END DEF r = 4.7 : h = 12.1 vol = FNCylVol(r,h) Теперь представим себе последовательность действий, необходимую для выполнения этой программы. Во-первых, вы присваиваете значения переменным r и h. Затем вы вызываете FNCylVol, передавая ей числовую информацию через r и h. Теперь необходимо уточнить, каким образом обеспечивается передача информации функции. Существуют два способа передачи информации: (1) использование числа 4.7 в качестве радиуса, а числа 12.1 в качестве высоты; (2) использование переменной r в качестве радиуса, и переменной h в качестве высоты. Первый способ называется передачей по значению, а второй - передачей по ссылке. Передача по значению означает копирование аргументов при вызове во временную память и последующую их передачу в вызванную программу по мере необходимости. Как только исполнение процедуры или функции завершится, эти значения удаляются из памяти; Таким образом, оригиналы передаваемых значений останутся неизмененными. Передача по ссылке означает передачу указателя, показывающего где хранятся данные (по какому адресу). В приведенном примере адреса переменных r и h передаются как параметры. Вызванная программа может затем получить и изменить реальные значения самих переданных величин. В Turbo Basic используются обе схемы передачи данных, что поясняется ниже. Метод передачи по значению позволяет использовать в качестве аргументов константы или выражения. На этапе выполнения вычисляется значение выражения и передается функции. Например: v = FNCylVol(r,h*2+4.1) При использовании метода передачи по значению не возникает никаких проблем при передаче значения h*2+4.1 функции FNCylVol. Значение выражения вычисляется, и результат передается функции. Однако с другой стороны, метод передачи по ссылке, поскольку он позволяет программе манипулировать переданным значением, не дает возможности передавать константы и выражения (выражение типа h*2+4.1 не имеет адреса в памяти - адреса имеют только переменные). Метод передачи по ссылке работает только тогда, когда аргументом процедуры является переменная. Первый закон передачи параметров: как переменные, так и выражения могут быть переданы при использовании метода передачи по значению. Метод передачи по ссылке позволяет передавать только переменные или массивы. Преимущество передачи по ссылке заключается в том, что вызываемая программа может изменять значения переменных, передаваемых ей, и, таким образом, передавать информацию обратно вызвавшей программе. Поскольку программе при передаче данных по ссылке дается адрес, то она знает, где эта переменная расположена и может как записывать в нее, так и считывать из нее информацию. В отличие от этого, программа, которой передается переменная по значению, не может изменить саму переменную, т.к. не знает, где она располагается в памяти. Второй закон передачи параметров: переменные, передаваемые по ссылке могут быть изменены вызванной программой; переменные, переданные по значению, изменены быть не могут. Чтобы проиллюстрировать это, рассмотрим программу: a = 0 : b = 2 : c = 3 CALL Add(a,b,c,total) PRINT a,total END SUB Add(i,j,k,sum) STATIC sum = i+j+k END SUB Когда подпрограмма Add возвращает управление, переменная total содержит сумму a, b и c. (Подпрограмма Add могла бы быть определена таким образом, чтобы изменить значения каждого из своих аргументов; однако, поскольку она присваивает значение только четвертому своему параметру, то только на переменную total оказывает воздействие вызов подпрограммы Add.) Третий закон является следствием из первых двух: аргументы функции передаются по значению; аргументы процедуры передаются по ссылке и по значению. Это означает, что имена отдельных переменных могут появляться в качестве аргументов при вызове процедуры, и что эти переменные могут быть в ней изменены. Если вы хотите какую-либо переменную передать процедуре по значению, то заключите ее в круглые скобки. Это заставляет Turbo Basic передавать ее как выражение. Процедуры могут также принимать константы и выражения, т.к. они передаются по значению. Вызываемые функции могут принимать константы, переменные и выражения, но они не могут изменять их значений. Вы свободны в присваивании значений формальным параметрам в пределах определения функций; действительно, часто бывает удобно использовать формальные параметры функции для хранения временных данных. Делая так, вы, однако, тем самым не измените фактического значения этого параметра; например: DEF FNDummy(a,b,c) a = a+b+c PRINT a END DEF x = 1 : y = 2 : z = 3 t = FNDummy(x,y,z) PRINT x Присвоение, сделанное в функции Dummy формальному параметру a, не влияет на значение переменной x. Поскольку передача переменной функции вызывает копирование значения этой переменной в область памяти для хранения локальных данных, то могут возникнуть проблемы, если эта переменная очень велика (т.е. она является массивом). Поэтому Turbo Basic не разрешает передачу массивов по значению, хотя вы можете таким образом передавать отдельные элементы массивов. Локальные переменные. В интерпретирующем Basic все переменные являются глобальными. Это означает, что независимо от того, где переменная появляется в программе - в наиболее важной части главной программы, или в самом тривиальном цикле обслуживающей подпрограммы, эта переменная доступна в любой части программы. Это делает возможным следующий вид ошибок: 'главная программа EmployeeCount = 10 n = 1 GOSUB CalcChecks n = n + 1 GOSUB PrintChecks CalcChecks: GOSUB CalcDeductions RETURN CalcDeductions: FOR n=1 TO EmployeeCount . . . NEXT n RETURN PrintChecks: . . . RETURN Переменная n в обслуживающей подпрограмме CalcDeductions и переменная n в главной программе представляют одну и ту же физическую величину. В результате, когда управление в конце концов возвратится в главную программу, то n не будет иметь значение 1, которое ранее было присвоено ей в главной программе, а будет содержать значение EmployeeCount+1, получившееся в результате выполнения цикла FOR/NEXT в CalcDeductions. В соответствии со своим неформальным стилем, Basic не требует, чтобы вы объявляли переменные (т.е. чтобы задавали в каком-либо операторе, что вы собираетесь использовать переменную, именованную так-то и так-то). Даже если вы самым тщательным образом построили свою программу, одна небольшая неточность может погубить все. Чтобы помочь решению этой проблемы, в Turbo Basic предусмотрены "локальные" переменные для процедур и функций. Локальная переменная, в отличие от глобальной, существует только в той программной структуре, где она объявлена. Только наличие локальных переменных является достаточно веским основанием, чтобы вообще отказаться от использования подпрограмм. Например, рассмотрим функцию AddReceipts: DEF FNAddReceipts LOCAL x,y,total FOR x=1 TO 12 FOR y=1 TO 30 total = total + receipts(x,y) NEXT y NEXT x FNAddReceipts = total END DEF Поскольку переменные x и y объявлены как локальные в FNAddReceipts, вы можете использовать имена переменных x и y во всей остальной программе (программисты с математическим образованием склонны использовать имена x и y для всех переменных подряд) без какого-либо влияния при этом на значения x и y в функции FNAddReceipts (и наоборот). Локальные переменные функции FNAddReceipts существуют только пока эта функция вызвана - до и после вызова этой функции ничего не говорит о том, что они вообще когда-то существовали. Чтобы проиллюстрировать это, рассмотрим фрагмент программы, в котором осуществляется вызов FNAddReceipts: x = 35 thisYear = FNAddReceipts PRINT x Тот факт, что имя x используется для обозначения других переменных в процессе вычисления значения, возвращаемого функцией FNAddReceipts, никак не отражается на переменной x в строках 1 и 3. Благодаря чудесным возможностям стековой памяти, x в FNAddReceipts является совершенно другой переменной, которая не может существовать после того, как функция возвратит управление. Локальные переменные должны быть объявлены до первого выполняемого оператора процедуры или функции. Локальные переменные могут быть массивами; просто надо задать размерность массива после того, как обозначающий его идентификатор объявлен локальным: SUB Dummy LOCAL a,locArray() DIM DYNAMIC locArray(50) . . . ERASE locArray END SUB Локальные массивы автоматически уничтожаются при выходе из процедуры или функции. Недостатком локальных переменных является то, что они теряют свое значение между последовательными входами в содержащую их программу. При каждом обращении к программе локальные переменные создаются заново, под них выделяется память и они инициализируются нулем (или пустой строкой). Например: SUB Dummy LOCAL c PRINT c c = c + 1 END SUB Вы можете целый день делать вызов CALL Dummy, и при этом каждый раз будет печататься 0. Общие переменные. Процедуры и функции могут также объявлять переменные с атрибутом SHARED (общий). Общая переменная по своей сути противоположна локальной: она видима и может быть использована в любой части программы (такие переменные часто называют глобальными). DEF FNDummy SHARED a a = 6 FNDummy = a END DEF PRINT FNDummy,a Поскольку было использовано описание SHARED (общий), то переменная "a" в функции FNDummy и переменная "a" в операторе PRINT являются одним и тем же объектом. Неописанные в функции переменные по умолчанию считаются общими; например, в функции AddReceipts, приведенной ранее, подразумевалось, что массив receipts является общим. В определениях процедур атрибутом по умолчанию является STATIC (статический). Однако, мы настоятельно рекомендуем вам в явном виде описывать все переменные, используемые в определениях процедур и функций. Статические переменные. Статические переменные занимают промежуточное положение между локальными и общими. Подобно локальной переменной, статическая переменная не пересекается с другими переменными в программе, имеющими тот же идентификатор, - она видима только в пределах процедуры или функции, объявившей ее. Подобно общей переменной, статическая переменная занимает постоянное место в памяти, и поэтому не теряет свое значение между обращениями к функции или процедуре. Она инициализируется нулем (или пустой строкой) только при начальном запуске программы. SUB Dummy STATIC STATIC i i = i + 1 PRINT i END SUB i = 16 CALL Dummy CALL Dummy PRINT i Статическая переменная i в процедуре Dummy не совпадает с переменной i в "главной программе". Однако, в отличие от локальной переменной, она сохраняет свое значение между вызовами содержащей ее процедуры. Начальным ее значением, как и любой переменной, является 0, и оно дважды увеличивается на 1 двумя вызовами процедуры Dummy. При соответствующем использовании аргументов и локальных переменных, процедуры и функции могут быть сделаны совершенно независимыми от программы, в которой они используются. Использование принципа "главный файл/рабочий файл", заложенного в Turbo Basic, и метаоператора $INCLUDE позволяет без каких-либо трудностей передавать их новым программам. Рекурсия. Turbo Basic поддерживает рекурсию - процесс, при котором функция или процедура вызывает сама себя прямо, или косвенно. Приведем описание функции FNFactorial с использованием рекурсии: DEF FNFactorial#(n%) IF n%>1 AND n%<=170 THEN FNFactorial# = n%*FNFactorial#(n%-1) ELSEIF n%=0 OR n%=1 THEN FNFactorial# = 1 ELSE FNFactorial# = -1 END IF END DEF Одно обстоятельство сразу становится очевидным: рекурсивный алгоритм короче, чем нерекурсивный. Функция FNFactorial свелась к одному блоку IF, не содержащему локальных переменных. Краткость является свойством рекурсивных программ. Другим свойством рекурсивной программы является ее сложность. Наилучшим способом понять рекурсивный алгоритм служит просчет некоторых тестовых вариантов с помощью карандаша и бумаги. Проделаем такую операцию для вычисления факториала от 3, как если бы в программе на Turbo Basic встретился оператор: PRINT FNFactorial#(3) В самом начале аргумент 3 передается в функцию по значению. Первое, что делает FNFactorial, это проверяет, что заданный аргумент больше 1 и меньше или равен 170; число 3 удовлетворяет этой проверке, поэтому выполняется оператор, следующий за первым THEN: FNFactorial# = 3*FNFactorial#(2) В этой строке имени функции присваивается значение, равное 3 умноженному на значение функции FNFactorial(2). Прежде, чем будет осуществлено присваивание, необходимо еще раз вызвать FNFactorial, на этот раз - с аргументом 2. Пока забудем про необходимость присваивания, чтобы вернуться к нему позже. При втором обращении функция FNFactorial получает аргумент 2 и продолжает нормально выполняться. Она снова определяет, что ее аргумент больше 1 и меньше или равен 170, и снова вы получаете рекурсивное выражение: FNFactorial# = 2*FNFactorial#(1) Мы еще раз на время забудем про выполнение присваивания и вызовем FNFactorial в третий раз - с аргументом 1. Легко обнаружить, что FNFactorial(1) дает значение 1 при выполнении второго THEN. На этот раз, наконец, FNFactorial выполняет возврат и возвращает значение 1 предыдущей отложенной функции FNFactorial. Теперь может быть выполнен соответствующий ей оператор присваивания: FNFactorial# = 2*1 По завершении этого промежуточного обращения к FNFactorial, значение 2 возвращается первому обращению к FNFactorial, и может быть выполнен первый оператор присваивания: FNFactorial# = 3*2 После выполнения этого последнего присваивания, управление возвращается на оператор PRINT и число "6" появляется на экране. Нельзя дать однозначного ответа на вопрос, когда следует использовать рекурсию, но в общем можно сказать, что ее целесообразно использовать, когда решаемая задача по своей сути рекурсивна. Факториалы, например, иногда в математических справочниках определяются рекурсивно: Для любого положительного целого n, если n>1, то n! = n * (n-1)! иначе n! = 1 Использование рекурсивного алгоритма возможно потребует, чтобы вы увеличили размер стека вашей программы посредством метаоператора $STACK, т.к. каждый уровень рекурсии может потребовать 125 байтов из области стека (это количество может меняться). Чтобы определить размер оставшегося в стеке свободного пространства, используйте функцию FRE(-2). Файлы. Как только вы создали программу или набор данных, к которым вам потребуется впоследствии снова обращаться, следующим логическим шагом будет их сохранение. Сохраняя свои данные, вы создаете файл, который может быть использован для ввода и вывода. Сохраняя свои данные, вы создаете файл, который может быть использован для ввода и вывода. Вы можете создавать файлы трех типов: последовательные, с произвольным доступом и двоичные. Далее мы рассмотрим каждый из этих типов, но сначала поясним, каким образом присваиваются имена файлам и/или справочникам (которые содержат несколько файлов или подсправочников). Как граждане страны MS-DOS, файлы, которые вы создаете и к которым обращаетесь с помощью Turbo Basic, должны удовлетворять соглашению об именах, принятому в MS-DOS. Имена файлов состоят из двух частей, разделенных точкой: имяфайла.рас где "имяфайла" может иметь от одного до восьми символов, а "рас" является факультативным расширением, или типом, содержащим до трех символов. Если имя файла имеет больше восьми символов, то Turbo Basic автоматически усекает его и добавляет в конце точку. Например, если вы ввели: TESTINGDATA то файл получит имя: TESTINGD. Если введенная строка содержит точку, разделяющую имя файла и его расширение, но имя файла длиннее восьми символов, то Turbo Basic усекает имя до восьми символов и добавляет к ним заданное расширение; так, из: VERYLONGFILENAME.TBS формируется: VERYLONG.TBS Если вы ввели расширение, состоящее более, чем из трех символов, то все лишние символы будут усечены; например, из: TESTING.DATA получается: TESTING.DAT Имена файлов и расширения могут содержать следующие символы: A-Z 0-9 () {} @ # $ % ^ & ! - _ ' / ~ Заметим, что символ пробела не может быть использован, а символы, введенные на нижнем регистре, автоматически переводится на верхний регистр. В следующих примерах показаны допустимые имена файлов: MYFIRST.TBS MY1ST.TBS MY_ABCS.(1) 10-25-51.@@@ Кроме операторов для создания, чтения и записи файлов, в Turbo Basic имеются средства для выполнения некоторых функций, свойственных DOS, непосредственно из программы. Оператор NAME переименовывает файлы. KILL уничтожает файлы. MKDIR создает справочники. CHDIR изменяет активный справочник. RMDIR уничтожает справочники. Однако, нет команды COPY; вместо этого следует использовать методы работы с двоичными файлами (или использовать команду SHELL, чтобы задействовать COMMAND.COM). Имена файлов, используемые в операторах Turbo Basic (например, KILL или OPEN), должны быть заданы в форме символьных строк; например: KILL "myfile.bak" или a$ = "myfile.bak" : KILL a$ но не так: KILL myfile.bak Более подробная информация о файлах и справочниках приведена в Приложении G "Введения в DOS", а также в руководстве по DOS. Имена справочников и путей. В MS-DOS, версия 2.0 и больше (Turbo Basic и программы, которые он создает, не могут работать на более ранних версиях), при форматировании гибкого или жесткого диска создается справочник фиксированного размера, называемый root (корневой). Элементами корневого справочника могут быть как файлы, так и дополнительные справочники (называемые подсправочниками). Как и обычные файлы, подсправочники имеют имя и расширение стандартного вида, и могут расти и расширяться по мере необходимости. Подсправочники могут содержать свои собственные подсправочники, что в результате создает древовидную структуру файлов и справочников (см.рис.4-1). (корневой справочник) _____________________________________________________ | | | BIN TURBOBAS WORDSTAR | | _____________ | | | | CHKDSK FORMAT | | ____________________________________ | | | EXAMPLES MYFIRST.BAS MYFIRST.EXE | _________________ | | EX1.BAS EX2.BAS Рис.4-1. Иерархия файловой системы. В начале дерева файловой системы находится корневой справочник, имя которого определено заранее как обратная косая черта (\). Файлы на дереве определяются по цепочке справочников, или имени пути, которая ведет к ним. Имена путей формируются в виде перечисления подсправочников, ведущих к файлу, разделенных обратными косыми чертами (\). Другими словами, полное описание файла CHESS.BAS в справочнике \TURBO\BASIC \GAMES будет выглядеть так: буква, обозначающая дисковод и двоеточие | C:\TURBO\BASIC\GAMES\CHESS.BAS | | | | |----путь---------|-----|---| | | | расширение | имя файла Идущая спереди обратная косая черта (\) означает, что путь начинается из корневого справочника, в отличие от начала пути из текущего справочника. DOS помнит имя текущего справочника (называемого также активным, или справочником по умолчанию), в котором она осуществляет поиск файлов, если вы не задали путь к файлу. Если имя пути начинается не с обратной косой черты, то оно описывает путь относительно текущего справочника. Например, если \TURBO\BASIC является текущим справочником, то следующие строки точно описывают расположение файла CHESS.BAS: GAMES\CHESS.BAS или \TURBO\BASIC\GAMES\CHESS.BAS В листинге каждого подсправочника, полученном либо в DOS, либо в Turbo Basic (с использованием оператора FILES), имеются два специальных файла: . и .. . Имя файла в виде одной точки идентифицирует распечатываемый справочник как подсправочник. Имя файла в виде двух точек содержит ссылку на справочник-родитель данного справочника (т.е. стоящий на одну ступень выше по дереву). Например, чтобы сменить активный справочник на справочник-родитель текущего активного справочника, используйте оператор CHDIR со специальным именем файла в виде двух точек: CHDIR ".." Методы хранения файлов. Turbo Basic предлагает три различных способа запоминания и считывания информации с диска: последовательный, произвольный и двоичный ввод/вывод файлов. Каждый из них имеет свои преимущества и недостатки, поэтому который из них больше подойдет вам, зависит от специфики вашей задачи. Краткие основы управления базой данных. Традиционные методы программирования подразделяют файлы с данными на отдельные записи, каждая их которых состоит из одного или более полей. Например, в программе списка почтовых адресов, каждая запись в файле данных представляет отдельного адресата. В каждой записи имеются поля, содержащие конкретные данные об этом адресате. Например, штат и почтовый индекс являются двумя полями, которые вы можете найти в файле почтовых адресов. При воспроизведении файла на бумаге, каждая строка представляет собой запись, а колонки соответствуют полям: _____________________________________________________________ Имя Адрес Город Штат Индекс Класс Вклад _____________________________________________________________ Cathy Harvey 1010 E.Redwood Sioux City IA 51103 73 0.00 Andrew Rich 37 Anderson Rd Houston TX 77018 58 500.00 Larry Irving 3210 Main Lindsborg KS 67456 81 0.00 _____________________________________________________________ Этот файл почтовых адресов имеет три записи, в каждой из которых имеется семь полей. По причинам, которые мы вкратце объясним позднее, обычно делается различие между числовыми и символьными полями. В данных записях последние три поля являются числовыми, а остальные - символьными. Последовательные файлы. Методы работы с последовательными файлами сводятся к простому чтению и записи информации в файлы. Команды Turbo Basic для работы с последоательными файлами создают текстовые файлы: файлы из символов кода ASCII с разделителями записей в виде пар символов возврат каретки/перевод строки. Вполне возможно, что самой существенной причиной для использования последовательных файлов является их степень переносимости на другие программы, языки программирования и компьютеры. Вследствие этого, вы часто можете встретить мнение, что последовательные файлы являются краеугольным камнем в обработке данных. Они могут читаться программами обработки слов и редакторами (такими, как редактор Turbo Basic), могут использоваться другими прикладными программами MS-DOS, такими как системы управления базами данных, и могут передаваться через последовательные интерфейсы на подсоединенные другие компьютеры. Идея, положенная в основу последовательных файлов, по своей сути проста: записывать в них данные так, как если бы они были экраном, и считывать из них так, как если бы они были клавиатурой. Чтобы создать последовательный файл, надо выполнить следующие действия: 1. Открыть файл в режиме последовательнго вывода. Для этого в Turbo Basic служит оператор OPEN. Последовательные файлы могут иметь два факультативных параметра, определяющих режим вывода: OUTPUT: Если файл не существует, то создается новый файл. Если файл уже существует, то его содержимое стирается, после чего этот файл трактуется как новый. APPEND: Если файл не существует, то создается новый файл. Если файл уже существует, то Turbo Basic добавляет все данные, записываемые в файл, в его конец. 2. Вывести данные в файл. Для записи данных в последовательный файл используются операторы WRITE#, PRINT# или PRINT#USING. 3. Закрыть файл. Оператор CLOSE закрывает файл после того, как программа завершит все операции ввода/вывода. Чтобы прочитать данные из последовательного файла, надо выполнить следующие действия: 1. Открыть файл в режиме последовательного ввода (оператор OPEN с параметром INPUT). При этом файл будет подготовлен для чтения. 2. Прочитать данные из файла. Для этого используются операторы Turbo Basic INPUT#, INPUT$ или LINE INPUT#. 3. Закрыть файл. Оператор CLOSE закрывает файл после того, как программа завершит все операции ввода/вывода. (Более подробная информация об операциях над файлами, упомянутыми здесь, приведена в Главе 5 "Справочное руководство по Turbo Basic".) Недостатком последовательных файлов является то, что вы имеете возможность только последовательного доступа к данным. За один раз вы обращаетесь к одной записи, начиная при этом с первой записи. Это означает, что если вы хотите прочитать последнюю запись из файла, содержащего 23000 записей, то вы должны будете до этого прочитать 22999 записей. Поэтому последовательные файлы наиболее подходят для применений, в которых осуществляется последовательная обработка данных (например, подсчет слов, проверка правописания, печать почтовых адресов в порядке записей в файле), или в которых все данные могут одновременно находится в памяти. Это позволяет считать весь файл в одну область памяти при запуске программы и записать в него все обратно в конце программы. В промежутке между этим доступ к информации может быть организован через временные структуры с произвольным доступом в числовых или символьных массивах. Последовательные файлы применяются в таких базах данных, в которых длина отдельных записей может меняться. Например, предположим, что наш список имеет поле комментариев. Но для некоторых людей комментарий может содержать 100 байтов и более, для других, которых, пожалуй, большинство, никакого комментария нет вообще. Последовательные файлы решают эту проблему, не расходуя лишнего пространства на диске. С помощью Turbo Basic можно создать два типа последовательных файлов: (1) последовательные файлы с разделением полей, в которых каждое поле в каждой строке отделено от соседей специальными символами; (2) последовательные файлы без разделителей, в которых каждый файл выглядит точно так же, как если бы эти данные были выведены на экран, или распечатаны на принтере. Эти два типа файлов создаются с использованием операторов WRITE# и PRINT#, соответственно. (Для чтения информации из последовательных файлов любого типа используются операторы INPUT#, INPUT$ и LINE INPUT#.) Последовательные файлы с разделением полей. Если вы посмотрите на последовательный файл, созданный в Turbo Basic, то вы сможете увидеть, что данные в файле отделены от соседей запятыми, а любая символьная строка заключена в двойные кавычки - т.е. все находится точно в таком виде, в каком оператор INPUT# ожидает найти данные. (Двойные кавычки, в которые заключаются символьные строки, позволяют избежать неправильной интерпретации запятых. Числа не требуют кавычек, поскольку они записываются без запятых.) Рассмотрим следующую программу и выполним ее: 'Эта программа открывает последовательный файл для 'вывода. Она записывает в файл пару строк с различными 'типами данных, используя оператор WRITE#. OPEN "SEQUENTI.BAS" FOR OUTPUT AS #1 'назначить 'переменной 'файла номер 1 StringVariable$ = "This is a string of text" 'определить Integer% = 1000 'несколько переменных FloatingPoint!= 30000.1234 'и инициализировать их 'теперь запишем строку текста в последовательный файл WRITE# 1,StringVariable$,Integer%,FloatingPoint! StringVariable$ = "Another String" Integer% = -32767 FloatingPoint! = 12345.54321 'запишеь другую строку текста WRITE# 1,Integer%,StringVariable$,FloatingPoint! CLOSE #1 'файл закрывается END 'конец программы Содержимое файла SEQUENTI.BAS выглядит следующим образом: "This is a string of text",1000,30000,123046875 -32767,"Another String",12345.54296875 Самым важным, что здесь следует отметить, является то, что оператор WRITE# выводит информацию в последовательный файл точно в таком виде, в каком оператор INPUT# ожидает их найти. Следующая программа считывает последовательный файл, который был создан предыдущей программой. 'Эта программа открывает последовательный файл для ввода. 'Она считывает пару строк данных разного типа из файла, 'используя оператор INPUT#. OPEN "SEQUENTI.BAS" FOR INPUT AS #1 'присвоить 'переменной 'файла номер 1 StringVariable$="" 'определить некоторые Integer% = 0 'переменные и FloatingPoint! = 0 'инициадизировать их 'теперь считаем строку текста из последовательного файла INPUT# 1,StringVariable$,Integer%,Floating Point! PRINT StringVariable$,Integer%,FloatingPoint! StringVariable$ = "" Integer% = 0 FloatingPoint! = 0 'считаем другую строку текста INPUT# 1,Integer%,StringVariable$,FloatingPoint! PRINT Integer%,StringVariable$,FloatingPoint! CLOSE #1 'закрыть файл END 'конец программы Здесь важно отметить, что предыдущие примеры не работали бы правильно, если бы вы использовали для создания файла данных оператор PRINT. Если вы создаете файл, который впоследствии будет читаться оператором INPUT#, то используйте оператор WRITE#, а не PRINT#. Последовательные файлы без разделителей. В последовательном файле без разделителей данные хранятся точно в таком виде, в каком они бы были выведены на экран оператором PRINT, или распечатаны на принтере оператором LPRINT. Вы можете использовать дополнительный параметр USING при выводе данных в последовательный файл в таком же виде, как бы вы выводили на экран или на принтер. Рассмотрим следующую программу и выполним ее: 'Эта программа открывает последовательный файл для вывода. 'Она записывает в файл пару строк данных различного типа, 'используя операторы PRINT# и PRINT# USING. OPEN "SEQUENTI.BAS" FOR OUTPUT AS #1 'присвоить переменной 'файла номер 1 StringVariable$ = "This is a string of text" 'определить Integer% = 1000 'несколько переменных и FloatingPoint! = 30000.1234 'инициализировать их 'теперь запишем строку текста в последовательный файл PRINT # 1, StringVariable$,Integer%,FloatingPoint! StringVariable$ = "Another String" Integer% = -32767 FloatingPoint! = 12345.54321 'запишем еще одну строку текста, но сформатируем ее 'с помощью параметра USING PRINT # 1, USING "+#####&##.##^^^^"; Integer%,_ StringVariable$,FloatingPoint! CLOSE #1 'закрыть файл END 'конец программы Содержимое файла SEQUENTI.BAS будет выглядеть следующим образом: This is a string of text 1000 30000.123046875 -32767 Another String 12.35E+03 Как и для последовательных файлов с разделителями полей, самым важным является формат данных и способ, каким они могут быть считаны. Если вы попытаетесь использовать тот же самый оператор INPUT#, что и во втором примере, то во время выполнения программы Turbo Basic может зафиксировать ошибку. Turbo Basic будет читать слово "This" в первой строке как символьную переменную и попытается прочитать следующие два слова как числовые переменные. Вместо этого вы должны использовать для чтения этой информации операторы INPUT$ или LINE INPUT#. Следующая программа читает из последовательного файла, который был создан в последнем примере: 'Эта программа открывает последовательный файл для ввода. 'Она считывает пару строк данных различного типа, 'используя операторы LINE INPUT# и INPUT$. OPEN "SEQUENTI.BAS" FOR INPUT AS #1 'присвоить переменной 'файла номер 1 StringVariable$ = "" 'теперь считаем строку из 80 символов из последовательного 'файла StringVariable$ = INPUT$(80,1) PRINT StringVariable$ 'введем всю строку независимо от ее длины LINE INPUT# 1, StringVariable$ PRINT StringVariable$ CLOSE #1 'закрыть файл END 'конец программы Следующие операторы и функции Turbo Basic управляют вводом/выводом в последовательные файлы: _____________________________________________________________ Оператор/Функция Действие _____________________________________________________________ CLOSE Завершает операции с файлом (файлами) EOF Возвращает извещение о достижении конца файла INPUT# Считывает запись (строку текста) в заданную переменную (переменные) INPUT$ Считывает n символов в символьную переменную LINE INPUT# Считывает всю строку в одну символьную переменную OPEN Открывает файл для работы в режимах INPUT, OUTPUT и APPEND и задает его номер PRINT#, PRINT #USING Осуществляют вывод в файл таким же образом, как если бы вывод шел на экран WRITE# Записывает данные, разделенные запятыми, в файл _____________________________________________________________ Файлы с произвольным доступом. Файлы с произвольным доступом состоят из записей, доступ к которым может быть осуществлен в любой последовательности. Это означает, что данные хранятся точно в таком виде, в котором они представляются в памяти, обеспечивая таким образом экономию времени при обработке (поскольку не требуется никакого преобразования), как при записи в файл, так и при чтении из него. Вообще говоря, файлы с произвольным доступом являются лучшим решением задачи организации базы данных, чем последовательные файлы, хотя и они не свободны от недостатков. Одним из них является то, что файлы с произвольным доступом не являются особо переносимыми. Вы не можете проникнуть внутрь них с помощью редактора или распечатать их в осмысленном виде на экране. Действительно, перенесение файла с произвольным доступом, созданного в Turbo Basic, на другой компьютер или язык возможно потребует того, чтобы вы написали программу-транслятор для чтения информации из файла с произвольным доступом и вывода ее в текстовый (последовательный) файл. Можно привести еще один пример проблемы переносимости. Поскольку интерпретирующий Basic использует нестандартный формат фирмы "Microsoft" для представления чисел с плавающей запятой, а Turbo Basic использует стандартные соглашения IEEE, то вы не можете читать в программах на Turbo Basic данные с плавающей запятой из файлов с произвольным доступом, созданных в интерпретирующем Basic, и наоборот, без некоторой дополнительной работы. В Turbo Basic имеется четыре специальные функции для решения этих задач: CVMS и CVMD - для перевода числовых полей из формата фирмы "Microsoft" в формат переменных обычной и двойной точности Turbo Basic; MKMS$ и MKMD$ - для перевода чисел обычной и двойной точности в симольные строки в формате фирмы "Microsoft", которые могут быть записаны в файл. Основное преимущество файлов с произвольным доступом заключено в следующем: каждая запись в файле доступна в любое время. Например, в базе данных из 23000 элементов программа может непосредственно обратиться к 22709-й или 11663-й записи без считывания всех предыдущих. Это свойство делает этот тип единственно возможным вариантом при работе с большими файлами, а может быть также и лучшим вариантом для небольших файлов, если они имеют относительно постоянную длину записей. Файлы с произвольным доступом расходуют лишнее пространство на диске, т.к. пространство под каждую запись выделяется из расчета на самую длинную запись. Например, включение поля комментариев из 100 байтов делает каждую запись длиннее на 100 байтов, даже если это поле комментариев использует только одна запись из тысячи. С другой стороны, если записи имеют постоянную длину, особенно, если они состоят в основном из чисел, то файлы с произвольным доступом могут сэкономить занимаемое пространство по сравнению с последовательными файлами. В файле с произвольным доступом все числа одного и того же типа (целое, длинное целое, обычной точности, двойной точности) занимают одинаковое пространство на диске. Например, каждое из следующих пяти чисел обычной точности требует для своего представления 4 байта (такое же пространство они занимают и в памяти): 0 1.660565E-27 15000.1 641 623000000 В отличие от этого, в последовательном файле для представления чисел требуется столько байтов, сколько в них имеется символов в коде ASCII, плюс еще один для разделительной запятой. Например: WRITE #1, 0; 0 требует 3 байта, а PRINT #1, 0; 0 требует 6 байтов, а PRINT #1.660565E-27 требует 13 байтов. Самая скромная цена, которую вы заплатите за преимущества файлов с произвольным доступом, это небольшая дополнительная обработка, необходимая для перевода символьных строк и чисел в и из формата, в котором их могут обрабатывать программы работы с файлами с произвольным доступом. Вы можете создавать, записывать и читать файлы с произвольным доступом, используя следующую последовательность шагов: 1. Открыть файл оператором OPEN и задать длину каждой записи. OPEN файлспец AS [#]имяфайла LEN = запись.размер Параметр LEN показывает для Turbo Basic, что это файл с произвольным доступом. В отличие от последовательных файлов, в данном случае вам не надо объявлять, открываете ли вы файл для ввода или для вывода, т.к. в файл с произвольным доступом вы можете одновременно и писать и читать. 2. Выполнить оператор FIELD, чтобы определить соответствие между рядом символьных переменных (после выполнения этого оператора они становятся "переменными полей") и "буфером файла". FIELD имяфайла,ширина AS симв-пер[ширина AS симв-пер]... Этот буфер является приемником для данных, записываемых или считываемых из данного конкретного файла. Оператор FIELD должен быть выполнен по крайней мере один раз для данного файла с произвольным доступом. 3. Чтобы записать запись в файл, используйте операторы LSET и RSET для загрузки переменных полей с данными, которые должны быть записаны. Числа должны быть преобразованы в символьную форму посредством соответствующей функции (например, MKS$ для обычной точности), а потом уже могут быть использованы операторы LSET и RSET. Наконец, используйте оператор PUT, чтобы записать запись в файл на место, которое вы укажете. 4. Чтобы прочитать запись из файла, используйте оператор GET. Затем загрузите прочитанные значения в ваши символьные или числовые переменные из соответствующих позиций в буфере. Прежде, чем вы сможете что-нибудь с ними сделать, числовые данные должны быть преобразованы из символьного формата с помощью соответствующей функции (например, CVS для чисел обычной точности). 5. Когда вы все сделаете, закройте файл оператором CLOSE. Ниже перечислены операторы и функции Turbo Basic, которые управляют чтением и записью в файлы с произвольным доступом: _____________________________________________________________ Оператор/Функция Действие _____________________________________________________________ CLOSE Закрывает файл. CVI, CVL, CVS, CVD Преобразовывают переменные поля в соответствующий числовой тип. FIELD Определяет переменные поля. GET Считывает запись. LOC Определяет номер последней считанной записи. LSET, RSET Присваивают значения переменным поля. MKI$, MKL$, MKS$, MKD$ Преобразуют числа заданного типа в формат, в котором они могут быть присвоены переменным поля. MKMS$,MKMD$,CVMS,CVMD Специальные функции преобразования в и из формата фирмы "Microsoft". OPEN Открывает файл с произвольным доступом. PUT Записывает запись в файл. _____________________________________________________________ Покажем пример программы, использующей файлы с произвольным доступом: 'Программа для чтения из базы данных почтовых адресов. 'Пользователь вводит номер записи; программа выводит все 'поля этой записи. Эта программа не может читать из 'последовательных файлов, описанных ранее. OPEN "ADDRESS.DTA" AS #1 LEN = 81 '"LEN=81" объявляет 'файл, как файл с 'произвольным доступом 'определим формат записи файла #1 'отметим использование символа продолжения строки FIELD #1, 25 AS FileName$, 25 AS address$,_ 15 AS city$, 2 AS state$,_ 4 AS zip$, 2AS class$, 8 AS contrib$ 'zip$ имеет тип длинное целое, class$ - целое, contrib$ - 'двойной точности. 'Теперь все они существуют в файле как символьные строки. 'Когда мы считаем одно из этих числовых полей, мы должны 'преобразовать его обратно в число прежде, чем будем его 'использовать. INPUT "Which record do you want to see: ", recnumber GET #1, recnumber 'теперь данные находятся в буфере файла PRINT "Data for record" recnumber PRINT "Name: " FileName$ PRINT "Address: " address$ PRINT "City/State/Zip " city$, state$, CVL(zip$) PRINT "Class: " CVI(class$) PRINT "Most recent contrib: " CVL(contrib$) Предупреждение: никогда не делайте присваивания значения переменной поля; т.е. не используйте переменную поля в левой части оператора присваивания. Присваивание значения переменной поля разрывает связь между этой переменной и назначенным ей буфером. Например, после выполнения zip$ = a$ переменная поля zip$ больше не будет соответствовать буферу, которому она была назначена оператором FIELD. И последующие операторы LSET и RSET не смогут восстановить эту связь. Двоичные файлы. Двоичные файлы Turbo Basic являются расширением соответствующих возможностей интерпретирующего Basic, который позволяет вам рассматривать любой файл как последовательность байтов, не привязывая их к кодам ASCII, к типу данных, длине записи, символам возврата каретки, или к чему-либо еще. При двоичном подходе к работе с файлами, вы осуществляете чтение или запись в файл, задавая байты, которые вы хотите записать, и место в файле, куда должна быть осуществлена запись. Это похоже на услуги, предоставляемые системными вызовами DOS, по чтению и записи в файлы, которые используются в программах на ассемблере. За гибкость всегда приходится платить. Файлы, определенные в режиме BINARY, требуют, чтобы вы делали всю работу по принятию решений о том, что и куда записать. Использование двоичных файлов, возможно, является наилучшим выбором, когда вы имеете дело с файлами, содержимое которых не представлено в кодах ASCII; например, с файлами, созданными системами dBASE или Lotus. Конечно, вы должны точно знать структуру файла прежде, чем вы попытаетесь передать его содержимое в числовые и символьные переменные, с которыми работает Turbo Basic. Каждый файл, открытый в режиме BINARY, имеет связанный с ним указатель позиции, который указывает на место в файле, в которое будет осуществляться запись или считывание при следующем обращении. Используйте оператор SEEK для задания позиции указателя и функцию LOC для считывания ее. Доступ к двоичным файлам осуществляется следующим образом: 1. Открыть файл оператором OPEN в режиме BINARY. Вам не надо определять, будете ли вы считывать или записывать в файл - вы можете делать то, или другое, или оба действия вместе. 2. Чтобы прочитать информацию из файла, используйте оператор SEEK для позиционирования указателя файла на байт, который вы хотите прочитать. Затем используйте оператор GET$ для чтения заданного числа символов (от 1 до 32767) в символьную переменную. 3. Чтобы записать в файл, занесите в символьную переменную записываемую информацию. Затем используйте оператор PUT$ для задания символьных данных и места в файле, куда они должны быть записаны. 4. Когда вы завершите работу с файлом, закройте его оператором CLOSE. Ниже перечислены операторы и функции Turbo Basic, которые управляют чтением и записью в двоичные файлы: _____________________________________________________________ Оператор/Функция Действие _____________________________________________________________ CLOSE Закрывает файл. GET$ Читает заданное число байтов, начиная с установленной позиции. LOC Определяет установленную позицию в файле. LOF Возвращает длину файла. OPEN Открывает файл и объявляет его двоичным. PUT$ Записывает в файл заданное число байтов, начиная с установленной позиции. SEEK Перемещает указатель позиции. _____________________________________________________________ Ввод/вывод на устройства. Turbo Basic поддерживает так называемые файлы на устройствах, т.е. он поддерживает аппаратные средства, такие как клавиатура, экран и принтер, таким образом, как если бы это были последовательные файлы. Каждое поддерживаемое устройство имеет зарезервированное имя, которое завершается двоеточием: _____________________________________________________________ Имя Функция _____________________________________________________________ KYBD: Клавиатура может быть открыта для ввода. Считывание из файла на устройстве KYBD: осуществляется подобно использованию оператора INKEY$. SCRN: Экран может быть открыт для вывода. Запись в файл на устройстве SCRN: осуществляется подобно использованию оператора PRINT. LPT1-3: Принтеры с номерами от 1 до 3. COM1-2: Каналы последовательной связи с номерами 1 и 2. _____________________________________________________________ Например: OPEN "SCRN:" FOR OUTPUT AS #1 : PRINT #1, "Hello" эквивалентно следующему: PRINT "Hello" а OPEN "KYBD:" FOR INPUT AS #1 : INPUT #1, a$, b$ эквивалентно следующему: INPUT a$, b$ Графика. Когда наступает пора выводить информацию на экран, программа, сгенерированная Turbo Basic, должна работать с учетом особенностей имеющейся аппаратуры. Turbo Basic поддерживает следующие типы видеоинтерфейсов персональных компьютеров: монохромный дисплейный адаптер, который может выводить только монохромный текст; цветной графический адаптер (CGA) и расширенный графический адаптер (EGA), любой из которых может выводить текст и изображения в черно-белом или цветном режиме; многоцветный графический матричный адаптер (MCGA), который работает на компьютере IBM PS/2, модель 30; и графический видеоадаптер (VGA), который работает на компьютерах IBM PS/2 модели 30, 50, 60 и 80 (см.таблицу 4-5). В соответствии с возможностями этих видеоконтроллеров, в Turbo Basic можно выбрать любой необходимый режим с помощью операторов SCREEN и/или WIDTH. Таблица 4-5. Характеристики графических адаптеров. _____________________________________________________________ Адаптер Экранный Формат текста Комментарии режим _____________________________________________________________ Монохромный 0 80 колонок 80х25 символов с 4 атрибутами (нормальный, яркий, мерцающий, подчеркнутый). CGA 0, 1, 2 40/80 колонок До 16 цветов (только в текстовом режиме); до 4 цветов в графическом режиме. Разрешающая способность экрана: 640х200 пикселей. EGA 0,1,2,7,8, 40/80 колонок Разрешающая 9,10 способность экрана: до 640х350 пикселей. До 16 цветов из 64-цветной палитры (в зависимости от памяти EGA). MCGA 0,1,2,11 40/80 колонок Соответствует CGA, но поддерживает разрешающую способность экрана 640х480 пикселей; черно-белый вывод в экранном режиме 11. VGA 0,1,2,7,8,9, 40/80 колонок Соответствует EGA и 10,11,12 MCGA,но поддерживает разрешающую способность экрана 640х480 пикселей; до 16 цветов в экранном режиме 12. CGA = цветной графический адаптер EGA = расширенный графический адаптер MCGA = многоцветный графический матричный адаптер VGA = графический видеоадаптер ______________________________________________________________ Текстовые режимы. В 80-колонном текстовом режиме (единственный режим, доступный для монохромного дисплейного адаптера) на экране размещаются 25 строк по 80 символов каждая, пронумерованные от 1 до 25 (сверху вниз) и от 1 до 80 (слева направо) (см.рис.4-2). В 40-колонном текстовом режиме (доступном на адаптерах CGA и EGA) на экране размещаются 25 строк по 40 символов. В каждой позиции на каждой строке может содержаться любой из символов, перечисленных в списке символов в Приложении F. Строка 1, колонка 1 Колонки (1-80) 80 ___________________________________________________________ |. | С | | т | | р | | о | | к | | и | | | | 1 | | - | | 25| | | | |__________________________________________________________| __________________________________________________________ Cтрока 25, зарезервированная для Строка 25,колонка 80 программных клавиш дисплея Рис.4-2. Экран в текстовом режиме. Вообще говоря, вы выводите символы на экран, перемещая курсор на желаемую позицию с помощью оператора LOCATE и используя затем оператор PRINT. Экзотические символы, которые трудно сгенерировать помощью клавиатуры, могут быть воспроизведены посредством функции CHR$ (см.Приложение F). 25-я (самая нижняя) строка экрана требует специального рассмотрения: оператор KEY размещает на ней названия функциональных клавиш ("программные клавиши"). Чтобы защитить эти названия клавиш, 25-я строка никогда не перемещается по экрану (в режиме "Scroll" (прокрутка)), и на нее ничего не выводится до тех пор, пока вы не выключите изображение функциональных клавиш оператором KEY OFF. Для монохромных адаптеров оператор COLOR может быть использован для создания специальных эффектов, таких как инверсное и уменьшенной интенсивности изображения, а также подчеркнутый или мерцающий текст. Для адаптеров CGA/EGA оператор COLOR используется для выбора цвета, в котором будет осуществляться вывод с помощью операторов PRINT. В текстовом режиме адаптеры CGA/EGA поддерживают до 8 выводимых "страниц"; обрабатываемая и/или выводимая страница задается оператором SCREEN. Графические режимы. Turbo Basic имеет полный набор команд для вывода на экран точек, линий и графических контуров различного цвета. Если у вас нет соответствующей аппаратуры, такой как цветной графический адаптер, или расширенный графический адаптер, или их эквивалентов, то эти команды не будут работать так, как описано здесь. (Вообще говоря, попытка использовать графические команды на аппаратуре, допускающей только текстовый режим, вызывает фиксацию ошибки "Illegal Function Call" (Неправильный вызов функции).) В графических режимах экран рассматривается как сетка, состоящая из небольших ячеек, или пикселей, каждая из которых может быть "включена" (белый, или заданный цвет), или "выключена" (цвет фона, обычно - черный). Пиксели идентифицируются по своей позиции в системе координат (x,y), начало которой по умолчанию располагается в левом верхнем углу экрана. Значения координаты x представляют горизонтальные расстояния от левого края экрана, а значения координаты y - вертикальные расстояния от верхнего края экрана. Заметим, что принятое направление координаты y обратно тому, которое используется в обычной декартовой геометрии, в которой значения y уменьшаются при движении сверху вниз. В зависимости от выбранного режима (и, возможно, от объема памяти, установленной на видеоконтроллере), горизонтальная разрешающая способность может быть 320 или 640 пикселей, а вертикальная - 200 или 350 пикселей (см.рис.4-3). Эта комбинация также определяет количество доступных цветов (2, 4 или 16), а также максимальное количество "видео-страниц" (1, 2, 4 или 8). Нумерация пикселей начинается с нуля, в отличие от нумерации рядов и колонок в текстовом режиме, которая начинается с единицы. (0,0) ------------320 пикселей по горизонтали--------(319,0) ___________________________________________________________ | | 200 | | п | | и | | к | | с | | е | .(160,100) | л | | е | | й | | | | | | |__________________________________________________________| (0,199) (319,199) Рис.4-3. Пример координатной сетки экрана при среднем разрешении. С каждым пикселем связано число (или атрибут), обозначающее цвет и имеющее значение от 0 до максимума, зависящего от режима. Значение атрибута, задающего цвет, управляется операторами COLOR и PALETTE. Последняя обслуженная точка (LPR). После большинства графических операций, позиция светового пера на экране определяется координатами x,y. Позиция пера называется последней обслуженной точкой, или LPR. Когда вы впервые задаете графический режим оператором SCREEN, положение LPR задается в центре экрана. Некоторые графические команды способны принимать координаты LPR. Например, если оператором LINE задается только конечная точка, то линия проводится от LPR до заданной конечной точки. После этого конечная точка становится LPR. Абсолютные и относительные координаты. Большинство графических операторов Turbo Basic может работать с координатами, заданными как в абсолютной, так и в относительной форме. В абсолютной форме пара координат (x,y) описывает точное место, в котором должна выполняться операция; например, PSET(50,75) включает пиксель, расположенный на 50 пикселей от левого края экрана и на 75 пикселей от верхнего края. В относительной форме координаты задают положение точки относительно LPR и представляют собой горизонтальное и вертикальное смещение относительно LPR. При задании координат в этой форме используется ключевое слово STEP, чтобы различить ее от стандартных абсолютных координат. Например, если координаты LPR равны (60,75), то PSET (10,20) задаст точку (10,20), а PSET STEP (10,20) задаст точку (70,95), расположенную на 10 пикселей вправо и на 20 пикселей вниз от LPR. Отрицательные значения относительных коорди- нат задают точку, расположенную над и слева от LPR. Переопределение координат экрана. Если вам неудобно работать в такой системе адресации экрана, то используйте оператор WINDOW, чтобы изменить соответствие между парой чисел (x,y), задаваемой в графических операторах и пикселями на экране. Например: WINDOW (-1,1) - (1,-1) переопределяет координаты экрана так, что они более точно будут соответствовать декартовой системе координат в аналитической геометрии с началом координат в середине экрана и осью y, направленной вверх. После выполнения такого оператора WINDOW, оператор PSET(0,0) включает пиксель с физическими координатами (100,160); PSET(-1,-1) включает самый левый нижний пиксель; PSET(5,5) включает пиксель с физическими координатами (220,50), расположенный в середине правого верхнего квадранта. Использование оператора WINDOW может существенно упростить вычерчивание математических диаграмм и графиков. Оператор VIEW позволяет создавать на экране активную область, или "окно", и дополнительно моежт задавать координаты относительно верхнего левого угла окна. Вы не можете манипулировать пикселями, расположенными вне окна. В Turbo Basic имеются следующие графические команды: _____________________________________________________________ Команда Функция _____________________________________________________________ CIRCLE Вычерчивает целую окружность, или ее часть. COLOR Выбирает цветовую палитру и цвет фона. DRAW Язык мини-графики. GET Загружает числовой массив информацией о состоянии пикселей на экране. LINE Вычерчивает линию, или прямоугольник,заданную двумя точками. PAINT Заполняет замкнутую область на экране заданным цветом или шаблоном. PALETTE Управляет и выбирает один или несколько цветов в палитре. PALETTE USING Изменяет все составляющие палитры за один раз. PMAP Устанавливает соответствие между физическими и системными координатами. POINT Возвращает информацию о точке,или о последней обслуженной точке. PRESET Выводит точку (по умолчанию = атрибут 0). PSET Выводит точку (по умолчанию = максимальному атрибуту для установленной разрешающей способности). PUT Копирует содержимое числового массива на экран (см. GET). SCREEN Выбирает графический режим. VIEW Объявляет активную область для графических операций. WINDOW Задает координаты окна. _____________________________________________________________ Глава 5. Справочное руководство по Turbo Basic. Около 200 команд Turbo Basic можно разбить на следующие классы: функции, операторы, системные переменные и метаоператоры. Функции (заранее определенные и определенные пользователем) возвращают значение и, следовательно, должны использоваться в выражениях. Большинство функций требуют одного или более аргументов; например: t = COS(3.1) 'числовая функция / 1 числовой аргумент t$ = LEFT$("Cat",2) 'символьная функция / 1 символьный и '1 числовой аргумент Операторы - неделимые блоки, из которых составляются программы. Операторы должны располагаться либо на отдельной строке, либо отделяться друг от друга двоеточием; например: CIRCLE (160,100), 50 'нарисовать окружность CALL MySub (x,y,z) 'вызвать процедуру a = a + 1 'присвоить значение (см. оператор LET) Системные переменные - это заранее определенные идентификаторы для доступа и управления определенной системной информацией; например: a$ = DATE$ 'чтение системной даты TIME$ = "00:00" 'установка системного времени Метаоператоры представляют собой директивы компилятора. Строго говоря, они не являются частью языка, поскольку действуют на другом уровне, управляя работой компилятора; например: $INCLUDE "module1.tbs" 'загрузить и обработать включаемый 'файл $STACK &H1000 'установить размер стека Метаоператоры, как и ключи в меню Options компилятора, управляют компилятором в период компиляции, а не компьютером в период выполнения программы. Метаоператоры начинаются всегда со знака доллара ($), чтобы отличать их от обычных операторов. На строке может располагаться только один метаоператор и, в отличие от некоторых других компиляторов BASIC, они могут располагаться в комментариях. Структура данного руководства. Каждый раздел руководства содержит определение, систаксис, описание и примеры использования оператора, функции или процедуры. Где нужно, перечислены родственные разделы, представлены ограничения использования и отмечены некоторые различия в использовании этой структуры в Turbo Basic и интерпретирующем BASIC. Ниже описаны обозначения, принятые при описании синтаксиса команд. Числовое выражение. Числовая константа, числовая функция, или числовая переменная, или их комбинация, использующая арифметические и логические операторы и операции отношения. Иногда задается тип числового выражения; например: целое выражение Примеры: 16 x 16 * x SIN(3.14159) SIN(x / (16 * x)) Символьное выражение. Символьная константа, символьная переменная, или символьная функция, или их комбинация, которая может включать оператор конкатенации - знак плюс (+). Примеры: "Cat" a$ + "Cat" LEFT$(a$ + "Cat",4) Имя файла. Символьное выражение, описывающее имя файла в MS-DOS (восемь символов с необязятельным расширением из трех символов, отделенных точкой; регистр, на котором набран символ, не имеет значения), возможно включающее спецификацию устройства и/или пути. Кроме специально отмеченных случаев, имена файлов должны быть выражены как символьные переменные или заключены в кавычки; например: "MYFIRST.BAS" "turbobas\myfirst.bas" "a:\turbobas\myfirst.bas" Путь. Символьное выражение, описывающее разрешенные подсправочники на рабочем устройстве. Например: "\TURBOBAS" "GAMES" LPR "Last Point Referenced" (последняя обслуженная точка) используется для неявного задания координат в некоторых графических операциях; и ее значение устанавливается большинством графических операторов. Метка. Метка представляет собой лишь алфавитно-цифровую метку, либо число, определяющее строку программы. Номера строк и метки более или менее равнозначны в синтаксисе Turbo Basic, за исключением того, что метки должны располагаться на отдельных строках. Условные обозначения. Курсив (в данном переводе - символы на нижнем регистре) обозначает позиции в командах, в которые должна заноситься информация, связанная с применением команды. Например: REG регистр,значение Верхний регистр используется для выделения части команды, которая должна быть введена именно в таком виде. Например: RESUME NEXT Квадратные скобки ([]) означают, что заключенная в них информация необязательна. Например: OPEN filespec AS [#] filenum означает, что вы можете включить знак номера (#) перед номером файла в операторе OPEN, или пропустить его (на ваше усмотрение). Поэтому оба следующие выражения допустимы: OPEN "cust.dta" AS 1 OPEN "cust.dta" AS #1 Фигурные скобки ({}) обозначают возможности выбора из двух или более вариантов, один из которых должен быть использован обязательно. Предлагаемые варианты разделяются вертикальной чертой (|). Например: KEY {ONN|OFF} означает, что и KEY ONN, и KEY OFF - разрешенные операторы, а просто KEY - нет. Многоточие (...) показывает, что часть команды можно повторять столько раз, сколько необходимо. Например: READ переменная [,переменная]... означает, что множество переменных, разделенных запятыми, можно задавать в одном операторе READ: READ a$ READ a$, b$, a, b, c Три вертикальные точки показывают, что пропущены одна или более строк текста программы; например: FOR n = 1 TO 10 . . . NEXT n Метаоператор $COM Функция: $COM выделяет область памяти для приемного буфера последовательного интерфейса. Синтаксис: $COMn размер Комментарии: n обозначает адаптер связи (1 или 2), а "размер" является целой константой, определяющей объем буфера для этого адаптера (от 0 до 32767). По умолчанию - 256. Значение по умолчанию можно задать и сохранить посредством меню Options. Действие значения по умолчанию может быть отменено метаоператорами в программе. Ограничения: Размер буфера, задаваемый метаоператором $COM должен находиться в пределах от 0 до 32767. Интерпретирующий BASIC выделяет буферы одного и того же для обоих интерфейсов связи, если они существуют. В Turbo Basic размеры этих двух буферов устанавливаются независимо. Различия: В интерпретирующем BASIC эта функциональная возможность может быть обеспечена только через параметры командной строки. Пример: 'метаоператор $COM используется для изменения 'области памяти по умолчанию, отводимой под 'буферы последовательных интерфейсов ' установочная программа для обработки ' последовательного ввода $COM1 1024 ' установка буфера объемом 1K ON COM(1) GOSUB GetComInput COM(1) ON ' включение обработки ввода с COM OPEN "COM1:" AS #1 ' открыть переменную файла COM1 PRINT "Press any key to terminate the program..." 'пока клавиша не нажата WHILE NOT INSTAT LOCATE 2,1 PRINT TIME$ ' вывести время WEND END ' конец программы GetComInput: ' обработка прерывания от ' последовательного интерфейса ' чтение данных из буфера последовательного ' интерфейса INPUT# 1,ComPortInput$ RETURN Метаоператор $DYNAMIC Функция: $DYNAMIC объявляет размещение массивов, установленное по умолчанию, динамическим. Синтаксис: $DYNAMIC Комментарии: Метаоператор $DYNAMIC не имеет аргументов и объявляет тип по умолчанию размещаемого массива - динамический. Пространство для динамических массивов распределяются в период выполнения. Можно использовать оператор ERASE для удаления массива из памяти. Динамические массивы обеспечивают более эффективное использование памяти. Массивы можно также объявить динамическими, используя ключевое слово DYNAMIC или соответствующее выражение в качестве аргументов в операторе DIM. Массивы с переменными размерами, объявленные общими или локальными в процедурах или функциях, всегда являются динамическими. Смотри также: DIM ERASE FRE $STATIC Пример: $DYNAMIC ' установка программы обработки ошибок ON ERROR GOTO ErrorHandler ' показать память, доступную в области массивов PRINT FRE(-1) DIM BigArray(10000) ' объявить динамический массив BigArray(6666) = 66 ' присвоить данные ' показать память, доступную в области массивов PRINT FRE(-1) ERASE BigArray ' удалить динамический массив ' показать память, доступную в области массивов. PRINT FRE(-1) ' выводится ошибка периода выполнения, если ' задана проверка границ массива PRINT BigArray(6666) END 'конец программы ErrorHandler: PRINT "An error of type" ERR; PRINT "has occurred at address" ERADR END Метаоператор $EVENT. Функция: $EVENT управляет генерацией программы обработки прерывания по событию. Синтаксис: $EVENT{ON|OFF} Комментарии: Если ваша программа содержит какую-либо обработку прерываний по событиям (например: ON KEY, ON COM), то по умолчанию $EVENT имеет значение ON, т.е. компилятор генерирует команды проверки наличия данного события после каждого оператора вашей программы. Если в программе не предусмотрена реакция на прерывания, то $EVENT имеет значение OFF и команды проверки событий не генерируются. $EVENT обеспечивает управление над тем, в каких частях вашей программы будет осуществляться проверка событий. Если есть области программы, где более важна максимальная скорость выполнения, чем мгновенная реакция на событие, то ограничьте ее метаоператорами $EVENT OFF и $EVENT ON. Пример: 'пример метаоператора $EVENT ON TIMER (1) GOSUB WasteTime TIMER ON PRINT "Slow loop" x = timer FOR i = 1 TO 10000 i = i + i - i NEXT i y = timer PRINT "loop time is" y-x $EVENT OFF PRINT "Fast loop" x = timer FOR i = 1 TO 10000 i = i + i - i NEXT i y = timer PRINT "loop time is" y-x END WasteTime: FOR j = 1 TO 1000 : j = j + j - j : NEXT j : PRINT RETURN Метаоператоры $IF/$ELSE/$ENDIF Функция: $IF, $ELSE и $ENDIF определяют части исходной программы, которые должны быть либо скомпилированы, либо пропущены (часто это называется условной компиляцией). Синтаксис: $IF конст . . операторы . [$ELSE . . операторы] . $ENDIF Комментарии: Параметр "конст" представляет собой именованую константу или просто константу. Если значение "конст" не равно нулю (что соответствует значению ИСТИНА), то операторы, заключенные между $IF и $ELSE, компилируются, а операторы между $ELSE и $ENDIF - нет. Если значение "конст" равно нулю (ЛОЖЬ), то операторы, заключенные между $IF и $ELSE, игнорируются, а между $ELSE и $ENDIF - компилируются. Ключевое слово $ELSE и следующие за ним операторы необязательны, а $ENDIF - требуется всегда. Операторы условной компиляции могут быть вложенными на глубину не более 256 уровней. Пример: %ColorScreen = 1 ' задание именованой константы ' с ненулевым значением означает ' работу с цветным дисплеем ' задание нулевого значения означает работу ' с монохромным дисплеем $IF %ColorScreen DEF SEG = &HB800 ' адрес графической экранной ' памяти $ELSE DEF SEG = &HB000 ' адрес монохромной экранной ' памяти $ENDIF FOR I% = 0 to 4000 STEP 2 POKE I%,ASC("A") ' заполнение экрана символами A NEXT I% ' сохранить все 4000 байта видеоинформации BSAVE "$IF.DTA",0,4000 END ' конец программы Метаоператор $INCLUDE Функция: $INCLUDE включает в программу текстовые файлы. Синтаксис: $INCLUDE имя файла Комментарии: Используйте $INCLUDE для компиляции текста другого файла вместе с текущим файлом. Параметр "имя файла" - символьная константа, а файл, который он определяет, должен соответствовать соглашениям для имен файлов в DOS и должен представлять собой исходный файл Turbo Basic. Если для включаемого файла не задано имя, то предполагается расширение .BAS. Метаоператор $INCLUDE заставляет компилятор рассматривать включаемый файл, как физически находящийся в данной точке исходного файла. Это позволяет вам разделять исходную программу на отдельные части. Принцип деления файлов на главный и рабочие, принятый в Turbo Basic, относится и к $INCLUDE. Для иллюстрации рассмотрим файлы CALCAREA.BAS и CONST.BAS: Файл CALCAREA.BAS PRINT "Circle area calculating program" PRINT "If you find this program useful" PRINT "Please send $3500 to: PRINT PRINT "Frank Borland" PRINT "4585 Scotts Valley Drive" PRINT "Scotts Valley, CA 95066" PRINT "--------------------------------" $INCLUDE "CONST.BAS" INPUT "Enter radius", r PRINT "Area = " pi * r * r END Файл CONST.BAS ' Все нужные константы pi = ATN(1) * 4 %true = -1 %false = 0 %maxx = 319 %maxy = 199 Для компиляции этой программы, CALCAREA должен быть сделан "главным файлом", поскольку это файл с оператором $INCLUDE. Рабочим файлом становится поочередно один из этих файлов, в зависимости от того, какой из них нужно редактировать (т.е. какой имеет ошибки). Независимо от того, какой файл является рабочим, компиляция всегда начинается с CALCAREA (главного файла). (Для получения более полной информации см. раздел "Главное меню" в главе 3). Когда компилятор Turbo Basic встречает метаоператор $INCLUDE в строке 7 файла CALCAREA, он приостанавливает считывание этой программы и загружает и начинает считывать символы из файла CONST.BAS. Когда этот файл будет исчерпан, компилятор возвращается туда, где он покинул первоначальную программу. Метаоператоры $INCLUDE могут быть вложенными на глубину до 5 уровней; т.е. включаемый файл может содержать внутри себя метаоператоры $INCLUDE. Пример: ' Сохранить следующее в файле, ' называемом "EXAMPLE.INC" SUB SayHello ' процедура вывода PRINT "Hello" ' Hello на экран END SUB ' Далее следует главная программа $INCLUDE "EXAMPLE.INC" ' включить исходный файл CALL SayHello ' вызов процедуры, определенной ' во включаемом файле END ' конец программы Метаоператор $INLINE Функция: $INLINE встроенный фрагмент программы на машинном языке. Синтаксис: $INLINE [список байтов] [имя файла] Комментарии: $INLINE может использоваться только внутри тела внутренней подпроцедуры. Параметр "список байтов" задает последовательность целых значений в диапазоне от 0 до 255, которая должна быть включена в объектную программу в этом месте. Параметр "имя файла" задает имя файла, который содержит встраиваемую программу. Эта программа должна быть перемещаемой и должна сохранять и восстанавливать следующие регистры: Stack Segment (SS - сегмент стека), Stack Pointer (SP - указатель стека), Base Pointer (BP - указатель базы), Data Segment (DS - сегмент данных). Встроенная программа может использовать параметры, используя относительную адресацию через BP. Для получения более полной информации см. Приложение A "Внутреннее представление чисел" и Приложение C "Интерфейс с языком Ассемблера". Пример: SUB Shriek INLINE ' $INLINE вызывают подачу звуковых сигналов $INLINE &HBA, &H00, &H07, &HE4, &H61, &H24 $INLINE &HFC, &H34, &H02, &HE6, &H61, &HB9 $INLINE &H40, &H01, &HE2, &HFE, &H4A, &H74 $INLINE &H02, &HEB, &HF2 END SUB CALL Shriek END ' конец программы Метаоператор $SEGMENT Функция: $SEGMENT объявляет новый сегмент программы. Синтаксис: $SEGMENT Комментарии: Используйте "безаргументный" метаоператор $SEGMENT для разделения вашей исходной программы, - если компилятор сообщает, что превышен максимально допустимый размер сегмента программы - 64K: Error 409 Segment Overflow Press (Ошибка 409 Переполение сегмента. Нажмите .) Все, что идет после метаоператора $SEGMENT, будет располагаться в новом сегменте программы. При этом все операторы управления программой (GOSUB, GOTO), которые передают управление через эту границу, преобразуются для межсегментной (дальней) пересылки, вызова или перехода, что требует немного больше времени и объема стека. Этот эффект можно минимизировать, размещая операторы $SEGMENT там, где проходят естественые линии раздела в вашей программе; например, между основными подпрограммами или между главной программой и начальной или заключительной ее частью. В программе на Turbo Basic может быть не более 16 сегментов. В статистических данных компиляции, выводимых после ее завершения, будут указаны размеры всех сегментов, разделенные косой чертой (/). Примечание: Нельзя использовать оператор $SEGMENT внутри структурированных блоков; например: FOR/NEXT, DO/LOOP, WHILE/WEND, IF BLOCK. Пример: SUB Proc1 PRINT "This is a dummy procedure" END SUB $SEGMENT ' определим второй сегмент SUB Proc2 PRINT "This is another dummy procedure" END SUB $SEGMENT ' определим третий сегмент SUB Proc3 PRINT "This is another dummy procedure" END SUB CALL Proc1 CALL Proc2 CALL Proc3 END ' конец программы Метаоператор $SOUND Функция: $SOUND задает объем фонового музыкального буфера. Синтаксис: $SOUND размер буфера Комментарии: "Размер буфера" - числовая константа, задающая объем фонового буфера оператора PLAY в нотах от 1 до 4096. Увеличение объема буфера до максимального числа нот, которые должны звучать в данной программе, приводит к тому, что отслеживание количества оставшихся нот (и вытекающее из этого снижение быстродействия) становится ненужным. Каждая нота требует 8 байт памяти; по умолчанию объем буфера 32 ноты или 256 байт. Значение по умолчанию можно изменить и сохранить, используя команду Music Buffer в меню Options. Действие значения по умолчанию может быть изменено метаоператорами, включенными в программу. Метаоператор $STACK Функция: $STACK задает объем стека периода выполнения. Синтаксис: $STACK счетчик Комментарии: "Счетчик" - числовая константа от 1024 до 32K. $STACK определяет, сколько памяти в период выполнения будет отведено под стек. Стек используется для хранения адресов возврата при вызове подпрограмм и в структурированных операторах, а также для хранения локальных переменных многострочных функций. По умолчанию используется минимальный размер стека - 1024 (400H) байт. Вы можете пожелать отвести больше пространства под стек, если ваша программа имеет очень большое число вложений, использует много локальных переменных или рекурсию. Если вы подозреваете, что программа выходит за пределы стека, перекомпилируйте ее, установив команду-ключ Stack test в меню Options. Программы, сгенерированные при установленном значении этого отладочного ключа, всегда проверяют имеющееся пространство стека перед входом в подпрограммы, процедуры и функции. Действие значений по умолчанию может быть изменено с помощью включенных в программу метаоператоров. Вы можете сами проверять в вашей программе размер свободного пространства в стеке с помощью функции FRE(-2). Смотри также: FRE Пример: ' задание стека объемом 4096 байт $STACK &H1000 PRINT FRE(-2) ' вывод на экран объема ' доступного пространства ' стека Метаоператор $STATIC Функция: $STATIC задает объявление массивов по умолчанию статическими. Синтаксис: $STATIC Комментарии: Метаоператор $STATIC не имеет аргументов и задает тип по умолчанию объявляемых статическим. Пространство под статические массивы отводится в период компиляции. Массивы с постоянными размерами всегда статические, кроме тех случаев, когда массив объявлен локальным в процедуре или функции или когда для одного и того же массива задаются более одного размера. Статические массивы нельзя стереть. Оператор ERASE только инициализирует каждый элемент массива, занося в них нули или пустые строки. Заметим, что метаоператор $STATIC, несмотря на внешнее сходство, не имеет ничего общего с оператором STATIC, который объявляет особый тип локальных переменных в процедурах и функциях. По умолчанию компилятор предполагает действие метаоператора $STATIC. Смотри также: DIM $DYNAMIC ERASE FRE Пример: $STATIC ' явное задание статических массивов PRINT "Memory available:", FRE(-1) ' память остается неизменной DIM A(50) ' A - статический массив PRINT "Memory available:", FRE(-1) N = 50 ' B - динамический массив, потому что как аргумент ' в операторе DIM используется выражение DIM B(N) PRINT "Memory available:", FRE(-1) ' теперь памяти стало меньше ERASE A PRINT "Memory available:", FRE(-1) ' никаких изменений, т.к. A не удален из ' памяти, а только инициализирован нулями ERASE B PRINT "Memory available:", FRE(-1) ' теперь памяти стало больше, т.к. стирание ' динамических массивов освобождает память END 'конец программы Функция ABS Функция: ABS возвращает абсолютное значение. Синтаксис: y = ABS(числовое выражение) Комментарии: ABS возвращает абсолютное значение числового выражения. Абсолютное значение х равно его значению без знака. Например, абсолютное значение -3 равно 3; абсолютное значение +3 равно 3. Пример: ' ABS возвращает текущее расстояние от нуля, ' определяя абсолютное значение расстояния ' назначение местоположения Location# = -6.5 ' вывод на экран текущего положения PRINT " Сurrent location: ",Location# ' выводит на экран расстояние от нуля PRINT " Distance from home: ",ABS(Distance#)(Location#) Функция ASC Функция: ASC возвращает численное значение, соответствующее коду ASCII первого символа строки. Синтаксис: y = ASC(символьное выражение) Комментарии: ASC возвращает численное значение, соответствующее коду ASCII первого символа "символьного выражения". Обратитесь к описанию функции CHR$ для преобразования целого числа в символьную строку, которая возврашает строку из одного символа в ответ на числовое значение, коду ASCII. Ограничения: Если "символьное выражение" представляет пустую строку, то выводится сообщение об ошибке 5 периода выполнения "Illegal Function Call" (Неправильный вызов функции). Смотри также: CHR$ Пример: PRINT "The ASCII value of A is";ASC("A") Функция ATN Функция: Возвращает значение тригонометрической функции арктангенс. Синтаксис: y = ATN (числовое выражение); Комментарии: Возвращает арктангенс (обратный тангенс) числового выражения, т.е. угол, тангенс которого равен числовому выражению. ATN возвращает результат с двойной точностью. Результат, как и для всех операций с углами в Turbo Basic, выражен в радианах. Радиан - единица измерения угла; математически она более удобная, чем градус. В градусах углы определяются в дипазоне от 0 до 360 градусов, а в радианах - в диапазоне от 0 до 2*pi. Угол, равный 0 радиан, соответствует направлению луча вдоль положительной оси х; его значение возрастает в направлении противополжном движению часовой стрелки. Лучу, направленному вдоль положительной оси y, соответствует угол 90 градусов, или pi/2 радиан, вдоль отрицательной оси x - 180 градусов, или pi радиан, вдоль отрицательной оси y - 270 градусов или 3*pi/2 радиан. Если вам более удобно работать с углами, выраженными в градусах, то радианы могут быть преобразованы в градусы умножением значения угла в радианах на 57.2958. Например, артангенс 0.23456 равен ATN(.23456) радиан = 0.230395 радиан = (0.230395*57.2958) градусов = 13.2 градуса Для преобразования градусов в радианы следует умножать на 0.0174533. Например, 14 градусов = (0.0174533*14) радиан = 0.24435 радиан Чтобы не запоминать значения этих коэффициентов, можно самим вычислить их с помощью соотношения: 2*pi радиан равны полному кругу, т.е. 360 градусам: таким образом, 1 радиан равен 180/pi градусов. Наборот, 1 градус равен pi/180 радиан. Для справки, pi с точностью до 16 цифр равно: 3.14159 26535 89793 Это значение может быть вычислено в выражении: pi# = 4 * ATN(1) Преобразования из градусов в радианы и из радиан в градусы являются хорошим применением однострочных функций: Смотри также: COS SIN TAN Пример: 'Вычисляет значение pi,используя ATN PI# = 4 * ATN(1) PRINT PI# Оператор BEEP Функция: BEEP заставляет динамик издавать звук. Синтаксис: BEEP [счетчик] Комментарии: Заставляет динамик издавать звук на частоте 800 гц (800 периодов в секунду) в течение одной четверти секунды. Необязательный числовой аргумент задает количество издаваемых звуков. BEEP имеет одинаковый эффект с выдачей символа звуковой сигнализации ASCII (код 7) на экран; например, PRINT CHR$(7). Более мелодичные тона могут быть созданы с помощью операторов SOUND и PLAY. Смотри также: PLAY SOUND Примеры: BEEP 2 'привлекает внимание пользователя Функция BIN$ Функция: BIN$ возвращает двоичный символьный эквивалент числа. Синтаксис: s$ = BIN$ (числовое_выражение) Комментарии: Параметр "числовоe_выражениe" может быть в диапазоне от -32,768 до 65,535. Любая дробная часть числа округляется перед формированием строки. Если "числовое_выражение" - отрицательно, BIN$ возвращает двоичный дополнительный код числа. Смотри также: HEX$ OCT$ Пример: ' В этом примере на экран выводятся десятичные и двоичные ' значения от -5 до 5. FOR I% = -5 TO 5 'значения от -5 до 5 ' выводит на экран десятичные и двоичные значения I& PRINT USING "The binary equivalent of -## = &";I%,BIN$(I%) NEXT I% END 'конец программы Оператор BLOAD Функция: BLOAD загружает файл, созданный с помощью BSAVE, в память. Синтаксис: BLOAD имя_файла [,адрес] Комментарии: Имя_файла - это допустимое символьное выражение, содержащее имя файла, который следует загрузить; удовлетворяющее стандартным требованиян присвоения имен в DOS, и факультативно включающее имя устройства и/или путь. Адрес - это необязательное числовое выражение, имеющее значение в диапазоне от 0 до 65535. Этот адрес определяет первую ячейку в текущем сегменте, начиная с которой будет происходить загрузка файла. Если этот параметр в командной строке опущен, то используется адрес, заданный в команде BSAVE; т.е. файл загружается на то же самое место, из которого он был сохранен на диске.