Автор |
Сообщение |
|
|
Заголовок сообщения: |
|
|
|
Pretorian писал(а): А кстати неплохая мысль сделать словарь (подключаемую библиотеку) стандартных сообщений. А если можно еще что бы дополнительно и дополнительно подключаемых от разработчика.
уже есть
но не словарь, а просто список. Сообщения как в СПФе лежат в файле отдельном. У каждого потока может быть свой список.
[quote="Pretorian"]А кстати неплохая мысль сделать словарь (подключаемую библиотеку) стандартных сообщений. А если можно еще что бы дополнительно и дополнительно подключаемых от разработчика.[/quote]
уже есть :)
но не словарь, а просто список. Сообщения как в СПФе лежат в файле отдельном. У каждого потока может быть свой список.
|
|
|
|
Добавлено: Ср дек 17, 2008 13:56 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
mOleg писал(а): вообще я думал сделать словарь сообщений, но после длительных размышлений, отказался (то есть выигрыш не так велик, да и не понятно нужно ли).
А кстати неплохая мысль сделать словарь (подключаемую библиотеку) стандартных сообщений. А если можно еще что бы дополнительно и дополнительно подключаемых от разработчика.
[quote="mOleg"]вообще я думал сделать словарь сообщений, но после длительных размышлений, отказался (то есть выигрыш не так велик, да и не понятно нужно ли).[/quote]
А кстати неплохая мысль сделать словарь (подключаемую библиотеку) стандартных сообщений. А если можно еще что бы дополнительно и дополнительно подключаемых от разработчика.
|
|
|
|
Добавлено: Вт дек 16, 2008 20:55 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
вообще я думал сделать словарь сообщений, но после длительных размышлений, отказался (то есть выигрыш не так велик, да и не понятно нужно ли).
вообще я думал сделать словарь сообщений, но после длительных размышлений, отказался (то есть выигрыш не так велик, да и не понятно нужно ли).
|
|
|
|
Добавлено: Вт дек 16, 2008 18:47 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
mOleg писал(а): если честно всеравно не понимаю, зачем такие сложности?несколько сообшений подряд вывести не сложно просто удобство. И использование возможности получить часть текстов из документации... И учесть возможность расширения без пересборки, например, либы. Оставить резерв на несколько сообщений - потом добавлять. Но либа со вкомпилированными константами работать будет. А выравнивание mOleg писал(а): можно сделать и более сложную реакцию на сообщения, например, таким образом, чтобы сообщение хранило не только строку, но и код, но это уже вариант словаря получится. Если будут разрывы, то так и надо...
[quote="mOleg"]если честно всеравно не понимаю, зачем такие сложности?несколько сообшений подряд вывести не сложно[/quote]просто удобство. И использование возможности получить часть текстов из документации... ;) И учесть возможность расширения без пересборки, например, либы. Оставить резерв на несколько сообщений - потом добавлять. Но либа со вкомпилированными константами работать будет. А выравнивание [quote="mOleg"]можно сделать и более сложную реакцию на сообщения, например, таким образом, чтобы сообщение хранило не только строку, но и код, но это уже вариант словаря получится.[/quote]Если будут разрывы, то так и надо...
|
|
|
|
Добавлено: Вт дек 16, 2008 03:56 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
in4 писал(а): не совсем понял о чем речь. Речь о нескольких списках сообщений?
Нет. В одном списке сделать, например вывод скорости обмена (из нескольких строк общего списка) по содержимому регистра. Или признаки файла(в текстовом виде) по байту состояния. Т.е. к базе такого подсписка прибавил (за OR-ил) еще число для вывода определенной строки. если честно всеравно не понимаю, зачем такие сложности? несколько сообшений подряд вывести не сложно in4 писал(а): Хочется чтоб можно было называть в тексте "нету файла", "глюк системы", а при расшифровке выводилось "необходимый файл отсутствует на диске", "системная ошибка" и т.п.
и так можно делать. Просто потом файл с сообщениями придется править в ручную в любом редакторе.
можно сделать и более сложную реакцию на сообщения, например, таким образом, чтобы сообщение хранило не только строку, но и код, но это уже вариант словаря получится.
[quote="in4"]не совсем понял о чем речь. Речь о нескольких списках сообщений?
Нет. В одном списке сделать, например вывод скорости обмена (из нескольких строк общего списка) по содержимому регистра. Или признаки файла(в текстовом виде) по байту состояния. Т.е. к базе такого подсписка прибавил (за OR-ил) еще число для вывода определенной строки.[/quote] если честно всеравно не понимаю, зачем такие сложности? несколько сообшений подряд вывести не сложно
[quote="in4"]Хочется чтоб можно было называть в тексте "нету файла", "глюк системы", а при расшифровке выводилось "необходимый файл отсутствует на диске", "системная ошибка" и т.п.[/quote]
и так можно делать. Просто потом файл с сообщениями придется править в ручную в любом редакторе.
можно сделать и более сложную реакцию на сообщения, например, таким образом, чтобы сообщение хранило не только строку, но и код, но это уже вариант словаря получится.
|
|
|
|
Добавлено: Чт дек 11, 2008 19:27 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
mOleg писал(а): in4 писал(а): выбирать одно сообщение из группы по задаваемому программой индексу, возможно с использованием масок(требуется выравнивание номеров сообщений на какое-то число) не совсем понял о чем речь. Речь о нескольких списках сообщений? Нет. В одном списке сделать, например вывод скорости обмена (из нескольких строк общего списка) по содержимому регистра. Или признаки файла(в текстовом виде) по байту состояния. Т.е. к базе такого подсписка прибавил (за OR-ил) еще число для вывода определенной строки. mOleg писал(а): in4 писал(а): возможность иметь короткие тексты сообщений(алиасы, сленг), которые опционально заменять на более подробные/точные(возможно, в отдельном редакторе) А зачем? в случае отсутствия списка сообщений будет выдаваться код сообщения. Понятно, что код особо полезной информации не несет. Хочется чтоб можно было называть в тексте "нету файла", "глюк системы", а при расшифровке выводилось "необходимый файл отсутствует на диске", "системная ошибка" и т.п.
Применение сленга упрощает запоминание и позволяет более разнообразно и красочно называть ситуации.
Да и при переводе удобно, исходник не надо трогать. Разве что комментарии...
[quote="mOleg"][quote="in4"]выбирать одно сообщение из группы по задаваемому программой индексу, возможно с использованием масок(требуется выравнивание номеров сообщений на какое-то число)[/quote] не совсем понял о чем речь. Речь о нескольких списках сообщений?[/quote] Нет. В одном списке сделать, например вывод скорости обмена (из нескольких строк общего списка) по содержимому регистра. Или признаки файла(в текстовом виде) по байту состояния. Т.е. к базе такого подсписка прибавил (за OR-ил) еще число для вывода определенной строки. [quote="mOleg"][quote="in4"]возможность иметь короткие тексты сообщений(алиасы, сленг), которые опционально заменять на более подробные/точные(возможно, в отдельном редакторе)[/quote]А зачем? в случае отсутствия списка сообщений будет выдаваться код сообщения. Понятно, что код особо полезной информации не несет.[/quote]Хочется чтоб можно было называть в тексте "нету файла", "глюк системы", а при расшифровке выводилось "необходимый файл отсутствует на диске", "системная ошибка" и т.п.
Применение сленга упрощает запоминание и позволяет более разнообразно и красочно называть ситуации.
Да и при переводе удобно, исходник не надо трогать. Разве что комментарии... ;)
|
|
|
|
Добавлено: Чт дек 11, 2008 01:19 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Из опыта реальных разработок дальнейшие расширения идеи:
- резервировать место для некоторого количества сообщений(которые можно добавить позже)
- выбирать одно сообщение из группы по задаваемому программой индексу, возможно с использованием масок(требуется выравнивание номеров сообщений на какое-то число)
- возможность иметь короткие тексты сообщений(алиасы, сленг), которые опционально заменять на более подробные/точные(возможно, в отдельном редакторе)
Из опыта реальных разработок дальнейшие расширения идеи:
[list=1][*]резервировать место для некоторого количества сообщений(которые можно добавить позже)[*]выбирать одно сообщение из группы по задаваемому [b]программой[/b] индексу, возможно с использованием масок(требуется выравнивание номеров сообщений на какое-то число)[*]возможность иметь короткие тексты сообщений(алиасы, сленг), которые опционально заменять на более подробные/точные(возможно, в отдельном редакторе)[/list]
|
|
|
|
Добавлено: Ср дек 10, 2008 04:11 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Цитата: Пожалуй, этот абзац можно без малейших изменений вставлять в конец любой статьи ...
и тут он не помеха
[quote]Пожалуй, этот абзац можно без малейших изменений вставлять в конец любой статьи ...[/quote]
и тут он не помеха
|
|
|
|
Добавлено: Пн дек 08, 2008 21:58 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Цитата: Вывод: Все перечисленные методики часто встречаются с небольшими модификациями в программах, причем, может использоваться несколько вариантов одновременно, в зависимости от удобства применения. Так что как всегда стоит в каждом конкретном случае выбирать наиболее удобный вариант и модифицировать под конкретные условия.
Пожалуй, этот абзац можно без малейших изменений вставлять в конец любой статьи ...
[quote]Вывод: Все перечисленные методики часто встречаются с небольшими модификациями в программах, причем, может использоваться несколько вариантов одновременно, в зависимости от удобства применения. Так что как всегда стоит в каждом конкретном случае выбирать наиболее удобный вариант и модифицировать под конкретные условия.[/quote]
Пожалуй, этот абзац можно без малейших изменений вставлять в конец любой статьи ...
|
|
|
|
Добавлено: Пн дек 08, 2008 21:28 |
|
|
|
|
|
Заголовок сообщения: |
Сообщения в форте |
|
|
Автор: 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
Автор: [url=http://fforum.winglion.ru/viewtopic.php?t=1240]mOleg[/url] Дата публикации: 2008-12-08 публикуется впервые
[color=blue][size=200]Сообщения[/size][/color]
[size=150][color=green]Аннотация[/color][/size] В статье обсуждаются методики организации, хранения и вывода текстовых сообщений, как принятых в существующих Форт-системах, так и новых. Так же обсуждаются преимущества и недостатки подходов к решению проблемы хранения сообщений.
[color=green][size=150]Самый простой вариант[/size][/color] Самый простой вариант – это литеральные строки в коде, например:
… S” простое сообщение” TYPE …
либо, как вариант сообщения вместе с ошибкой: … ABORT” простое сообщение об ошибке” ...
Этот метод хорош тем, что проще него придумать практически не возможно, но имеет ряд недостатков: -невозможно изменить текст сообщения без пересборки (перекомпиляции) кода, -сообщение находится в статическом пространстве программы, поэтому отнимает место у кода и данных, -одно и то же сообщение придется повторять в нескольких местах программы, если оно вызывается несколько раз, -невозможно просмотреть все сообщения программы, так как они разбросаны по коду программы. Тем не менее, использование литеральных строк для организации сообщений принятая практика.
[color=green][size=150]Одно слово – одно сообщение[/size][/color] Более универсальным вариантом, который является развитием предыдущего метода – оформлять каждое сообщение в отдельное слово, и уже это слово вызывать в случае необходимости. Причем, полученные таким образом сообщения могут самостоятельно принимать решения о необходимости вывода сообщения: [pre]: Err001 ( flag --> ) IF .” сообщение в отдельном определении” -1 THROW THEN ;[/pre] Имя сообщения (в нашем случае Err001) не обязательно должно быть цифробуквенным, и может быть вполне осмысленным. Тем не менее, недостатки остаются: - в собранном виде текст сообщения не изменить без перекомпиляции кода, - сообщение так же продолжает отнимать место у кода и данных. Тем не менее, все сообщения можно разместить в одном файле, и поэтому легче контролировать. Если сообщение вызывается из нескольких мест программы, дополнительного пространства на повторное включение текста, как это было в первом примере, не занимается. Но появляются новые недостатки: - расходуются имена в словаре на именование ошибок, - ошибки в тексте программы становятся не очень читабельными, особенно, если имя ошибки не содержит в закодированном виде информации о типе сообщения.
[color=green][size=150]Еще один классический метод[/size][/color] Еще одним методом работы с сообщениями любили пользоваться Форт-системы во времена ДОСа. Выглядело это примерно так: [pre]CREATE messages S” первое сообщение” S”, S” второе сообщение” S”, S” n-тое сообщение” S”,[/pre] Поиск сообщений в таком текстовом массиве выглядел так: [pre]: message ( u --> ) 0 messages 0 2SWAP DO + COUNT LOOP TYPE ;[/pre] Соответственно, чтобы вывести сообщение, необходимо было компилировать его код в виде литерала, а так же компилировать код, который бы умел находить по номеру сообщения само сообщение и выводить его куда необходимо: [pre]: Error ( u --> ) COMPILE message COMPILE ABORT ; IMMEDIATE[/pre] и в программе это используется так: [pre]… 123 Error …[/pre] Опять же, одни недостатки ушли, например, все сообщения находятся в одном месте, не расходуются имена слов. Основной недостаток у такого подхода заключается в том, что код сообщения не несет никакой информации о содержимом сообщения. И преимущества у нас следующие: - сообщения хранятся в одном месте, - сообщения могут храниться отдельно от кода.
[color=green][size=150]А что же у нас с СПФ?[/size][/color] Предыдущий вариант достаточно хорош, но его можно улучшить, например, сообщения можно хранить во внешнем файле, и подгружать в динамическую область памяти уже после запуска программы. Номер сообщения можно сделать произвольным, и хранить в теле самого сообщения. И в СПФ так и сделали: [pre]\ найти ошибку с номером 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 ;[/pre] А вот так: … 2 <> IF -2007 THROW THEN … выглядит вывод сообщения.
Итак, основной недостаток у такого подхода заключается в том, что код сообщения не несет никакой информации о содержимом сообщения, правда второй недостаток заключается в том, что при возникновении ошибки каждый раз файл со списком ошибок транслируется заново.
Но зато имеется много преимуществ: - сообщения хранятся в одном месте во внешнем файле, а значит - сообщения могут меняться независимо от кода программы и при новом запуске - сообщения могут грузиться (но не грузятся) в произвольный участок памяти, а это значит, что - количество сообщений может даже изменяться. Такой список сообщений легко поддерживать, но достаточно сложно отслеживать в коде, на то ли сообщение сделана ссылка, либо что означает конкретное сообщение с номером n.
[color=green][size=150]Вариант организации сообщений из Win32Forth[/size][/color] Win32Forth близок к традиционной схеме с массивом сообщений, и выглядит следующим образом: [pre]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 …[/pre] То есть все сообщения находятся в статической области памяти и разделяют пространство кода/данных, но все сообщения связаны в список, каждая запись в котором содержит: ссылку на предыдущее сообщение, код сообщения, и само сообщение. Таким подходом «убивается несколько зайцев»: - сообщения можно добавлять в список по необходимости, - сообщения можно перекрывать новыми с таким же кодом, - нет необходимости специальным образом сохранять и загружать список сообщений. Недостаток тот же, что и у СПФа – не читабельны самые важные места в коде, которые и вызывают сообщение.
[color=green][size=150]А что, если у каждого метода взять лучшее?[/size][/color] Собственно, ведь нам не так много нужно! Хочется, чтобы было удобно и понятно в тексте программы отслеживать сообщения, хочется, чтобы сообщения можно было менять, например, перевести на другой язык, в процессе работы с программой даже не имея ее исходных текстов, хочется, чтобы сообщения не загромождали код программы. И еще иногда все же удобно работать с номерами сообщений, например, в местах вызова сообщений. [pre]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[/pre] Теперь в тексте можно везде писать так, как и в самом первом случае: … ABORT” какая-то там ошибка!” … Причем, такое сообщение может многократно присутствовать в исходных текстах программы, но в коде в каждом таком месте будет скомпилирован только номер сообщения, а не само сообщение, для чего каждый раз само сообщение ищется в списке msg-list, и если находится, то номер уже существующего сообщения используется. Этим мы добиваемся читабельности текстов.
Все сообщения, добавленные в систему, необходимо будет сохранить на диск в отдельный файл таким образом, чтобы одна строка соответствовала одному сообщению, и в начале каждой строки присутствовал номер сообщения (то есть так же, как в СПФ). [pre]\ сохранить все сообщения в файл с указанным именем : 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 ;[/pre] Так как номера сообщений фиксируются в теле самого сообщения, порядок следования сообщений в файле может быть произвольным, в приведенном случае – обратным.
Загрузка списка сообщений: [pre]\ загрузить список сообщений в память из файла 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 ;[/pre] Необходимо учитывать, что для хранения строк сообщений используется хип, а это значит, что для каждого потока сообщения будут локальны, то есть в каждом потоке можно использовать собственный набор сообщений. Для хранения сообщений используется линейный список, а это значит, что для сотен тысяч сообщений лучше модифицировать методику хранения сообщений для более быстрого поиска сообщений, как по номеру сообщения, так и по содержимому. Причем, повышение скорости поиска по содержимому ускорит время компиляции кода, в то время, как по номеру – ускорит поиск во время работы готовой программы. Для пары сотен сообщений скорости поиска по линейному списку вполне достаточно для нормальной работы. Рабочую библиотеку можно взять в spf\devel\~mOleg\lib\strings\msg.f с cvs.
[color=geen][size=150]Вывод[/size][/color] Все перечисленные методики часто встречаются с небольшими модификациями в программах, причем, может использоваться несколько вариантов одновременно, в зависимости от удобства применения. Так что как всегда стоит в каждом конкретном случае выбирать наиболее удобный вариант и модифицировать под конкретные условия.
[size=150][color=green]Литература:[/color][/size]
[color=red][size=75] 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 [/size] [/color]
|
|
|
|
Добавлено: Пн дек 08, 2008 15:37 |
|
|
|
|