Forth https://fforum.winglion.ru/ |
|
Трансляторы Си в Форт https://fforum.winglion.ru/viewtopic.php?f=4&t=3389 |
Страница 1 из 3 |
Автор: | Total Vacuum [ Пт окт 06, 2023 02:37 ] |
Заголовок сообщения: | Трансляторы Си в Форт |
Загорелся внезапно идеей сделать транслятор Си в свой uf \ micro forth \ для самодельных Форт-процессоров. На сдачу должны получиться трансляторы из Си в традиционный Форт, а также, возможно, трансляторы с других близких и не очень по синтаксису ЯВУ в Форт. В грубом приближении можно утверждать, что любая программа на Форте - это всего лишь распечатка листьев/узлов синтаксического дерева, полученного в процессе трансляции какой-нибудь написанной на ЯВУ программы. А поскольку uf \ micro forth \ у меня выступает в роли ассемблера, то предполагаю, что скорость работы скомпилированных таким транслятором программ не будет неприлично низкой даже в случае, если выхлоп такого транслятора будет не самым качественным. Хотел оценить состояние дел в этой области на сегодня, но Гоголь-поисковик по запросу "c2forth compiler" не выдает чего-то заслуживающего внимания: пара ссылок на сайт mpe, где вроде как должен лежать их c2forth, но ссылка с их сайта на их же продукт битая, еще имеется ссылка на гитхаб, где непонятное подмножество си транслируется в некий эзотерический форт, вот вроде бы и все. Почему-то для меня это удивительно. Неужели все теперь только в условный LLVM транслируют и не заморачиваются? ![]() Что касается моей поделки, то степень готовности примерно 50%: осталось подправить адресную арифметику, не реализовано несколько операторов (break, continue, goto, switch, case), из базовых типов на первом этапе будут только char и int (short/long - синонимы) (а, например, для 16-битных Форт-процессоров даже char будет синонимом int) и массивы/структуры/указатели на их основе, в перспективе добавлю float, ну и по мелочи некоторые вещи доделать нужно типа инициализации, препроцессор пока даже не начинал - это по сути отдельный язык со своим синтаксисом, начну не раньше, чем будет готов хотя бы на 90% транслятор. ![]() |
Автор: | Hishnik [ Сб окт 07, 2023 20:24 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Еще ведь важный вопрос - как? С точки зрения архитектуры, алгоритмов, практических подходов. Потому что на уровне "где скачать" - это как-то даже скучно. |
Автор: | Total Vacuum [ Вс окт 08, 2023 16:42 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Безусловно, скачивать чужое не вариант. И не только потому, что скучно. Но и потому, например, что лично мне проще свое написать, чем с чужим разбираться и переделывать. Да и скачивать-то по сути нечего, всё какие-то наколенные поделки попадаются, мое в любом случае не хуже будет в итоге. Какие-то идеи подсмотреть, конечно же, интересно, но не более того ![]() Пока все крутится вокруг таблицы символов. Изначально предполагалось, что это будет массив структур и что таких таблиц будет несколько. Но потом пошел по пути наименьшего сопротивления, а также держал в уме, что в перспективе код захочется переписать на Форте, поэтому на данный момент осталась одна таблица, причем не в виде массива структур, а просто несколько отдельных массивов под каждое поле. Все-таки писанины будет меньше без постоянных обращений к полям структуры. В дальнейшем переделаю через указатели, т.к. доступ к таблице по индексу тоже добавляет писанины. Поля таблицы такие: - id - идентификатор; - mod - модификаторы типа; - type - номер типа; - size - размер; - addr - адрес для глобальных переменных/смещение для параметров функции, локальных переменных или полей структуры; - scope - область видимости; и т.д. Это не полный и не окончательный перечень полей: какие-то будут добавляться или удаляться в процессе. Например, для кода Код: struct point { int x , y , color ; } ( * f [ 10 ] ) ( char a , char b ) ; получается такая таблица символов:void main ( ) { } Код: \ ### addr size sco de typ lv stk loc mod name \ \ 0 0 0 0 0 0 0 0 0 \ \ 1 0 0 0 0 0 0 0 0 void \ \ 2 0 1 0 0 0 0 0 0 char \ \ 3 0 2 0 0 0 0 0 0 int \ \ 4 0 6 0 0 0 0 0 6 {} struct point \ \ 5 0 2 4 1 3 0 1 2 x \ \ 6 2 2 4 1 3 0 1 2 y \ \ 7 4 2 4 1 3 0 1 2 color \ \ 8 0 20 0 0 4 0 1 20 [10]*() f \ \ 9 0 1 8 0 2 0 1 0 a \ \ 10 2 1 8 0 2 0 1 0 b \ \ 11 20 0 0 0 1 0 0 0 () main \ По этой таблице, например, f - это массив указателей на функцию, возвращающую тип 4, а тип 4 - это структура point. Эта таблица организована как стек, т.е. там есть push, swap, drop, но с другой стороны всегда имеем возможность изменить/прочитать любое поле по индексу в таблице. В процессе разбора выражений используется эта же таблица: подвыражения склеиваются в одну строку, в результате, например, printn ( a + b ) ; превращается в строку a @ b @ + printn, которая лежит в поле id одного из элементов таблицы, после завершения разбора каждого выражения и вывода соответствующей этому выражению строки на Форте элемент из таблицы удаляется. Пара мыслей по поводу аргументов функций и локальных переменных. Все вычисления в Форте производятся над содержимым стека данных, поэтому желательно передавать аргументы и возвращать результат работы функции через стек данных, то же самое можно сказать про локальные переменные. Но почему-то в Форте придумали команду pick (аналог команды @ для стека) для чтения произвольной ячейки из стека, а придумать команду для записи в произвольную ячейку стека (аналог команды ! для стека) забыли. Поэтому если мы передаем аргументы через стек, то мы не имеем возможность использования их в качестве локальных переменных. Поэтому либо аргументы в стеке (без возможности их модификации), либо в массиве с локальными переменными (возможность модификации есть, но каждый раз при входе в подпрограмму придется переносить значения со стека данных в массив). Пока аргументы в стеке данных, но переделать не проблема. |
Автор: | Total Vacuum [ Вс окт 15, 2023 01:40 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
![]() - система базовых типов, в си она чуть более развитая, обычно имеется минимум 4 целых типа 3-х и более разных размеров, а также штуки 3 float'a, а в среднестатистическом форте обычно есть целое и байт, часто есть поддержка двойных целых, опционально может присутствовать одна разновидность float, если же рассматривать форт-процессоры и форт для них, то там вполне может быть один единственный тип - целое; - строки, в си asciiz, а в тех фортах, где не asciiz-строки, есть строки со счетчиком, т.е. при трансляции из си придется дописывать 0 ей в хвост и убирать счетчик длины из гривы; - true, в си это 1, а в форте чаще всего -1, поэтому если подходить строго, придется при реализации логических операций, операций сравнения и т.д. накладывать маску 1 & на результат; - кадры стека при вызове функций си, понятно, что это лишь одна из возможных реализаций, тем не менее речь о присутствии в регистровых архитектурах возможности работы с кадром стека через отдельный регистр (например, bp), а в гипотетическом стековом процессоре (внезапно) и в не менее стековом форте возможность работы со стеком таким же способом сильно ограничена: отдельного регистра нет, более того, нет команды, которая пишет в стек на произвольную глубину, т.е. pick (аналог @ для стека) есть, а аналога ! не предусмотрено; Вроде не смертельный (возможно, неполный) перечень несовместимостей получается, с этим вполне можно жить ![]() |
Автор: | Total Vacuum [ Сб окт 28, 2023 02:11 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Небольшая демонстрация того, что пока получается: http://totalvacuum.ru/c2fdemo.zip В вариантах под spf (32-битный int, сам spf лежит здесь же) и gforth (64-битный int, проверял в онлайне на https://www.jdoodle.com/execute-forth-online/). в каждой папке транслятор uc.exe, исходники на Си (*.c) и результат их трансляции в Форт (*.f), также имеется файт c.f, в котором собраны основные прокладки между Си и Фортом, причем в варианте для spf он подключается автоматически через included, а для gforth-online надо сначала воткнуть содержимое этого файла в редактор на сайте, а потом добавлять к нему скомпилированные тесты. Примеры компилируются так: Код: uc.exe <hello.c >hello.f Но лучше сначала вывести на экран, чтобы убедиться, что не зависает, ибо проверок на ошибки нет:Код: uc.exe <hello.c Из забавного тут asm.c с примерами "ассемблерных" Форт-вставок и "ассемблерных" функций на Форте и redefine.c, где мы переопределяем операцию сложения (да, так можно, это ж транслируется в Форт! ![]() Препроцессор пока не начинал, комментариев, а также #include/#define пока нет, токены необходимо разделять пробелами (как в Форте ![]() Некоторый затык произошел с трансляцией switch-case: т.е. я легко могу оттранслировать это в фортовский case-of-endof, но это будет неправильно, ибо не все case обязаны заканчиваться break. А кроме того, case не во всех Фортах есть. И с break/continue/goto примерно того же сорта раздумия. ![]() |
Автор: | Hishnik [ Вс окт 29, 2023 22:58 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Интересно. А вот бы архитектуру этого всего, алгоритмы и идеи. |
Автор: | KPG [ Вс ноя 19, 2023 16:12 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Hishnik писал(а): Интересно. А вот бы архитектуру этого всего, алгоритмы и идеи. А, что в архитектуре решения, с точки зрения Фортёра, там может быть особенного? (вижу задачу -> делаю своё решение ![]() к Total Vacuum P.S. Ссылки на то как сам делал, при некотором оформлении и собирании архивов в актуальном виде, добавлю на форум или как сейчас могу отправить в личку (с каким то попутным Форт "мусором"), |
Автор: | Hishnik [ Вс ноя 19, 2023 19:40 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
KPG писал(а): А, что в архитектуре решения, с точки зрения Фортёра, там может быть особенного? (вижу задачу -> делаю своё решение Архитектура конкретного транслятора как раз особенна. Как получается код, какая модель памяти, как организовано взаимодействие с ОС и т.д. |
Автор: | Total Vacuum [ Вс ноя 19, 2023 22:35 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
KPG писал(а): Ссылки на то как сам делал, при некотором оформлении и собирании архивов в актуальном виде, добавлю на форум или как сейчас могу отправить в личку (с каким то попутным Форт "мусором"), Было бы здорово, тема как раз для того и создана, чтобы сравнивать/обсуждать существующие решения и рожать свои ![]() Пока рано говорить про архитектуру в отношении транслятора на полторы тысячи строк (сейчас именно столько, но не думаю, что в итоговом варианте сильно больше будет, ибо в коде много лишних комментариев и лишних кусков кода), т.к. еще далеко до завершения и еще сто раз все поменяется. Да и стыдно пока такие исходники показывать ![]() У меня, увы, круг интересов временно сместился с "написать транслятор си-в-форт" на "скачать и установить голый виндоус без регистрации и смс" ![]() ![]() Что касается самого транслятора, то до апокалипсиса с виндой успел прикрутить туда break/continue, но только в версию для uf \ micro forth \, а для традиционного форта еще в этом месте подумать придется. Ну и, кстати, в итоге получается компилятор под что угодно, т.к. перелопатить uf \ micro forth \ под любую платформу не составляет труда. Например, под Dendy (NES): http://totalvacuum.ru/nescdemo.zip ![]() |
Автор: | Hishnik [ Чт ноя 23, 2023 02:16 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
При наличии хотя бы минимального опыта самым интересным становится выяснение, как можно запустить очередной вариант Форта. Сколько ж можно переписывать dup... Важнее выяснить, как сделан стек и как к нему обращаться. Как можно скомпилировать слово и вызвать его (машинный код? указатель на функцию? специальный токен и адресный интерпретатор?). Как взаимодействовать с операционной системой - например, файл прочитать, взяв для этого данные со стека. Как на экран что-то вывести. И так далее. А наполнение словами потом пойдет. |
Автор: | Total Vacuum [ Ср мар 20, 2024 01:02 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Что-то все притихли подозрительно... ![]() Мой транслятор си-в-форт понемногу развивается, хотя только урывками и гораздо медленне, чем хотелось бы. На сегодня реализованы: Код: - объявления (auto register static extern typedef void char short int long float double signed unsigned struct enum typedef-name const volatile); Конечно, я изначально немного упростил себе задачу: из базовых типов реализованы только void/char/int/struct/union и массивы/указатели для всего этого безобразия, short/long/float/double/signed/unsigned пока являются синонимами int, а auto/register/static/extern/const/volatile пока игнорируются. Операторы реализованы все, но некоторые работают только в версии под мой микрофорт, а с классическим фортом работать не будут (case default switch goto continue break), точнее, можно было бы безболезненно реализовать трансляцию конструкции switch-case-break-default, но только в варианте с принудительным break после каждого case, также есть мысли по поводу прочего (goto continue break), но по большому счету версия под классический форт - это в моем случае побочная ветка, она тоже развивается параллельно с версиями под другие платформы, но некоторые сложные и неочевидные вещи поставлены на паузу - операторы (case default expr {} if else switch while do for goto continue break return); - выражения (, = *= /= %= += -= <<= >>= &= ^= |= ?: || && | ^ & == != < > <= >= << >> + - * / % (type-name) ++ -- & * + - ~ ! sizeof [] () . -> ++ -- id num chr str (expr)); ![]() Код: void printc ( char c ) ; Выводитvoid printn ( int n ) ; void prints ( char * s ) ; int va_count ( ) ; int va_arg ( int n ) ; void printf ( char * fmt , ... ) { char * p = fmt ; int n = 0 ; char c ; while ( c = * p ++ ) { if ( c == '%' ) { switch ( c = * p ++ ) { case 'c' : printc ( va_arg ( n ++ ) ) ; break ; case 'X' : printn ( va_arg ( n ++ ) ) ; break ; case 's' : prints ( va_arg ( n ++ ) ) ; break ; default : printc ( c ) ; } } else printc ( c ) ; } } void main ( ) { printf ( "%c%X, %s%c" , 'H' , 0xE110 , "WORLD" , '!' ) ; } Код: HE110, WORLD! Сейчас сделано нестандартно, но это вынужденно, т.к. препроцессора и, соответственно, макросов пока нет, но как только появятся, с переходом к стандартным va_list/va_start/va_arg/va_end никаких проблем не будет.По большому счету, из глобальных недоделок нереализованными остались только указатели на функции и параметры/результат типа struct. А дальше можно будет приступать к препроцессору, добавлять float и т.д. Немного забавного. Присваивание структур транслируется в что-то вроде Код: s0 s1 16 <memcpy> Здесь s0, s1 - указатели на структуры, 16 - размер в байтах структуры s0, которая стоит в левой части оператора присваивания, а <memcpy> тупо пересылает указанное количество байт из одной области памяти в другую. При этом никаких проверок на соответствие типов левой и правой части оператора присваивания нет и в помине. А что же будет, если в левой части указать имя массива, а в правой, например, строку или другой массив? Правильно! ![]() Код: char msg0 [ 32 ] , msg1 [ 16 ] ; транслируется в... msg0 = "hello, world" ; msg1 = msg0 ; Код: msg0 "hello, world" 32 <memcpy> msg1 msg0 16 <memcpy> Т.е. работает присваивание массивов, чего не должно быть в классическом Си. Понятно, что если добавить проверки на "скалярность" и "l-valуйность" левой части, то "проблема" решится, но пока решать "проблему" не планирую, т.к. главное, чтобы правильно написанный си-код транслировался правильно, а то, что транслируется и работает неправильный си-код, так это не смертельно ![]() ![]() И еще забавно, что в исходнике транслятора все так же примерно полторы тысяч строк, а скомпилированный при помощи tcc транслятор весит примерно 25Kb. Т.е. оно получается достаточно компактным и не очень сложным. ![]() Кстати, вопрост тут возник по поводу инициализации массивов. Есть ли какой-то красивый и элегантный способ инициализации строки в Гарварде? При условии, что память программ для чтения недоступна. У меня пока тупо каждый байт строки выкладывается в нужную ячейку RAM. Или можно сделать c ... c n addr <strinit>, т.е. посимвольно выложить в стек, сверху добить ее длиной и вызвать примитив, который распихивает символы по нужным адресам, но так можно только если стек большой. |
Автор: | Total Vacuum [ Пт фев 14, 2025 20:04 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Немного подтянул транслятор Си-в-Форт до уровня базовой версии (под мой микрофорт). Сделал конструкцию switch/case/break/default, а также break для циклов. По сути на сегодня версии отличаются только наличием/отсутствием continue и goto. Сразу скажу, что сделано не для скорости, а "для галочки". Но зато теперь есть возможность скомпилировать, например, dhrystone под обычный Форт. http://totalvacuum.ru/c2fdhry.zip В архиве 2 варианта: под 32 и 64 бита. 32-битный можно пощупать совместно с SPF, который есть тут же в архиве, а 64-битный онлайн, например, на https://tio.run/#forth-gforth. Компилируется так: Код: ucp.exe dhry.c >dhry.p Запускается с SPF так:uc.exe <dhry.p >dhry.f Код: spf4.exe c.f dhry.f Или так, если хотим вывести результаты в файл:Код: spf4.exe c.f dhry.f BYE>dhry.txt Сейчас циклы и switch дополнительно оборачиваются в конструкцию 1 0 do ... loop, поэтому спокойно транслируем break в leave и выходим из циклов/switch. Но с Irbis почему-то такой трюк не сработал. Поэтому там чуть другая реализация, которая не использует do/loop/leave, но будет работать только со switch, да и то не во всех ситуациях, но для dhrystone этого достаточно. И еще таймер что-то с наскока не заработал как планировалось, хотя сам таймер запускается и увеличивает счетчик, но только после завершения всех итераций dhrystone. Тем не менее, сам тест запускается и считает правильно. В архиве 2 варианта под вчерашний компилятор без do-loop (uc0.exe, dhry0.f) и под сегодняшний с do-loop (uc.exe, dhry.f). http://totalvacuum.ru/IRBIS/dhry.zip Ах, да, добавил стековые нотации для функций и переводы строки в тех местах, где каждый осмысленный фрагмент заканчивается, так что Форт-выхлоп компилятора местами стал вполне читаемым. Осталось автоматические отступы сделать в зависимости от глубины вложенности конструкций, тогда вообще шоколадно станет. Кстати, а в Форте есть возможность объявить слово, которое будет определено (реализовано) когда-нибудь потом? Ну, например, сейчас реализуем drawline и активно используем putpixel, а сам putpixel реализуем позже. Ну или взаимная рекурсия как реализуется, когда слову A нужно использовать слово B, а слову B в свою очередь позарез нужно вызывать слово A. Понятно, что можно переменную объявить, позже записать туда адрес и прыгать на него, но все же. Есть ли в Форте "штатные" средства для этого? |
Автор: | Hishnik [ Пт фев 14, 2025 21:34 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Total Vacuum писал(а): Кстати, а в Форте есть возможность объявить слово, которое будет определено (реализовано) когда-нибудь потом? Ну, например, сейчас реализуем drawline и активно используем putpixel, а сам putpixel реализуем позже. Ну или взаимная рекурсия как реализуется, когда слову A нужно использовать слово B, а слову B в свою очередь позарез нужно вызывать слово A. Понятно, что можно переменную объявить, позже записать туда адрес и прыгать на него, но все же. Есть ли в Форте "штатные" средства для этого? Оно примерно так и делается. Это первоначально называлось VECT, от "слово с векторным полем кода". В него записывался адрес слова, а при выполнении происходил переход на него. VECT pixel : drawline ... pixel // слово в словаре есть, так что можно компилировать ; : my_pixel ... ; ' my_pixel to pixel В '94 вместо VECT записали DEFER с тем же поведением. В целом VECT действительно не вполне удачное имя, потому что поясняет не то, что делает слово, а то, как оно устроено внутри ("векторное поле кода"... ну и что, собственно? Таким образом можно не только адреса для будущего перехода хранить). Вполне можно писать VIRTUAL или POINTER, хотя VIRTUAL pixel сразу дает понять, что это пока "заглушка" для функции, а pointer может указывать и на структуру данных. |
Автор: | Total Vacuum [ Вт фев 18, 2025 22:40 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Запустил на нескольких компьютерах spf4 со "скомпилированным" dhrystone, добавил в архив результаты. Если сравнивать с сишным компилятором tcc, то проигрыш в 5-6.5 раз. Достойный ли результат? Безусловно. Особенно если учесть, что: - сишные примитивы в файле c.f реализованы на скорую руку на Форте, а не ассемблере, по опыту для других платформ, даже если memcpy/strcpy/strcmp переписать на ассемблере, станет раза в полтора быстрее; - транслятор пока без каких-либо оптимизаций, да даже константные выражения не вычисляются на этапе компиляции; - каждый цикл и switch обернуты (в большинстве случаев без необходимости) в 1 0 do ... loop, чтобы была возможность покинуть цикл/swicth по leave (сишный break), а чтобы понять, что обертка не нужна, нужен второй проход, но я пока делаю в самом простом однопроходном варианте; - пролог/эпилог <enter>/<leave> нужен только для функций, использующих локальные параметры, но сейчас добавляется поголовно для всех, тут опять же нужен второй проход; - строки каждый раз преобразовываются в формат asciiz, который принят в си, и т.д. и т.п., и таких мелочей куча. |
Автор: | Victor__v [ Чт фев 20, 2025 18:12 ] |
Заголовок сообщения: | Re: Трансляторы Си в Форт |
Total Vacuum писал(а): Запустил на нескольких компьютерах spf4 со "скомпилированным" dhrystone, добавил в архив результаты. Если сравнивать с сишным компилятором tcc, то проигрыш в 5-6.5 раз. Достойный ли результат? Безусловно. Особенно если учесть, что: - сишные примитивы в файле c.f реализованы на скорую руку на Форте, а не ассемблере, по опыту для других платформ, даже если memcpy/strcpy/strcmp переписать на ассемблере, станет раза в полтора быстрее; - транслятор пока без каких-либо оптимизаций, да даже константные выражения не вычисляются на этапе компиляции; - каждый цикл и switch обернуты (в большинстве случаев без необходимости) в 1 0 do ... loop, чтобы была возможность покинуть цикл/swicth по leave (сишный break), а чтобы понять, что обертка не нужна, нужен второй проход, но я пока делаю в самом простом однопроходном варианте; - пролог/эпилог <enter>/<leave> нужен только для функций, использующих локальные параметры, но сейчас добавляется поголовно для всех, тут опять же нужен второй проход; - строки каждый раз преобразовываются в формат asciiz, который принят в си, и т.д. и т.п., и таких мелочей куча. Хех, пока одни пишут трансляторы си в форт, ВПС пишет оптимизатор форта на форте для форта с маш.кодами just for lulz. Эх, заняться бы чем-то более практичным на форте... |
Страница 1 из 3 | Часовой пояс: UTC + 3 часа [ Летнее время ] |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |