Forth http://www.fforum.winglion.ru/ |
|
Трансляторы Си в Форт http://www.fforum.winglion.ru/viewtopic.php?f=4&t=3389 |
Страница 1 из 1 |
Автор: | 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 (аналог @ для стека) есть, а аналога ! не предусмотрено; Вроде не смертельный (возможно, неполный) перечень несовместимостей получается, с этим вполне можно жить На первом этапе планируется только 2 базовых типа (char и int), другие (short/long и один float) по желанию в перспективе, ну а пока они все являются синонимами типа int, со строками понятно, будет чуть медленнее, чем в форте, логические выражения тоже сделаны (строгое совпадение в этой части с си можно при желании отключить, тогда код будет работать быстрее), с аргументами и локальными переменными пока так: результат возвращается через стек данных, аргументы лежат там же, возможность их изменения в процессе работы функции отсутствует, локальные переменные лежат в отдельном массиве, если вдруг понадобится модифицировать значение аргументов, их тоже можно будет в этот же массив сложить, со структурами пока не решил, скорее всего результат и аргументы типа struct будут передаваться через этот же массив. |
Автор: | 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, где мы переопределяем операцию сложения (да, так можно, это ж транслируется в Форт! ), после чего начинаем получать неправильные результаты сложения, в тесте от 8cc arith.c тоже пара переопределений, но на примерно то же самое, поэтому на результат не влияет.Препроцессор пока не начинал, комментариев, а также #include/#define пока нет, токены необходимо разделять пробелами (как в Форте ) Не реализовано enum/typedef/break/continue/switch/case/goto/sizeof/указатели на функции. Некоторый затык произошел с трансляцией 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 писал(а): Ссылки на то как сам делал, при некотором оформлении и собирании архивов в актуальном виде, добавлю на форум или как сейчас могу отправить в личку (с каким то попутным Форт "мусором"), Было бы здорово, тема как раз для того и создана, чтобы сравнивать/обсуждать существующие решения и рожать свои Пока рано говорить про архитектуру в отношении транслятора на полторы тысячи строк (сейчас именно столько, но не думаю, что в итоговом варианте сильно больше будет, ибо в коде много лишних комментариев и лишних кусков кода), т.к. еще далеко до завершения и еще сто раз все поменяется. Да и стыдно пока такие исходники показывать У меня, увы, круг интересов временно сместился с "написать транслятор си-в-форт" на "скачать и установить голый виндоус без регистрации и смс" Эта гадина на основном рабочем ноутбуке при отключенных интернете и обновлениях умудрилась за год с небольшим несколько раз поломаться, но при этом успешно восстанавливалась при помощи "восстановления при загрузке". А в крайний раз сломала не только свой раздел, но и раздел с Ubuntu Studio, а также соседний, где файловый архив был. Как все-таки хорошо было на XP и Win7: они могли работать десяток-другой лет и не ломались, да чего уж там, у меня до сих пор работают XP на крохе Sony Vaio P19 и Win7 на Acer Aspire 3830. Десять лет работают или больше, я даже не помню, когда на них что-то переустанавливал. И это при достаточно активном использовании. А win10 протух за год с небольшим. И бесит весь этот сговор производителей оборудования и мелкософта. Старую нормальную ось на рабочий ноутбук я, конечно, могу поставить, но драйверов, увы, не найти. Так что придется мириться с уродливой мелкософтовской поделкой. Все, ворчать закончил Что касается самого транслятора, то до апокалипсиса с виндой успел прикрутить туда 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), но по большому счету версия под классический форт - это в моем случае побочная ветка, она тоже развивается параллельно с версиями под другие платформы, но некоторые сложные и неочевидные вещи поставлены на паузу За вчера/сегодня практически доделал инициализацию массивов и функции с переменным количеством параметров. Теперь есть возможность делать свой мини-printf:- операторы (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. Т.е. оно получается достаточно компактным и не очень сложным. В теории транслятор уже близок к самокомпиляции, т.к. в коде активно используются printf и sprintf, а в трансляторе до сего дня не были реализованы функции с переменным числом параметров, но теперь уже это в прошлом. Если быть точным, то функции с переменным числом параметров все же были реализованы раньше, но их тело до сей поры приходилось реализовывать на "ассемблере" (точнее - на форте). Кстати, вопрост тут возник по поводу инициализации массивов. Есть ли какой-то красивый и элегантный способ инициализации строки в Гарварде? При условии, что память программ для чтения недоступна. У меня пока тупо каждый байт строки выкладывается в нужную ячейку RAM. Или можно сделать c ... c n addr <strinit>, т.е. посимвольно выложить в стек, сверху добить ее длиной и вызвать примитив, который распихивает символы по нужным адресам, но так можно только если стек большой. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа [ Летнее время ] |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |