Введение

Commodore BASIC, также известный как PET BASIC или CBM BASIC, — это диалект языка программирования BASIC, использовавшийся в 8-битных домашних компьютерах Commodore International, начиная с PET (1977) и заканчивая Commodore 128 (1985). Ядро основано на 6502 Microsoft BASIC, и поэтому он имеет много общих черт с другими 6502 BASIC того времени, такими как Applesoft BASIC. Commodore лицензировал BASIC у Microsoft в 1977 году на условиях единовременной оплаты без выплаты роялти, после того как Джек Трамиэль отклонил предложение Билла Гейтса о плате за каждую единицу, заявив: "Я уже женат" и согласившись заплатить только за бессрочную лицензию. Оригинальная версия PET была очень похожа на исходную реализацию Microsoft с незначительными изменениями. BASIC 2.0 на C64 также был похож и встречался на C128 (в режиме C64) и других моделях. Более поздние модели PET оснащались BASIC 4.0, который был похож на оригинал, но добавлял ряд команд для работы с дискетами. BASIC 3.5 стал первым, кто значительно отличался, добавив ряд команд для поддержки графики и звука на C16 и Plus/4. BASIC 7.0 поставлялся с Commodore 128 и включал команды структурированного программирования из BASIC 3.5 Plus/4, а также ключевые слова, разработанные специально для использования новых возможностей компьютера. Был добавлен редактор спрайтов и монитор машинного кода. Последняя версия, BASIC 10.0, была частью так и не выпущенного Commodore 65.

История

Commodore взяла исходный код BASIC с фиксированной платой и продолжила его разработку внутри компании для всех своих других 8-битных домашних компьютеров. Уведомление об авторских правах Microsoft впервые появилось только на Commodore 128 (с V7.0). Однако Microsoft встроила "пасхальное яйцо" в версию 2 или "обновлённый" Commodore BASIC, которое подтверждало его происхождение: ввод малоизвестной команды WAIT 6502, 1 приводил к появлению на экране слова Microsoft! ("Пасхальное яйцо" было тщательно замаскировано – сообщение не отображалось при разборке интерпретатора). Популярный Commodore 64 поставлялся с BASIC v2.0 в ПЗУ, несмотря на то, что компьютер был выпущен после серии PET/CBM, в которой использовалась версия 4.0. Это объясняется тем, что Commodore 64 позиционировался как домашний компьютер, а серия PET/CBM была ориентирована на бизнес и образование, где встроенный язык программирования, как предполагалось, использовался более интенсивно. Это позволило снизить производственные затраты, так как V2 помещалась в ПЗУ меньшего размера.

Редактирование программы

Удобной особенностью интерпретатора BASIC и KERNAL для Commodore была полноэкранная программа редактирования. Несмотря на то, что клавиатуры Commodore имели всего два курсорных ключа, менявших направление при нажатии клавиши Shift, редактор экрана позволял пользователям вводить прямые команды или вводить и редактировать строки программы из любой точки экрана. Если строка начиналась с номера строки, она токенизировалась и сохранялась в памяти программы. Строки, не начинающиеся с номера, выполнялись при нажатии клавиши, когда курсор находился на этой строке. Это было значительным улучшением интерфейса ввода программ по сравнению с другими распространенными домашними компьютерами BASIC того времени, которые обычно использовали редакторы строк, вызываемые отдельной командой EDIT, или "курсор копирования", обрезавший строку в позиции курсора. Также была возможность сохранять именованные файлы на любое устройство, включая кассету – популярное устройство хранения во времена PET и которое оставалось в использовании на протяжении всего жизненного цикла 8-битных Commodore как недорогой способ массового хранения. Большинство систем поддерживали только имена файлов на дискетах, что затрудняло сохранение нескольких файлов на других устройствах. Пользователю этих систем приходилось запоминать показания счетчика магнитофона в месте расположения файла, но это было неточно и подвержено ошибкам. С PET (и BASIC 2.0) файлы с кассет можно было запрашивать по имени. Устройство искало имя файла, последовательно считывая данные и игнорируя несовпадающие имена. Файловая система также поддерживалась мощной структурой записей, которые можно было загружать или сохранять в файлы. Данные на кассетах Commodore записывались в цифровом виде, а не менее дорогими (и менее надежными) аналоговыми методами, используемыми другими производителями. Поэтому требовался специализированный Datasette, а не обычный магнитофон. Существовали адаптеры, использующие аналого-цифровой преобразователь для работы со стандартным магнитофоном, но они стоили лишь немного дешевле Datasette. Команда может использоваться с необязательным параметром, который загрузит программу в адрес памяти, содержащийся в первых двух байтах файла (эти байты отбрасываются и не сохраняются в памяти). Если параметр не указан, программа загружается в начало области программы BASIC, которая сильно различается на разных машинах. Некоторые варианты Commodore BASIC поставлялись с командами BLOAD и BSAVE, которые работали аналогично своим аналогам в Applesoft BASIC, загружая или сохраняя растровые изображения из указанных областей памяти. PET не поддерживает перемещаемые программы, и команда всегда загружается, начиная с первых двух байтов, содержащихся в файле программы. Это создавало проблему при попытке загрузить программы BASIC, сохраненные на других машинах Commodore, поскольку они загружались по более высокому адресу, чем ожидала BASIC PET, и требовало обходных путей для "перемещения" программ в нужное место. Если программа была сохранена на машине CBM II, единственный способ загрузить ее на PET заключался в изменении первых двух байтов с помощью редактора секторов диска, поскольку серия CBM II имела область программы BASIC по адресу $0, что приводило бы к попытке PET загрузить нулевую страницу и зависанию. Ключевые слова Commodore BASIC можно было сокращать, сначала вводя немодифицированный символ, а затем модифицированный символ следующей буквы. Это устанавливало старший бит, заставляя интерпретатор прекращать чтение и разбирать выражение в соответствии с таблицей поиска. Это означало, что выражение до старшего бита принималось как замена полного ввода команды. Однако, поскольку все ключевые слова BASIC хранились в памяти как однобайтовые токены, это было удобством для ввода выражений, а не оптимизацией. В наборе символов, содержащем только прописные буквы, модифицированные символы отображаются как графические символы; например, команда GOTO можно было сократить до G{Shift O} (которая на экране выглядела как GΓ). Большинство таких команд состояли из двух букв, но в некоторых случаях они были длиннее. В таких случаях возникала неоднозначность, поэтому требовалось больше немодифицированных букв команды, например, GO{Shift S} (GO♥) для GOSUB. Некоторые команды не имели сокращенной формы из-за краткости или неоднозначности с другими командами. Например, команда INPUT не имела сокращения, поскольку ее написание совпадало с отдельным ключевым словом INPUT#, которое находилось ближе к началу таблицы ключевых слов. Часто используемая команда PRINT имела сокращение ?, как и в большинстве диалектов Microsoft BASIC. Сокращение команд с помощью модифицированных букв уникально для Commodore BASIC. Этот метод токенизации имел ошибку: если включать REM (оператор BASIC для добавления комментария к коду), за которым следовал {Shift L}, при попытке просмотреть листинг программы интерпретатор BASIC немедленно прерывал листинг, отображал ?SYNTAX ERROR и возвращался к подсказке READY. Программисты использовали эту ошибку для защиты своей работы, хотя ее было довольно легко обойти. Сокращая ключевые слова, можно было поместить больше кода на одной строке программы (которая могла занимать две строки экрана на дисплеях с 40 столбцами, т. е. C64 или PET, или четыре строки на 22-столбцовом дисплее VIC 20). Это позволяло немного сэкономить на накладных расходах на хранение дополнительных строк программы, но не более того. Все команды BASIC токенизировались и занимали 1 байт (или два, в случае нескольких команд BASIC 7 или BASIC 10) в памяти, независимо от способа ввода. Такие длинные строки было неудобно редактировать. Команда LIST отображала все ключевое слово команды, расширяя строку программы за пределы 2 или 4 строк экрана, которые можно было ввести в память программы.

Выступление

Как и оригинальный интерпретатор Microsoft BASIC, Commodore BASIC работает медленнее, чем машинный код. Результаты тестов показали, что копирование 16 килобайт из ПЗУ в ОЗУ занимает менее секунды в машинном коде, по сравнению с более чем минутой в BASIC. Чтобы ускорить выполнение программ, программисты начали использовать различные техники. Одной из них было хранение часто используемых чисел с плавающей точкой в переменных, а не использование литералов, так как интерпретация имени переменной была быстрее, чем интерпретация числового литерала. Поскольку тип с плавающей точкой является типом по умолчанию для всех команд, использование чисел с плавающей точкой в качестве аргументов быстрее, чем целых чисел. Когда скорость была критична, некоторые программисты переводили части программ BASIC на ассемблер 6502 или 6510, который загружался отдельно из файла или записывался в память из инструкций DATA в конце программы BASIC, а затем выполнялся из BASIC с помощью команды SYS, либо в прямом режиме, либо из самой программы. Если скорость машинного кода была слишком высокой, например, в играх или при ожидании ввода пользователя, программисты могли выполнять опрос, считывая выбранные ячейки памяти (например, для 64 или для 128, обозначающие размер буфера клавиатуры), чтобы замедлить или остановить выполнение. Уникальной особенностью Commodore BASIC является использование управляющих кодов для выполнения задач, таких как очистка экрана или позиционирование курсора в программе. Их можно вызвать либо с помощью команды, где X соответствует коду управления (например, является кодом управления для очистки экрана), либо нажатием соответствующей клавиши в кавычках. Например, нажатие после кавычки заставит BASIC отобразить визуальное представление управляющего кода (в данном случае, перевернутое сердце), которое будет выполнено при запуске программы (прямая печать управляющих кодов использует меньше памяти и выполняется быстрее, чем вызов функции). Это отличается от других реализаций BASIC, которые обычно имеют отдельные команды для очистки экрана или перемещения курсора. BASIC 3.5 и более поздние версии имеют специальные команды для очистки экрана и перемещения курсора. В Commodore BASIC строки программ не требуют пробелов (но команда всегда отображает один пробел между номером строки и оператором), например, , и было принято писать программы без пробелов. Эта функция была добавлена для экономии памяти, поскольку токенайзер не удаляет пробелы между ключевыми словами: наличие пробелов приводит к дополнительным 0x20 байтам в токенизированной программе, которые просто пропускаются при выполнении. Токенайзер удаляет пробелы между номером строки и оператором программы. На большинстве машин строки программы могут содержать до 80 символов, но машины с 40-колонковым текстом переносили строку на следующую строку на экране, а на VIC 20, с 22-колонковым дисплеем, строки программы могли занимать до четырех строк. BASIC 7.0 на Commodore 128 увеличил лимит строки программы до 160 символов (четыре строки по 40 символов или две строки по 80 символов). Используя сокращения, такие как вместо , можно поместить больше кода в строку. BASIC 7.0 выдает ошибку, если пользователь вводит строку программы длиной более 160 символов. В более ранних версиях ошибка не выдается, а просто отображается запрос READY на две строки ниже, если длина строки превышена. Номер строки учитывается в общем количестве символов в строке программы, поэтому пятизначный номер строки уменьшает допустимое количество символов на четыре. Порядок выполнения строк Commodore BASIC не определялся нумерацией строк; вместо этого он следовал порядку, в котором строки были связаны в памяти. Строки программы хранились в памяти в виде односвязного списка с указателем (содержащим адрес начала следующей строки программы), номером строки и затем токенизированным кодом строки. Во время ввода программы BASIC постоянно переупорядочивал строки программы в памяти, чтобы номера строк и указатели были в порядке возрастания. Однако после ввода программы ручное изменение номеров строк и указателей с помощью команд POKE могло привести к выполнению строк в неправильном порядке или даже присвоить всем строкам один и тот же номер строки. В ранние годы, когда BASIC использовался в коммерческих целях, это был метод защиты программного обеспечения от несанкционированных изменений. Номера строк могут быть от 0 до 65520 и занимают пять байт для хранения, независимо от количества цифр в номере строки, хотя выполнение происходит быстрее, если номер строки содержит меньше цифр. Размещение нескольких операторов в одной строке позволяет сэкономить память и ускорить выполнение. Операторы и будут искать строку с указанным номером вниз от текущей строки, если выполняется прямой переход, а в случае обратного перехода вернутся к началу программы для поиска. Это замедляет выполнение больших программ, поэтому желательно размещать часто используемые подпрограммы в начале программы. Имена переменных учитываются только первые два символа; таким образом, имена переменных VARIABLE1, VARIABLE2 и VA относятся к одной и той же переменной. Commodore BASIC также поддерживает побитовые операторы , и , хотя эта функция была частью основного кода Microsoft 6502 BASIC, она часто отсутствовала в других реализациях, таких как Applesoft BASIC. Собственный формат чисел в Commodore BASIC, как и в его родительском MS BASIC, — это числа с плавающей точкой. Большинство современных реализаций BASIC использовали один байт для мантиссы (экспоненты) и три байта для мантиссы. Точность числа с плавающей точкой с трехбайтовой мантиссой составляет около 6,5 десятичных знаков, и округление является распространенной проблемой. 6502 реализации Microsoft BASIC использовали 40-битную арифметику с плавающей точкой, что означает, что переменные занимали пять байт для хранения (четырехбайтовая мантисса и один байт для экспоненты), в отличие от 32-битной арифметики с плавающей точкой в BASIC 80. В то время как 8080/Z80 реализации Microsoft BASIC поддерживали целочисленные и переменные двойной точности, 6502 реализации поддерживали только числа с плавающей точкой. Хотя Commodore BASIC поддерживает целочисленные переменные со знаком (обозначаются знаком процента) в диапазоне от -32768 до 32767, на практике они используются только для переменных массивов и служат для экономии памяти, ограничивая элементы массива двумя байтами каждый (массив из 2000 элементов займет 10 000 байт, если он объявлен как массив чисел с плавающей точкой, но только 4000 байт, если он объявлен как целочисленный массив). Объявление любой переменной как целочисленной просто приводит к тому, что BASIC преобразует ее обратно в число с плавающей точкой, замедляя выполнение программы и тратя память, поскольку каждый знак процента занимает один дополнительный байт для хранения (поскольку это также относится к целочисленным массивам, программисту следует избегать их использования, если только не используются очень большие массивы, которые превысили бы доступную память, если бы они хранились как числа с плавающей точкой). Кроме того, невозможно с помощью или получить доступ к ячейкам памяти выше 32767 с адресом, определенным как целочисленная переменная. Точку (.) можно использовать вместо числа 0 (например, вместо или вместо ), что приведет к немного более быстрому выполнению. Оператор, используемый для запуска программ на машинном коде, был добавлен Commodore и отсутствовал в оригинальном коде Microsoft BASIC, который содержал только функцию USR для вызова подпрограмм на машинном коде. Он автоматически загружает регистры процессора значениями из (C64, варьируется на других машинах), что можно использовать для передачи данных в подпрограммы на машинном коде или в качестве средства вызова функций ядра из BASIC (например, очищает экран). Поскольку 8-битные компьютеры Commodore, отличные от C128, не могут автоматически загружать дисковое программное обеспечение, обычно используется базовая заглушка, такая как , для начала выполнения программы. Можно автоматически запускать программное обеспечение после загрузки, не требуя от пользователя ввода оператора , это делается путем перехвата вектора "ready" BASIC по адресу .
Как и в большинстве других версий Microsoft BASIC, если массив не объявлен с помощью оператора , он автоматически устанавливается в десять элементов...

Альтернативы

Многие расширения BASIC были выпущены для Commodore 64 из-за относительно ограниченных возможностей его встроенного BASIC 2.0. Одним из самых популярных расширений был DOS Wedge, который поставлялся с Commodore 1541 Test/Demo Disk. Это расширение BASIC размером 1 КБ добавило ряд команд, связанных с диском, включая возможность чтения каталога диска без уничтожения программы в памяти. Его функции впоследствии были включены в различные сторонние расширения, такие как популярный картридж Epyx FastLoad. Другие расширения BASIC добавили дополнительные ключевые слова для упрощения кодирования спрайтов, звука и графики высокого разрешения, например Simons' BASIC (1983) и Vision BASIC (2022). Хотя отсутствие звуковых или графических функций в BASIC 2.0 расстраивало многих пользователей, некоторые критики утверждали, что это в конечном итоге было полезно, поскольку заставляло пользователя изучать машинный язык. Ограничения BASIC 2.0 на C64 привели к использованию встроенного в ПЗУ машинного языка из BASIC. Для загрузки файла в указанное местоположение памяти имя файла, диск и номер устройства считывались с помощью вызова: ; местоположение указывалось в регистрах X и Y: ; и вызывалась подпрограмма загрузки: Дисковый журнал для C64, Loadstar, был площадкой для программистов-любителей, которые делились коллекциями протоколов команд для BASIC, вызываемых командой. С точки зрения современного программирования, ранние версии Commodore BASIC представляли собой множество опасных ловушек для программиста. Поскольку большинство этих проблем были унаследованы от Microsoft BASIC, практически каждый домашний компьютер BASIC той эпохи страдал от подобных недостатков. Каждой строке программы Microsoft BASIC присваивался номер строки программистом. Обычно номера увеличивали на определенное значение (5, 10 или 100), чтобы упростить вставку строк во время редактирования или отладки программы, но плохое планирование означало, что вставка больших разделов в программу часто требовала реструктуризации всего кода. Распространенной техникой было начинать программу с небольшого номера строки с таблицей переходов, а тело программы структурировалось на разделы, начинающиеся с определенного номера строки, например 1000, 2000 и так далее. Если нужно было добавить большой раздел, ему можно было просто присвоить следующий доступный номер главной строки и вставить его в таблицу переходов. Кроме того, все переменные рассматриваются как глобальные переменные. Четко определенные циклы, отличные от конструкции FOR NEXT, сложно создавать, что часто заставляло программиста полагаться на команду (это было исправлено позже в BASIC 3.5 с добавлением команд и). Для выполнения определенных задач часто требовалось создавать переменные-флаги. Более поздние версии BASIC на Commodore и других платформах включали команды и, а также команду автоматической нумерации строк AUTO, которая автоматически выбирала и вставляла номера строк в соответствии с выбранным шагом. Ранние версии BASIC от Commodore также не имели команд отладки, что затрудняло обнаружение ошибок и неиспользуемых переменных. Структуры, стандартная часть Z80 Microsoft BASIC, были добавлены в BASIC 3.5 после того, как они были недоступны в более ранних версиях Commodore BASIC.

Использовать в качестве пользовательского интерфейса

Как и другие домашние компьютеры, компьютеры Commodore загружались непосредственно в интерпретатор BASIC. Файловые команды и команды программирования BASIC можно было вводить в прямом режиме для загрузки и выполнения программ. Если выполнение программы прерывалось клавишей RUN/STOP, значения переменных сохранялись в оперативной памяти и могли быть выведены на экран для отладки. Модель 128 даже выделяла свой второй 64-килобайтный блок памяти для хранения переменных, позволяя им сохраняться до ввода команды NEW или RUN. Это, в сочетании с расширенным редактором экрана, включенным в Commodore BASIC, придавало среде программирования ощущение REPL: программисты могли вставлять и редактировать строки программы в любом месте экрана, интерактивно создавая программу. Это отличалось от бизнес-ориентированных операционных систем того времени, таких как CP/M или MS-DOS, которые обычно загружались в интерфейс командной строки. Если на этих платформах требовался язык программирования, его необходимо было загружать отдельно. Хотя некоторые версии Commodore BASIC включали дисковые команды DLOAD и DSAVE, в версии для Commodore 64 они отсутствовали, поэтому пользователю приходилось указывать номер устройства дисковода (обычно 8 или 9) в стандартной команде LOAD, которая по умолчанию работала с кассетой. Другим недостатком BASIC 2.0 в Commodore 64 была отсутствие команды DIRECTORY для отображения содержимого диска без очистки основной памяти. На Commodore 64 просмотр файлов на диске осуществлялся путем загрузки "программы", которая при выводе на экран отображала каталог в виде псевдо-BASIC программы, где размер блока файла служил номером строки. Это приводило к перезаписи текущей программы. Дополнения, такие как DOS Wedge, решали эту проблему, выводя список каталогов непосредственно в видеопамять.