26

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

> Topaz2.DSK 840 kb

Исходники NEW на диске с ИКП. Но собрать в ДОК не получилось - ошибки валит. Массово. Сборку начинал  с MAIN.


Там очень непростая сборка. В 2 прохода. Начинать надо с файла ZLOAD оба раза.

1-проход:

файл ZLOAD строка 2
;DSECT
файл HDOS строка 853
CHN SPRITE

Исходный файл: ZLOAD
Объектный файл: SM0
Тип объектного: BINARY

2 проход:
файл  ZLOAD строка 2
DSECT
файл HDOS строка 853
;CHN SPRITE

Исходный файл: ZLOAD
Объектный файл: SM5
Тип объектного: BINARY

Далее в Бейсике собираю все вместе
BLOAD SM0
BLOAD SM1,A$2000
BLOAD SCRIPT,A$3000
BLOAD SM2,A$3800
BLOAD SM3,A$4000
BLOAD SM4,A$5600
BLOAD SM5,A$6800
BLOAD SM6,A$7400
BLOAD SM7,A$8400

BSAVE TOPAZ,A$1E00,L$7800

CALL$1E00

Текстовый редактор NEW компилируется при 2-м проходе. А вот файл с подпрограммами MAIN при первом. Сложности оттого, что у меня наступило переполнение буфера имен меток. Да, и такое бывает))

27 Отредактировано Voldemar0 (10-03-2018 13:08)

Re: Немного сложный, немного простой текстовый редактор

Перетащил OLD под cc65, пробую. Компилируется нормально, но при запуске лезут ошибки. Сперва думал, что где-то закосячил.... Попробовал первоначальную сборку usr10e - то же самое.

Самое-самое: на свежезагруженном редакторе несколько раз сдвинуть стрелкой курсор вправо, а потом попытаться вернуть влево. Не возвращается :)

-=-=

NEW посмотрел - не, те же самые проблемы, с которых начался OLD - абсолютные адреса переменных, суперкороткие метки... Буду доводить OLD до кондиции.

В OLD удалил печать экрана и поддержку графики. Работает с клавиатурой/экраном через IOSUB ДОК (пока что. Потом буду мультисборку: версия для бейсика и для BTK). Скорее всего будет полноэкранным, может быть только сделаю строку подсказок по клавишам, но, вероятнее, вывод подсказок будет только по F1. Пока не решил, как лучше.
Ещё добавил смену вида курсора - подчерк в тексте и "^" - на виртуальных пробелах.
Исходный текст разделил на 5 файлов: отдельной библиотекой интерфейс с IOSUB + 4 части: заголовки, процедуры обработки клавиш, процедуры работы с указателями (inc, dec, поиск начал-концов строк по буферу) и процедуры вывода буфера на экран.

-=-=

Вроде бы удалось хорошо выстроить весь процесс. Четыре окна: 1) редактор текстов (с вкладками), 2) скрипт компиляции/сборки, 3) dos33c2 для закидывания fil в образ диска и 4) эмулятор.
Всё открыто постоянно, из одной проги в другую результат перетекает.

Выяснил, как можно вытряхнуть их cc65 массив меток для отладки. Нужно в компилятору указать ключ -g , а линкеру ключ -Ln и имя файла - там будут собраны все метки, не только экспортируемые.
Дальше небольшая утилитка самописная, которая этот массив конвертирует в формат Agat-Free, чтобы их было видно эмулятору.

28

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

Самое-самое: на свежезагруженном редакторе несколько раз сдвинуть стрелкой курсор вправо, а потом попытаться вернуть влево. Не возвращается :)

Ну это нормально)) Вообще я всегда исправляю ошибки, которые заметил. Видимо эту не увидел((

Voldemar0 пишет:

NEW посмотрел - не, те же самые проблемы, с которых начался OLD - абсолютные адреса переменных, суперкороткие метки... Буду доводить OLD до кондиции.

Увы. Все мои программы этим страдают. Надо менять стиль))

29 Отредактировано Voldemar0 (10-03-2018 21:07)

Re: Немного сложный, немного простой текстовый редактор

USR пишет:
Voldemar0 пишет:

Самое-самое: на свежезагруженном редакторе несколько раз сдвинуть стрелкой курсор вправо, а потом попытаться вернуть влево. Не возвращается :)

Ну это нормально)) Вообще я всегда исправляю ошибки, которые заметил. Видимо эту не увидел((

Тут всё просто: при движении вправо создаются виртуальные пробелы, а при движении влево сперва проверяется, не стоим ли мы в начале буфера. Но сначала нужно проверить, нет ли накопленных виртуальных пробелов и только если их нет, проверять на совпадение с началом буфера (и двигаться по буферу).

Сейчас ещё одну нашел: также, на свежезагруженном редакторе, нажимаем ВВОД и стрелку вверх - курсор отказывается идти вверх. Скорее всего, причина в том, что в разным местах редактора проверяется условие LO_BUF > LO_CUR , но иногда LO_BUF >= LO_CUR. Я пока так и не понял - может курсор стоять на начале буфера или обязательно должен отстоять от него на один символ (CR) ? При инициализации они совпадают, но ... но кажется, тут есть путаница.


USR пишет:

Увы. Все мои программы этим страдают. Надо менять стиль))

Звучит как "начну новую жизнь с понедельника" :)
Я менял стили раз пять уже, но это происходит как-то плавно. Порой, дописываешь кусок с старой программе, и он уже создаётся в новом стиле.

30

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

Сейчас ещё одну нашел: также, на свежезагруженном редакторе, нажимаем ВВОД и стрелку вверх - курсор отказывается идти вверх.

Это не все)) Если на свежезагруженном нажать сначала "1", потом ввод, потом 2 раза вверх-будут кошмары))

Трудно сказать в чем причина, надо смотреть...

31 Отредактировано Voldemar0 (11-03-2018 10:31)

Re: Немного сложный, немного простой текстовый редактор

> Это не все)) Если на свежезагруженном нажать сначала "1", потом ввод, потом 2 раза вверх-будут кошмары))

СУПЕР!
Я эту гадость не мог никак найти - последствия вижу, а в какой момент возникает - не мог понять! Щас разберу...

-=-=

Процедура обработки стрелки вверх самая сложная! В ней баг, возможно, не один.
Уточнил работу указателей:

; За пределами изменяемых байт лежат два символа CHAR_CR, они не должны изменяться.

; Часто бывает так что, LO_CUR указывает на то же значение,
; что и HI_CUR. Велика ошибка полагать, что то бывает всегда !

ED_P_LO_BUF     .res 2  ; Первый ИЗМЕНЯЕМЫЙ байт буфера.
ED_P_LO_CUR     .res 2  ; Первый свободный байт в нижней части буфера.
ED_P_HI_CUR     .res 2  ; Первый занятый байт в верхней части буфера.
ED_P_HI_BUF     .res 2  ; Последний НЕИЗМЕНЯЕМЫЙ байты буфера.

таким образом LDY #0; LDA (ED_P_LO_CUR),Y некорректно вообще.

32 Отредактировано Voldemar0 (11-03-2018 15:28)

Re: Немного сложный, немного простой текстовый редактор

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

Собственно, отличие макроассемблера от ассемблера не только в поддержке макросов, как следует из названия. Обычно макроассемблеры имеет ещё много полезных возможностей, ... собственно, просто ассемблеры уже давно никто не пишет. Но также как и число версий бейсика соответствует числу его реализаций, так же и с ассемблерами - у каждого проца свои компиляторы со своими плюшками. А вот макросы - дело единое.


Что особенно приятно: 8086 и его потомки имеют целых два класса различных макроассемблеров: так называемые intel-style - это то, что считает правильным сама Intel, сюда входят всевозможные masm, tasm, fasm и иже с ними. С другого лагеря хитро поглядывает at&t-style, его реализует, например, gas.

Основное отличие в концепции: intel-style пытаются вычислять команду исходя из её аргументов, которые могут иметь разные типы. Получается что-то типа высокоуровневого языка: mov a, b - без контекста вы не знаете, во что это выльется (a, b - метки/адреса или непосредственные значения ?) и где какая будет разрядность.
В то же время at&t-style, хотя и допускает неявные указания типов, но всё же тяготеет к более чёткому выражению мыслей: movzbl 2,4 однозначно указывает, что 2 - это именно адрес (а не значение), причем по этому адресу хранится именно байт, а 4 - это тоже адрес, причем там живёт 32 битное беззнаковое и при копировании значения это нужно учесть.

В intel-style вы не можете, например, записать команду перехода на адрес за пределами программы: JMP 0x2800 просто вызовет ошибку компиляции, так как ассемблер сочёт константу непосредственным значением, а требуется указатель. Intel-style пытается помешать вам стрелять в ногу, в то время как at&t-style знает, что это невозможно и, тяжело вздохнув, помогает точнее прицелится.

Есть и другие отличия: например, в at&t имена регистров начинаются с символа %, таким образом нет запрета на использование переменных с именами, совпадающими с именами регистров (ax, ah и т.д.).


Но мы отвлеклись. Итак, макросы - это возможность собрать группу команд под некоторым именем и вставлять эту группу в текст программы, указывая только имя группы (что-то вроде inline-процедур). Какое занудство мы часто используем на 6502 ? В первую очередь работу с 16-разрядными указателями. Например, копирование b = a:

 lda a+0
 sta b+0
 lda a+1
 sta b+1

a и b по ходу программы бывают разными, сделаем для них макрос:

.macro copy_ptr src, dst
 lda src+0
 sta dst+0
 lda src+1
 sta dst+1
.endmacro

Теперь в программе можно писать:

 copy_ptr a, b

Макроассемблер здесь вставит соответствующую последовательность команд.

Это в общих чертах. Частности у разных компиляторов различаются.
Вот что я использовал в сабже темы:

;
; Очень полезный макрос
; Копирует содержимое двух байт из src в два байта dst1 и, если указаны, dst2 и dst3
;
.macro copy_ptr src, dst1, dst2, dst3
 lda src+0
 sta dst1+0
 .ifnblank dst2
   sta dst2+0
 .endif
 .ifnblank dst3
   sta dst3+0
 .endif

 lda src+1
 sta dst1+1
 .ifnblank dst2
   sta dst2+1
 .endif
 .ifnblank dst3
   sta dst3+1
 .endif
.endmacro

Теперь можно вызывать его так:

 copy_ptr ED_P_LO_CUR, ED_P_LO_BUF, ED_P_TOP_LN

или так:

 copy_ptr ED_P_HI_CUR, ED_P_HI_BUF

Первый аргумент - источник, последующие (один, два или три) - приёмники.
Как видно, можно использовать команды условной компиляции: если 3-й и 4-й аргументы не указаны, соответствующие команды sta не будут созданы.

Так подобный код отображается компилятором в листинге:

000020r 1  A5 rr 85 rr   copy_ptr ED_P_LO_CUR, ED_P_LO_BUF, ED_P_TOP_LN  
000024r 1  85 rr A5 rr   
000028r 1  85 rr 85 rr   
00002Cr 1  A5 rr 85 rr   copy_ptr ED_P_HI_CUR, ED_P_HI_BUF  
000030r 1  A5 rr 85 rr   

(rr - reallocate - т.е. значения этих переменных пока неизвестны, редактор связей потом подставит сюда фактические адреса)


Второй макрос:

;
; Декременты разных указателей и счётчиков
;
.macro dec_ptr ptr
 .local @0
 lda ptr+0
 bne @0
 dec ptr+1
@0:
 dec ptr+0
 rts
.endmacro

DEC_MS_PTR_A
 dec_ptr MS_PTR_A

DEC_P_TOP_LN
 dec_ptr ED_P_TOP_LN
 
DEC_P_HI_CUR
 dec_ptr ED_P_HI_CUR

DEC_P_LO_CUR
 dec_ptr ED_P_LO_CUR

Здесь через макрос синтезируются обычные подпрограммы, уменьшающие на 1 некоторые указатели. Вызвать их можно привычным JSR DEC_MS_PTR_A. Обратите внимание на команду .local: она позволяет сделать метку @0 локальной внутри макроса: она не будет никак проявлять себя вне определения макроса.

Что получается при компиляции:

000444r 2 DEC_MS_PTR_A  
000444r 2  A5 rr D0 02   dec_ptr MS_PTR_A   
000448r 2  C6 rr C6 rr   
00044Cr 2  60 
00044Dr 2   
00044Dr 2 DEC_P_TOP_LN  
00044Dr 2  A5 rr D0 02   dec_ptr ED_P_TOP_LN  
000451r 2  C6 rr C6 rr   
000455r 2  60 
000456r 2   
000456r 2 DEC_P_HI_CUR  
000456r 2  A5 rr D0 02   dec_ptr ED_P_HI_CUR  
00045Ar 2  C6 rr C6 rr   
00045Er 2  60 
00045Fr 2   
00045Fr 2 DEC_P_LO_CUR  
00045Fr 2  A5 rr D0 02   dec_ptr ED_P_LO_CUR  
000463r 2  C6 rr C6 rr   
000467r 2  60   

33 Отредактировано Voldemar0 (11-03-2018 15:21)

Re: Немного сложный, немного простой текстовый редактор

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

-=-=

Итак:
1) добавил макросы, распихал в них некоторые части кода;
2) добавил удаление строки (ф9), удаление символов от курсора до начала (ф7) и до конца строки (ф8);
3) сделал режим вставки символов (ф2, переключает режим и меняется курсор на расширенном знакогенераторе);
4) удаление символов (del, ф1).

Выкладываю в первом сообщении темы результат (исходник + образ).
Образ грузится на семёрке, затем выбираем "выйти в отладчик" и там пишем:

[execc

Используется не всё пространство экрана, это специально для контроля глюков разных.

-=-=

Дальше:

1) чтение/запись файлов;
2) переключение видеорежимов + отключение вывода номеров строк;
3) листание постранично (или, проще, на 20 логических строк);
4) порты на разные ОС;
5) перемещение фрагмента;
6) вставка файла;
7) запись фрагмента;
8) поиск текста;
9) переход к заданной строке;
10) ? что-то ещё ?

34 Отредактировано USR (11-03-2018 21:11)

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

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

Вот и отлично!

Voldemar0 пишет:

2) переключение видеорежимов ...

10) ? что-то ещё ?

Переключение видеорежимов это TEXT32/TEXT64?

Тогда неплохо бы, в цветном режиме метки отображать красным, а комментарии голубым, например. Как по мне, так удобнее...
Например метки в редакторе NEW выглядят так:

Post's attachments

t7.png, 17.72 kb, 512 x 512
t7.png 17.72 kb, 265 downloads since 2018-03-11 

35 Отредактировано Voldemar0 (12-03-2018 20:10)

Re: Немного сложный, немного простой текстовый редактор

Ещё пример использования макросов.

Как обычно пишутся процедуры табличных обработчиков ? Например, на нажатие разных клавиш нужно вызвать разные процедуры.

Суперэконом вариант:

T_LO:  DFB >route1-1,>route2-1
T_HI:  DFB <route1-1,<route2-1
T_KEY: DFB $8D,$9B

main:
 jsr get_key
 ldy #1
loop:
 cmp t_key,y
 beq call
 dey
 bpl loop
 bmi main

call:
 lda T_HI,y   ; возможно в обратном порядке HI/LO, не помню точно
 pha
 lda T_LO,y
 pha
 rts

В цикле loop ищем совпадение полученного в get_key кода с кодами обрабатываемых клавиш, если не нашли возвращаемся на начало, иначе переходим на call и там, выбрав значение адреса обработчика из таблиц T_LO, T_HI, засылаем его в стек и вызываем переход по заданному адресу через команду rts. Таким образом на клавишу ВВОД ($8D) будет вызван обработчик route1, а на РЕД ($9B) - route2.

Вычитание единицы из адреса нужно потому, что rts переходит на адрес + 1 от того, что хранится на стеке.

Чем плох этот код ? Только синтаксически !

1) нужно вычитать 1 (лишние символы каждый раз писать).
2) адрес обработчика указывается дважды (надоедает).
3) если список длинный (а зачастую там клавиш 10-20 может быть), попробуйте удалить элемент из его середины. Найдите нужный код и соответствующий ему обработчик :)
4) количество элементов в таблице задано явно в теле цикла. Добавление/удаление элемента таблицы этого требует правки этого значения.
5) переход на обработчики идёт по схеме jmp. Значит возврат нужно делать тоже по jmp. Удобнее сделать по jsr: как правило, возврат будет требоваться в одно и то же место, jsr позволит использовать для возврата rts - это удобно при написании обработчиков.

Я, в начале своей программистской карьеры, именно так и писал. Это даёт самый компактный код, но поддерживать его тяжело.

Попробуем исправить некоторые косяки:

vec = $E0
T_PROC: DW route1,route2
T_KEY:  DFB $8D,$9B
T_KEY_F:

main:
 jsr get_key
 ldy #T_KEY_F-T_KEY-1
loop:
 cmp t_key,y
 beq find
 dey
 bpl loop
 bmi main

find:
 jsr call
 jmp main

call:
 tya
 asl a
 tay
 lda T_PROC+0,y
 sta vec+0
 lda T_PROC+1,y
 sta vec+1
 jmp (vec)

Процедурка заметно подросла: появились новые команды.
Зато:
1) адрес процедуры упоминается один раз, нет вычитания 1;
2) сделали автоматический расчёт размера таблицы (T_KEY_F-T_KEY);
3) возврат из обработчиков по rts за счёт вызова внутренней процедуры call через jsr.

Так я писал уже в конце 90-х.

Но список пока ещё неудобный. Удобнее, если бы код клавиш чередовался со ссылками на соответствующие обработчики.

Усложним:

vec = $E0
t_router:
 DFB $8D
 DW  route1
 DFB $9B
 DW  route2
 DFB $00
 DW  default_route

main:
 jsr get_key
 ldy #0
 tax

loop:
 lda t_router,y
 beq found
 txa
 cmp t_router,y
 beq found
 iny
 iny
 iny
 jmp loop

found:
 jsr call
 jmp main

call:
 iny
 lda t_router,y
 sta vec+0
 iny
 lda t_router,y
 sta vec+1
 jmp (vec)

Теперь править таблицу гораздо удобнее. Кроме того мы отказались от статического расчёта размера таблицы и ввели специальную закрывающую строку с кодом клавиши 0. Она соответствует любой клавише, т.е. будет срабатывать в случае, если в таблице запись для данной клавиши не найдена.

Если ваша программа достаточно сложная и в ней, в разное время, используются разные таблицы (например, у вас есть процедуры: полноэкранного текстового редактора, строчного редактора и управления выпадающим меню), можно ещё дополнить логику этой процедуры. Например, спроектировать селектор в виде отдельной процедуры, причем таблицу при вызове передавать ей через адрес в стеке:

main:
 jsr get_key
 jsr router
 DFB $8d
 DW  key_enter
 DFB $9b
 DW  key_esc
 DFB 0
 DW  key_default
 jmp main

Т.е. процедура router, получив управление, извлекает из стека адрес возврата, по которому будет расположена таблица. Просмотрев таблицу и вызвав нужный обработчик, router доходит таблицу до конца и возвращает управление на следующую за таблицей команду jmp main.

Такой механизм я использовал в последней крупной агатовской разработке, компилируемой ещё пока ассемблером ДОК.

А что насчёт макросов? Переходим к cc65 и теме топика:

.rodata                         ; таблицы располагаем в сегменте констант

.macro key_descriptor code, proc; описываем простенький макрос, который позволит
  .byte code                    ; создавать что-то вроде "записи" или "структуры"
  .word proc
.endmacro

; объединяем таблицу в единый блок, при необходимости можно будет запросить
; его фактический размер: .sizeof(ED_KEYS_TABLE)

.scope ED_KEYS_TABLE
  key_descriptor $8D, ED_K_ENTER
 
  key_descriptor $95, ED_K_RIGHT
  key_descriptor $88, ED_K_LEFT
  key_descriptor $99, ED_K_UP
  key_descriptor $9A, ED_K_DOWN

  key_descriptor $9B, ED_K_ESC

  key_descriptor $9D, ED_K_LEFT_CUTLINE ; ф7
  key_descriptor $9E, ED_K_RIGHT_CUTLINE        ; ф8
  key_descriptor $9F, ED_K_DELLINE              ; ф9
  key_descriptor $91, ED_K_INS_MODE             ; ф2
  key_descriptor $90, ED_K_DELETE               ; ф1
  key_descriptor $81, ED_K_SCR_MODE             ; ф0

  key_descriptor 0,   ED_K_SYMBOL
.endscope

Красивее получилось ? И нагляднее ! Ещё можно заменить коды клавиш на константы (key_f0, key_...), но и так хорошо.

Ассемблер считается сложным языком. Я не согласен с этим утверждением. Сложны, скорее, задачи, ради которых выбирается ассемблер: работа в условиях жесткой экономии рессурсов, суперпростые операционки, не всегда есть возможность пошаговой отладки программ. Это если проц простой и периферия тоже супербюджетная. А если проц мощный и памяти полно ? Тогда ассемблер может использоваться для управление режимами процессоров, для разработки кода инициализации системы, автозагрузчиков...

Но проблема ассемблера в другом: на нём очень легко создать совершенно не читаемый код, в котором легко потеряться. Этого можно добится на любом языке, но ассемблер - чемпион в этой дисциплине. Если начинающий берётся за изучение PHP и пишет пока ещё корявый код, он всё равно вызывает кучу готовых процедур с понятными именами. А в ассемблере можно избежать даже этого и начать сразу с тёмных материй.

2USR: не принимай на свой счёт, это я в целом.

36 Отредактировано Voldemar0 (12-03-2018 20:14)

Re: Немного сложный, немного простой текстовый редактор

За сегодня:

Изменил концепцию работы с координатами курсора.

Раньше они всегда пересчитывались в обработчиках клавиш, при выводе буфера на экран координаты сохранялись, после вывода восстанавливались.

Теперь при выводе экрана, в момент пересечения границы деления буфера, текущие координаты сохраняются как координаты курсора. Это позволило избавиться от отдельного пересчёта координат во вновь создаваемых процедурах. Пересчёт остался внутри наиболее часто используемых обработчиков (стрелки, набор текста), минимально модифицирующих экран (к которым высоки требования по скорости исполнения).

-=-

Сделал переключение видеорежимов, а также отключение вывода номеров строк (одновременно на 5 знаков увеличивается ширина окна).

Нашел небольшую ошибку в процедуре удаления строки.

-=-

Цветовая схема: я её внесу в список хотелок, но:

- Обычно асм-текст пишется в две колонки: колонка меток, колонка команд. Так было в rt11, например, я с неё начинал. Но это хорошо, если есть TAB, когда колонка команд не зависит от колонки меток.

LAB:  COMMAND
      COMMAND
      COMMAND

Благодаря TAB можно редактировать LAB не затрагивая положение COMMAND. Однако на  Агате TAB никак не предусмотрен. Когда -то я пытался писать на Агате также, но выравнивая всё пробелами. А потом подсмотрел у Цикозы более удобный стиль:
метки оканчивать двоеточием (необязательное, но хорошо их подчёркивает), а команды писать на отдельных строках, не комбинируя метку и команду в одной строке. Мне это настолько понравилось, что сейчас я так пишу и на других ассемблерах.

LAB:
 COMMAND
 COMMAND

Здесь метка геометрически выделяется, так что в отдельном цветовом выделении уже нет большой потребности. Да и в 64x32 цвета всё равно нет :(.

- У меня нет планов ориентировать этот редактор только для работы с текстами программ. Конкретно сейчас он мне будет нужен для редактирования файла настроек и для мелкой правки (не набора) исходников (при работе непосредственно на Агате). Если уж делать подсветку синтаксиса, то как-то более комплексно, настраиваемо... В общем, это останется волонтёрам :) (как и некоторые другие пункты моего списка).  Я хочу только показать современный удобный способ разработки прог для Агата. Ну и сам в нём потренироваться.

37

Re: Немного сложный, немного простой текстовый редактор

встречал я людей говорящих самих с собой, но никто из них не писал текстовых редакторов, да ещё и с ED_VIRT_SPC EQU $90... мораль: Делать редактор молча. и можно даже с ED_VIRT_SPC EQU $10.

1917

38

Re: Немного сложный, немного простой текстовый редактор

Ещё один любопытный пример игр с макросами и сегментами.

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

Вопрос в том, как процедура вывода должна найти сообщение по номеру?
Варианта два: либо начать от символа первого сообщения и посчитать количество символов завершения строк, т.е. найти нужно сообщение перебором всех сообщений от первого.
Второй вариант: в программе составляется таблица начал (указателей) на каждое сообщение.
Чаще делали именно так.

MSG1: DCI "сообщение 1"
MSG2: DCI "сообщение 2"

Затем составлялась таблица:

table:
 DW MSG1
 DW MSG2

Вывод происходит такой процедурой:

ERR_MSG:
 lda BTK_OTZV
 cmp #14
 bcc @0
 lda #14
@0:
 asl a                  ; Код ошибки умножаем на 2
 tay
 ldx table+0,Y          ; и вытаскиваем указатель на строку из таблицы
 lda table+1,Y
 jmp IOS_PRINT_PTR      ; Вывод строки от A/X

Проблемы тут две:
1) каждому сообщению соответствует своя запись в таблице указателей, редактируя одну таблицу нужно соответственно редактировать вторую.
2) нужно придумать уникальные метки по числу сообщний.

Макросы позволяют изобразить это всё гораздо проще:

.macro errmsg str
 .local @0
 .rodata
   @0: .asciiz str
 .code
   .word @0
.endmacro

rodata - сегмент неизменных данных, реально будет размещены, например, после кода в файле программы.
code - сегмент кода программы.

Этот макрос записывает в сегмент rodata строки, а в сегмент кода - ссылки на них.
Теперь обращаемся к созданному макросу:

table:
 errmsg "Нет ошибки"                    ; 0
 errmsg "Ошибка обмена"                 ; 1
 errmsg "Диск закрыт на запись"         ; 2
 errmsg "Файл не найден"                ; 3
 errmsg "Нет места на диске"            ; 4
 errmsg "Неверный тип файла"            ; 5
 errmsg "Не системный диск"             ; 6
 errmsg "Нет места в каталоге"          ; 7
 errmsg "Слишком большой файл"          ; 8
 errmsg "Вложенный 'EXEC'"              ; 9     ? CATFLER   DS 1 $09 REXECER в 5.0 ?
 errmsg "Недопустимый адрес"            ; 10
 errmsg "ALREAD ER"                     ; 11
 errmsg "Ошибка в параметрах"           ; 12
 errmsg "NOCOM ER"                      ; 13
 errmsg "Неизвестная ошибка"            ; 14

В результате по адресу table в сегменте кода получается та же самая таблица ссылок, а где-то в конце файла программы - сами сообщения (здесь приводятся ошибки Best Tool Kit). Процедура их вывода остаётся неизменной.

39 Отредактировано Voldemar0 (07-04-2018 16:43)

Re: Немного сложный, немного простой текстовый редактор

Исправил мелкую ошибку в редакторе, дальше пишу обёртку для разных ОС.

Разделил все на три семейства:
1) Все бейсики;
2) ДОК / Ассемблер / Агат-Ассемблер;
3) BTK / The BEST.

Под каждое семейство будет своя сборка редактора, но внутри семейств различия разбираются автоматом.

Обёртки написал для IOSub (ввод/вывод на экран) и для ДОС-операций: чтение/запись файла любого типа, чтение/запись сектора и составление каталога диска в указанном буфере (читает каталог, выделяет из него только не удалённые файла: имя, тип, размер) - это для меню выбора файла.

По семействам 2 и 3 всё путём, работает. Тестирую на простенькой проге, которая читает два текстовых файла и потом записывает результат в один файл. Затем читает каталог и выводит его на экран.

Тестировать приходится всё: ошибки лезут где угодно. В каждой версии бейсика (ну и других систем) то одно, то другое косячит. Хуже всего, конечно, дело с бейсиками: если ДОК и BTK как-то документированы и документация вынуждала авторов всё таки проверять свои работы, то с у бейсика драйвер файловой системы - его личное дело, и чем дальше от AppleSoft, тем больше Фу. Если Бейсик-60 прокатил вполне сходу, в ИКП-7-СЧМ тоже почти всё было нормально (не без проблем, конечно, но на форум я это уже не пишу, всё идёт в комментариях внутри исходников), то в ИКП-7 базовом какие-то совсем уж чудеса: открываю и читаю первый файл - ошибок нет. Но не читается ничего. На fopen второго файла внезапно считывается первый файл..... Но я всё равно хочу добить эту работу, так как очень уж вкусные перспективы по дальнейшему использованию фич, которые есть в эплсофтном наследии.

Да, именно так: как выясняется, все ДОСы бейсиков - это всё таки стивовознятское.
Ну то есть про Бейсик-60 никто и не сомневался, но сейчас я вижу жирные куски почти такого же когда уже в ИКП-бейсике. Да, там адреса другие, видно, что кой что правили, причем имея исходник (никаких там добивок NOP'ами или внезапных JSR/JMP на заплатки), но когда десятки команд подряд почти не отличаются - ну это же не совпадение.
В ИКП код ДОС лопатили основательно, достаточно того, что он из адресов 9xxx..bfff переехал на dxxx, но всё таки это почти тот же код.

Кой где, в процессе лопатинга, забывали о некоторых взаимосвязях. Например, fopen требует флажка "w+" - т.е. можно создать файл, если он не найден. Так вот в Бейсик-60 это работает как описано в книжке "Под яблоней ДОС", а вот в ИКП уже без костылей не обошлось: там про этот флажёк забыли: сохраняют его в одном месте, а читают совсем из другого, там, где его никто и не задаёт (кроме собственного анализатора комстроки, который вызывает ядерные функции немного не по стандартному входу (ну это и в эплософт также)).

40

Re: Немного сложный, немного простой текстовый редактор

Кстати, а каким годом датируется начало разработки этого редактора ?

41

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

Кстати, а каким годом датируется начало разработки этого редактора ?

Точно не могу сказать, но думаю что первая половина 93-го. Где-то с лета 92-го стал делать собственный ДОС, а редактор делал уже точно, когда ДОС был запущен.

42 Отредактировано Voldemar0 (10-04-2018 06:00)

Re: Немного сложный, немного простой текстовый редактор

Закончил обёртки, вернулся к редактору. Думал, как сделать меню: двухуровневое, выпадающее сверху (есть готовая либа, хотя, по ныншеним меркам, не очень удобная) или агат-style: отдельный экран, на нём список в одну колонку + комментарии (типа как в Комплексном тесте). Остановился на втором варианте: реализуется проще, а пунктов меню набралось всего 6. Нарисовал дизайн, реализовал всё. Заодно встроил небольшую подсказку по используемым в редакторе клавишам (можно смотреть и из меню и из редактора). Сделал мелкие процедуры (выход из редактора, вызов справки, очистку буфера). Осталось дописать процедуры чтения/записи буфера, выбор файла из списка и ввод имени файла с клавиатуры.

Сейчас загрузочный файл весит 15 блоков, ДОК-версия. BTK будет примерно столько же, Бейсик-версия блоков на 5 больше.
Пока вполне скромно получается. В чистом виде редактор блоков 8.

43 Отредактировано garnizon (05-02-2022 17:13)

Re: Немного сложный, немного простой текстовый редактор

На мой взгляд самое лучшее это как ты в "СИРИУС" сделал
http://agatcomp.ru/agat/Software/Graphic/Sirius/SIRIUS.png

44

Re: Немного сложный, немного простой текстовый редактор

Закончил пару процедур: ввод имени файла и выбор файла из каталога.

Post's attachments

1.png, 12.39 kb, 672 x 512
1.png 12.39 kb, 265 downloads since 2018-04-13 

2.png, 11.99 kb, 672 x 512
2.png 11.99 kb, 261 downloads since 2018-04-13 

3.png, 12.13 kb, 672 x 512
3.png 12.13 kb, 272 downloads since 2018-04-13 

45

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

Закончил пару процедур: ввод имени файла и выбор файла из каталога.

Класс! А на переполнение буфера текста сам редактор проверял? Там вообще изначально такие проверки были?)) Я то точно в свое время не проверял))

46 Отредактировано Voldemar0 (14-04-2018 20:38)

Re: Немного сложный, немного простой текстовый редактор

Именно в твоём коде как раз есть проверки на переполнение, только они немного неочевидны для пользователя: выводится окно "Ошибка" и ничего больше. Какая ошибка - угадай сам.

Я убрал текст и окно, просто бип оставил. Тут как бы очевиднее: символ не вставляется новый и слышно пищание. Но не проверял, как это работает.

Хуже то, что хотя во всех ОС есть проверка на то или иное ограничение при чтении файла, реально я их не использую, так как они реализованы очень специфически:

1) ДОС3.3, по сути, не работает с ОЗУ напрямую: ты сам ей задаешь какого размера кусок файла по какому адресу прочитать. Соответственно, можешь свободно контролировать границы.
2) BTK читает до BFFF, если не ошибаюсь, и этот лимит - hardcoded.
3) ДОК читает до TOPPAGE (т.е. с точностью до блока в 256 байт), причем проверяет именно факт чтения в страницу TOPPAGE (= $7Fxx, но это переменная). Если сектор прочитался в эту страницу, следующий не читается. Соответственно, если сделать "[load xxx,A8000", например, то лимитов нет вообще - можно спокойно зачитаться в Cxxx, хотя, на самом деле, гораздо раньше будет креш, так как такое чтение просто забъёт код самой ДОС.

Поэтому в редакторе я вообще отказался от каких либо проверок объёма при чтении, но аккуратно занёс это в ToDo. Если у дела будут продолжатели, пусть они уже думают - что, как и зачем проверять.

-=-=

В аттаче преальфа, пока только для ДОК (любые версиями, 140/840/9/7/...), можно пробовать.
Рекомендую ДОК семёрочный, так как у него нет ограничений на строчные символы (девяточный, который в самом ходовом ИКП, почему-то всё приводит к верхнему регистру).

В ней есть ошибки. Например, если переключить видеорежим так, чтобы курсор оказался ниже последней строки, будет мощный глюк. Но стабильной версии в ближайшие дни, наверное, ещё не будет.

47 Отредактировано Voldemar0 (16-04-2018 20:47)

Re: Немного сложный, немного простой текстовый редактор

Впервые за 4 года у меня права проверили на мотаке :)
Обычно от моей техники всегда отворачивались или вовсе не смотрели.

-=-

Сделал сборку под бейсик, вроде работает.

Но пока в самом редакторе проблемы пролазят: при переключении видеорежимов и включении/отключении выводов номеров строк курсор может оказаться за пределами окна (ниже нижней строки). Написал относительно простую (но очень медленную) процедуру прокрутки экрана до положения, в котором курсор будет виден, но то ли она подглючивает, то ли где-то ещё есть ошибки: сложно поймать, они не сразу проявляются.

Ошибок в коде, конечно, не стало больше, но сейчас уже можно читать файлы, что приводит к куче различных комбинаций размеров строк и всяких тестовых случаев.

Ловлю их, проверяя в главном цикле условия:
LO_BUF <= TOP_LN <= LO_CUR <= HI_CUR <= HI_BUF.

Общее число меток в программе зашкалило за 512. Ну это не только вручную написанные (в сумме, по всем модулям), но и синтезированные внутри макросов и всякие встроенные. А 512 - это лимит эмулятора. Можно увеличить лимит, но, на самом деле, собранный билд пестрит метками, так что, для начала, исключил из отладочной инфы локальные метки макросов. Всё равно они пользы большой не несут при отладке.

Но, в целом, всё работает как задумано.

48 Отредактировано USR (16-04-2018 22:50)

Re: Немного сложный, немного простой текстовый редактор

Voldemar0 пишет:

Я убрал текст и окно, просто бип оставил. Тут как бы очевиднее: символ не вставляется новый и слышно пищание. Но не проверял, как это работает.

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

Voldemar0 пишет:

Но пока в самом редакторе проблемы пролазят: при переключении видеорежимов и включении/отключении выводов номеров строк курсор может оказаться за пределами окна (ниже нижней строки). Написал относительно простую (но очень медленную) процедуру прокрутки экрана до положения, в котором курсор будет виден, но то ли она подглючивает, то ли где-то ещё есть ошибки: сложно поймать, они не сразу проявляются.

Может при переключении режимов строку с курсором делать самой верхней на экране да и все?

49 Отредактировано Voldemar0 (17-04-2018 05:50)

Re: Немного сложный, немного простой текстовый редактор

> Может при переключении режимов строку с курсором делать самой верхней на экране да и все?
В имеющейся архитектуре редактора даже просто сделать перемещение курсора куда-то или найти начало текущей строки - дело не так, чтобы пары команд. Чтобы строка с курсором оказалась вверху, нужно:
1) Найти начало строки. Проще искать начало логической строки. Задать её как TOP_LINE_PTR  - это указатель на логическую строку, выводимую в начале окна.
2) Потом надо найти количество переводов строк между текущей TOP_LINE и новой. И на вычисленное число изменить TOP_LINE_NUMBER. Это номер строки, выводимой в начале окна.

У меня процедура попроще: я сперва нахожу начало текущей логической строки, выводимой в TOP и задаю его как TOP (т.е. если верхняя логическая строка выводилась не с начала, то экран скролится вниз), а затем, при построении экрана проверяю, был ли переход между LO_CUR и HI_CUR. Если его не было, то отматываю TOP либо до перевода строки либо на число символов = ширине окна (экран скролится вверх). И возвращаюсь на этап построения экрана. Кроме того, в самом начале сбрасываю VIRT_SPC = 0, иначе тоже будут сюрпризы (число виртуальных пробелов не может быть больше ширины окна минус размер хвоста строки).

Получается цикл перестроений экрана, оканчивающийся при условии, что курсор попал в окно.
Если курсор загнать в самую нижнюю строку 64x32, то требуется где-то секунды 4 на переключение в 32x32. Но я не думаю, что такие переключения нужны часто, так что не критично.

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

-=-

Вчера всё таки поймал какой-то баг, явно не в этой процедуре. Когда длина логических строк как раз совпадает с экранными, что-то там резко улетает в ловушку: курсор оказывается ровно на байт ниже TOP при движении по стрелке вверх.
(Ловушка: при нарушении условий неравенства указателей выполняется ".byte 2" - эмулятор останавливается и сообщает о недокументированной команде.)

50 Отредактировано Voldemar0 (17-04-2018 20:38)

Re: Немного сложный, немного простой текстовый редактор

Баг оказался в процедуре обработки стрелки вверх: там, в самом конце, есть конструкция: dec ПОЗИЦИЯ_СИМВОЛА_В_ОКНЕ / BNE loop. Она участвует в вычислении числа виртуальных пробелов.
Так как изначально номера строк были обязательными, позиция_символа не могла быть равна нулю, BNE использовался как JMP. В связи с появлением возможности отключения выводов номеров строк цикл стал прекращаться сильно заранее, в результате с числом виртуальных пробелов возникали баги, а за ними следом являлись чудеса.

-=-

Добавил в проверку указателей вывод сообщения с отладочным дампом.
Теперь даже на реале можно будет понять, что что-то пошло не так.

-=-

Добавил в конце текста справки информацию о дате сборки редактора, результаты распознавания типа ОС, полный объём буфера текста и свободный его остаток. В зависимости от сборки, версии и прочего эти цифры могут меняться. Пересчитываются они автоматически компилятором.

-=-

При обнаружении Бейсика-60 пришлось принудительно включать видеостраницу в адресе
$800, так как по дефолоту ставится $7800, а это накладывается на часть буфера текста.
Плохо, и желательно бы восстанавливать при выходе в дефолтное состояние, иначе могут обрушиваться некоторые бейсик-проги, но оставлю это в ToDo последователям.

-=-

Стал экспериментировать с огромными текстами, на почти весь буфер. Обнаружил ошибку в процедуре записи: текст слегка портился в некоторых случаях.