http://spf.sourceforge.net/docs/devel.ru.html
SPF -- самая "живая", выходит, система?
--
Best regards,
Sergey mailto:sergey.ka...@gmail.com
SP-Forth прекрасно умеет юзать длл:
http://spf.sourceforge.net/docs/intro.ru.html#dll
Особенности SPF
Краткое вступление для тех, кто уже знаком с какой-либо Форт-системой и стандартом ANS'94.
Последнее обновление: $Date: 2008/03/02 20:15:32 $
--------------------------------------------------------------------------------
[Русский] [Английский]
--------------------------------------------------------------------------------
Содержание
Установил SPF4. И где здесь что-куда?
Оптимизатор
Поддержка ANS
Как запускать и подключать файлы?
REQUIRE
Пути поиска файлов для INCLUDED
Модули
Регистро-зависимость
Ввод чисел
Вещественные числа (числа с плавающей точкой)
Структуры
Где FORGET?
Где NOT?
Где DEFER?
Как одним словом очистить стек?
Средства отладки
Комментарии
Строки
Генерация исполняемых модулей (exe-файлов)
Локальные и временные переменные
Подключение dll-библиотек
Callback'и
Слово NOTFOUND
Scattered colons
Многозадачность
Словари
Область видимости
Обработка исключений
--------------------------------------------------------------------------------
Установил SPF4. И где здесь что-куда?
Первое и самое важное - расположение ваших рабочих файлов. В дистрибутиве SPF есть каталог DEVEL, предназначенный для разработчиков (в том числе и вас). Создайте в ней ваш подкаталог, например, ~vasya. И теперь вы можете подключать ваши файлы написав сокращённый путь в виде ~vasya/prog/myprog.f. Это упрощает взаимный доступ к библиотекам и программам. Общепринято библиотеки класть в подкаталог lib, а примеры программ в prog.
В каталоге DEVEL собраны наработки других SP-Forth'еров, с кратким (очень кратким) их обзором вы можете ознакомиться в SPF_DEVEL, либо пройтись по файлам самому.
В каталоге samples/win/spfwc вы найдёте GUI фронтенд для SPF. Просто запустите compile.bat и скопируйте полученный бинарный файл spf4wc.exe в корневой каталог установки (рядом с spf4.exe).
--------------------------------------------------------------------------------
Оптимизатор
SPF - форт-система с подпрограммным шитым кодом, то есть компиляция проходит сразу в исполняемый код в виде цепочек CALL <адрес-cfa-слова>. Этот код можно запускать и непосредственно, но в системе по-умолчанию есть ещё и оптимизатор, который обрабатывает машкод для большего быстродействия, выполняя inline-подстановку и peephole-оптимизацию. Подробнее на ForthWiki: "Оптимизирующий компилятор".
Управление оптимизатором (значения по умолчанию работают в подавляющем большинстве случаев, вам скорее всего не нужны эти опции!)
DIS-OPT отключает макрооптимизацию
SET-OPT включает макрооптимизацию (по-умолчанию включена)
0 TO MM_SIZE отключает inline подстановку оптимизатора (помните что inline подстановка для DO LOOP и некоторый других слов выполняется ядром spf и не зависит от этой опции)
TRUE TO ?C-JMP включает оптимизацию хвостовой рекурсии (экспериментальная, по-умолчанию выключена, иногда глючит)
NB: Если вдруг ваша программа начинает выкидывать неожиданные фортели - отключите временно оптимизацию словом DIS-OPT, есть вероятность (очень маленькая!), что это может быть ошибка в оптимизаторе. Если это так - локализуйте её и напишите пожалуйста багрепорт.
Результат компиляции слова в виде машинного кода можно посмотреть вручную с помощью дизассемблера:
REQUIRE SEE lib/ext/disasm.f
SEE слово
или получить построчный листинг (форт-код и соответствующий машкод)
REQUIRE INCLUDED_L ~mak/listing2.f
S" файл, машкод которого хотим посмотреть" INCLUDED_L
\ листинг будет лежать рядом с подключаемым файлом
--------------------------------------------------------------------------------
Поддержка ANS
Максимального соответствия ANS'94 можно добиться подключив lib/include/ansi.f. Там определяются дополнительные наборы слов, некоторые заглушки и т. д.
Также исправляется нарушающая стандарт оптимизация слов из ядра для работы с файлами - OPEN-FILE, CREATE-FILE и другие неявно требуют строку оканчивающуюся нулём, тогда как стандарт этого не требует. lib/include/ansi-file.f при получении строки без нуля в конце самостоятельно добавляет нулевой байт. При этом имя файла копируется во временный динамический буфер, который остаётся неосвобожденным для последующего использования. При явном указании имени файла с помощью строчных литералов S" и строчных библиотек ~ac/lib/str*.f необходимости в этом исправлении нет, т.к. строки всегда заканчиваются нулем. Но при использовании не-SPF-библиотек это может пригодиться.
--------------------------------------------------------------------------------
Как запускать и подключать файлы?
В командной строке скормить файл SPF'у можно просто указав путь к нему в параметрах запуска,
spf.exe ~vasya/prog/myprog.f
Заметьте, что путь для включения могут быть как абсолютным, так и относительно каталога devel.
В консоли SPF (в режиме интерпретации) достаточно набрать имя файла:
~vasya/prog/myprog.f
В целях совместимости лучше подключать явно:
S" ~vasya/prog/myprog.f" INCLUDED
Но правильнее всего использовать REQUIRE.
--------------------------------------------------------------------------------
REQUIRE
В SPF есть нестандартное слово REQUIRE ("word" "file" -- ), где word - некоторое слово определённое в библиотеке file. Если слово word присутствует в контекстном словаре, REQUIRE считает, что библиотека уже была подключена и не загружает её. Так избегается двойная загрузка библиотек. Если же найти word не удаётся - библиотека подключается обычным образом (через INCLUDED). Например:
REQUIRE CreateSocket ~ac/lib/win/winsock/sockets.f
REQUIRE ForEach-Word ~pinka/lib/words.f
REQUIRE ENUM ~nn/lib/enum.f
NB: В качестве word выбирайте всегда наиболее уникальное слово из подключаемой библиотеки.
--------------------------------------------------------------------------------
Пути поиска файлов для INCLUDED
S" file.f" INCLUDED будет искать в перечисленных ниже местах в именно таком порядке
короткое имя файла file.f (т.е. в текущем каталоге)
PATH_TO_SPF.EXE/devel/file.f (т.о. удобно использовать чужие наработки),
PATH_TO_SPF.EXE/file.f (так подключаются стандартные либы и другие файлы из поставки SPF).
Если требуется указать больше путей поиска (например использовать форт код разделяемый между системами, или неважно - любой код вне дерева каталогов SPF который не может быть адресован относительно текущего файла), то можно либо переопределить FIND-FULLNAME (который VECT) либо использовать внешнюю либу - ~ygrek/spf/included.f.
TODO: Вынести отдельно
Тогда потребуется только прописать в spf4.ini
~ygrek/spf/included.f
with: my_path\
S" my path with spaces/" with
и все файлы будут искаться в my_path в дополнение к описанному выше алгоритму (my_path может быть как абсолютным так и относительно spf.exe).
--------------------------------------------------------------------------------
Модули
В SPF есть модули, которые позволяют скрывать некоторые внутренние слова библиотек выводя наружу только слова для взаимодействия.
MODULE: vasya-lib
\ внутренние слова
EXPORT
\ слова взаимодействия, видные снаружи, компилируются во внешний словарь.
DEFINITIONS
\ опять внутренние слова
EXPORT
\ ну вы поняли :)
;MODULE
Код MODULE: vasya-lib можно писать много раз - последующие вызовы будут докомпилировать слова в тот же модуль. На самом деле слово определённое через MODULE: это обычный словарь.
--------------------------------------------------------------------------------
Регистро-зависимость
SPF регистрозависим, то есть для него слова CHAR , Char и char - три разных слова. Сделать SPF независимым от регистра слова можно подключив файл lib/ext/caseins.f. По умолчанию, регистро-независимость включается сразу после подключения lib/ext/caseins.f.
Чтобы регистро-независимость временно выключать/включать, используйте переменную CASE-INS:
REQUIRE CASE-INS lib/ext/caseins.f
2 dup * .
CASE-INS OFF \ вернуть обратно режим зависимости от регистра
2 DUP * .
CASE-INS ON \ включить регистро-независимость
2 dup * .
--------------------------------------------------------------------------------
Ввод чисел
SPF позволяет вводить шестнадцатеричные числа вне зависимости от текущей системы счисления (значения переменной BASE) так:
0x7FFFFFFF
Если в числе последний символ будет точкой, то оно воспримется как двойное (то есть - 64-битное, занимающее две ячейки на стеке):
9999999999. 1. D+ D.
--------------------------------------------------------------------------------
Вещественные числа (числа с плавающей точкой)
Подключив либу lib/include/float2.f, можно вводить вещественные числа в формате [+|-][dddd][.][dddd]e[+|-][dddd]. То есть главным определителем что число вещественное, является наличие символа e.
Слова для работы с вещественными числам реализованы согласно стандарта ANS-94:
REQUIRE F. lib/include/float2.f
0.1e 0.2e F+ F.
FVARIABLE a
FPI a F!
a F@ F.
Для переноса целых двойных значений между стеком данных и float-стеком в SPF есть слова D>F ( D: d -- F: f ) и F>D ( F: f -- D: d ). При переносе нецелого значения на стек данных часть после запятой отбрасывается без округления. Есть также аналогичные слова для работы с одинарными значениями:
10 DS>F 3 DS>F F+ F>DS .
Так как для float-стека в SPF используется аппаратный стек сопроцессора, то его особенности нужно иметь в виду (закольцованность и ограниченность 8-ью ячейками).
--------------------------------------------------------------------------------
Структуры
Структуры в SPF создаются через слово -- (оно же FIELD). Пример:
0
CHAR -- flag
CELL -- field
10 CELLS -- arr
CONSTANT struct
Слова flag, field и arr будут прибавлять к адресу своё смещение относительно начала структуры. А в struct записан общий размер всей структуры. То есть, можно:
struct ALLOCATE THROW TO s \ взяли память из кучи под один экземпляр struct
1 s flag С! 10 s field ! \ записали значения в поля структуры
s arr 10 CELLS DUMP \ вывели содержимое массива в структуре
s FREE THROW \ сняли экземпляр struct
Структуры можно наследовать:
0
CELL -- x
CELL -- y
CONSTANT point \ у point два поля
point
CELL -- radius
CONSTANT circle \ у circle три поля: x, y, radius
point
CELL -- w
CELL -- h
CONSTANT rect \ у rect четыре поля: x, y, w, h
--------------------------------------------------------------------------------
Где FORGET?
FORGET нет. Но есть MARKER ( "name" -- ) (в lib/include/core-ext.f).
--------------------------------------------------------------------------------
Где NOT?
Слова NOT (лог. отрицание) в ядре SPF нет. Его можно добавить расширением ~profit/lib/logic.f. Также там определяются другие слова для работы логикой: >= (больше или равно) и <= (меньше или равно).
--------------------------------------------------------------------------------
Где DEFER?
Для создания "векторов" (DEFERred words) в SPF используется слово VECT ( "word" -- ). Присвоение действия вектору делается словом TO ( xt "word" -- ).
Если вам нужно использовать именно DEFER и IS, то эти слова можно подключить дополнительно из файла lib/include/defer.f.
Вариант с размещением ячейки вектора в USER-области потока называется USER-VECT ( "word" -- ). Обратите внимание: так как вектор порождённый USER-VECT на равных правах со другими переменными расположенными в USER-блоке (USER , USER-VALUE) заполняется нулём (что является неправильным xt), то выставить вектор в начальное значение нужно вам (например через AT-THREAD-STARTING).
--------------------------------------------------------------------------------
Как одним словом очистить стек?
Наберите lalala. Или bububu. Или лялятополя. Возникнет ошибка и стек сбросится. На самом деле стек сбросит слово ABORT, которое будет вызвано если интерпретатор не найдёт введённое слово. Ну а на самом-самом деле - это делается так: S0 @ SP!
--------------------------------------------------------------------------------
Средства отладки
Слово STARTLOG включает запись всего консольного вывода (TYPE, . -- любые слова, выводящие в stdout) в лог-файл spf.log в текущем каталоге. ENDLOG соответственно выключает такое поведение.
Больше средств в devel
--------------------------------------------------------------------------------
Комментарии
В SPF есть комментарий до конца строки \. Есть и обычные, скобочные, комментарии, которые к тому же ещё и многострочные. То есть:
\ комментарий до конца строки
( комментарий
и даже в несколько строк )
Есть слово \EOF которое делает комментарием всё идущее после него в файле. Таким образом удобно отделять примеры использования библиотеки от самой библиотеки.
word1 word2
\EOF
комментарий до конца файла
--------------------------------------------------------------------------------
Строки
В SPF в основном используются строки со счётчиком на стеке - т.е. два значения (addr u). Для записи строковых литералов (строковых констант) используется слово S", которое в зависимости от текущего режима выполняет несколько разные действия:
В режиме интерпретации строка находится во временном текстовом буфере разбора (TIB), и соответственно, работает только в пределах одной строки.
В режиме компиляции строка вкомпилируется непосредственно в шитый код определяемого слова.
NB: В память после символов строки добавляется один нулевой байт, в счётчике символов он не учитывается - это сделано для удобства работы с функциями WinAPI.
Слово S" создаёт т. н. статическую строку, она находится или в буфере, или в словарной структуре SPF. Для работы со динамическими строками, которые резервируются в "куче" и снимаются оттуда есть библиотека ~ac/lib/str5.f. Пример её использования:
REQUIRE STR@ ~ac/lib/str5.f
"" VALUE r \ создаём пустую строку
" мама, мама, " VALUE m
" что я буду делать?" VALUE w
m r S+ w r S+
r STYPE
> мама, мама, что я буду делать?
Кроме конкатенации строк можно использовать и подстановку (в том числе и других строк):
" 2+2={2 2 +}" STYPE
> 2+2=4
Исчерпывающее описание и более подробные примеры см. в самой библиотеке.
Надо также заметить что в ядре SPF поддерживается соглашение об именовании слов начинающихся с S-, и слов кончающихся -ED.
Префикс S- означает что слово принимает строку с явно заданной длиной (например есть SFIND в дополнение к стандартному FIND, есть SLITERAL к LITERAL).
Суффикс -ED есть в словах CREATED, INCLUDED, REQUIRED, ALIGNED. Он обозначает что это слово, в отличие от своего "корня", будет ожидать параметры на стеке, а не выбирать их из входного потока (или из глобальной переменной, как это происходит в случае с ALIGN и ALIGNED).
Например, стандартный CREATE берёт свой параметр из входного потока, тогда как CREATED явно забирает параметр со стека данных в виде начала строки и её длины.
--------------------------------------------------------------------------------
Генерация исполняемых модулей (exe-файлов)
Слово SAVE ( a u -- ) сохраняет всю форт-систему, включая все словарные структуры (кроме временных!) в исполняемый модуль путь к которому задаётся строкой a u. Точка входа определяется value-переменной <MAIN> для консольного режима и переменной MAINX для GUI. Режим определяется value-переменными ?CONSOLE и ?GUI. SPF-INIT? контролирует интерпретацию командной строки и подключение spf4.ini:
0 TO SPF-INIT?
' ANSI>OEM TO ANSI><OEM
TRUE TO ?GUI
' NOOP TO <MAIN>
' run MAINX !
S" gui.exe" SAVE
или
' run TO <MAIN>
S" console.exe" SAVE
--------------------------------------------------------------------------------
Локальные и временные переменные
Не входят в ядро, но подключаются:
REQUIRE { lib/ext/locals.f
\ пример простого использования
: test { a b | c d } \ a b инициализируются со стека, c и d нулями
a TO c
b TO d
c . d . ;
1 2 test
>1 2
> Ok
Подробное описание и примеры использования смотрите в самой библиотеке lib/ext/locals.f.
lib/ext/locals.f реализует синтаксис несовместимый со стандартом ANS-94. ANS-реализация локальных переменных есть в библиотеке ~af/lib/locals-ans.f:
REQUIRE LOCALS| ~af/lib/locals-ans.f
: plus LOCALS| a b |
a b + TO a
a b * ;
2 3 plus .
>10
> Ok
--------------------------------------------------------------------------------
Подключение dll-библиотек
Для функций использующих формат вызова stdcall (например Win32 API) :
WINAPI: SevenZip 7-zip32.dll
Для формата вызова cdecl (например msvcrt.dll) и функций с переменным числом параметров используйте :
REQUIRE CAPI: ~af/lib/c/capi.f
2 CAPI: strstr msvcrt.dll
Если нужно подключить все функции из dll-файла то можно использовать для stdcall :
REQUIRE UseDLL ~nn/lib/usedll.f
UseDLL "имя_библиотеки"
или:
REQUIRE DLL ~ac/lib/ns/dll-xt.f
DLL NEW: "имя_библиотеки"
Для cdecl :
REQUIRE USES_C ~af/lib/c/capi-func.f
USES_C "имя_библиотеки"
или:
REQUIRE SO ~ac/lib/ns/so-xt.f
SO NEW: "имя_библиотеки"
Генерация исполняемых модулей (exe-файлов)
http://spf.sourceforge.net/docs/intro.ru.html#save
Слово SAVE ( a u -- ) сохраняет всю форт-систему, включая все словарные структуры (кроме временных!) в исполняемый модуль путь к которому задаётся строкой a u. Точка входа определяется value-переменной <MAIN> для консольного режима и переменной MAINX для GUI. Режим определяется value-переменными ?CONSOLE и ?GUI. SPF-INIT? контролирует интерпретацию командной строки и подключение spf4.ini:
0 TO SPF-INIT?
' ANSI>OEM TO ANSI><OEM
TRUE TO ?GUI
' NOOP TO <MAIN>
' run MAINX !
S" gui.exe" SAVE
или
' run TO <MAIN>
S" console.exe" SAVE
Как создать -- пока не знаю; видимо, это "не стандартно" для SPF, к
сожалению. Как узнаю, напишу в группу сразу же.
Хотя можно посмотреть и другие системы VFX (но он только под Linux),
bigForth - его почти не копал.
--
Best regards,
Sergey mailto:sergey.ka...@gmail.com
Ну можно так попробовать:
\SP-Forth\devel\~pinka\lib\tools\exe2dll.f
А вообще поиск по слову dll в devel.
--
Best regards,
Sergey mailto:sergey.ka...@gmail.com