Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Пн окт 22, 2018 16:48

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 10 ] 
Автор Сообщение
 Заголовок сообщения: Сообщения в форте
СообщениеДобавлено: Пн дек 08, 2008 15:37 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 4954
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 18 раз.
Поблагодарили: 56 раз.
Автор: mOleg
Дата публикации: 2008-12-08
публикуется впервые

Сообщения

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

Самый простой вариант
Самый простой вариант – это литеральные строки в коде, например:

… S” простое сообщение” TYPE …

либо, как вариант сообщения вместе с ошибкой:
… ABORT” простое сообщение об ошибке” ...

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

Одно слово – одно сообщение
Более универсальным вариантом, который является развитием предыдущего метода – оформлять каждое сообщение в отдельное слово, и уже это слово вызывать в случае необходимости. Причем, полученные таким образом сообщения могут самостоятельно принимать решения о необходимости вывода сообщения:
: Err001 ( flag --> ) IF .” сообщение в отдельном определении” -1 THROW THEN ;

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

Еще один классический метод
Еще одним методом работы с сообщениями любили пользоваться Форт-системы во времена ДОСа. Выглядело это примерно так:
CREATE messages 
S” первое сообщение” S”,
S” второе сообщение” S”,
S” n-тое сообщение” S”,

Поиск сообщений в таком текстовом массиве выглядел так:
: message ( u --> ) 0 messages 0 2SWAP DO + COUNT LOOP TYPE ;

Соответственно, чтобы вывести сообщение, необходимо было компилировать его код в виде литерала, а так же компилировать код, который бы умел находить по номеру сообщения само сообщение и выводить его куда необходимо:
: Error ( u --> ) COMPILE message COMPILE ABORT ; IMMEDIATE

и в программе это используется так:
… 123 Error …

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

А что же у нас с СПФ?
Предыдущий вариант достаточно хорош, но его можно улучшить, например, сообщения можно хранить во внешнем файле, и подгружать в динамическую область памяти уже после запуска программы. Номер сообщения можно сделать произвольным, и хранить в теле самого сообщения. И в СПФ так и сделали:
\ найти ошибку с номером n в списке ошибок, вернуть строку сообщения
: (DECODE-ERROR) ( n --> c-addr u )
STATE @ >R STATE 0!
BEGIN
REFILL
WHILE ( n )
PARSE-NAME ['] ?SLITERAL CATCH
IF 2DROP DROP S" Error while error decoding!" R> STATE ! EXIT THEN
OVER = IF ( n )
DROP >IN 0! [CHAR] \ PARSE
TUCK SYSTEM-PAD SWAP CHARS MOVE
SYSTEM-PAD SWAP R> STATE ! EXIT
THEN
REPEAT ( n )
<# SOURCE SWAP CHAR+ SWAP 1 - HOLDS DUP 0< IF DUP S>D #(SIGNED) 2DROP THEN U>D #S #> R> STATE ! ;

\ Возвратить строку, содержащую расшифровку кода ошибки n при условии u.
: DECODE-ERROR ( n u --> c-addr u )
DROP
S" lib/SPF.ERR" +ModuleDirName 2DUP FILE-EXIST 0=
IF
2DROP
S" SPF.ERR" +ModuleDirName
THEN
R/O OPEN-FILE-SHARED
IF DROP DUP >R ABS 0 <# #S R> SIGN S" ERROR #" HOLDS #>
TUCK SYSTEM-PAD SWAP CHARS MOVE SYSTEM-PAD SWAP
ELSE
DUP >R
['] (DECODE-ERROR) RECEIVE-WITH DROP
R> CLOSE-FILE THROW
2DUP -TRAILING + 0 SWAP C!
THEN ;

А вот так: … 2 <> IF -2007 THROW THEN … выглядит вывод сообщения.

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

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

Вариант организации сообщений из Win32Forth
Win32Forth близок к традиционной схеме с массивом сообщений, и выглядит следующим образом:
VARIABLE THROW_MSGS  \ список сообщений

THROW_MSGS LINK, THROW_STACKUNDER , ," stack underflow"
THROW_MSGS LINK, THROW_UNDEFINED , ," is undefined"
THROW_MSGS LINK, THROW_COMPONLY , ," is compilation only"
THROW_MSGS LINK, THROW_NAMEREQD , ," requires a name"

\ кусок, отвечающий за поиск сообщения
… THROW_MSGS
BEGIN @ ?DUP
WHILE DUP CELL+ @ LAST-ERROR =
IF 2 CELLS+ ?TYPE PTRNULL THEN
REPEAT …

То есть все сообщения находятся в статической области памяти и разделяют пространство кода/данных, но все сообщения связаны в список, каждая запись в котором содержит: ссылку на предыдущее сообщение, код сообщения, и само сообщение. Таким подходом «убивается несколько зайцев»:
- сообщения можно добавлять в список по необходимости,
- сообщения можно перекрывать новыми с таким же кодом,
- нет необходимости специальным образом сохранять и загружать список сообщений.
Недостаток тот же, что и у СПФа – не читабельны самые важные места в коде, которые и вызывают сообщение.

А что, если у каждого метода взять лучшее?
Собственно, ведь нам не так много нужно! Хочется, чтобы было удобно и понятно в тексте программы отслеживать сообщения, хочется, чтобы сообщения можно было менять, например, перевести на другой язык, в процессе работы с программой даже не имея ее исходных текстов, хочется, чтобы сообщения не загромождали код программы. И еще иногда все же удобно работать с номерами сообщений, например, в местах вызова сообщений.
USER msg-list \ ссылка на последнее сообщение в списке
USER-VALUE last-msg \ номер последнего созданного сообщения

0 \ формат записи сообщения
CELL -- off_msgPrev \ адрес предыдущего сообщения
CELL -- off_msgName \ номер текущего сообщения
1 -- off_msgBody \ строка сообщения вместе со счетчиком длины
CONSTANT /msgRecord

\ добавить новое сообщение в список сообщений
: new-msg ( asc # msg --> )
OVER /msgRecord + ALLOCATE THROW
TUCK off_msgName !
DUP >R off_msgBody SCOPY
R@ msg-list CHANGE
R> off_msgPrev ! ;

\ найти сообщение в списке сообщений по его номеру
: find-msg-num ( msg --> asc # true | msg false )
>R msg-list @
BEGIN DUP WHILE
DUP off_msgName @ R@ <> WHILE
off_msgPrev @
REPEAT RDROP off_msgBody COUNT TRUE EXIT
THEN R> SWAP ;

\ найти номер сообщения по содержимому сообщения
: find-msg-body ( asc # --> msg | asc # false )
2>R msg-list @
BEGIN DUP WHILE
DUP off_msgBody COUNT 2R@ COMPARE WHILE
off_msgPrev @
REPEAT off_msgName @ RDROP RDROP EXIT
THEN 2R> ROT ;

\ найти номер для следующего сообщения
: num-msg ( --> err )
last-msg BEGIN 1 + DUP find-msg-num WHILE 2DROP REPEAT TO last-msg ;

\ найти сообщение в списке msg-list, отобразить его текст
\ если сообщения с указанным индексом err не найдено, отобразить индекс
: ~MESSAGE ( err --> ) find-msg-num IF ELSE 0 (D.) THEN >STDERR ;

\ отобразить сообщение с номером msg если flag отличен от нуля,
\ выполнить THROW с кодом msg, если флаг = 0 действия не выполняются
: (ABORT) ( flag msg --> )
SWAP IF DUP ~MESSAGE THROW ELSE DROP THEN ;

\ по содержимому строки asc # определить номер сообщения
: reffered ( asc # --> msg )
find-msg-body DUP IF ELSE DROP num-msg DUP >R new-msg R> THEN ;

\ компилировать код, в случае ошибки выводящий сообщение message
: ABORT" ( / message" --> )
?COMP [CHAR] " PARSE reffered
[COMPILE] LITERAL POSTPONE (ABORT) ; IMMEDIATE

\ компилировать код, выводящий сообщение message
: MESSAGE" ( / message" --> )
[CHAR] " PARSE reffered
STATE @ IF [COMPILE] LITERAL POSTPONE ~MESSAGE
ELSE DROP \ в режиме интерпретации сообщение
\ добавляется к списку сообщений
THEN ; IMMEDIATE

Теперь в тексте можно везде писать так, как и в самом первом случае: … ABORT” какая-то там ошибка!” …
Причем, такое сообщение может многократно присутствовать в исходных текстах программы, но в коде в каждом таком месте будет скомпилирован только номер сообщения, а не само сообщение, для чего каждый раз само сообщение ищется в списке msg-list, и если находится, то номер уже существующего сообщения используется. Этим мы добиваемся читабельности текстов.

Все сообщения, добавленные в систему, необходимо будет сохранить на диск в отдельный файл таким образом, чтобы одна строка соответствовала одному сообщению, и в начале каждой строки присутствовал номер сообщения (то есть так же, как в СПФ).
\ сохранить все сообщения в файл с указанным именем
: save-messages ( asc # --> )
W/O CREATE-FILE THROW >R
msg-list
BEGIN @ DUP WHILE
DUP off_msgName @ 0 (D.) R@ WRITE-FILE THROW
S" " R@ WRITE-FILE THROW
DUP off_msgBody COUNT R@ WRITE-FILE THROW
LT LTL @ R@ WRITE-FILE THROW
off_msgPrev
REPEAT DROP R> CLOSE-FILE THROW ;

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

Загрузка списка сообщений:
\ загрузить список сообщений в память из файла Asc #
: load-messages ( asc # --> ) FILE>HEAP
IF SAVE-SOURCE N>R SOURCE! 0 >IN !
BEGIN NextWord DUP WHILE
val >R 0x0D PARSE R> new-msg 1 >IN +!
REPEAT 2DROP
NR> RESTORE-SOURCE
ELSE -1 THROW
THEN ;

Необходимо учитывать, что для хранения строк сообщений используется хип, а это значит, что для каждого потока сообщения будут локальны, то есть в каждом потоке можно использовать собственный набор сообщений. Для хранения сообщений используется линейный список, а это значит, что для сотен тысяч сообщений лучше модифицировать методику хранения сообщений для более быстрого поиска сообщений, как по номеру сообщения, так и по содержимому. Причем, повышение скорости поиска по содержимому ускорит время компиляции кода, в то время, как по номеру – ускорит поиск во время работы готовой программы. Для пары сотен сообщений скорости поиска по линейному списку вполне достаточно для нормальной работы. Рабочую библиотеку можно взять в spf\devel\~mOleg\lib\strings\msg.f с cvs.

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

Литература:


1. spf\devel\~mOleg\lib\strings\messages.f , messages.dsc
2. spf\devel\~mOleg\lib\strings\msg.f
3. исходные тексты системы info-forth 4 версии text.scr
4. исходные тексты системы SPF версии 4.17 и выше
5. исходные тексты системы Win32Forth


Последний раз редактировалось mOleg Пн апр 27, 2009 03:25, всего редактировалось 3 раз(а).

Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пн дек 08, 2008 21:28 
Не в сети

Зарегистрирован: Пн окт 15, 2007 17:24
Сообщения: 164
Откуда: Бийск
Благодарил (а): 0 раз.
Поблагодарили: 2 раз.
Цитата:
Вывод:
Все перечисленные методики часто встречаются с небольшими модификациями в программах, причем, может использоваться несколько вариантов одновременно, в зависимости от удобства применения. Так что как всегда стоит в каждом конкретном случае выбирать наиболее удобный вариант и модифицировать под конкретные условия.

Пожалуй, этот абзац можно без малейших изменений вставлять в конец любой статьи ...

_________________
And so forth ...


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пн дек 08, 2008 21:58 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
Цитата:
Пожалуй, этот абзац можно без малейших изменений вставлять в конец любой статьи ...

и тут он не помеха

_________________
понимаю некоторую бестолковость некоторых вопросов


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 10, 2008 04:11 
Не в сети

Зарегистрирован: Сб май 06, 2006 12:01
Сообщения: 959
Откуда: Украина, Харьков
Благодарил (а): 2 раз.
Поблагодарили: 7 раз.
Из опыта реальных разработок дальнейшие расширения идеи:
  1. резервировать место для некоторого количества сообщений(которые можно добавить позже)
  2. выбирать одно сообщение из группы по задаваемому программой индексу, возможно с использованием масок(требуется выравнивание номеров сообщений на какое-то число)
  3. возможность иметь короткие тексты сообщений(алиасы, сленг), которые опционально заменять на более подробные/точные(возможно, в отдельном редакторе)

_________________
With best wishes, in4.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Чт дек 11, 2008 01:19 
Не в сети

Зарегистрирован: Сб май 06, 2006 12:01
Сообщения: 959
Откуда: Украина, Харьков
Благодарил (а): 2 раз.
Поблагодарили: 7 раз.
mOleg писал(а):
in4 писал(а):
выбирать одно сообщение из группы по задаваемому программой индексу, возможно с использованием масок(требуется выравнивание номеров сообщений на какое-то число)

не совсем понял о чем речь. Речь о нескольких списках сообщений?

Нет. В одном списке сделать, например вывод скорости обмена (из нескольких строк общего списка) по содержимому регистра. Или признаки файла(в текстовом виде) по байту состояния.
Т.е. к базе такого подсписка прибавил (за OR-ил) еще число для вывода определенной строки.
mOleg писал(а):
in4 писал(а):
возможность иметь короткие тексты сообщений(алиасы, сленг), которые опционально заменять на более подробные/точные(возможно, в отдельном редакторе)
А зачем? в случае отсутствия списка сообщений будет выдаваться код сообщения. Понятно, что код особо полезной информации не несет.
Хочется чтоб можно было называть в тексте "нету файла", "глюк системы", а при расшифровке выводилось "необходимый файл отсутствует на диске", "системная ошибка" и т.п.
Применение сленга упрощает запоминание и позволяет более разнообразно и красочно называть ситуации.
Да и при переводе удобно, исходник не надо трогать. Разве что комментарии... ;)

_________________
With best wishes, in4.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Чт дек 11, 2008 19:27 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 4954
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 18 раз.
Поблагодарили: 56 раз.
in4 писал(а):
не совсем понял о чем речь. Речь о нескольких списках сообщений?

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

если честно всеравно не понимаю, зачем такие сложности?
несколько сообшений подряд вывести не сложно

in4 писал(а):
Хочется чтоб можно было называть в тексте "нету файла", "глюк системы", а при расшифровке выводилось "необходимый файл отсутствует на диске", "системная ошибка" и т.п.

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

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт дек 16, 2008 03:56 
Не в сети

Зарегистрирован: Сб май 06, 2006 12:01
Сообщения: 959
Откуда: Украина, Харьков
Благодарил (а): 2 раз.
Поблагодарили: 7 раз.
mOleg писал(а):
если честно всеравно не понимаю, зачем такие сложности?несколько сообшений подряд вывести не сложно
просто удобство. И использование возможности получить часть текстов из документации... ;) И учесть возможность расширения без пересборки, например, либы. Оставить резерв на несколько сообщений - потом добавлять. Но либа со вкомпилированными константами работать будет. А выравнивание
mOleg писал(а):
можно сделать и более сложную реакцию на сообщения, например, таким образом, чтобы сообщение хранило не только строку, но и код, но это уже вариант словаря получится.
Если будут разрывы, то так и надо...

_________________
With best wishes, in4.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт дек 16, 2008 18:47 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 4954
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 18 раз.
Поблагодарили: 56 раз.
вообще я думал сделать словарь сообщений, но после длительных размышлений, отказался (то есть выигрыш не так велик, да и не понятно нужно ли).

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт дек 16, 2008 20:55 
Не в сети

Зарегистрирован: Ср сен 13, 2006 10:06
Сообщения: 636
Откуда: Омск
Благодарил (а): 0 раз.
Поблагодарили: 3 раз.
mOleg писал(а):
вообще я думал сделать словарь сообщений, но после длительных размышлений, отказался (то есть выигрыш не так велик, да и не понятно нужно ли).

А кстати неплохая мысль сделать словарь (подключаемую библиотеку) стандартных сообщений. А если можно еще что бы дополнительно и дополнительно подключаемых от разработчика.

_________________
Меня нет, не будет и не было.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 17, 2008 13:56 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 4954
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 18 раз.
Поблагодарили: 56 раз.
Pretorian писал(а):
А кстати неплохая мысль сделать словарь (подключаемую библиотеку) стандартных сообщений. А если можно еще что бы дополнительно и дополнительно подключаемых от разработчика.

уже есть :)
но не словарь, а просто список. Сообщения как в СПФе лежат в файле отдельном. У каждого потока может быть свой список.

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 10 ] 

Часовой пояс: UTC + 3 часа [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB