-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbas10-04.txt
436 lines (403 loc) · 31.6 KB
/
bas10-04.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
X.8. Ф у н к ц и я FRE
Garbage collection ("чистка памяти","сборка мусора") - действия
системы динамического распределения памяти для обнаружения неис-
пользуемых программой блоков памяти и присоединения их к списку
свободной памяти для повторного использования.
Англо-русский словарь по программированию и информатике
Информацию о размере свободной области ("Free Area") в RAM можно полу-
чить с помощью функции FRE, обращение к которой имеет вид:
FRE(A)
где: FRE ("FREe"-"свободный") - служебное слово;
A - арифметическое или строковое выражение, причем для интерпретато-
ра важным является лишь тип выражения, а не его значение.
На практике применяется следующий синтаксис:
FRE(0) или FRE("") .
Функция FRE(0) возвращает количество байтов, оставленных для расшире-
ния PIT, VT, стека, строковой области и блока управления файлами.
П р и м е р 1.
─────────────
10 ? FRE(0):X=451:? FRE(0):Z#=7.5:? FRE(0)
20 Y!=555:? FRE(0):W%=111:? FRE(0)
run
28739
28728 ◀──т.к. переменная Х по умолчанию - двойной точности, а,следова-
тельно, занимает в памяти 11 байтов;
28717 ◀──т.к. переменная Z - двойной точности (занимает в памяти так-
же 11 байтов);
28710 ◀──т.к. переменная Y - одинарной точности (занимает в памяти 7
байтов);
28705 ◀──т.к. переменная W - целого типа (занимает в памяти 5 байтов).
Ok
Функция FRE(0) выдает сообщение:
"Out of memory" ("Н е х в а т а е т п а м я т и")
при достижении значения, меньшего 145 байтов, минимально допустимого для
стека системы MSX-BASIC. Посмотрите (предварительно нажав кнопку "RESET"):
CLEAR 28868:PRINT FRE(0) CLEAR 28869:PRINT FRE(0)
147 Out of memory
Ok Ok
Заметим,что слово VARTAB отличается от слова TXTTAB на 2 байта (при от-
сутствии программы!), поэтому, добавив эти 2 байта к 145 байтам, необходи-
мым для работы стека, получаем число 147!
Функция FRE("") возвращает количество свободных байтов в строковом про-
странстве. Например:
print FRE("") X$="2²"+"3²":print FRE("")
200 196
Ok Ok
Кроме того, функция FRE("") выполняет важное дополнительное действие.
Оно связано с наличием в MSX-BASIC строк переменной длины, обработка кото-
рых может привести к явлению "фрагментации памяти" (внутри строковой обла-
сти появляются участки,содержащие неиспользуемую информацию -"м у с о р").
Поэтому, если в качестве аргумента функции FRE задано выражение строково-
го типа, перед вычислением объема свободной памяти функция выполняет
"с б о р к у м у с о р а", т.е. удаление всех неиспользуемых данных и
освобождение занимаемых ими областей.
П р и м е р 2. Оказывается,что если у Вас в начале программы встречает-
───────────── ся оператор A$="ABCD"+"EF", а затем-оператор A$="X"+"Y",
то Вы сразу же создадите 6-байтовое пространство, заполненное "мусором"!
Покажем это:
print HEX$(PEEK(&HF69C)); HEX$(PEEK(&HF69B));
F168 ────▲───
Ok └── Адрес "верхушки" строкового
a$="ABCD"+"EF" пространства
Ok
for t=0 to 5:print chr$(peek(&HF168-t));:next
FEDCBA
Ok
a$="X"+"Y"
Ok
for t=0 to 7:print chr$(peek(&hF168-t));:next
FEDCBAYX
└──▲─┘
Ok └─── "м у с о р"
print fre("")'Избавимся от "мусора"!
198
Ok
for t=0 to 7:print chr$(peek(&hF168-t));:next
YXXCBAYX
└──▲─┘
Ok └─── "м у с о р"
Из примера следует, что строки хранятся в строковом пространстве в том
порядке, в каком они были определены.
Таким образом, функция FRE("") изменила положение значения строковой
переменной (это и называется "с б о р к о й м у с о р а").
Если под строки зарезервирован большой объем строкового пространства и
определено много символьных переменных, время "сборки мусора" может соста-
вить несколько минут. При выполнении этой операции компьютер полностью
"застывает". Посмотрите...
П р и м е р 3.
─────────────
10 CLEAR 5000 'Объявлен размер строковой области - 5000 байтов
15 DEFINT A-Z:DIM A$(1500):FOR I=1 TO 1500:A$(I)="2"+"":NEXT
30 'Размещение данных в строковой области, "мусора" нет!
40 TIME=0:PRINT FRE(""),TIME/60/60"мин"
run run
·3500··········3.61638888888 мин ·3500··········3.3716666666667 мин
Ok (для MSX-1) Ok (для MSX-2)
Интересно, что при изменении в строке 10 оператора CLEAR 5000 на опера-
тор CLEAR 1600, результат получается почти тот же (≈3.607 мин. для компью-
тера MSX-1 и ≈3.38 мин. для компьютера MSX-2)!
Е д и н с т в е н н ы й способ уменьшить время "сборки мусора" - это
использовать минимальное количество строк и особенно строковых массивов!
Следует заметить, что некоторые строки хранятся в тексте самой програм-
мы и, таким образом, не занимают места в строковой области.
П р и м е р 4.
─────────────
10 ? FRE("");:U$="fywapro":D$="K":? FRE("");:DIM E$(150):? FRE("")
20 FOR K=1 TO 150:E$(K)=CHR$(K):NEXT:? FRE("")
30 E$(1)="APR":? FRE(""):E$(1)=" "+E$(1):? FRE("")
run
200 200 200 Далее пауза для "сборки мусора"...
50
51 ◀── Произошла "сборка мусора" (свободное место в строковой облас-
47 ти увеличилось, т.к. значение элемента массива E$(1) уже хра-
Ok нится в тексте программы)...
Таким образом, строковая область является областью памяти, резервируе-
мой для хранения строковых данных. Если Вы хотите зарезервировать в стро-
ковом пространстве место для хранения 10 строк, содержащих каждая макси-
мум 5 символов, то воспользуйтесь, например, оператором цикла:
FOR I=1 TO 10:A$(I)=SPACE$(5):NEXT
Во избежание "сборки мусора":
α) определяйте все переменные в начале программы;
β) используйте строковые функции MID$, LEFT$, RIGHT$.
Перед работой со следующим примером выключите, а затем снова включите
Ваш компьютер.
П р и м е р 5.
─────────────
A$="полет"
Ok
for t=0 to 10:print chr$(peek(&HF168-t));:next
телопп██
Ok └▲─┘
└─────── "м у с о р"
A$="налет"
Ok
for t=0 to 10:print chr$(peek(&HF168-t));:next
телоптеланн
└─▲─┘ ▲
└───────└──── "м у с о р"
Ok
print fre("")
195
Ok
for t=0 to 10:print chr$(peek(&HF168-t));:next
теланнеланн
└─▲──┘
└─────── "м у с о р"
Ok
mid$(A$,1,2)="по"
Ok
for t=0 to 10:print chr$(peek(&HF168-t));:next
телоппеланн
└──▲─┘
└── "м у с о р" (он остался на прежнем месте!)
Ok
Отметим, что строковые функции MID$, LEFT$, RIGHT$ не изменяют указате-
ли на значения строковых переменных. Обычный же оператор присваивания, ра-
зумеется, указатели изменяет! Покажем это на примере (не забудьте о коман-
де CLEAR !).
П р и м е р 6.
─────────────
a$="полет"
Ok
print hex$(peek(varptr(a$)+2)); hex$(peek(varptr(a$)+1))
F164
Ok
a$="налет"
Ok
print hex$(peek(varptr(a$)+2)); hex$(peek(varptr(a$)+1))
F15F
Ok
а теперь...
mid$(a$,1,2)="по"
Ok
print hex$(peek(varptr(a$)+2)); hex$(peek(varptr(a$)+1))
F15F ◀── Обратите внимание, это значение совпадает с предыдущим!
Ok
Как видим, значение указателя в последнем случае не изменилось!
γ) при необходимости используйте оператор SWAP A$,В$ , который не меня-
ет расположение значений переменных, а лишь меняет местами указатели на
эти значения. Проиллюстрируем этот факт на примере...
П р и м е р 7.
─────────────
clear
Ok
print HEX$(PEEK(&HF69C)); HEX$(PEEK(&HF69B))
F168
Ok
A$="Зачет":B$="Автомат"
Оk
for t=0 to len(a$)+len(b$):print chr$(peek(&hF168-t));:next
течаЗтамотвАА
Ok
swap A$,B$
Ok
for t=0 to len(a$)+len(b$):print chr$(peek(&hF168-t));:next
течаЗтамотвАА
Ok
И наконец, функция FRE() может помочь Вам также в з а щ и т е Вашей
программы. Например, в "укромном" месте программы, работающей со строко-
вой информацией, поместите оператор X$=SPACE$(FRE(""))- конечно,Вы должны
учесть, что целая часть значения аргумента функции SPACE$ должна принадле-
жать отрезку [0,255]!. Это удержит "любознательных" от модификации значе-
ний переменных Вашей программы (разумеется, в данном случае строковых)!
Посмотрите:
10 X$=SPACE$(FRE("")):Y$="2"+Y$
run
Out of string space in 10
Ok
X.9. Р а б о ч а я о б л а с т ь
В рабочей области содержатся системные подпрограммы, системные перемен-
ные и "ловушки", используемые интерпретатором во время выполнения операто-
ров Вашей программы. В рабочей области хранятся данные о позиции курсора,
цвете текста, состоянии функциональных клавиш и другая полезная информа-
ция, инициализируемая при включении компьютера.
┌─────────────────────────────────────────────────────────────────┐
│ Адрес, отмечающий н а ч а л о рабочей области, указан в │
│ самой этой области в слове HIMEM, содержимое которого за- │
│ нимает 2 байта, расположенных с адреса &HFC4A . │
└─────────────────────────────────────────────────────────────────┘
Еще раз напомним Вам, что адреса, занимающие два байта, всегда записы-
ваются так: вначале записывается содержимое младшего байта, а затем - со-
держимое старшего байта!
Отметим, что значением выражения HEX$(PEEK(&HFC4A)+256*PEEK(&HFC4B))
является а д р е с н а ч а л а р а б о ч е й области.
Поскольку рабочая область расположена в RAM, ее переменные могут изме-
няться операторами POKE. Но это следует делать только в том случае, если
Вы з н а е т е, что за этим последует!
X.9.1. М а т р и ц а к л а в и а т у р ы
М а т р и ц е й клавиатуры для MSX-компьютеров назовем таблицу вида:
0-й 1-й 2-й 3-й 4-й 5-й 6-й 7-й
бит бит бит бит бит бит бит бит
┌──────┬─────┬─────┬─────┬─────┬─────┬─────┬──────┬──────┐
│Адреса│ │ │ │ │ │ │ │ │
│байтов│ 254 │ 253 │ 251 │ 247 │ 239 │ 223 │ 191 │ 127 │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
0-я строка │ FBE5 │ 9 │ ; │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
1-я строка │ FBE6 │ 7 │ 8 │ 0 │ = │ - │ H │ : │ V │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
2-я строка │ FBE7 │ \ │ . │ B │ @ │ , │ / │ F │ I │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
3-я строка │ FBE8 │ S │ W │ U │ A │ P │ R │ [ │ O │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
4-я строка │ FBE9 │ L │ D │ X │ T │ ] │ Z │ J │ K │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
5-я строка │ FBEA │ Y │ E │ G │ M │ C │ ~ │ N │ Q │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
6-я строка │ FBEB │SHIFT│ CTRL│GRAPH│ CAPS│ РУС │ F1 │ F2 │ F3 │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
│ │ │ │ │ │ │ │ │ │
7-я строка │ FBEC │ F4 │ F5 │ ESC │ TAB │ STOP│ BS │SELECT│RETURN│
│ │ │ │ │ │ │ │ │ │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
│ │ │ │ │ │ │ ▲ │ │ │
8-я строка │ FBED │SPACE│ HOME│ INS │ DEL │◀────│ │ │ │ │ ───▶ │
│ │ │ │ │ │ │ │ ▼ │ │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
9-я строка │ FBEE │ RET │ + │ * │ 0 │ 1 │ 2 │ 3 │ 4 │
├──────┼─────┼─────┼─────┼─────┼─────┼─────┼──────┼──────┤
10-я строка │ FBEF │ 5 │ 6 │ 7 │ 8 │ 9 │ - │ , │ . │
└──────┴─────┴─────┴─────┴─────┴─────┴─────┴──────┴──────┘
Последние две строки соответствуют цифровой (правой) зоне клавиатуры
учительского компьютера серии MSX-2.
Ответим теперь на Ваш очевидный вопрос:
┌───────────────────────────────────────┐
│ Как воспользоваться этой таблицей? │
└───────────────────────────────────────┘
П р и м е р 1. Ниже приведены программа, останавливаемая нажатием кла-
───────────── виши "GRAPH":
10 Z=PEEK(&HFBEB):IF Z<>251 THEN 10
и программа, останавливаемая нажатием клавиш "SHIFT"+"CTRL":
10 Z=PEEK(&HFBEB):IF Z<>(254 AND 253) THEN 10
А теперь ответ на Ваш следующий вопрос:
┌─────────────────────────────────────────┐
│ А как получить матрицу клавиатуры ? │
└─────────────────────────────────────────┘
Для "чтения" нажатой клавиши достаточно "прочесть"слово NEWKEY (11 бай-
тов) по адресу &HFBE5 из таблицы системных переменных.
П р и м е р 2. Программа "пробегает" все клавиши и возвращает позицию
───────────── нажатой клавиши (X,Y) матрицы клавиатуры. 11 значений,
записанных в слове NEWKEY, соответствуют 11 строкам матрицы клавиатуры.
Если не нажата ни одна клавиша, содержанием каждого из 8 байтов, соответ-
ствующих строке матрицы является 1. Это фиксируется двоичным числом
&B11111111=255. Когда же клавиша нажата, считанное на этой строке значе-
ние отличается от 255: бит соответствующей колонки "сбрасывается" в 0.
10 FOR Y=0 TO 10:Z=PEEK(&HFBE5+Y)
30 IF Z=255 THEN 80 '──▶
40 PRINT"Y=";Y:Z$=RIGHT$("00000000"+BIN$(Z),8)
60 PRINT"X=";8-INSTR(Z$,"0"):PRINT
80 NEXT:GOTO 10 '──▶
X.9.2. Д и н а м и ч е с к а я к л а в и а т у р а [46]
Промедление с легким делом превращает его в
трудное, промедление же с трудным делом пре-
вращает его в невозможное.
Д.Лоример
Исследуем один подход к разработке учебных программ, работающих под
управлением интерпретатора MSX-BASIC. Существенная особенность этого под-
хода состоит в том, что программа в процессе выполнения модифицируется
(происходит изменение отдельных строк BASIC-программы или добавление но-
вых строк). Считается,что допущение самомодификации программы во время вы-
полнения является признаком плохого стиля программирования,поэтому начнем
с примера, который показывает, что предлагаемый подход является не только
оправданным, но и в ряде случаев единственно возможным.
Пусть необходимо табулировать функцию y=f(x), конкретно x², то есть
для каждого значения аргумента вычислить значение функции и результат за-
писать в таблицу. Соответствующая программа выглядит следующим образом:
10 'Программа табулирования функции.
20 DIM X(200),Y(200)
30 INPUT XN,XK 'Задание границ изменения аргумента функции.
···
100 GOSUB 1000 'Обращение к подпрограмме табулирования.
···
999 END
1000 FOR I=1 TO 200:Y(I)=X(I)*X(I):NEXT I:RETURN
Части программы между строками 30 и 100, 100 и 999 содержат операторы,
обеспечивающие масштабирование, заполнение таблицы, защиту от ошибочных
действий пользователя и т.д. Простота программы обусловлена тем, что зада-
ча табулирования решается для ф и к с и р о в а н н о й функции. Попыта-
емся теперь разработать программу, которая позволяет табулировать любую
функцию одной переменной, аналитическое выражение которой вводится с кла-
виатуры!
Для реализации на ПЭВМ"YAMAHA" используем специальный механизм, введен-
ный Дж.Баттерфилдом (J.Batterfield) и названный им принципом "д и н а м и-
ч е с к о й к л а в и а т у р ы".
В к о м а н д н о м (!) режиме информация,набираемая пользователем на
клавиатуре, аппаратно записывается в буфер (называемый в дальнейшем б у-
ф е р о м к л а в и а т у р ы , БК). БК размещается в рабочей области
с адреса &HFBF0 по адрес &HFC17 и занимает 40 байтов. При нажатии клавиши
"RETURN" содержимое БК считывается интерпретатором и выполняется соответ-
ствующая команда.
Имитация действий пользователя на основе принципа "динамической клавиа-
туры" осуществляется следующим образом:
1) с помощью оператора INPUT вводится текст запроса (в данном случае -
аналитическое выражение табулируемой функции) в символьную строку F$ (в
приведенной ниже программе - строка 10);
2) символьная строка дополняется впереди номером, а в конце - кодом ко-
манды "RETURN" (строки 15 и 1890): F$="номер строки 1"+F$+CHR$(13) ;
3) строка побайтно переписывается в БК, начиная с aдреса &HFBF0, при
помощи оператора POKE и функции PEEK (подпрограмма, начинающаяся со стро-
ки 1880);
4) строка S$="goto"+"номер строки 2"+CHR$(13), где н о м е р с т р о-
к и 2 - номер строки программы, куда после модификации необходимо пере-
дать управление, побайтно переписывается в БК (строка 25);
5) выполнение программы прекращается командой END, в результате проис-
ходит переход из программного режима в командный. Интерпретатор считывает
содержимое БК до первого появления CHR$(13) и выполняет его как команду,
то есть модифицирует строку с номером н о м е р с т р о к и 1. Далее
считывается остаток содержимого БК до второго появления CHR$(13), и он
также выполняется интерпретатором, как команда, после чего происходит пе-
реход в программный режим с передачей управления в строку с номером н о-
м е р с т р о к и 2.
Таким образом, указанный алгоритм решает задачу автоматической модифи-
кации программы в соответствии с текстом запроса, вводимого пользователем
с клавиатуры, и запуска ее с указанного номера строки.
П р и м е р.
───────────
1 GOTO 10
2 GOTO 30
10 LINEINPUT"Введите аналитическую запись функции:";F$
11 INPUT"Укажите номер строки, содержащей оператор описания функции по
льзователя DEFFN (51< номер строки <59)";SN:GOSUB 2410
13 GOSUB 1550 'Сохранение F$
15 F$=STR$(SN)+F$:F$=MID$(F$,2,LEN(F$)-1)
20 GOSUB 1880
25 F$="goto2":GOSUB 1880:END
30 GOSUB 1730 'Восстановление F$
50 '∗∗ Программа табулирования функции Y(x) ∗∗
60 INPUT"Введите[A,B] и шаг табулирования H";A,B,H
65 FOR X=A TO B STEP H:PRINT X;FNY(X):NEXT
90 END
1550 '∗∗∗∗∗ Ф о р м и р о в а н и е F$ ∗∗∗∗∗
1590 F$="deffny(x)="+F$:POKE &HF600,LEN(F$)
1620 FOR I=1 TO LEN(F$):POKE &HF601+I,ASC(MID$(F$,I,1)):NEXT
1720 RETURN'──▶
1730 '∗∗∗∗∗ В о с с т а н о в л е н и е F$ ∗∗∗∗∗
1740 LF=PEEK(&HF600):F$=""
1750 FOR I=1 TO LF:C=PEEK(&HF601+I):F$=F$+CHR$(C):NEXT
1780 RETURN'──▶
1880 '∗∗∗∗∗ Д и н а м и ч е с к а я к л а в и а т у р а ∗∗∗∗∗
1890 F$=F$+CHR$(13)
1900 AD=PEEK(&HF3F9)*256+PEEK(&HF3F8)-65536!
1910 L1=&HFC17-AD+1
1920 IF LEN(F$)<=L1 THEN GOTO 1990
1930 L2=LEN(F$)-L1:N=0
1940 FOR I=AD TO &HFC17:N=N+1
1950 POKE I,ASC(MID$(F$,N,1)):NEXT
1960 FOR I=&HFBF0 TO &HFBF0+L2-1:N=N+1
1970 POKE I,ASC(MID$(F$,N,1)):NEXT
1980 AD=&HFBF0+L2+65536!:POKE&HF3F9,FIX(AD/256):POKE&HF3F8,AD-FIX(AD/2
56)*256:GOTO 2050
1990 N=0
2000 FOR I=AD TO AD+LEN(F$)-1:N=N+1
2010 POKE I,ASC(MID$(F$,N,1)):NEXT
2020 IF LEN(F$)<L1 THEN AD=AD+LEN(F$) ELSE AD=&HFBF0
2030 AD=AD+65536!
2040 POKE&HF3F9,FIX(AD/256):POKE&HF3F8,AD-FIX(AD/256)*256
2050 RETURN'──▶
2410 IF LEN(F$)>19 THEN CLS:LOCATE 1,10:PRINT"Эта программа имеет огра
ничение:":GOTO 2420 ELSE GOTO 2460
2420 PRINT:PRINT "Длина формулы не должна превосходить 19 символов!";L
EN(F$)
2440 PRINT:LOCATE 1,23:PRINT"Для продолжения нажмите любую клавишу"
2450 W$=INKEY$:IF W$="" THEN 2450 ELSE GOTO 10
2460 RETURN'──▶