Профессиональный подход
(Продолжение)
Продолжая печатать рекомендации известного британского программиста Стива Тернера для тех, кто делает первые шаги в написании больших и сложных программ в машинных кодах, мы поговорим о структурном программировании.
Структурное программирование - это метод организации программного проекта и самого процесса программирования. Существуют и другие методы, но этот наилучшим способом обеспечивает понимание главной задачи - что программа должна выполнять. После этого гораздо проще решать практический вопрос - как это сделать.
Я вижу следующие преимущества в структурном программировании:
1. Огромная неохватная задача разбивается на несколько простых подзадач.
2. Этот метод дисциплинирует образ мышления и порядок программирования. Каждая процедура выполняет свою частную, отдельную задачу.
3. Разные процедуры нередко имеют сходные черты, что очень упрощает программирование.
4. Значительно упрощается процесс отладки, т.к. снижается количество ошибок.
Примечание "ИНФОРКОМА"
Стив Тернер не привел на наш взгляд самого главного достоинства структурного программирования - возможности организации коллективного программирования, а в наши дни 95% программ создаются коллективно.
При таком подходе каждый член команды может заниматься своим блоком процедур, и результат после "сшивки" должен работать, если распределение работ было произведено правильно.
Более того, достижения одного сразу становятся достижениями всех членов команды и прогресс в разработке быстро нарастает.
Правда, при коллективном подходе кроме просто структурирования программы до уровня мелких процедур необходимо еще выполнять анализ структуры с целью максимального выявления общих мест и производить согласование процедур, написанных разными программистами, а может быть и в разное время и для разных проектов.
Элементы структурированной программы.
Любую задачу, будь то какая-либо программа или инструкция по изготовлению садовой теплицы можно разделить на 3 типа команд.
1. Последовательные команды.
Одна команда идет за другой.
Компьютер выполняет свои команды последовательно. На рис. 1 это показано на структурной диаграмме.
Каждый квадрат представляет отдельную задачу.
Последовательность их исполнения - слева направо, в отличие от блок-схем, в
Рис.1
2. Условное ветвление.
Если <условие> исполнить <задача>
IF < условие > DO < задача>
Все программные языки имеют средства для того, чтобы исполнять какую-либо задачу только если это необходимо. В языках высокого уровня операторы могут выполняться или не выполняться в зависимости от какого-либо условия. В языках низкого уровня (например в АССЕМБЛЕРе) есть инструкции, после исполнения которых определяется, какая инструкция будет выполняться следующей. Это переходы (JP и JR), вызовы (CALL) и возвраты (RET). Рекомендуется всячески избегать излишних переходов и, если использовать переходы, так только условные, например JR NC, JR Z,... и т.п.
На рис.2 представлен элементарный блок "IF" (если).
Рис.2
Имейте в виду, что как бы ни было сложно и многовариантно исходное условие, его всегда можно раздробить на серию таких элементарных IF. На рис. 3 показана комплексная структура IF.
Рис.3
Здесь представлено условие IF, что делать, если оно выполняется (задача E) и что делать в ином случае - ELSE (задача F).
3. Циклы (итерации).
Они позволяют выполнить задачу многократно, пока соблюдается какое-то условие.
DO <задача> UNTIL <условие>
Задача может быть выполнена столько раз, сколько это необходимо. В Бейсике этим занимаются операторы FOR...NEXT. На АССЕМБЛЕРе это можно сделать двумя командами перехода. Одна ставится в конце задачи и выполняет переход к началу, а вторая - условие выхода из образовавшейся петли. Если первый переход может и не быть условным, то уж второй - обязательно условный. Часто, когда я пишу программу, ставлю условие выхода последней командой в цикле. В этом случае можно обойтись одним переходом вместо двух. Тогда программа автоматически "вываливается" из цикла, когда выходное условие перехода перестает выполняться. По этому же принципу работает и команда АССЕМБЛЕРа DJNZ.
На рис. 4 показан элементарный цикл.
X |
|
loop UNTIL условие задача G |
|
Рис.4
Работая с циклами, я всегда выполняю дополнительные операции:
1). Инициализация переменных перед циклом. Установка исходных значений в регистрах и т.п.
2). Программирование цикла.
3). Финишные операции после завершения цикла.
Рис.5
Объединение элементов.
Рассмотрим как объединяются эти три основные типа структурных элементов в единое целое на примере задачи о чашке кофе. На рис. 6 показана последовательность действии при выполнении этой задачи. (Судя по схеме, Стив Тернер пьет растворимый кофе или просто не хочет раскрывать глубоких секретов приготовления кофе натурального -Прим. "Инфоркома").
В правом верхнем углу блоков с условиями типа IF поставлен символ "O", а в блоках с циклами символ "*".
Предположим, что нам надо запрограммировать кухонного робота на выполнение этой задачи. Если он уже это делал, то нам достаточно одного верхнего блока "приготовить кофе", но если эта задача выполняется впервые, то она разбивается на ряд микро-задач, объединенных связями, как показано на рис. 6. Вы видите, что сначала главная задача разбивается на три под-задачи, которые далее еще более детализируются.
NB! Обратите внимание на то, что каждый горизонтальный уровень на схеме представляет полное решение задачи, но только на разных уровнях различается детальность описания. Именно в этом состоит основное преимущество структурной схемы, по сравнению со столь привычными для нас блок-схемами.
Приготовление кофе
о
Если кофейник пуст, наполнить водой
Включить нагреватель
Ждать, пока вода закипит
Взять чашку Насыпать кофе Залить воду
о
Если надо добавить сахар
Если надо добавить молоко
Рис.6
Можно идти от уровня к уровню все ниже и ниже, все больше и больше дробя элементарные задачи. До каких пор это делается? До тех пор, пока мы не придем к элементарным задачам, каждая из которых уже знакома нашему гипотетическому кухонному роботу.
Такой подход к подготовке программы удобен еще тем, что любой свой проект Вы всегда можете уместить на одном стандартном листе бумаги и окинуть взглядом. Одного листа бывает достаточно для размещения до восьми уровней. А как быть, если Вам их не хватило? Все равно весь проект уложится в одну страницу, просто в нижнем уровне будут блоки, которые представляют собой тоже самостоятельные задачи, и в свое время для них будут созданы свои структурные диаграммы на своих отдельных листах.
Итак, если Вы хотите, чтобы в Вашем рисунке одновременно сочетались детальность и компактность, то структурные диаграммы гораздо удобнее традиционных блок-схем.
Как структурировать программу?
Может быть сначала это кажется несколько необычным, но поверьте, потратить усилия стоят. Это вполне окупится.
Как только Вы освоите структурное программирование, то сразу увидите поразительную вещь, что в мире существуют всего лишь несколько видов программ! Вы увидите, что основные структуры из раза в раз повторяются и повторяются.
Как только Вы твердо определитесь с тем, что Ваша программа должна делать, можете приступать к ее структурированию. Если, например, Ваша программа предназначена для обработки каких-то данных (например текстовых файлов), то обычно структура такой программы отражает структуру данных и поэтому имеет смысл сначала разобраться с ними.
Например, если в конце текстовых записей в файле стоит маркер, говорящий о том, что записи закончились, то определенно в программе будет блок типа:
UNTIL
маркер Обработка данных
В то же время, если взять игровые программы, они редко развиваются вокруг одного файла данных. Здесь целесообразнее строить структуру не от структуры данных, а от тех процессов, которые будет выполнять программа.
Начните с того, что перечислите главные задачи, выполняемые программой. После этого попробуйте рассортировать их по порядку очередности исполнения.
Следующий шаг - наметьте основные циклы повторений исполнения этих главных
задач.
Теперь начинайте чертить структурную диаграмму, правильно выбирая уровень, на который "подвешивается" каждая из перечисленных задач.
Вам знакома игра SPACE INVADERS? На рис. 7 приведена структурная диаграмма этой игры и, надо сказать, в эту структуру уложились бы еще сотни разных "стрелялок".
Попробуем шаг за шагом подойти к этой структуре.
1. Запишем основные задачи.
Перемещение вашей базы.
Огонь.
Перемещение кораблей противника.
Построение игровой страницы (экрана).
Ведение счета очков.
Инициализация волны вражеского налета.
Три жизни.
Начать новую игру по окончании.
На этом этапе мы пока не задумывались над очередностью исполнения этих задач.
2. Наметим основные циклы.
Здесь очень важно правильно соблюсти порядок.
После хорошего размышления у нас может получиться нечто следующее:
Игра SPACE INVADERS состоит из ряда игр, каждая из которых состоит из трех попыток (три жизни), каждая из которых включает несколько страниц (экранов), каждый из которых может многократно изменяться.
3. Теперь будем рисовать структурную диаграмму.
Начнем с верхнего бокса, в котором запишем имя программы. Теперь, используя список циклов, будем продвигаться вниз на очередной уровень и внимательно продумывать, что должно быть сделано до цикла и что после.
Иногда Вам может показаться, что бывает что-то такое, что не вписывается в структуру ни на каком уровне. Например, после определенного количества выстрелов может появиться премиальный корабль, за сбивание которого даются повышенные очки.
Если бы мы сочли эту задачу достаточно важной для рассмотрения, то должны были бы встроить еще один уровень где то между уровнем организации экранов и уровнем изменения экранов. С другой стороны, если этот элемент игры не считать таким уж очень важным, поскольку он не оказывает существенного влияния на код остальной части игры, я бы добавил его в нижний уровень, сделав условным (IF).
Рис. 7
Продолжительность циклов: 1. Бесконечно или до отказа от продолжения игры.
2. Три раза.
3. До гибели.
4. До гибели или по окончании волны атаки.
Очень часто в структуру приходится вводить новые уровни и перечерчивать диаграмму. Мне иногда даже приходится это делать, когда я уже активно занимаюсь программированием. И если текст моей программы строго соответствует разработанной структуре, то сделать это совсем несложно.
Обратите внимание на то, что самый последний цикл (самого низкого уровня) в своем конце должен содержать не только условие проверки окончания самого себя, но и условия проверки окончания всех остальных вышележащих циклов.
Процедура INPUT
В завершение данного выпуска я предлагаю процедуру, которая в машинных кодах выполняет то, что делает команда БЕЙСИКа INPUT.
Если бы Вы знали, как много существует коммерческих программ, в которых при вводе данных по запросу от программы нельзя стереть допущенную ошибку или вставить пропущенную букву! Если Вы используете эту процедуру вместе с процедурой PRINT, напечатанной в прошлом выпуске, то сможете в машиннокодовых программах выполнять INPUT и PRINT, как если Вы работаете в Бейсике, только конечно гораздо быстрее.
Я привожу здесь же в учебных целях и структурную диаграмму этой процедуры (рис. 8). Посмотрите на нее и постарайтесь разыскать показанные на ней блоки в программном коде.
Для того, чтобы воспользоваться процедурой, Вам надо сначала напечатать сообщение (запрос) от программы. Это можно сделать процедурой прошлого выпуска PRINT. Затем надо в регистровой паре DE установить координаты экранной позиции, в которой выполняется INPUT (D - координата y в пикселях; E - координата x в знакоместах).
Предполагаемая длина вводимой информации задается в регистре A (от 1 до 32 символов).
Обратите внимание на то, что буфер INPUT сделан в том же формате, который поддерживается подпрограммой PRINT. Первый байт буфера содержит длину самого буфера.
INPUT
Обработка нажатой клавиши
Определение нажатой клавиши (GETKEY)
Изображение буфера на экране
Определение какая клавиша нажата
О
CAPS LOCK
Рис.8
0000 |
00010 |
|
|
0000 |
00020 |
ORG 0М00Н |
|
C000 |
00030 |
;Пример программы INPUTX |
C000 |
00040 |
|
|
C000 110000 |
00050 |
LD DE,0 |
Координаты x,y |
C003 2124C0 |
00060 |
LD HL,MESS1 |
|
C006 CD88C1 |
00070 |
CALL PRINT |
Печать сообщения |
C009 111000 |
00080 |
LD DE,10 |
Координаты x,y |
C00C 3E10 |
00090 |
LD A,16 |
Длина поля |
C00E CD42C0 |
00100 |
CALL INPUTX |
|
C011 |
00110 |
|
|
C011 |
00120 |
|
Данные для ввода |
C011 |
00130 |
|
дятся в буфере и |
C011 |
00140 |
|
к использованию |
C011 |
00150 |
|
|
C011 110010 |
00160 |
LD DE,1000H |
|
C014 2134C0 |
00170 |
LD HL,MESS2 |
|
C017 CD88C1 |
00180 |
CALL PRINT |
Печать сообщ. |
C01A 110E10 |
00190 |
LD DE,100EH |
|
C01D 214DC1 |
00200 |
LD HL,LENGH |
|
C020 CD88C1 |
00210 |
CALL PRINT |
Печать резуль. |
C023 C9 |
00220 |
RET |
|
C024 |
00230 |
|
|
C024 |
00240 MESS1 |
DB 15 |
|
C025 454E5445 |
00250 |
DM 'ENTER YOUR NAME |
|
C029 5220594F |
|
|
|
C02D |
5552204E |
|
|
|
C031 |
414D45 |
|
|
|
C034 |
0D |
00260 |
MESS2 |
DB 13 |
C035 |
594F5552 |
00270 |
|
DM 'YOUR NAME IS' |
C039 |
204E414D |
|
|
|
C03D |
45204953 |
|
|
|
C041 |
20 |
|
|
|
C042 |
|
00280 |
|
|
C042 |
|
00290 |
;----------- |
|
C042 |
|
00300 |
|
|
C042 |
|
00310 |
; Условия вызова процедуры |
C042 |
|
00320 |
; INPUTX: |
|
C042 |
|
00330 |
; A - длина |
вводимых данных 1-32 |
C042 |
|
00340 |
; D - y координата (0 - верх) |
C042 |
|
00350 |
; E - x координата |
C042 |
|
00360 |
|
|
C042 |
|
00370 |
INPUTX |
;Начало процедуры |
C042 |
|
00380 |
|
;Инициализация буфера |
C042 |
324DC1 |
00390 |
OK |
LD (LENGTH),A |
C045 |
6F |
00400 |
|
LD L,A |
C046 |
ED5375C1 |
00410 |
|
LD (OUTPOS),DE |
C04A |
AE |
00420 |
|
XOR A |
C04B |
3E73C1 |
00430 |
|
LD (CURSOR),A |
C04E |
67 |
00440 |
|
LD H,A |
C04F |
114EC1 |
00450 |
|
LD DE,BUFFER |
C052 |
19 |
00460 |
|
ADD HL,DE |
C053 |
2270C1 |
00470 |
|
LD (BUFEND),HL |
C056 |
3A4DC1 |
00480 |
|
LD A,(LENGTH) |
C059 |
47 |
00490 |
|
LD B,A |
C05A |
214EC1 |
00500 |
|
LD HL,BUFFER |
C05D |
367F |
00510 |
|
LD (HL),CURS |
C05F |
23 |
00530 |
|
INC HL |
C060 |
3E2D |
00530 |
|
LD A,ULINE |
C062 |
77 |
00540 |
CLEAR |
LD (HL),A |
C063 |
23 |
00550 |
|
INC HL |
C064 |
10FC |
00560 |
|
DJNZ CLEAR |
C066 |
213B5C |
00570 |
|
LD HL,FLAGS |
C069 |
CBAE |
00580 |
|
RES 5,(HL) |
C06B |
|
00590 |
|
|
C06B |
|
00600 |
;Обработка принятой клавиши |
C06B |
|
00610 |
;в ожидании |
клавиши ENTER |
C06B |
|
00620 |
|
|
C06B |
|
00630 |
ACCEPT |
|
C06B |
ED5BT5C1 |
00640 |
|
LD DE,(OUTPOS) |
C06F |
214DC1 |
00600 |
|
LD HL,LENGTH |
C072 |
CD88C1 |
00660 |
|
CALL PRINT |
C075 |
|
00670 |
|
|
C075 |
|
00680 |
;Прием очередной клавиши |
C075 |
|
00690 |
|
|
C075 |
213B5C |
00700 |
GETKEY |
LD HL,FLAGS |
C078 |
CB6E |
00710 |
|
BIT 5,(HL) |
C07A |
28F9 |
00720 |
|
JR Z,GETKEY |
C07C |
3A065C |
00730 |
|
LD A,(LASTK) |
C07F |
CBAF |
00740 |
|
RES 5,(HL) |
C061 |
FE06 |
00750 |
|
CP 6 |
C083 |
38F0 |
00760 |
|
JR C,GETKEY |
C085 |
FE0D |
00770 |
|
CP 0DH |
C087 |
CA2FC1 |
00780 |
|
JP Z,ENTER |
TO8A |
FE08 |
00790 |
|
CP 8 |
C08C |
283A |
00800 |
|
JR Z,CRLEFT |
C08E |
FE09 |
00810 |
|
CP 9 |
C090 |
284F |
00820 |
|
JR Z,CRRIGT |
C092 |
FE0C |
00830 |
|
CP 0CH |
C094 |
2669 |
00840 |
|
JR Z,DELETE |
C096 |
FE06 |
00850 |
|
CP 6 |
C098 |
CA25C1 |
00860 |
JP Z,CAPSLK |
C09B |
FE20 |
00870 |
CP 20H |
C09D |
38D6 |
00880 |
JR C,GETKEY |
C09F |
FE80 |
00890 |
CP 80H |
C0A1 |
30D2 |
00900 |
JR NC,GETKEY |
C0A3 |
|
00910 |
|
C0A3 |
|
00920 |
;Если принят печатный символ |
C0A3 |
|
00930 |
|
C0A3 |
3274C1 |
00940 |
LD (LETTER),A |
C0A6 |
3A73C1 |
00950 |
LD A,(CURSOR) |
C0A9 |
47 |
00960 |
LD B,A |
C0AA |
3A4DC1 |
00970 |
LD A,(LENGTH) |
C0AD |
90 |
00980 |
SUB B |
C0AE |
8805 |
00990 |
JK Z,GETKEY |
C0B0 |
4F |
01000 |
LD C,A |
C0B1 |
78 |
01010 |
LD A,B |
C0B2 |
3C |
01020 |
INC A |
C0B3 |
3273C1 |
01030 |
LD (CURSOR),A |
C0B6 |
|
01040 |
|
C0B6 |
ED5B70C1 |
01050 |
LD DE,(BUFEND) |
C0BA |
2A70C1 |
01060 |
LD HL,(BUFEND) |
C0BD |
2B |
01070 |
DEC HL |
C0BE |
0600 |
01080 |
LD B,0 |
C0C0 |
EDB8 |
01090 |
LDDR |
C0C2 |
3A74C1 |
01100 |
LD A,(LETTER) |
C0C5 |
12 |
01110 |
LD (DE),H |
C0C6 |
18A3 |
01120 |
JR ACCEPT |
C0C8 |
|
01130 |
|
C0C8 |
|
01140 |
;Если курсор влево |
C0C8 |
|
01150 |
|
C0C8 |
3A73C1 |
01160 |
CRLEFT LD A,(CURSOR) |
C0CB |
A7 |
01170 |
AND A |
C0CC |
28A7 |
01180 |
JR Z,GETKEY |
C0CE |
3D |
01190 |
DEC A |
C0CF |
3273C1 |
01200 |
LD (CURSOR),A |
C0D2 |
214EC1 |
01210 |
LD HL,BUFFER |
C0D5 |
5F |
01220 |
LD E,A |
C0D6 |
1600 |
01230 |
LD D,0 |
C0D8 |
19 |
01240 |
ADD HL,DE |
C0D9 |
7E |
01250 |
LD A,(HL) |
C0DA |
367F |
01260 |
LD (HL),CURS |
C0DC |
23 |
01270 |
INC HL |
C0DD |
77 |
01280 |
LD (HL),A |
C0DE |
C36BC0 |
01290 |
JP ACCEPT |
C0E1 |
|
01300 |
|
C0E1 |
|
01310 |
;Если курсор вправо |
C0E1 |
|
01320 |
|
C0E1 |
|
01330 |
CRRIGT |
C0E1 |
3A4DC1 |
01340 |
LD A,(LENGTH) |
C0E4 |
4F |
01350 |
LD C,A |
C0E5 |
3A73C1 |
01360 |
LD A,(CURSOR) |
C0E8 |
B9 |
01370 |
CP C |
C0E9 |
CA75C0 |
01360 |
JP Z,GETKEY |
C0EC |
3C |
01390 |
INC A |
C0ED |
3273C1 |
01400 |
LD (CURSOR),A |
C0F0 |
214EC1 |
01410 |
LD HL,BUFFER |
C0F3 |
5F |
01420 |
LD E,A |
C0F4 |
1600 |
01430 |
LD D,0 |
C0F6 |
19 |
01440 |
ADD HL,DE |
C0F7 |
7E |
01450 |
LD A,(HL) |
C0F6 |
367F |
01460 |
LD (HL),CURS |
C0FA |
2B |
01470 |
DEC HL |
C0FB |
77 |
01480 |
LD (HL),A |
C0FC |
C36BC0 |
01490 |
JP ACCEPT |
C0FF |
|
01500 |
|
;Временный стек
;Буфер полон ;Смещение курсора
C0FF |
|
01510 |
;Если DELETE |
|
|
C0FF |
|
01520 |
|
|
|
C0FF |
|
01530 |
DELETE |
|
|
C0FF |
3A73C1 |
01540 |
|
LD A,(CURSOR) |
|
C102 |
A7 |
01550 |
|
AND A |
|
C103 |
CA75C0 |
01560 |
|
JP Z,GETKEY |
|
C106 |
5F |
01570 |
|
LD E,A |
|
C107 |
3A4DC1 |
01560 |
|
LD A,(LENGTH) |
|
C10A |
93 |
01590 |
|
SUB E |
|
C10B |
3C |
01600 |
|
INC A |
|
C10C |
4F |
01610 |
|
LD C,A |
|
C10D |
7B |
01620 |
|
LD A,E |
|
C10E |
3D |
01630 |
|
DEC A |
;Курсор влево |
C10F |
3273C1 |
01640 |
|
LD (CURSOR),A |
|
C112 |
|
01650 |
|
|
|
C112 |
214EC1 |
01660 |
|
LD HL,BUFFER |
|
C115 |
1600 |
01670 |
|
LD D,0 |
|
C117 |
19 |
01680 |
|
ADD HL,DE |
|
C116 |
54 |
01690 |
|
LD D,H |
|
C119 |
5D |
01700 |
|
LD E,L |
|
C11A |
1B |
01710 |
|
DEC DE |
|
C11B |
0600 |
01720 |
|
LD B,0 |
|
C11D |
EDB0 |
01730 |
|
LDIR |
|
C11F |
3E2D |
01740 |
|
LD A,ULINE |
|
C121 |
12 |
01750 |
|
LD (DE),A |
|
C122 |
C36BC0 |
01760 |
|
JP ACCEPT |
|
C125 |
|
01770 |
|
|
|
C125 |
|
01780 |
;Если CAPS LOCK |
|
C125 |
|
01790 |
|
|
|
C125 |
216A5C |
01800 |
CAPSLK |
LD HL,5C6AH |
|
C128 |
3E08 |
01810 |
|
LD A,8H |
|
C12A |
AE |
01820 |
|
XOR (HL) |
|
C12B |
77 |
01830 |
|
LD (HL),A |
|
C12C |
C36BC0 |
01840 |
|
JP ACCEPT |
|
C12F |
|
01850 |
|
|
|
C12F |
|
01860 |
;Если ENTER |
|
|
C12F |
|
01670 |
|
|
|
C12F |
|
01860 |
ENTER |
|
|
C12F |
114EC1 |
01890 |
|
LD DE,BUFFER |
|
C132 |
214EC1 |
01900 |
|
LD HL,BUFFER |
|
C135 |
3A4DC1 |
01910 |
|
LD A,(LENGTH) |
|
C138 |
47 |
01920 |
|
LD B,A |
|
C139 |
7E |
01930 |
CLEAN |
LD A,(HL) |
|
C13A |
23 |
01940 |
|
INC HL |
|
C13B |
FE7F |
01950 |
|
CP CURS |
|
C13D |
2808 |
01960 |
|
JR Z,IGNORE |
|
C13F |
FE2D |
01970 |
|
CP ULINE |
|
C141 |
2002 |
01980 |
|
JR NZ,PACK |
|
C143 |
3E20 |
01990 |
|
LD A,SPACE |
|
C145 |
12 |
02000 |
PACK |
LD (DE),A |
|
C146 |
13 |
02010 |
|
INC DE |
|
C147 |
10F0 |
02020 |
IGNORE |
DJNZ CLEAN |
|
C149 |
3E20 |
02030 |
|
LD A,SPACE |
|
C14B |
12 |
02040 |
|
LD (DE),A |
|
C14C |
C9 |
02050 |
|
RET |
|
C14D |
|
02060 |
|
|
|
C14D |
|
02070 |
|
|
|
C14D |
|
02060 |
;Переменные буфера |
|
C14D |
0E090 |
|
|
|
|
C14D |
00 |
02100 |
LENGTH |
DB 0 |
|
C14E |
|
02110 |
BUFFER |
DS 34 ; |
Резервирует 34 б |
C170 |
|
02120 |
|
|
|
C170 |
0000 |
02130 |
BUFEND |
DW 0 |
|
002D |
|
02140 |
ULINE |
EQU '-' |
|
007F |
|
02150 |
CURS |
EQU 127 |
|
0020 |
|
02160 |
SPACE |
EQU ' ' |
C172 |
|
02170 |
|
|
C172 |
|
02180 |
;Настройка |
переменных печати |
C172 |
|
02190 |
|
|
5C3B |
|
02200 |
FLAGS |
EQU 5C3BH |
5C6A |
|
02210 |
FLAGS2 |
EQU 5C6AH |
5C08 |
|
02220 |
LASTK |
EQU 23560 |
с172 |
00 |
02230 |
COUNT |
DB 0 |
C173 |
00 |
02240 |
CURSOR |
DB 0 |
C174 |
00 |
02250 |
LETTER |
DB 0 |
C175 |
0000 |
02260 |
OUTPOS |
DW 0 |
C177 |
|
02270 |
|
|