Школа начинающего программиста-24

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

  Занятие двадцать четвёртое, где продолжается разговор о языке Бейсик-БК. По сравнению с Фокалом он работает в несколько раз быстрее, транслятор этого языка представляет более широкие возможности, но тем не менее серьёзных и интересных программ на Бейсике-БК так и не создано. Дело не в том, что Фокал отбил охоту программировать на языках высокого уровня, и не в том, что Бейсик оставляет программисту чуть ли не вдвое меньше места в памяти машины, чем тот же Фокал. Причина кроется в незаметных на первый взгляд "мелочах", которые свели на нет все потенциальные возможности языка и превратили популярную версию Бейсик-МСХ в Бейсик-БК.
  Если на прошлом занятии мы рассмотрели основные команды и операторы языка, то на этот раз речь пойдёт о функциях и операторах, которые встречаются на практике, может быть, не столь часто, но тем не менее заслуживают внимания всех, кто собирается освоить Бейсик-БК.
  Ведёт занятие инженер А. Борисов (город Москва).

Работаем с памятью
  Оператор POKE Адр, V позволяет записывать значение непосредственно в ячейку Адр оперативного запоминающего устройства БК. V может быть константой, переменной или целым выражением. Поскольку ячейки ОЗУ нумеруются чётными числами, Адр должен быть чётным. Если Адр окажется нечётным, то значение V будет записано по адресу Адр=Адр-1. Этот оператор - удобное средство для ввода данных в ОЗУ компьютера, например, текста подпрограммы-функции в машинных кодах.
  Пару к оператору POKE составляет функция PEEK (Адр), позволяющая получить десятичное целое число, хранящееся в ячейке Адр. Адрес можно записывать в различных системах счисления, но обычно пользуются восьмеричной или десятичной системами счисления. В десятичной системе вместо адресов от 32768 до 65535 записывают числа от -32768 до -1.
  Близка к PEEK-POKE (читается "Пиик-поук") функция INP (Адр, M), необходимая для того, чтобы прочесть часть информации, записанной в шестнадцатиразрядную ячейку памяти. Двоичное число M выбирают по правилу: если требуется проверить - записана ли единица, например, в третьем разряде ячейки, то в третьем разряде в числе M также записывают единицу. Тогда, если в результате вычисления функции INP получится число, в третьем разряде которого записана опять-таки единица, значит, исходное предположение оказалось верным. Одновременно можно проверять любое число разрядов ячейки.
  Ещё один из операторов, работающих с памятью, - это оператор OUT Адр, M, C. Адр и M имеют те же функции, что и в случае с функцией INP, а C определяет - идёт ли речь об установке в 1 разрядов, указанных в M (C не равно нулю), или об очистке этих разрядов (C равно нулю).
  Функция FRE(V) выводит на экран свободный объём памяти в байтах для программы (когда V - любое число) или для символьных переменных (когда V - любой символ).
  Оператор CALL предназначен для работы с внешним постоянным запоминающим устройство. Автору не приходилось на практике сталкиваться с этим оператором.

Динамик, клавиатура, экран
  Один из простейших операторов этого раздела - BEEP. Всякий раз, когда он выполняется, встроенный пьезодинамик БК издаёт короткий звуковой сигнал, напоминающий сигнал нажатия клавиши.
  Функция INKEY$ принимает значение символа, код которого в данный момент хранится в регистре данных клавиатуры. При этом в регистр данных записывается 0. Для выполнения этой функции БК не останавливается, поэтому её удобно использовать всякий раз, когда диалоговый режим не требуется, например, в динамических играх.
  Функция CRSLIN позволяет узнать вертикальную координату курсора. Начало координат (0, 0) - в левом верхнем углу экрана из двадцати четырёх строк. Горизонтальную координату от нуля до тридцати одного (или от нуля до шестидесяти трёх) выдаёт функция POS. Крайне редко применяется функция LPOS, указывающая, какое положение в строке занимает в данный момент печатающая головка принтера, подключённого к БК.
  Установить курсор в заданную позицию можно с помощью оператора LOCATE X, Y, C. Здесь X и Y - константы, переменные или выражения, - координаты курсора: по горизонтали - X (тридцать две/шестьдесят четыре позиции) и по вертикали - Y (двадцать четыре строки), а C - код, определяющий наличие курсора (если C не равно нулю) или его гашение (если C равно нулю). В любом случае значения X и Y не должны превышать двухсот пятидесяти пяти. Краткая форма оператора - LOCATE X работает со строками длиной не по тридцать два/шестьдесят четыре символа, а по двести пятьдесят пять символов, то есть оператор 10 LOCATE 70 установит курсор на шестую позицию второй строки экрана, считая от строки с командой RUN. Краткая форма - LOCATE, Y устанавливает курсор в первую позицию Y-строки.
  Если выводить информацию на экран оператором PRINT, то для того чтобы сдвинуть курсор вправо от текущей позиции до позиции X, где X отсчитывается от начала строки, используют функцию TAB(X). На практике, однако, ею пользуются довольно редко - в этом качестве чаще выступают несколько пробелов, заключённых в кавычки.

Ключи и отладка программ
  С оператором отладки программ связали по смыслу и оператор работы с ключами KEY K, A$, где K - это номер так называемого ключа, а A$ - новая функция ключа. Программируемые ключи - средство, облегчающее ввод и редактирование программы. Это аналог функциональных клавиш персональных компьютеров, то есть клавиш, за которыми можно временно закреплять произвольное значение, например, ввод одной или нескольких команд. Каждая клавиша - это как бы миниатюрный специализированный компьютер, который в ответ на нажатие своей единственной клавиши выполняет какую-то заранее заданную программу. Программа функциональной клавиши БК должна состоять не более чем из шестнадцати символов. После включения питания все десять клавиш запрограммированы самыми употребительными, с точки зрения конструкторов БК, командами. Напомним их:
 - K1 - COLOR
 - K2 - AUTO
 - K3 - GOTO
 - K4 - LIST
 - K5 - RUN:CHR$ (12)
 - K6 - COLOR1, 0 : CHR$(12)
 - K7 - CLOAD<<
 - K8 - CONT : CHR$(12)
 - K9 - << . >> : CHR$(12)
 - K10 - CHR$(14) : RUN : CHR$(12)
  Пара операторов TRON-TROFF - прекрасные помощники для отладки программы. Встретив в программе оператор TRON, БК начинает отчитываться о каждой выполненной строке, выводя на экран её номер. Такой режим работы компьютера называют трассировкой. Оператор TROFF отменяет действие TRON (знатокам английского подскажем, что названия операторов происходят от выражений "trace on" и "trace off").

Числовые функции Бейсика-БК
  Эти функции практически полностью заимствованы из Фортрана, который оказал значительное влияние на формирование первых стандартов Бейсика. Аргументом функции может быть число, переменная или арифметическое выражение. В приложенную таблицу включены четырнадцать числовых функций. К ним иногда относят RND(S), которая служит для обращения к генератору псевдослучайных чисел Бейсика-БК. Здесь число со знаком. При S больше нуля генерируется каждый раз новая последовательность чисел, при S меньше нуля - последовательность чётко определяется мантиссой S. В случае, если S равно нулю, выдаётся одно и то же число. К сожалению, автору неизвестен алгоритм, по которому работает этот генератор. Некоторые рекомендации по проверке генератора можно найти в заметке Ю. Зальцмана ("Наука и жизнь", тысяча девятьсот восемьдесят седьмой год).

Символьные функции
  Говорят, что именно символьным функциям Бейсик обязан своей популярностью. По сравнению с Фортраном Бейсик дал возможность работать с цепочками символов, приспосабливая компьютер-вычислитель для решения не математических и инженерных, а повседневных "кухонных" задач, типа расчёта биоритмов или создания психологических тестов. Было бы трудно собрать все функции в табличку, но и здесь можно выполнить взаимодополняющие пары функций.
  Первая такая пара - это VAL(A$) - STR$(A). Если символьное выражение A$ начинается цифрами, то их последовательность будет преобразована в вещественное число двойной точности (учтён будет знак, если он и есть и символ порядка E или D). В противном случае VAL(A$) окажется равно нулю. Функция STR$(A), напротив, преобразует результат арифметического выражения A (значение переменной или константы) в цепочку символов - цифр, составляющих число. К сожалению, в версии Бейсика-БК функция STR$(A) получила новое "качество" - слева и справа она дополняет результат пробелами.
  Вторая пара - функции ASC(A$) - CHR$(A). Действие функции ASC распространяется только на первый символ выражения A$. Результат вычисления функции - это код данного символа. Функция CHR$(A), напротив, принимает значение символа, код которого определяет A. В обоих случаях код символа лежит в интервале от нуля до двухсот пятидесяти пяти.
  С помощью функции STRING$ (X, C) создают символьную переменную произвольной длины (в пределах от нуля до двухсот пятидесяти пяти символов), которая состоит из одинаковых символов. Что это будут за символы - определяет переменная C. Либо это код символа, либо символьное выражение, в последнем случае первый символ этого выражения будет выбран за эталон. И, напротив, узнать длину символьной переменной A$, то есть количество составляющих её символов, позволяет функция LEN(A$).
  Для того чтобы выделить фрагмент длиной X из цепочки символов A$, начиная с символа N в самостоятельную символьную переменную B$, предназначена функция MID$(A$, N, X). Впрочем, так она действует только в том случае, если B$ стоит слева от знака присваивания, а MID$ - справа. Если поменять их местами, изменится и роль функции MID$. Она в этом случае заменит часть текста символьной цепочки A$ длиной X, начиная отсчёт с символа N, содержимым символьной переменной B$.
  Перевод из одной системы счисления в другую в Бейсике-БК решён на уровне функций. О функции STR$(A) уже говорилось, её аналог для двоичных чисел - это BIN$(A). Любое A из диапазона (-32768, 32767) преобразуется в строку символов, соответствующих двоичному представлению. Функция OCT$(A) вычисляет строку из шести символов, соответствующих восьмеричному представлению числа A, результат вычисления HEX$(A) - самая короткая строка всего из четырёх шестнадцатеричных символов.
  Среди прочих факторов, которые не добавляют привлекательности Бейсику-БК, - низкое быстродействие символьных функций. Это особенно заметно, если попытаться обрабатывать какой-либо текст, например, набор слов для словаря терминов.

Работаем с магнитофоном
  Операторы и функция, о которых пойдёт речь, - одни из наиболее важных, но, к сожалению, они довольно капризны. Подобно тому как на магнитную ленту записывают программу для БК, чтобы затем считывать её в память компьютера, так и данные - значения переменных - можно сохранять на магнитной ленте и вводить их вновь, всякий раз, когда это необходимо. Записи на ленте организованы в виде так называемых файлов - последовательных списков значений переменных. Для того чтобы подготовить Бейсик-систему к записи, служит оператор OPEN <<FN>> FOR OUTPUT, где FN - имя данного файла, - комбинация не более чем шести символов. Имя нередко дополняют расширением, которое указывает на тип файла, например, "СТАТЬЯ.TXT". Если не указывать тип файла, Бейсик-БК автоматически дополнит его расширением .DAT.
  Итак, файл создан, и его можно заполнять данными. Для этого предназначен оператор PRINT # A. В данном случае A - это тоже имя, но уже имя переменной - числовой или символьной, значение которой мы собираемся сохранить в файле на магнитной ленте. В открытый файл можно вывести любое число переменных (информация автоматически выводится на магнитофон блоками по двести пятьдесят шесть байт). Здесь кроется один из досадных недостатков версии Бейсика-БК - каждую переменную необходимо выводить собственным оператором PRINT #. Это единственная из нескольких, известных автору версий Бейсика, которая столь неэкономно относится к и без того скромным ресурсам памяти БК. Вдобавок капризный оператор не позволяет, чтобы его эксплуатировали в цикле - в этом случае, а также, если между двумя операторами PRINT # вклинится любой другой оператор, не удастся считать с магнитной ленты "записанные" таким образом данные.
  На этом можно было бы и завершить описание операторов, работающих с файлами, поскольку маловероятно, чтобы они нашли серьёзное практическое применение до тез пор, пока кто-нибудь не позаботится об устранении дефектов транслятора Бейсика-БК. И всё же имеет смысл завершить описание, поскольку в целом действие этих операторов напоминает систему работы с файлами на других домашних компьютерах и пригодится, если не в практических, так в учебных целях.
  Итак, данные записаны на ленту. Чтобы компьютер получил указание об этом, необходима команда CLOSE. Эта команда закрывает открытый файл, то есть запрещает доступ в область оперативной памяти компьютера, где он временно хранится. Запись на ленте дополняется двумя восьмеричными кодами 12 и 32 (перенос строки и указатель конца файла).
  Чтобы данные с магнитной ленты попали в программу, необходимо повторить последовательность действий. Вновь первым шагом будет команда открыть файл, но на этот раз не для записи, а для считывания - оператор OPEN <<FN>> FOR INPUT. Разумеется, FN - старое имя файла, под которым он хранится на магнитной ленте. Файл открыт, но чтобы считать из него данные, используют ещё один оператор - INPUT #... Точками обозначен список переменных, значения которых мы собираемся считать из файла. Имена переменных в списке должны разделяться запятыми. К тому же последовательность и расположения и написание имён должны в точности соответствовать тому порядку, который был принят в момент записи. Несмотря на все оговорки, этот оператор на практике оказывается не менее капризным, чем PRINT #.
  Важно помнить, что следующим оператором после INPUT # должен быть CLOSE. Кстати, роль CLOSE могут сыграть также команды LOAD или CLEAR.
  Считывая файл с данными, можно поэкспериментировать с функцией EOF. Если случится так, что очередной код, считанный оператором INPUT #, оказывается равен восьмеричному числу 32, то функция "End-Of-File" - "конец файла" примет значение -1. В противном случае она будет равна нулю. Без использования функции EOF всякий раз, когда число имён в списке оператора INPUT окажется больше числа значений, записанных в файле, произойдёт ошибка, которая прервёт выполнение программы. Функция позволяет в критической ситуации прекратить вычисления и закрыть файл.

Функции на любой вкус
  Казалось бы, в нашем описании собраны все нужные, относительно полезные и вряд ли необходимые функции. Между тем их список можно было бы продолжать сколь угодно долго. Парадокса нет, всё дело в том, что вне нашего внимания до сих пор оставались ещё две функции или, скорее, два типа возможных функций.
  Ближе всего к Бейсику функции пользователя типа FN. С помощью оператора DEF FN ИМЯ (...) = ФУНКЦИЯ к стандартному арсеналу можно добавить те функции, которых, по вашему мнению, не хватает в Бейсике-БК. ИМЯ в данном случае - это обозначение вновь создаваемой функции, отточия означают список переменных, которые будут её аргументами. Разумеется, список может состоять из одного имени или вовсе отсутствовать. ФУНКЦИЯ - это любое выражение, связывающее переменные из списка (...) любыми математическими операциями или другими функциями. Здесь важно выполнять лишь два правила: запрещена рекурсия или обращение функции к самой себе, а кроме того, тип переменных в списке (...) должен в точности соответствовать тем, что использованы в определении функции.
  Первое обращение к новой функции должно следовать за её определением. Иными словами, все определения функций, сколько бы их ни было, лучше выносить в начальную часть программы. Тогда можно будет использовать их, где это необходимо по тексту, не задумываясь об определениях, подобно тому, как это происходит со стандартными функциями.
  Обращаются к "самодельной" функции практически так же, как к любой стандартной, с той лишь разницей, что к имени новой функции добавляют FN. Например, если была создана функция ROOT(X) = P1 * SQR(X/2), то обращаться к ней можно, например, так: W=FNROOT(ALFA). Переменная ALFA правомерно заменяет X, который стоял в определении, поскольку относится к тому же типу. Транслятор Бейсика-БК на тот раз оказался на высоте и способен различить одинаково называющиеся переменные и имена функций.
  Всякий пользователь БК, которого возможности Бейсика совершенно не удовлетворяют, имеет возможность несколько (иногда довольно значительно) расширить их с помощью функции USR. Прежде всего имеется в виду повышение быстродействия программы или появление в Бейсике дополнительных и весьма эффективных функций. К сожалению, описание будет поверхностным, мы лишь обрисуем потенциальные возможности, поскольку для настоящего использования функции, о которой идёт речь, необходимо представлять себе особенности устройства БК и уметь программировать в машинных кодах.
  Функция USR, как и FN, вводит оператором DEF USRC = Адр. Она позволяет обращаться к подпрограмме с номером C (от нуля до девяти), которая составлена пользователем в машинных кодах и хранится в оперативной памяти БК, начиная с адреса Адр. В качестве Адр допустимо использовать не только константу, но и переменную или арифметическое выражение. Текст машинной подпрограммы-функции USR записывают на магнитную ленту вместе с основной программой - командой BSAVE. Прежде чем вводить функцию, для неё выделяют дополнительный объём памяти оператором CLEAR. В программе на Бейсике обращение к подпрограмме-функции в машинных кодах выглядит как USRC (Адр), где C - цифра от нуля до девяти.
  Впрочем, есть и другой способ работы, позволяющий использовать функцию USR, несмотря на все каверзы разработчиков транслятора. Всех, кто собирается на практике работать с USR, адресуем к статье Д. Баронова (брошюра "Логическое программирование": Москва, "Знание", тысяча девятьсот восемьдесят восьмой год).

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

Таблица математических функций (CSV-форматирование)
"Название функции",Обозначение,Особенности
"Абсолютное значение X","ABS(X)",-
"Преобразует X в число с двойной точностью","CDBL(X)",-
"Преобразует X  в целое число, отбрасывая дробную часть","CINT(X)","Мантисса X должна быть в интервале (-32768, 32767)"
"Косинус X","COS(X)","X - в радианах"
"Преобразует X в число с одинарной точностью","CSNG(X)","Происходит округление"
"Экспонента X","EXP(X)","X должен быть в интервале (-88.499; 88.029)"
"Целая часть вещественного числа X","FIX(X)","Число остаётся вещественным"
"Вычисляет ближайшее целое вещественное число, меньшее X","INT(X)",-
"Вычисляет знак числа","SGN(X)","Значение функции равно: единица для X больше нуля, ноль при равном нулю X и минус один при X меньше нуля"
"Синус X","SIN(X)","X - в радианах"
"Вычисляет квадратный корень из X","SQR(X)","X больше или равно нулю"
"Вычисляет натуральный логарифм X","LOG(X)","X больше нуля"
"Вычисляет тангенс X","TAN(X)","X - в радианах"
"Вычисляет арктангенс X","ATN(X)","X - в радианах"


Приложение. Примеры текстов программ

Код первый
  БК выдаёт звуковые сигналы, длительность которых зависит от кода символа, соответствующего нажатой клавише. Опрашивается клавиатура (1, 2), вычисляется длительность сигнала (3), организуется цикл с необходимым числом повторений (4, 9), формируется заданная высота звука (6, 7).
1 POKE &0177660,&0100
2 IF INP(&0177660,&0200) YJEN 3 ELSE 2
3 T%=PEEK(&0177662)+20
4 FOR J%=1 TO T%
5 OUT &0177716,64%,1%
6 FOR I%=1 TO 9
7 NEXT I%
8 OUT &0177716,64%,0%
9 NEXT J%

Код второй
  Курсор на экране, где бы он ни находился, гасится (1), формируется звуковой сигнал (2-4), и вновь включается курсор (5). Если нажата какая-то клавиша, управление переходит на строку 1. Последний оператор ничего не напечатает, но курсор сместится вниз.
1 LOCATE POS,CRSLIN,0%
2 FOR I%=1 TO 10%
3 BEEP
4 NEXT I%
5 LOCATE POS,CRSLIN,1%
6 A$=INKKEY$
7 IF A$<>"" THEN 1
8 PRINT A$

Код третий
  Исходные значения ключей K1, K2 изменятся соответственно на TRON и TROFF.
1 KEY1,"TRON"+CHR$(12)
2 KEY2,"TROFF"+CHR$(12)

Код четвёртый
  Первая программа из одной строки последовательно выделяет константу 56 из символьной константы "56-КОТ", преобразует 56 в символьную константу "56" и печатает её длину - четыре. Вторая программа вычисляет код первого символа символьной переменной, а затем печатает символ, соответствующий коду, то есть S. Третья программа выделяет фрагменты из символьной константы (3-4) и заменяет её часть.
1 PRINT LEN(STR$(VAL("56-КОТ")))
RUN
4
1 PRINT CHR$(ASC("SIGMA"))
RUN
S
1 S$="SIGMA"
2 M$="MIK"
3 A$=MID$(S$,1,3)
4 B$=MID$(S$,4,2)
5 MID$(S$,1,3)=M$
6 PRINT A$,B$,S$
RUN
SIG    MA    MIKMA

Код пятый
  Программа формирует на магнитной ленте файл под названием FILE.DAT (3, 6) и записывает в него значения числовой и символьной переменных (4-5).
1 A=1
2 B$="ALFA"
3 OPEN "FILE" FOR OUTPUT
4 PRINT#A
5 PRINT#B$
6 CLOSE

Код шестой
  Программа считывает с магнитофона файл, который называется "FILE.DAT" (1, 3), присваивает переменным значения, извлечённые из файла (2), и выводит их на дисплей (4).
1 OPEN "FILE" FOR INPUT
2 INPUT# A,B$
3 CLOSE
4 PRINT B$,A
RUN
ALFA    1


Рецензии