Адаптация программ к системе TR-DOS. 1992 г.

Глава 3 - ещё о бейсике.


Глава 3

ЕЩЕ   О БЕЙСИКЕ

 

Программист, не знакомый с представлением чисел бейсик - интерпретатором компьютера ZX Spectrum, немало удивится, столкнувшись со следующей программой:

 

     10 CLEAR  100

     20 PAPER 27: INK 8E-12: BORDER 65536: CLS

     30 PRINT AT -10000,22E22;"PLEASE WAIT"

     40 LOAD  ""CODE  0,0

     50 RANDOMIZE  USR  0

 

Такой программист будет настоятельно утверждать, что этот бред написан не иначе, как пациентом учреждения на Пряжке, до тех пор, пока не запустит программу и не увидит результаты ее работы. Что произойдет с программистом после того, как в середине экрана появится надпись PLEASE WAIT, затем загрузится и запустится игра, предсказать трудно. Вероятнее всего, он побежит в ПНД с предполагаемым диагнозом «маниакально-депрессивный психоз на почве программирования».

Для того чтобы с Вами этого не произошло, раскрою Вам одну тайну. Все дело в том, что при обработке чисел бейсик-интерпретатор использует два их представления. Первое представление — это приятная для глаз символьная форма, в которой число 16389, например, будет записано пятью байтами согласно таблице ASCII. Однако такая форма относительно долго обрабатывается бейсик-интерпретатором, посему для своих нужд он использует другое представление числа — двоичное. Двоичная форма числа, предваряемая префиксом — кодом 14 (ОЕh), хранится в памяти непосредственно после символьной формы. Число 16389, например, выглядит в памяти следующим образом:

 

 

символьная форма

префикс

двоичная форма

 

 

1

6

3

8

9

 

...

49

54

51

56

57

14

0

0

5

64

0

...

 

Отсюда видно, что двоичная форма числа занимает 5 байт плюс байт префикса. При записи целых констант в промежутке от 0 до 65535 «значащими» являются 3-й и 4-й байты после префикса. В этом случае двоичную форму числа можно перевести в десятичную с помощью оператора

     PRINT PEEK (n+3)+256*РЕЕК (n+4)

 

- где n — адрес, по которому хранится байт префикса. Двоичная и символьная формы числа существуют параллельно.

При выполнении инструкций бейсик-интерпретатор руководствуется только двоичной формой, символьная форма его не интересует, она сохраняется ради удобочитаемости программ. Поэтому «порча» символьного представления чисел приводит в ужасный вид листинг программы, но не влияет на ее работоспособность.

Двоичная форма числа добавляется в момент проверки синтаксиса строки, то есть по окончании набора строки и нажатии клавиши Enter. При вызове на редактирование строки двоичная форма удаляется, а после ввода исправленной строки восстанавливается в соответствии с новой редакцией. Из сказанного должно быть понятно, что загадочная программа, приведенная в начале этой главы, не будет работать, если ее ввести с клавиатуры обычным способом, не используя каких-либо специальных приемов (быть может, Вы уже попробовали ее набрать и запустить и решили, что не кто иной, как я, и являюсь пациентом вышеуказанной клиники).

Для того, чтобы привести программу к такому извращенному виду, при этом оставив ее работоспособной, необходимы внешние средства, например, монитор-отладчик MONS4 или подобные. Однако мы пока ведем разговор об адаптации программ на диск, а не о приведении их в состояние алкогольного опьянения, поэтому задачи у нас стоят обратные.

Можно было бы заняться пространным описанием представления чисел в двоичной форме, но я предпочту дать практические советы по вычислению того, что скрыто под маской символьной формы.

Наиболее простым и эффективным способом определения истинных значений чисел, по моему опыту, является подстановка оператора PRINT вместо операторов программы. В этом случае все числа, используемые программой, будут последовательно выведены на экран в нормальном виде.

Если приведенную в начале главы программу изменить следующим образом (обратите внимание, что не использующие чисел операторы и другие «лишние» символы заменены пробелами, обозначенными в данном случае знаком подчеркивания):

     10 PRINT 100

     20 PRINT 27: PRINT 8E-12: PRINT 65536:_

     30 PRINT _-10000,22E22;________________

     40 PRINT ___0,0

     50 PRINT _0

— то в результате ее выполнения на экране появится:

     24999

     0

     4

     0

     10     10

     25000  40000

     25000

 

     0 ОК, 50:1

  Подставив полученные значения в программу, получим привычный и понятный текст:

 

     10 CLEAR 24999

     20 PAPER 0: INK 4: BORDER 0: CLS

     30 PRINT AT 10,10;"PLEASE WAIT"

     40 LOAD  ""CODE 25000,40000

     50 RANDOMIZE  USR  25000

 

Если Вы уже потянулись к клавише Edit, чтобы побыстрее расставить операторы PRINT, советую Вам прочесть все с начала. Как уже говорилось, при вызове на редактирование двоичная форма числа безвозвратно теряется, остается только символьная, и если Вы исправите INK 8E—12 на PRINT 8E—12 с помощью бейсик-редактора, то и получите не что иное, как 8Е-12. Чтобы заменить операторы программы на PRINT, не «сломав» двоичной формы чисел, нужны другие способы. Можно воспользоваться все тем же отладчиком MONS4; в крайнем случае сойдет и оператор РОКЕ. В этой брошюре я ставлю своей целью обучать работе с отладчиком, поэтому расскажу лучше, как победить программу без подручных средств.

Оператор РОКЕ очень хорош, но только тогда, когда знаешь, какие параметры должны следовать после него. А для этого нужно заглянуть в память компьютера. Можно, например, воспользоваться строчкой, которая выводит на экран адрес и содержимое ячеек памяти и символьное представление этого содержимого:

 

     FOR n=23755  TO 4E10: PRINT n,PEEK n;ТАВ 22;

        CHR$  (PEEK n*(PEEK n=32)): NEXT n

 

   Выполнив эту строку, на экране получим:

 

     23755  0     ?          номер строки

     23756  10    ?

     23757  11    ?          длина строки

     23758  0     ?

     23759  253   CLEAR      ключевое слово

     23760  49    1

     23761  48    0          символьная форма параметра

     23762  48    О

     23763  14    ?          префикс

     23764  0     ?

     23765  0     ?

     23766  167   COS        двоичная форма параметра

     23767  97

     23768  0     ?

     23769  13    ?          возврат каретки

     23770  0     ?          номер строки

     23771  20    ?

     23772  38    &

     23773  0     ?

     23774  218   PAPER

     23775  50    2

     23776  55    7

 

     scroll?

 

Теперь нужно внимательно изучить содержимое экрана. Как Вы уже знаете, первые два байта — это номер строки, следующие два — длина строки, далее ключевое слово CLEAR, которое, собственно, нам и нужно. Берем листок бумаги и карандаш и записываем адрес, по которому находится CLEAR (23759), и продолжаем сей высокоинтеллектуальный труд. После CLEAR следует символьная форма числа, затем двоичная, далее — символ «возврат каретки» (конец строки), номер и длина следующей строки и оператор PAPER. Опять берем карандаш и записываем адрес оператора PAPER.

Просмотрев программу до конца и записав все адреса, которые необходимо заменить, можно приступать к изменениям:

 

     РОКЕ  23759,245: REM Заменяем CLEAR

     РОКЕ  23774,245: REM Заменяем PAPER

     РОКЕ  23884,245: REM Заменяем INK

     РОКЕ  23997,245: REM Заменяем BORDER

     РОКЕ  24110,32:  REM Заменяем  CLS

     РОКЕ  24117,32:  REM Заменяем  AT

 

и т. д. Число 245 — это код ключевого слова PRINT, a 32 — код пробела. В данном примере пробелами заменяются следующие операторы и символы:

 

     CLS

     AT

     "PLEASE WAIT"

     ""CODE

     USR

 

Когда будут сделаны все необходимые изменения, просмотрите листинг программы, дабы убедиться в том, что исправлено все, что нужно. Затем программу можно запустить и изучать полученные результаты.

 

Иногда эту операцию можно несколько упростить. Если в двоичном представлении чисел используются целые константы от О до 65535, то определить их истинные значения можно непосредственно при просмотре памяти. Для этого желательно добавить к карандашу и бумаге калькулятор.

Найдите в памяти символьную форму числа, которое нужно «разоблачить»; за ней следует префикс и двоичная форма. Если число целое в промежутке от 0 до 65535, то после префикса будут следовать два нуля, затем два числа в интервале от 0 до 255 и еще один ноль. Если это не так, то определенно можно сказать, что число либо не целое, либо выходит за пределы указанного диапазона. В этом случае проще прибегнуть к предыдущему способу. Если число «подходит», то умножьте 4-й после префикса байт на 256 и прибавьте 3-й (см. стр. 14). В рассматриваемом примере, чтобы получить параметр оператора CLEAR, нужно вычислить:

 

     PRINT PEEK (23763+3)+256*РЕЕК (23763+4)

 

или

 

     PRINT 167+256*97

 

Полученный результат (24999) и есть то, что от нас пытались утаить.

Раскроем секрет еще одного распространенного фокуса, основанного на знании формата записи чисел бейсик-интерпретатором (хотя, возможно, отгадку Вы уже знаете).

Вам, наверняка, встречались подобные строки:

 

     10 CLEAR  VAL  "24999": INK VAL "7": PAPER BIN:

        BORDER  BIN

 

Таким образом программисты экономят оперативную память. Как ни парадоксально, но запись VAL "24999" занимает меньше места, чем просто 24999. Так как в первом случае число 24999 заключено в кавычки, то оно является символьной строкой, а не числом и не имеет после себя шести байт двоичного представления. При выполнении функции VAL эта строка переводится в число. Таким образом экономится три байта. Что же касается BIN, то выигрыш еще более очевиден. Если вместо BIN подставить 0, то памяти будет занято на шесть байт больше, а результат — тот же.

Этот способ экономии памяти несколько замедляет выполнение программы, но его можно и нужно использовать в загрузчиках, так как именно они, как правило, наиболее критичны к размеру и не критичны к скорости выполнения.

 

 




  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Обзор - Спектрум в Калининграде; цены и места продажи.
Рассказ - Элеонора.
События - чешский фестиваль DoxyCon'98. Информация, итоги, фото.
Фенечки - говорят дети.
AD&D - описания монстров AD&D (часть вторая).

В этот день...   21 ноября