Предыдущая часть:
Когда-то BASIC был первым и фактически единственным языком программирования, доступным рядовому пользователю.
Слово basic переводится как "простой". Но на самом деле это аббревиатура из слов Beginners' All-purpose Symbolic Instruction Code, то есть "Символический код инструкций широкого назначения для начинающих"... СКИШНАН? Следовательно, название BASIC нужно писать большими буквами.
Язык, как видно из его названия, предназначался для новичков. Если ранжировать языки для новичков, то ассемблер можно считать самым сложным, а BASIC, по идее, должен быть самым простым. Но самое интересное, что BASIC на самом деле имеет много общего с ассемблером, и мы далее увидим, почему.
Среда исполнения
Когда компьютер включается, в его память должна быть загружена какая-то программа, которая и будет работать дальше. В первых домашних компьютерах такой программой часто был интерпретатор языка Бейсик.
Он был интерактивным, и вы могли набрать в нём какую-нибудь инструкцию и сразу же выполнить её:
Чтобы начать писать программу, нужно добавлять номера строк перед инструкциями:
После ввода ничего не происходит, потому что строка с номером 10 записалась в память. Таким образом, вы можете вводить программу построчно, увеличивая номера строк:
Было принято нумеровать строки с шагом 10, чтобы можно было вставить новую строку между уже введёнными:
Здесь я добавил строку с номером 15. Она должна выполняться после строки 10, но в листинге находится на последнем месте. Такая неразбериха, конечно же, недопустима, поэтому для вывода "чистовой" версии программы есть команда LIST:
Также возможен случай, когда промежуточных строк между 10 и 20 нужно вставить очень много, так что номеров не хватит. На этот случай есть команда RENUM:
Она перенумеровывает все строки заново.
Ну и чтобы запустить программу, используется команда RUN:
Борьба за память
Размер памяти старых компьютеров измерялся даже не в мегабайтах, а в килобайтах. В эти килобайты, во-первых, уже был загружен сам интерпретатор языка Бейсик, и во-вторых, текст вашей программы.
Программа после запуска могла использовать только оставшуюся память. Которой зачастую хватало только на то, чтобы написать простейшую игру вроде пинг-понга.
Получить чуть больше памяти удавалось за счёт сокращения самого текста программы. Бейсик был нечувствительным к пробелам, поэтому инструкции можно было писать без них:
Некоторые инструкции, в зависимости от версии Бейсика, можно было также сокращать. Например, вот такую строку:
IF X = 5 THEN PRINT "YES" ELSE PRINT "NO"
В Вильнюс-Бейсике (УК НЦ) можно было сократить вплоть до такой (точно не помню, но это как пример):
IFX=5THPRI"YES"ELPRI"NO"
И как следствие, экономия нескольких символов в каждой строке давала неплохую прибавку к памяти. Правда, читать такой код было невозможно без привычки. Но привычка вырабатывалась быстро :)
Типы данных
Даже в таком "новичковом" языке уже была в некотором роде жёсткая типизация. Тип указывался не отдельно, а прямо в имени переменной. Так, строковые переменные требуется дополнять знаком "$":
Остальные переменные считаются числовыми, но и там есть разделение. Если вы хотите сделать переменную целочисленной, то дописываете в имя знак "%":
Как видим, если присвоить вещественный результат целочисленной переменной, дробная часть будет отброшена.
Кроме того, явное указание целочисленных типов позволяло сделать программу существенно быстрее.
GOTO
Как я писал в предыдущем материале про ассемблер, GOTO, или прыжок на определённый адрес, это единственный способ управления программой. В Бейсике ситуация похожая. Мы можем сделать высокоуровневый цикл, типа
Но перейти из условного оператора на нужный блок кода нельзя другим способом, кроме как с помощью GOTO. На этом примере показан алгоритм решения квадратного уравнения:
В строке номер 30 дискриминант проверяется на отрицательное значение. Если это так, то уравнение не имеет решений, и происходит переход на строку 100, где программа заканчивается. В строке 60, после вычисления одного корня, дискриминант проверяется на 0, и если это так, то корней больше нет и также происходит переход на строку 100.
В языках с C-подобным синтаксисом мы написали бы так:
Обратите внимание, как инвертируются условия и логика программы как бы выворачивается наизнанку.
Но в Бейсике нет функциональных блоков*, и нет уровней вложенности (кроме циклов), поэтому его можно рассматривать как аналог ассемблера: инструкции идут последовательным потоком, и чтобы выйти из этого потока и войти в него в другом месте, мы должны использовать GOTO.
Если в ассемблере мы указывали адрес, на который надо перейти, то в Бейсике указываем номер строки – тоже своего рода адрес. И так работать даже тяжелее, чем в ассемблере, потому что в ассемблере есть хотя бы символьные метки!*
GOSUB
В Бейсике также не было привычных нам процедур или функций, то есть кусков кода, которые выступают как самостоятельные и автономные сущности, и которые можно вызывать из любого места программы, передавая им параметры.
Вместо этого была команда GOSUB. Это то же самое, что GOTO, только с запоминанием адреса возврата. Таким образом, подпрограмма располагалась в общем листинге программы где-то например со строки 1000, и вызывалась с помощью GOSUB 1000. Для возврата из функции использовалась команда RETURN.
У подпрограммы не было какого-то специального начала, она вообще никак не была отделена от программы. И программа, если бы дошла естественным путём до строчки 1000, просто стала бы выполнять код подпрограммы как обычно.
Абсолютно аналогично в ассемблере использовались инструкции call и ret, и там тоже подпрограмма просто начиналась с какого-то адреса.
В Бейсике параметры в подпрограмму передавать было нельзя*. Вместо этого все переменные программы были глобальными, и подпрограмма могла обращаться к ним. В ассемблере можно передавать параметры любым способом: хоть через регистры, хоть через стек.
POKE и PEEK
А вот это неожиданно для "языка новичков". Бейсик позволял делать запись значения в любой адрес памяти с помощью команды POKE:
POKE 1000, 5
и читать значение из адреса с помощью команды PEEK:
LET X = PEEK(1000)
Не любой из современных языков такое умеет, а Бейсик умел. Что опять же сближает его с ассемблером.
*Развитие Бейсика
Новые версии Бейсика, например QBasic, становились более удобными. Появился нормальный редактор с функционалом IDE. Программа редактировалась как целое, а не по одной строчке. Исчезла необходимость нумеровать строки. Переходы и вызовы подпрограмм стали возможны по символьным меткам. Также появились полноценные функции с именами и параметрами. Появились и функциональные блоки с возможностью вложения, то есть стало возможным писать несколько строк внутри одного блока. Наконец, появились объекты и ООП.
В общем, по возможностям современные Бейсики, в частности, Visual Basic, находятся на уровне остальных развитых языков, и поэтому ничего особенного из себя уже не представляют :)
Читайте дальше: