|
ZX Time
#10
22 ноября 2002 |
|
Кодерам - рекурсия на спектруме.

О том - o сем. (С) Денис Токарчук (DWT) Как известно, рекурсия в программи- ровании - это процесс вызова какой-либо процедуры "самой в себе". Пример прос- той, но тем не менее фатальной pekypcub- ной конструкции: МЕТКА NOP CALL МЕТКА Можно представить, что произойдет co стеком да и зависнет программа навсегда. Поэтому из рекурсивных функций (подпрог- рамм) необходимо предусмотреть выход при выполнении какого-то условия. Создавая оболочку к этому номеру, я довольно оригинально применил рекурсию вкупе co стеком. Дело в том, что в новом стандарте текстов (ZXTTFv2.0) применяется прими- тивнeнький "компрессор". Koe-какие коды и группы символов ASCII заменены на, как я их назвал, макросы (хотя это не совсем верно). Так вот, например, код #7F "вме- щaeт" в себя четыре знака - "(С) ", код #19 "вмещает" в себя 20 пробелов, код #F2 - "ZX", #F3 - "Time", #FA - "trum", и т.д. При написании листалки стала пробле- ма - как лучше вывести эти символы без значительного ущерба по отношению к па- мяти и скорости. По началу я планировал сделать две процедуры печати, однако при формате символов 6х8 это выливается в килобайты бесценной памяти, так как для печати таких символов необходимо как ми- нимум четыре подпрограммки. Это из-за того, что вся память компьютера разбита на ячейки по восемь бит, a символ 6х8 в ширину имеет 6 пикселей, т.e. 6 бит, из- за чего приходится четыре раза смещать изображение символа, для "втиcкивaния" их в "обрывки" байт. Четыре потому что 6 бит * 4 = 24 бита / 8 = 3 байта (пятый символ как бы "выравнивается" и его пе- чaтaeт та же подпрограммка, что и пер- вый; шестой - та же, что и второй; и т.д.) Если наглядно, то это выглядит следующим образом: 1 символ 2 символ 3 символ 4 символ ───┬──── ───┬──── ────┬─── ────┬─── └─┐ └─┐ ┌┘ ┌─┘ └┐ │ │ ┌┘ ┌─┴────┐───┴───┐───┴───┐───┴──┐ ││010001│01│0100│0100│01│011110││ │└──────┘──│────┘────│──┘──────┘│ └──────────┼─────────┼──────────┘ 1-ый байт │2-ой байт│ 3-ий байт Сами понимаете, что конструкции RLCA-RRCA-AND-OR просто неизбежны. Хотя некоторые программисты для увеличения скорости вывода генерировали по несколь- ку фонтов co "сдвигами" (смотрите, нап- ример, в Deja Vu), но это слишком боль- шая цена за ту скорость. Я знал, что c моими требованиями к оболочке, все равно не добиться "фреймовости" и c самого на- чала поставил цель написать просто быструю листалку. Но здесь не об этом. Я нарочно несколько отошел от темы рекурсии, чтобы в дальнейшем все было предельно понятно. Итак, как видно из схемы выше, для вывода строки символов 6х8 требуется 4 подпрограммки печати + единая для всех программа определения символа. Последняя занимается определением какой символ вы- водить, распознает код возврата из прог- раммы в случае конца строки. A в моем случае эта программа должна была также определять вышеназванные коды "макросов" и в случае "попадания" именно на него - печатать "следующими символами" соответ- cтвyющий коду кусок текста из специаль- ного буфера. Для наглядности приведу ку- сочек (схемку) программки, выводящей символы 6х8 на экран: СУС . . . CALL OPRSYM . . . программа печати 1-го символа . . . CALL OPRSYM . . . программа печати 2-го символа . . . CALL OPRSYM . . . программа печати 3-го символа . . . CALL OPRSYM . . . программа печати 4-го символа . . . JP СУС Как вы догадались, OPRSYM - это и есть та самая "единая" программа, o ко- торой я уже говорил. A вот, собственно интересующие нас "куски" OPRSYM. OPRSYM . . . LD A,(HL) ;берем код символа . . . СР #FF ;в ZXTTFv2.0 #FF - код ;конца строки JP NZ,OPRSYM1 ;если не #FF - ;продолжаем выпол- ;нение ;Если все-таки A=#FF, то: OPRSYMW POP DE ;снимаем co стека ;адрес, куда долж- ;на возвратиться ;программа после ;выполнения OPRSYM RET A здесь я хотел бы остановиться для более детального разъяснения. Итак, как вы знаете, если бы мы задали просто RET, то вернулись бы в программу вывода сим- вoлa на место, откуда вызывали OPRSYM (вернее, программа продолжила бы выпол- нение программы после CALL OPRSYM). Но так как был обнаружен конец строки, то нам необходимо возвратиться из программы вывода строки в то место, откуда ee вы- зывaли, но ни в коем случае не в продол- жение выполнения программы. Для этого и делается POP DE, чтобы как бы "снять" выполнение вывода символов и "nepeku- нуть" его (выполнение) в программу, от- куда вызывали программу вывода строки. Кроме того, адрес, "попавший" в DE, нам пригодиться, но об этом позже... OPRSYM1 . . . программы различных проверок, не интересующие нас:) . . . программа проверки пpинaдлeжнoc- ти символа к макросам . . . JP NC,OPRSYMM ;если принадле- ;жит - переходим ;на OPRSYMM . . . Программа также не интересующая нас . . . RET OPRSYMM - это программа вывода "мак- poca". Отрывок ee я также привожу здесь: OPRSYMM . . . Программа установки регистра HL на начало адреса, соответствую- щего найденному макросу . . . POP DE ;Интересное нача- ;лось! DEC DE DEC DE DEC DE LD (OPRSMM0),DE CALL 0 OPRSMM0 EQU $-2 PUSH DE . . . JP OPRSYM Прежде чем подробно начинать разбор вышенаписанного, скажу, что таблица, в которой находится текст "макроса", имеет ту же структуру, что и текст обычной строки, то есть конец каждого "макроса" обозначает код "#FF". Итак, по-порядку. Командой POP DE мы "снимаем" адрес, куда должен возвратить- ся "процесс" в случае его завершения командой RET. Но нам надо, чтобы он ука- зывал не на команду после CALL, a именно на CALL! Для этого делаем три раза DEC DE. Кстати, в HL уже находится адрес, где расположен текст макроса. Затем мы помещаем DE в ячейку, где находится CALL, кстати следующий сразу после этого "назначения" и выполняем пе- реход на дальнейший вывод символов. По сути, мы используем одну процедуру "саму в себе" для двух задач "вложенных одна в другую". И вот вывод макроса был выoлнeн. Выполнение возвратилось обратно во внутрь процедуры OPRSYMM. И нам нужно продолжать выводить строку... Но постойте! A как же определить те- перь адрес, куда возвратиться процедура OPRSYM, ведь вывод должен продолжаться уже после вывода "макроса"... A помните процедуру выхода из прог- раммы по окончании строки?.. Взгляните на нее. Что там? POP DE:RET!.. B DE y нас помещается на два абзаца выше упомянутый адрес! Te- перь нам его остается поместить на стек (PUSH DE), восстановить регистр HL, обозначающий адрес в тексте, увеличить его и спокойно JP`кать на OPRSYM... Выходит, что POP DE:RET нам тоже cocлyжилo, можно сказать, две службы! - - - И вот еще кое-что, что смог открыть для себя в процессе небольших экспери- ментов. Оказывается, альтернативный AF` не портится TR-DOS`ом (в отличии от BASIC48)! По крайней мере в группе стан- дартных команд через #3D13. Но даже не- смотря на лояльность:) к AF` TR-DOS`a, видится возможность использовать 4- тактовый ЕХ AF,AF` вместо, допустим, 11- тактовой PUSH AF, что в случаях, когда регистр нужно "запомнить" для его даль- нeйшeй "порчи" - выглядит хорошим peшe- нием! - - -
Другие статьи номера:
Похожие статьи:
В этот день... 1 января
SibNews #08,
Woot! #01,
Spectrum Magazine #01,
ACNews #25,
Psychoz #14,
ACNews #14,
Last 128 #08,
Last 128 #06,
Last 128 #05,
Last 128 #04,
Last 128 #03,
Last 128 #02,
Last 128 #09,
Last 128 #3.5,
Last 128 #8.025,
Sinclair Club #05,
Last 128 #M!R 01,
Fantadrom #01,
Buzz #20,
Last 128 #01,
DonNews #13,
Nicron #120,
Promised Land #01,
Inferno #01,
Marazm #25,
Ultimathum #01,
Marazm #21,
Hooy Mag #02,
KrNews #11,
Marazm #22,
Marazm #23,
ZX Football 2000 #01,
Codemania #01,
Always #03,
Bugs #02,
IzhNews #08,
Virtual Worlds #01,
Listok #04,
Scenergy #02,
Flash Info #18,
Marazm #16,
Marazm #17,
Zed #01,
Balagan #02,
ZX Format #08,
ZX Power #03,
Shock #01,
Impulse #02,
Deja Vu #03,
ZX Club #08,
ZX Club #06,
Numberology #01,
Marazm #13,
Marazm #12,
Marazm #14,
Gorodok #02,
Zodiac #01,
Marazm #15,
Deja Vu #07,
Marazm #11,
Deja Vu #07,
Playboy #03,
Crazy News #2,
Crazy News #4,
ZX Light #01,
Crazy News #5,
Playboy #02,
ZX News #03,
ZX Review #1-2,
Read Me #02,
Crazy News #3,
Nicron #13,
Read Me #01,
Public Spirit #01,
Faultless #06,
Faultless #05,
ZX Software #01,
Stump #04,
Speccy #07,
Возраждение #0,
Speccy #03,
On-Line #17,
Scene+ #01,
Welcome Press #01,
ZX Konig #04,
Adventurer #01,
Faultless #05,
Faultless #04,
Di Halt #01,
Faultless #01,
Playboy #01,
Crazy News #1,
Faultless #03,
Pioneer #03,
Sinclair Town #02,
ZX Magazine #01,
Eldorado #01,
ZX Magazine #02,
Spectron #01,
ZX News #01,
ZX Konig #02,
200 #W,
Welcome Press #00,
Dune #07,
Subliminal Extacy #01,
Subliminal Extacy #02,
ZX Konig #01,
Subliminal Extacy #00,
Muchomor #01,
Spectrofon #01,
ZX Revija #02,
Outlet #01,
Outlet #1-3