LINUX.ORG.RU

lisp как препроцессор для C


0

0

Ура, вот и настал мой звёздный час. Наконец-то я надёжно заработаю посмертное попадание в ад, где буду, загорая на сковородке, обсуждать с лисперами-сатанистами дела давно минувших дней. Но приступим к делу. Предлагается создать open-source библиотеку, являющуюся лисповым синтаксисом для С.

Это не будет embedded lisp. Это не будет связка lisp-C по FFI или через IPC (хотя это возможно). Это не будет очередная виртуальная машина (хотя и это возможно). Это будет лисповая оболочка над С.

Будет иметься постоянно запущенная лисп-среда, своего рода "пчела-матка", которая будет генерировать C-код. С-код будет компилироваться обычным C-компилятором и потом исполняться отдельно.

Что мы возьмём от С? Всё. Результатом работы первой фазы компилятора будет обычный С-код.

Что мы возьмём от лиспа? Синтаксис. Синтаксис лиспа - это синтаксис деревьев из идентификаторов и констант. Кроме того, от лиспа мы возьмём статическое МП. Т.е., у нас будет не только c::defun (определение с-функции) и не только с::typedef. Но и defmacro, обычное лисповое defmacro, которое заменит #define. Также у нас будет лисповый класс c-type (который уже есть в разных реализациях лиспа в связи с FFI). Также у нас будет парсер сишных заголовочных файлов, чтобы мы могли "заинклюдить" сишный код в наш лисповый код. Такой парсер в разных реализациях лиспа тоже есть.

Зачем это нужно? Например, чтобы писать более удобно, чем на С, программы, которые обычно пишутся на С.

★★★★★

Ответ на: комментарий от Vadim_Z

Ага, через жопу оно как-то.

Вообще, надо подождать, пока все основные реализации не начнут R6RS поддерживать. Пока что мне приходится жить на R5RS (но зато с define-macro).

anonymous
()
Ответ на: комментарий от anonymous

> Авторы в comp.lang.lisp обещали исходники после чистки отдать.

нашёл единственное упоминание mbase. Про исходники - ни слова :)

yyk ★★★★★
()
Ответ на: комментарий от yyk

Цитата из упомянутого http://srfi.schemers.org/srfi-93/srfi-93.html

> This SRFI is currently in ``withdrawn'' status.

Я всё правильно понял?

> > она слишком медленная

> Не в последнюю очередь благодаря call/cc

Если я правильно понимаю, применения call/cc естественным образом разбиваются на два класса. Первый - это "нелокальный выход", при котором стек только "раскручивается", а точнее - его кусок просто ампутируется. Второй - это "замораживание состояния вычисления", при котором стек должен быть умно скопирован. Проблемы производительности имеются со вторым вариантом (из-за слабости С). По-моему, всё это должно быть нетрудно учесть при компиляции и сделать быстрым хотя бы первый вариант.

> > Схема была бы лучше, но её изуродовали в плане макросов

> Кстати, конкретно в твоей задаче макросы не нужны, поскольку целевой язык для твоих DSLей это не сам Лисп, а внешний Си. Так что вместо макр у тебя простой print будет.

Я хочу транслировать defun в определение функции на С, а defmacro никак не транслировать, но использовать в тех defun-ах, которые потом будут переведены на С. Т.е., в общем-то, транслятор подмножества лиспа на С. Другое дело, что из этого транслятора можно исключить даже такие примитивы лиспа, как car, cdr и cons. Оставив их только в макропроцессоре и допустив специальные случаи для разбора списка аргументов в функции с переменным числом параметров. И добавить типичные для С struct, malloc, указатели и т.п.

> Это древний флейм - bondage&discipline vs. полная свобода. На одном конце Haskell, на другом - Си и Форт.

Я никакого "vs" не имел ввиду. Подумайте ещё раз об естественных языках. Например, ругаться матом в принципе можно, но не в любом обществе. Зачем лишать язык полезных матерных слов, если можно просто наложить на них запрет в уместных случаях? Техника вполне позволяет гарантировать исполнение запрета - матерное слово просто не скомпилируется. Т.е., не "vs", а "и".

Но уж если об этом зашла речь, то я бы не сказал, что на стороне полной свободы находится Си и Форт. Си не позволяет довольно много (например, динамическую кодогенерацию и такие операции, как копирование фрагмента стека, только что обсуждалось). Форт же слишком медленный и это даёт основания подозревать, что и у него свобода какая-то не такая ( http://shootout.alioth.debian.org/gp4sandbox/benchmark.php?test=all&lang=... )

В общем, конечно, грех требовать от языка для глупых железок той же мощи, как и от языков, исполняющихся человеческим мозгом - слишком уж несопоставима вычислительная мощь. Однако, какие-то аналогии всё же небезполезно провести.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

А вот кстати, какую Схему порекомендуете, чтобы требовала только чистого С, была весьма компактна, легко встраивалась и позволяла "грязные" макросы?

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

>> This SRFI is currently in ``withdrawn'' status.

>Я всё правильно понял?

Оно вошла как кусок в R6RS, потому и withdrawn.

This SRFI is being submitted by a member of the Scheme Language Editor's Committee as part of the R6RS Scheme standardization process. The purpose of such "R6RS SRFIs" is to inform the Scheme community of features and design ideas under consideration by the editors and to allow the community to give the editors some direct feedback that will be considered during the design process.

At the end of the discussion period, this SRFI will be withdrawn.

Vadim_Z
()
Ответ на: комментарий от yyk

Ну спроси сам у авторов. Мейл там есть.

anonymous
()
Ответ на: комментарий от Bohtvaroh

Это ещё фигня. Вот reflection на шаблонах вот это Ъ!!

точную ссылку не помню, что-то было зависимое от компилятора ( то ли typeof , то ли sizeof( static поле) раскрывается в разное для разных классов. Принцип там был такой же, как с факториалом, рекурсивно раскрывались шаблоны до корневого, корневой раскрывался в разное для разных типов классов.

а так более портабельный пример, через указатели на члены классов:

http://www.vollmann.com/pubs/meta/meta/meta.html

anonymous
()

> Будет иметься постоянно запущенная лисп-среда, своего рода "пчела-матка", которая будет
генерировать C-код. С-код будет компилироваться обычным C-компилятором и потом исполняться
отдельно.

Такое есть в PicoLisp ( простой встраиваемый интерпретатор):
http://www.software-lab.de/faq.html
http://www.software-lab.de/down.html

http://www.software-lab.de/cygwin.README :

A working, industrial-strength Lisp interpreter is Pico
Lisp, ready for writing applications that are succinct yet
powerful. Pico Lisp comes with a Prolog interpreter and
relational databases and flight simulators and chess games and
web servers and chat servers and sendmail and much more.

And Pico Lisp itself is written in highly portable C, running
on Linux and Windows. Pico Lisp is readily embedable, and will
be useful to add scripting languages (Lisp, Prolog) to other
applications, either statically linked, or as a shared library
(DLL).

Pico Lisp is a little dynamo. It even has the ability to use
in-line C code which is compiled on-the-fly into a shared
library. This in-line C ability uses gcc. (And it works with
tcc, the Tiny C Compiler, too.)

встраивается в Си программу, лисп машина вызывает лисп функцию, реализацию которой можно
подменить на Си. См. пример в дистрибутиве.

С другой стороны, лисп там не совсем правильный -- не CL, динамический, интерпретируемый
(хотя и довольно быстро за счёт простой лисп машины, см.
http://www.software-lab.de/ref.html#intro http://www.software-lab.de/faq.html#hardware)

есть пример ещё более простого ограниченного лиспа, см. GOAL
http://en.wikipedia.org/wiki/Game_Oriented_Assembly_Lisp . Выглядит похоже на то, что надо,
только целевой язык -- ассемблер а не Си.

Можно посмотреть на реализацию этого языка, чем он ограничен по сравнению с нормальным
лиспом или Си.

из нормального CL, есть встраиваемый ECL, см. http://ecls.sourceforge.net/

anonymous
()
Ответ на: комментарий от den73

> Я всё правильно понял?

Он теперь в R6RS

> По-моему, всё это должно быть нетрудно учесть при компиляции и сделать быстрым хотя бы первый вариант.

Как компиляторописатель доложу - оба варианта одинаково мозготрахские. Так что предпочитаю Лиспы без call/cc (хоть и делал реализации всяких лиспопохожих DSLей и с continuations, да и употреблял CPS-преобразование не по назначению, для всяких хитрых оптимизаций).

> Я хочу транслировать defun в определение функции на С

Ёклмн! Зачем? Ты хочешь написать транслятор полноценного Лиспа в Си? Возьми ECL тогда, или GCL на худенький кончик.

Если же это некий твой собственный язык - то и на фиг тебе не впились макры.

> Т.е., в общем-то, транслятор подмножества лиспа на С

Тут макры не нужны. Ты, по сути, полноценный компилятор пишешь, и при этом можешь, конечно же, сделать резервную трансляцию того же языка в Схему/Лисп, для изотропии макр, но это уже не обязательно.

> Я никакого "vs" не имел ввиду.

Однако, ты занял конкретную позицию (Си + Форт). Так что это автоматом и vs. выводит.

> ехника вполне позволяет гарантировать исполнение запрета - матерное слово просто не скомпилируется. Т.е., не "vs", а "и".

Это позиция аккурат посередине. Примеры - Common Lisp и C# (с его unsafe-конструкциями).

> Си не позволяет довольно много (например, динамическую кодогенерацию и такие операции, как копирование фрагмента стека, только что обсуждалось).

Ну, ладно, Си близок к правому краю, но не дотягивает до Ассемблера. Форт с Ассемблером рядом сидят.

> Форт же слишком медленный

4.2

Да и не относится никак скорострельность к ансейфности семантики.

anonymous
()
Ответ на: комментарий от den73

> есть ли там примитивы, транслирующиеся в сишные "функции с переменным числом аргументов"
и setjmp?

вот такая мысль про прозрачный Cи ABI <-> списки:

В си есть полиморфизм указателей (на функции). Это полиморфизм типов символов.

Си-функция с переменным числом параметров -- это фрейм на стеке. Список из неявного
адреса возврата, (очень неявной для фрейма) точки входа в функцию и списка параметров
произвольной длины. Список, то есть, аналог лисповой формы. Произвольность типов формы
задаёт фрейм из "клеток" с дырками (то есть, размер клетки расчитан на максимальный размер
типа элемента списка, фрейм -- это список таких клеток фиксированного размера, то есть,
вектор)

А дальше аналогия очевидна: атомы = клетки в фрейме = параметры си-функции,
символы=переменные-указатели, значение символа=(*указатель-на-символ);

то, что sizeof(*X) примерно одинаковый для разных наших-типов, обеспечивает полиморфизм
типов символа X.

Символы, первый элемент списка правильной формы транслируются в указатель на си-функцию,
представляющую этот символ. А второй и остальные элементы дописываются как параметры
си-функции. Полиморфизм параметров типов обеспечивается что значения передаются
символами, по ссылке или "клетками". "Система типов" собственно задаёт смещения в фрейме
(или фрейм из общих "клеток" как в PicoLisp VM)

список-дерево AST функций соответствует дереву фреймов.

То есть полный аналог continuations в лиспе. Просто тут один общий стек, а continuation
хранит в стеке список фреймов других continuations, делает из нескольких стеков(фреймов)
дерево http://www.intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons (про
подход стековый фрейм как глобальный хеш нескольких разных стеков).

То есть, continuations транслируются в списки в "сишные функции с переменным числом
параметров", в одном стеке, с автоматическим управлением. А setjmp/longjmp переключает
эти стеки вручную (то есть, ручной доступ к этой глобальной переменной в call/cc).

anonymous
()
Ответ на: комментарий от den73

> Тем более, что Scheme вообще более мощный язык, чем лисп, ввиду наличия call/cc.

изоморфно, можно сделать call/cc и на лиспе.

> Код - это деревья, а не строки. Просто эти деревья плоско написаны на листе бумаги.

деревья -- это деревья фреймов вызываемых в continuations функций, строки -- это единый стек, в которое их можно свернуть.

anonymous
()

> Зачем это нужно? Например, чтобы писать более удобно, чем на С, программы, которые обычно пишутся на С.

есть некоторая надежда, что использовав лисп в качестве "промежуточного представления" для Си-подобной программы + информацию о типах можно эту программу потом упростить, оптимизировать. То есть компилировать разные языки в лисп-подобное представление, которое потом оптимизировать и исполнять. Лисп как виртуальная машина.

anonymous
()
Ответ на: комментарий от den73

> А вот программисты 1С имеют некоторые шансы отмазаться от сковородки, тут анонимус заблуждается.

чем это? в 1С есть своя кривая виртуальная машина. Многие проекты-аналоги 1С, взять тот же Ананас, пытаются реализовать свой компилятор своего языка, и так и ниасиливают сам компилятор, или делают свой ни с чем не совместимый велосипед (который функциональность прототипа не покрывает толком). Если бы они компилировали в такую лисп-подобную вирт. машину, менее завязанную на реализацию, во-первых, надо было бы писать только парсер синтаксиса этого своего скрипта в лисповые s-выражения, во-вторых, можно было бы использовать CLOS/MOP-подобные OO, персистентность, пролог над лисп-машиной из этого скрипта уже сразу, нахаляву, "лисп как платформа", в-третьих, если транзакции записаны на этом скрипте, иметь промежуточное представление в виде лиспа, оптимизировать, переделать трансформациями/макрами к декларативному стилю в виде транзакций как лениво вычисляемых замыканий.

Так что у лиспа как промежуточного представления для "платформы", есть имхо, самостоятельная ценность. Хорошо бы определить границы применимости такой платформы.

anonymous
()
Ответ на: комментарий от den73

>> Это древний флейм - bondage&discipline vs. полная свобода. На одном конце Haskell, на другом - Си и Форт.

а по-моему, они похожи (Haskell vs. Forth). Представь, что есть не один стек с элементами разных типов, разных размеров, а несколько стеков-векторов с элементами одного типа, фиксированных размеров. И один управляющий стек смещений, указателей на значения в других типизированных стеках. Получается аналогичная семантика, вопрос в том известны ли все смещения во время компиляции. Если да, и есть жёсткие правила, имеем систему типов и Хаскелль, если нет -- динамическая типизация и Форт.

anonymous
()
Ответ на: комментарий от anonymous

> а по-моему, они похожи (Haskell vs. Forth)

Не надо! Есть строго типизированные стековые языки - тот же Cat, но это не Форт, конечно же. Форт позволяет прострелить себе ногу из любого оружия и под любым углом, Cat же - bondage&discipline почище Хаскелля.

anonymous
()
Ответ на: комментарий от anonymous

Анонимусы, вы б что ли зарегестрировались, а то у меня скоро будет комбинаторный взрыв в голове - непонятно, с одним я человеком говорю или с 10.

> Ёклмн! Зачем? Ты хочешь написать транслятор полноценного Лиспа в Си? Возьми ECL тогда, или GCL на худенький кончик. Если же это некий твой собственный язык - то и на фиг тебе не впились макры.

Так мне макросов как раз и не хватает в С. Это, так сказать, основной мотив всей темы. А ECL/GCL не катят из-за своего размера и (скорее всего) невозможности достаточно хорошо работать на iPhone/symbian.

Задача стоит так:

1. дать С синтаксис лиспа (путём тупого преобразования синтаксиса каждого конкретного примитива С).

2. поверх этого наложить макропроцессор лиспа.

3. с помощью пункта 2 обернуть результат пункта 1 так, чтобы получилось подмножество лиспа, расширенное тем, чего в лиспе нет.

Лисповый вид должны иметь конструкции: defun &key &optional &rest(?) defmacro let let* lambda cond do (хотя лучше бы iter) progn block tagbody unwind-protect(?) return-from declare(special) vector string fixnum float t nil package(только статика) symbol(только статика) ну надо дальше смотреть, что ещё взять. А также, константы-списки, константы-вектора.

> изоморфно, можно сделать call/cc и на лиспе.

Да? Если только через cps-преобразование, но это как-то... не совсем парламентский метод борьбы.

> Однако, ты занял конкретную позицию (Си + Форт). Так что это автоматом и vs. выводит.

Ну мне кажется, я всё же не занимал в этом споре позиции.

> вот такая мысль про прозрачный Cи ABI <-> списки

Попробую завтра понять (скорее из вежливости). В любом случае, я не это имел в виду. Это, видимо, предлагается дизайн рантайм-среды лиспа с продолжениями в С. Не совсем я понял, как тут мусор собирать, но это ладно. Может быть, и можно. Я-то хочу сделать так, чтобы (я в начале уже писал)

(c:defun int fact ((int n)) ...)

превращался конкретно в

int fact(int n) { ... }

и мудрить со стеком не входит в мои планы. Лучше уж тогда действительно cps.

> Лисп как виртуальная машина

Вот эта идея как раз мне кажется не столь плодотворной. Если уж есть лисп с его весом, так почему бы на лиспе и не писать? Здесь речь идёт о создании программ лёгких и быстрых, как на С. Не обязательно больших. Здесь действительно можно сделать то, чего сильно не хватает.

> чем это?

Я думаю, что попадание на сковородку больше связано не со степенью эстетического отвращения, которое будет испытывать апостол Пётр, глядя на наш код, сколько основных назначением этого кода. Код AI, поисковых машин, распознавания образов, социальных сетей, пластиковых карточек, электронных магазинов и прочих инструментов повязывания человека в сети ББ - вот за что будут жарить. А если человек просто помогал кому-то считать бабло, то это не так криминально. Хотя, если человек наивно работал на ББ, не понимая, что он творит, и при этом делал красивый код, то я думаю, что у него тоже есть шанс отмазаться. Я там не был, но я предполагаю, что вернее всего попадут на сковороду те, кто работал на Зло осознанно. А среди лисперов таких достаточно - люди-то на лиспе, в основном, работают умные и всё понимают. Хотя, может быть, если человек был обязан по своему уму понять, ЧЕМ он зарабатывает себе на хлеб, и не понял до самой смерти - то я бы такого тоже отправил на сковороду. Ему именно там и место! Хотя, в общем-то, всё это основывается на христианской модели нашего времени. Не думаю, что стоит ей полностью верить, но нужно отметить, что из всех известных мне моделей она почему-то имеет наибольшую предсказательную силу.

Вот опять непонятно - один анонимус пишет "лисп как промежуточное представление", другой анонимус - "лисп как виртуальная машина". Вот и разбирайся - это у одного человека мысль скачет или это два разных. Ладно, не буду разбираться. Спать пойду.

den73 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

вот тебе ещё ссылка в тему, http://www.cs.berkeley.edu/~harmonia/harmonia/help-wanted.html#preproc

может "боян", но см. публикации -- про подход, инкрементальный лексер и статью про interactive transformations, http://www.cs.berkeley.edu/~harmonia/harmonia/projects/langs/c/index.html. Может вдруг пригодится.

anonymous
()

> На сегодня всё. Скучно будет без вас, но нужно работать.

ещё ссылка в тему -- нагуглилось вот: конечно, не препроцессор С на CL, скорее что-то встраиваемое вроде PicoLisp. Dlisp, http://iteration-zero.blogspot.com/search/label/DLisp http://code.google.com/p/iteration-zero/downloads/list http://www.dsource.org/forums/viewforum.php?f=74 http://www.dsource.org/forums/viewtopic.php?t=1119

интерпретатор, и по функциям слабее того же PicoLisp. но что интересно: экспортирование D переменных/классов/методов в встроенный лисп делается во время компиляции, шаблонами (см. также MiniD, в котором ЕМНИП компилятор сделан шаблонами D. Может проще встроить в отдельно С/D программу отдельный лисп, и не генерировать С-код из лиспа, а писать С-код отдельно, лисп-код отдельно.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.