Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Win32FORTH
DF2 :: ФОРУМЫ > Основные форумы > Софт и железо > Программирование / Coding
Guevara-chan
...Идея написать подобный мини-учебник крутилась у меня в голове достаточно давно. Увы, реализацию приходилось каждый раз откладывать по самым различным причинам. И вот, наконец, решилась... Предупреждаю сразу: данная серия статей рассчитана на тех, кто понимает хотя бы основы программирования. Впрочем, если вы к ним не относитесь, то что вы вообще делается в данном разделе) ?

Lesson: 0.Основы
Win32FORTH является бесплатной open-source реализацией языка FORTH под (кто бы мог подумать...) семейство ОС Windows. Его компилятор, равно как и все вспомогательные элементы (IDE, Visual Editor) полностью написаны на нем самом. Единственное исключение представляет собой консоль диалоговой среды (Wincon.dll), но и от этого собираются избавиться в будущих версиях. Официальная страница проекта: http://www.win32forth.org.

Теперь немного о самом Форте. Являясь формально языком высокого уровня он, тем не менее, допускает ассемблерные вставки и прямой доступ к памяти. последний, к слову, был изначально единственным способом работы с любыми данными (даже переменными), ибо они традиционно хранились виде указателей. Сейчас, конечно, ситуация сильно смягчилась за счет введения ООП да и просто слова Value. Другой бесспорно любопытной особенностью данного семейства языков является их ориентированность на работу со стеком, вылившаяся в повсеместное использование польской нотации. Хорошо это или плохо - вопрос интересный, однако именно этот факт, в свое время, обеспечил сравнительно невысокую популярность Форта (в т.ч. из-за трудностей с переносом программ). Наконец, последняя вещь, на которую стоит обратить внимания новичку: это одновременная компилируемость и интерпретируемость языка. Кто-то, возможно, возразит что подобное уже было в QB\VB(до .NET), но это не верно: там ситуация совершенно другая. В Форте нет различий между компилятором и интерпретатором, они оба спокойно умещаются в одной программе и активируются банальной сменой одной переменной. Если что-то непонятно - это не страшно, позднее я разберу этот нюанс поподробнее. А сейчас лучше опробовать все это дело на практике...
;Lesson

Lesson: 1.Первые_шаги
Скачиваем. Запускаем установщик. Поначалу все стандартно, потом зададут серию вопросов насчет ассоциирования файлов. “.F” и .”FPJ” лучше ассоциировать с IDE. В конце любуемся на перекомпиляцию всех программ из исходников. поздравляю, отныне у вас установлен Win32Forth. Именно по ярлыку с этим названием я и предлагаю кликнуть. Перед вами окно рабочей среда. Гипотетически любую программу можно написать прямо отсюда, однако нормальные (не)люди так не делают по ряду причин. Вот в качестве отладчика или калькулятора - это другое дело. Ну да я отвлеклась. Сейчас среда в режиме интерпретации. Этим и воспользуюсь, заставив ее выполнить сакраментальную (для тех кто читал соотв. книжку) задачу - сложить 2 и 3. Итак, набираем:
Код
2 3 +  CR .[quote](хе-хе, сюрприз - Shift+Ins тут не работает)
Жмем Enter, получаем ответ
[code]5  ok

...А теперь разберем поподробнее, что же мы, собственно, натворили:
----
2 - кладет на стек соотв. цифру (в режиме интерпретации).
3 - аналогично.
+ - складывает верхние значения стека.
CR - выводит на консоль 2 символа ASCII: 13 и 10 (для тупых - переводит строку)
. - выводит на консоль верхнее значение стека.
---
Ну, со сложением худо-бедно разобрались. А вот что у нас с более сложными вещами ? Строками, к примеру. Да ничего особенного. Тот же “Hello World” можно реализовать, как минимум, 2-мя способами:
Код
CR ." Hello, World !!!!!11oneone"
...или...
Код
S" Hello, World !!!!!11oneone" CR TYPE
(обратите внимание - пробел после кавычки критически необходим, иначе будет ошибка)

Ну, с первым вариантом, я думаю, все понятно: слово (так в FORTH’е принято обозначать почти все, привыкаем) .” выводит на консоль константную строку. Этот вариант более быстрый и вообще удобный. со вторым чуть сложнее: сначала S” формирует строку в специальном буфере (да, лучше бы ее потом оттуда перенести, причем желательно сразу в соотв. объект) и кладет на стек 2 (да, здесь такое возможно) значения: ее адрес и длину. TYPE же, наоборот, 2 верхних значения со стека снимает и, приняв их за адрес и длину, выводит на консоль. Кстати, в более ранних реализациях языка (PCForth, скажем) TYPE очень резво валило всю программу при неправильных аргументах (вроде пустого стека). Сейчас же: отделаетесь ошибкой -4 (stack underflow) или исключением “ACCESS_VILOATION” в зависимости от ситуации. Это называется прогресс. Едем дальше. Допустим, консоль вам ни разу не нравится, и вы хотите вызвать сообщение в стандартном всплывающем окошке... ОК, набираем:
Код
z" Hello, Windows ! " z" Смотрите все: " 0 0 MessageBox

Ener. Окошко. А точку после “ok” все заметили ? Так вот - их может быть до восьми штук (включитльно), и каждая из них символизирует оставшееся на стеке значение. В данном случае это системный код выполнения, который вернул MessageBox. Он нам сейчас не нужен, так что набираем DROP (сбрасывает со стека последнее значение). Да, кстати: в отличие от s”, z” добавляет в конце строки нулевой байт и кладет на стек только ее адрес. Узнали ? Да, это строки в стиле C. Их Win32FORTH тоже поддерживает, что в будущем очень пригодится вам при работе с API. Но это... Не кажется ли вам, что вызов несколько громоздкий ? 2 ноля (стиль и окно-владелец) неплохо бы убрать, да и DROP автоматический поставить тоже не помешает. Сейчас все поправим:
Код
: MyMsgBox 0 0 MessageBox DROP;

Итак, вот вы и создали свое первое слово. Это умение вам в будущем очень пригодится, так что поздравляю. А теперь разберем синтаксис:
---
: - создает в текущем словаре (об этом потом) новое именованное (да, бывают и безымянные) вхождение. Подпрограмму, проще говоря. Имя выбирается на основе следующего за двоеточием (и расположенного на той же строке) слова. Оно может содержать любые символы кроме пробелов и CR\LF (да-да, те самые 13 и 10). Да, можно использовать русские буквы. Вот только нечувствительность к регистру на них не распространяется, так что потом не удивляйтесь ошибке 13 (слово не определено)... А теперь самое главное: после двоеточия среда переходит автоматически в режим компиляции. Да, вы меня правильно поняли: содержимое слова интерпретировать нельзя, оно всегда сначала компилируется (в память). Это порождает некоторые нестыковки, но об этом позже. Пока просто примите за факт.
; - заканчивает определение тела слова и переводит среду обратно в режим интерпретации. Обратите внимание - в отличие от завершающей кавычки, точка с запятой должна быть отделена пробелом. Ну, или расположена на новой строке, что здесь почти одно и то же...
---
А, кстати ! Вы еще не заметили ? В подавляющем большинству случаев компретору (помесь компилятора и интерпретатора, заложенная в основу диалоговой среды Win32FORTH) абсолютно плевать как и в каком порядке вы расположите слова. Это вам не BASIC и даже не C - здесь нет понятия разделения строк вообще, так что программу можно компоновать почти как заблагорассудится. Единственная проблема: названия не переносятся, что мы и видели на примере двоеточия. Ну да я опять отвлеклась. Следите за руками:
Код
: MyMsgBox 0 0 MessageBox DROP;
String Txt
: Main
s" 2 + 3 = " Put: Txt
2 3 + S>D (D.) Add: Txt
Get: Txt DROP
z" Смотрите все:" MyMsgBox
; Main

Ничего не поняли ? ОК, разжевываю новые слова:
---
String - создает новый экземпляр класса “String”. В данном случае - именованный (“Txt”).
Класс этот хорош всем, кроме одного: он хранит строку в статическом виде. Отсюда и жесткое ограничение на кол-во символов: до 255 (парадокс: на самом деле размер буффера составляет 260 байт, но поскольку размер строки там хранится в одном байте, то больше 255 символов сохранить не удастся при всем желании). Нам, впрочем это сейчас не страшно. Кстати: объект - это тоже слово. Унификация.
Put: - метод класса string. Берет со стека 2 верхних значения и, приняв их за адрес и длину строки, запоминает в теле объекта (старое значение теряется). Да, в Win32FORTH сначала пишется метод, а потом уже имя объекта. Польская нотация, хоть и абсолютно в данном случае не уместная.
S>D - преобразует верхнее значение на стеке в число двойной точности. Оные в FORTHе принято хранить 2мя элементами стека, а для работы с ними существует отдельный инструментарий операторов (D+, D* и т.д.). Но это так, на будущее...
(D.) - форматирует верхнее число двойной точности на стеке в строку типа «адрес + длина» (далее будет обозначаться как S-формате), возвращая взамен соответствующие значения. А куда ? Правильно, на стек.
Add: - тоже метод. Вот только он не просто запоминает строку, а добавляет ее к текущему содержимому (в конец). Угу, конкатенация. Кстати, встроенного метода для вставки строки в начало/середину почему-то не предусмотрено, так что в случае чего вам придется писать свой. Это, впрочем, совсем не трудно.
Get: - уже догадались ? Ну, конечно же, данный метод возвращает запомненную в теле объекта строку на стек. В общепринятом S-формате. Но ! Поскольку строка в объектах класса String всегда хранится с нулевым байтом на конце, то обычный DROP преобразует ее в нужный для MessageBox Z-формат. Удобно happy.gif ! ...Что такое Z-формат, надеюсь, объяснять не надо))) ?
---
Итак, вот мы и написали первую более-менее представительную программу.) Конечно, там есть еще поле для оптимизации (пересчитывать каждый раз сумму константных значений - не самая лучшая идея), но для первого дня - совсем не плохо. Единственное что: надо бы попробовать сделать из вышеуказанного хозяйства приложение Windows. Предупреждаю сразу: “.DLL” пока уже/сделать нельзя. Да, раньше было можно, но потом оптимизация убила ту возможность. Ждем-с... Возвращаясь к теме .EXE’шников: вы там консоль не закрыли ? Если нет, то просто скопируйте туда следующее:
Код
' Main Turnkey "First Steps.EXE"

Enter. Любуемся на отчет о сборке. Так вот, упреждая вопросы: апостроф возвращает на стек адрес следующего за ним слова, тогда как TurnKey сохраняет текущее состояние (sic!) компретора в виде .EXE, уничтожая там системный словарь (потом, потом...) и назначая точкой вхождений верхнее значение стека. Да, имя .EXE указывается как и все остальные названия... С одним-единственным исключением: здесь допустимы пробелы, но лишь при условии что адрес будущего файла взят в кавычки. Разобрались ? Н вот и отлично. Теперь отправляемся в директорию, где установлен Win32FORTH, и ищем там... Угу, “First Steps.EXE” (кто бы мог подумать...). Запускаем. О чудо, работает ! Вот только... Откройте-ка теперь диспетчер задач и сделайте там сортировку по имена процессов. Висит. А почему висит ? Да есть один такой ма-а-а-ленький нюанс... Кстати, почти не документированный. Имя ему BYE. Это слово завершает исполнение программы. В рабочей среде оно не только не нужно, но и вредно (т.к. выходит из нее), а вот для .EXE’шников - попросту необходимо. Да, не очень удобно... Но кому сейчас легко) ? Переписываем код с учетом новообретенных знаний:

Код
: MyMsgBox 0 0 MessageBox DROP;
String Txt
: Main
s" 2 + 3 = " Put: Txt
2 3 + S>D (D.) Add: Txt
Get: Txt DROP
z" Смотрите все:" MyMsgBox
BYE;
' Main Turnkey "First Steps.EXE"

Ммм, вы заметили ? Перезапись идет не только без предупреждения, но даже и без какого-либо уведомления. Это можно поправить только вручную, а пока просто имейте в виду. Опять ищем, запускаем... Не висит ? Ну, вот и славно. Нормальные (не)люди, правда, так обычно не собирают (ибо зависимость от wincon.dll данной программе нафиг не нужна), но об этом - в следующий раз. До скорых встреч и счастливого кодинга !
;Lesson
jeayukūlmal
C первого раза не осилил happy.gif Уставший какой-то уже. Но в целом, молодец smile.gif Как говорится "пеши исчо"
Guevara-chan
Цитата(jeayukūlmal @ 03 Feb 2009, 18:55)
C первого раза не осилил happy.gif Уставший какой-то уже. Но в целом, молодец smile.gif Как говорится "пеши исчо"

Спасибо, постраюсь. Как говорится: "кто, если не мы ?".
packpaul
Слушай, а напиши есчо? Я тебе даже денюжку переведу на WebMoney или YandexДеньги.

Попутно есть вопрос:
Мне необходимо грузить пользовательскую dll-ку в программу (ibr.dll). Пока делаю это так:

Код
TRUE VALUE ?TURNKEY

winlibrary libr.dll
__STDCALL
2 PROC GetString

100 VALUE STR_BUF_SIZE
CREATE STR_BUF
STR_BUF_SIZE ALLOT

: MAIN
 STR_BUF 1+ STR_BUF_SIZE 1-
 SWAP CALL GetString 0<> IF ABORT" GetString() ERROR" THEN
 STR_BUF 1+ ZCOUNT NIP STR_BUF C!
 STR_BUF 1+ 0 0 0 MessageBox DROP

 ?TURNKEY IF BYE THEN
;

?TURNKEY
[IF]
NEEDS NoConsole.f

NoConsoleIO
NoConsoleInImage

' MAIN turnkey LibrTest2.exe
bye
[ELSE]
FSAVE LibrTest2.exe
[THEN]


Но вот если dll-ка пока отсутсвует, как осуществить позднее связывание?
Буду очень тебе благодарен.
Guevara-chan
Цитата
Слушай, а напиши есчо?

Да надо бы, спасибо за напоминание. Просто в свое время никто не заинтересовался, да и subj, по всей видимости, помер окончательно, вот я и плюнула... Да и вообще: http://www.liveinternet.ru/users/chrono_sy.../post110447569/

Цитата
Но вот если dll-ка пока отсутсвует, как осуществить позднее связывание?

Грузить ее в ф-ии Main через LoadLibrary - так никогда не ошибешся.
sim732
Может кто подскажет начинающему изучать Forth. Такая вот проблема - скачал инсталяцию с win32forth.org (файл ц32а61200). При установке NOD32 Antivirus
ругается на исполнимые файлы, а затем их удаляет. В чем фишка ?
Guevara-chan
В том, что глубокоуважаемым ESET'овцам было лень разбирать код соотв. trojan'а (Autorun.HK), и они просто скопировали в базу вирусов первую же попавшуюся им на глаза сигнатуру. Я им уже писала об этом - реакции 0.
sim732
Цитата(Chrono Syndrome @ 23 Sep 2009, 18:24)
В том, что глубокоуважаемым ESET'овцам было лень разбирать код соотв. trojan'а (Autorun.HK), и они просто скопировали в базу вирусов первую же попавшуюся им на глаза сигнатуру. Я им уже писала об этом - реакции 0.


Понял. Спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2025 IPS, Inc.