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). Также у нас будет парсер сишных заголовочных файлов, чтобы мы могли "заинклюдить" сишный код в наш лисповый код. Такой парсер в разных реализациях лиспа тоже есть.

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

★★★★★

Приведи лучше пример кода для такого case'а (LISP macro definitions + C-code) -- очень любопытно взглянуть :).

kondor ★★★
()

Пример функции на C и её вида в лиспе:

void * xmalloc (size_t size)  {
       register void *value = malloc (size);
       if (value == 0) fatal ("virtual memory exhausted");
       return value;
      }

и два варианта лиспового представления: 

1. Более близкое к С. Здесь конструкции лиспа изменены. В них предусмотрено место для декларации типа

(c::defun void* xmalloc ((size_t size)) { 
  (let1 (void* :register t) value (malloc size)
    (when (== value 0) (fatal "virtual memory exhausted"))
    value))

2. Более лисповое. 
(c::defun xmalloc (size)
  (declare (ftype (function (size_t) void*) xmalloc)
  (let1 value (malloc size)
    (declare (register value)) ; такой декларации пока в лиспе нет
    (declare (void* value)) ; хотя можно сделать type inference
    (when (== value 0) (fatal "virtual memory exhausted"))
       value))

В обоих случаях применён макрос let1, который означает "let только с одной переменной" - экономится 4 скобки. Вот его определение:

(defmacro let1 (var init &body body) `(let ((,var ,init)) ,@body)) 
    

den73 ★★★★★
() автор топика

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

Я не знаю, зачем это нужно, т.к. SBCL с (declare (optimize (speed 3) (safety 0) (space 0))) генерирует машинный код не слишком хуже, чем gcc.

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

mv, конкретный повод - это желание сделать кросс-платформенную разработку под iPhone/Symbian. SBCL туда не протащишь. Ну и вообще, не все программы могут быть по 18 мегабайт :)

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

Многие мне не верят, но я не употребляю наркотики вообще.

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

Не все лисповоды захотят писать на таком "лиспе", в котором много лишних сущностей. Твои примеры больше похоже на FFI'шную обвязку :)

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

mv, я уже вырос из того возраста, когда хотел сделать счастливыми всех. Это - решение для конкретного класса задач, отличного от класса задач лиспа. Ничто не мешает написать какую-то часть программы на этом "лиспе". В котором не то, чтобы лишние сущности - это вообще другой язык, от лиспа у него только синтаксис и МП. В нём, например, не будет интерпретатора и сборки мусора. Не будет и универсального способа вызвать С-функцию из лиспа. Для каждой С-функции нужно будет определить место размещения кода (внешнюю либу или внешний экзешник) и механизм вызова этой либы или экзешника. Если вообще нужно вызывать её из лиспа.

den73 ★★★★★
() автор топика

Предлагаю добавить в новый синтаксис русскоязычные идентификаторы из набора языка 1С:Предприятия, чтоб сковородку пожарче забронировать.

anonymous
()

первое - смотри на http://www.intelib.org

второе - такое вполне себе быстро изготавливается из связки boost preprocessor + boost proto + еще пара библиотек

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

Похоже, я плохо объяснил. У нас есть обычный лисп, но он 
используется только как среда для порождения С-программ. Т.е., имеется, допустим, пр-во имен C. Есть lisp:let - обычный let. 
Есть C:let - let для C. При этом, lisp:let подразумевает 

(let ((var value)...) ...)

,но 

(c:let ((с-type var value)...) ... )

Здесь C становится как бы DSL внутри лиспа. Но мы не можем сделать
вызов функции, определённой с помощью c:defun. Можем сделать 
примерно так:
file "macro.lisp":
(defmacro c:let1 ...) 

file "a.lisp"
(defpackage :a (:use "C"))
(in-package :a)
(in-c-program "a.out")
(defun main ((int argc) (char** argv))
  {let1 int i (+ argc 1)
    (printf "%d,%s\n" i [argv 0])
    0}
)

и далее в интерпретаторе:
> (compile-file "a.lisp")
> (port:run-prog "a.out")
> (a::main 1 nil)
ERROR: a::main is undefined

Вот, в общем-то пример использования предполагаемой системы в её минимальном варианте. 

den73 ★★★★★
() автор топика

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

очень слабо себе представляю то же именно будет конечным потребителем этого чуда. лисперы? сомневаюсь. всем двум с половиной лисперам это нафик не нужно. сишники? ещё смешнее.

// wbr

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

Нда, спасибо за intelib.org, уже второй чел мне это сегодня предлагает. Не ошибся я и насчёт того, где и с кем я буду обсуждать эту тему посмертно.

Забавно, что у меня с Андреем Столяровым есть общие знакомые и я видел этот (L|) ещё в автореферате его диссера, на бумаге. И уже тогда мне было ясно, что это - не мой вариант. Когда-то я даже писал ему письмо на эту тему, хотя тогда думал больше про FFI. Но FFI его не торкнуло (и я теперь понимаю, что это было правильно). Забавно и то, что человек, которого я было загрузил темой МП и который мне принёс данный текст, сейчас работает чуть ли не руководителем отдела ИТ, вместо лиспа развлекается Варкрафтом и получает зарплату в 5 раз больше, чем я когда-либо получал. Такова ирония судьбы.

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

А мы всё же пойдём другим путём. Начнём с того, что в Symbian OS С++ весьма неполноценен. Да и вообще, я не люблю С++. Меня от него тошнит. Можно считать это моим закидоном (хотя причины тому вполне объективны и известны).

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

>Да и вообще, я не люблю С++. Меня от него тошнит.

Попробуй D. Там на языке шаблонов можно сцену отрейтрейсить в выходной elf - бинарь.

Absurd ★★★
()

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

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

>> Пример функции на C и её вида в лиспе:

Ни один вменяемый программист на C/C++ такой страшный нечитабильный ужас не станет использовать.

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

>> Пример функции на C и её вида в лиспе:

>Ни один вменяемый программист на C/C++ такой страшный нечитабильный ужас не станет использовать.

Программист на С++ по поводу страшного нечитаемого синтаксиса не имеет морального права даже заикаться.

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

>> Программист на С++ по поводу страшного нечитаемого синтаксиса не имеет морального права даже заикаться.

Да, да, да... Common lisp - самый читабельный, удобный, простой и понятный ЯП, подходящий для любых задач. А C++ - это неюзабельное говно для быдла, неосилившего CLisp.

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

Вообще-то этот синтаксис для кода, который генерится автоматически, а не живым человечишкой.

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

>А C++ - это неюзабельное говно для быдла, неосилившего CLisp.

Для тех кто вынужден с ним возиться в силу разных причин. Поэтому для новых проектов лучше подыскать что-либо менее эзотерическое.

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

Нешустрый интерпретатор Lua от метапрограммирования сильно более шустрым не становится, увы. А так - Лисп, но "с синтаксисом", для особо трусливых, которые боятся S-выражений.

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

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

Конечно, нет проблем. Есть даже такой проект PLisp. Но это вторично. Первична сама среда CL со всеми её возможностями. И на первых порах неохота, чтобы синтаксис путался под ногами. В лиспе есть квазицитирование, и придётся попариться перед тем, как его удастся приспособить к сишному синтаксису. Для квазицитирования нужно не меньше трёх свободных символов в языке. А в С их просто нету.

Кроме того, возможность писать char* в одно слово - это тоже довольно круто, а это в корне противоречит С-шному синтаксису. Можно, конечно, пойти на компромисс и сделать инфиксную запись, разделяя токены как в лиспе, пробелами, но имхо это только лишний гемор. Лисповую запись вполне можно читать, к тому же есть лисп-мода в редакторе, которая делает работу с лиспом действительно удобной. Достаточно сказать, что s-выражение можно вырезать одной командой. Далеко не в каждой среде для работы с С (ни в одной из виденных мной) подобной команды нет.

Касаемо D. Язык без препроцессора мне не нравится. Тем более, список платформ сразу не нашёл. Нужна вещь переносимая. Что переносимо лучше С? Lua тоже не годится, т.к. интерпретатор.

И давайте больше не будем спорить насчёт С++ и т.п. С++ как вариант не рассматривается, по определению. Лисп не идеален, но он принят за среду разработки, тоже по определению. Более интересны будут вопросы по существу предлагаемого решения. Может быть, я не вижу каких-то ужасных грабель?

Ну и самое интересное - это найти попутчиков.

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

> список платформ сразу не нашёл

Теоретически всё, что поддерживает gcc.

А вообще не вижу никаких причин просто не писать на лиспе. Какой то изврат вы придумываете.

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

> http://www.bitc-lang.org/docs/bitc/spec.html ?

В общем-то, за этим языком стоит здравый смысл. Но теоремы о коде - это имхо пока что рановато. Не доросло ещё железо до таких задач. Нужно его ускорить ещё хотя бы раз в сто-тысячу. Тогда можно будет всерьёз говорить о применении этого подхода в практичных языках. Мне кажется, язык этот всё же более академический. Да и его, в общем-то, ещё не существует в природе, судя по документации и версии. Поэтому, спасибо за подсказку, буду иметь в виду, но не более того. Сейчас речь всё же идёт о более прагматичных вещах - внедрении в С полноценного интерфейса к системе типов и полноценного МП времени компиляции.

Всё же, несколько вопросов по этому языку:

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

Есть ли там поддержка потоков и IPC? Есть ли МП (негигиеничное)?

Если на все вопросы ответ положительный, то это круто и я даже сразу ещё раз более внимательно на него посмотрю.

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

> А вообще не вижу никаких причин просто не писать на лиспе. Какой то изврат вы придумываете.

Причин не писать не лиспе много.

Только один пример: я недавно писал систему для управления печкой. Она открывает/закрывает COM-порт и обращается со звуковой платой. Если пользоваться FFI, то ошибка в последовательности вызовов соответствующих функций может приводить к неприятностям: либо зависает тред, либо какой-то ресурс не освобождается. Бывает и хуже - падает сам лисп. Лисп никогда не должен падать, т.к. он тяжёл, как слон. Ему падать - это очень больно и опасно. Естественным будет вынести такие вещи в отдельный процесс - при смерти процесса ОС всё приводит в порядок. И этот процесс вряд ли должен быть написан на CL.

Вторая причина - мобильные системы - я сразу об этом написал.

Мобильное приложение хочет состоять из двух частей - переносимое ядро и непереносимые драйвера/линки к ГУИ. На чём писать переносимое ядро? В мобильных приложениях скорость и компактность работы - это важное преимущество. Например, С намного лучше Явы, там, где С вообще есть. Имеется платформа Symbian (кастрированный C++) и iPhone (ObjC). Общий знаменатель у них - это С.

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

Absurd, спасибо за D. Будем смотреть более подробно. Похоже, что это -действительно тема. Хотя я не совсем понял. В лиспе МП имеет полный доступ ко всей инфраструктуре. Т.е., во время компиляции можно делать ровно всё то же, что и во время выполнения программы (т.к. компиляция - это тоже выполнение программы). Ограничения имеются на результат вычисления и на доступную информацию о компилируемой программе, но не на само вычисление. В частности, я могу запросить пользователя во время компиляции, вызвать внешнюю программу, обратиться к любым структурам данных, описывающим конфигурацию. Доступно ли это в D?

ACR, насчёт Scheme я думаю. Мне не нравится в Scheme её недостаточная прагматичность. Огромная польза лиспа - это &key, &optional, &body (негигиеничные макросы). Также очень здорово наличие (в стандарте) пр-в имён. Оптимизации в CL тоже гораздо более доступны и многообразны, в результате чего код получается на порядок быстрее. Хотя для метасредства скорость не столь критична. Не нравится наличие нескольких конкурирующих макросистем, не нравится попытка навязать гигиену (с defmacro и gensym в лиспе куда как лучше и при минимальном навыке наступить на грабли практически невозможно).

Хотя, возможно, я просто плохо знаю Scheme и пр-ва имён уже появились. С другой стороны, Scheme без вопросов встраивается даже в довольно небольшие программы, в отличие от CL.

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

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

Ты не понял. Я предлагаю отказаться от списков для представления сишного кода. Строк хватит. Тогда вместо квазицитирования просто (string-append ...)

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

Ладно еще один аргумент, лиспом пользуются только вы и еще два три человека в мире, остальные прагматичные люди шарахаются в сторону при одном только упоминании, в то время как perl, php и даже bash имееют куда более широкий круг адептов.

Согласен с тем что вставки в С код вида <?php SomeFun(); ?> выглядят коряво и грамоздко но у них больше шансов на то что на них хотябы кто то посмотрит.

Или для вас это не аргумент?

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

> Зачем лисп если есть Scheme?

Scheme это и есть лисп.

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

> Только один пример: я недавно писал систему для управления печкой. Она открывает/закрывает COM-порт и обращается со звуковой платой. Если пользоваться FFI, то ошибка в последовательности вызовов соответствующих функций может приводить к неприятностям: либо зависает тред, либо какой-то ресурс не освобождается. Бывает и хуже - падает сам лисп. Лисп никогда не должен падать, т.к. он тяжёл, как слон. Ему падать - это очень больно и опасно. Естественным будет вынести такие вещи в отдельный процесс - при смерти процесса ОС всё приводит в порядок. И этот процесс вряд ли должен быть написан на CL.

Если писать на С, то писать не много (не сотни тысяч строк), а значит метапрограммирование значимого выигрыша не даст.

> Вторая причина - мобильные системы - я сразу об этом написал.

> Мобильное приложение хочет состоять из двух частей - переносимое ядро и непереносимые драйвера/линки к ГУИ. На чём писать переносимое ядро? В мобильных приложениях скорость и компактность работы - это важное преимущество. Например, С намного лучше Явы, там, где С вообще есть. Имеется платформа Symbian (кастрированный C++) и iPhone (ObjC). Общий знаменатель у них - это С.

Можно компилировать лисп в С. На тех же симбианах куча программ на Java, которая не слишком шустра, тем не менее программы пишутся и используются.

Legioner ★★★★★
()

Ты не забыл, что лисп - функциональный язык? А C - процедурный. Может я не внимательно прочитал тему, но мне показалось, что ты предлагаешь писать в процедурном стиле, используя синтаксис лиспа. От этого вся его прелесть пропадает, так что в этом нет смысла, имхо.

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

Не обязательно использовать RnRS, можно привязаться к конкретной реализации, зачастую есть нестатандартные расширения и тд (те же негигиеничные макросы, пространства имён).

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

> Ты не забыл, что лисп - функциональный язык? А C - процедурный

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

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

> Ладно еще один аргумент, лиспом пользуются только вы и еще два три человека в мире,

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

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

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

> лиспом пользуются только вы и еще два три человека в мире

Источник статистики можно?

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

В любом случае, мне стандартный синтаксис С кажется более удобным для императивщины, чем лисповский.

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

> Может я не внимательно прочитал тему, но мне показалось, что ты предлагаешь писать в процедурном стиле, используя синтаксис лиспа.

Лисп - императивный язык. И главная его фича - это макры. Функциональную составляющую из Лиспа вообще можно безболезненно выкинуть.

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

> В любом случае, мне стандартный синтаксис С кажется более удобным для императивщины, чем лисповский.

Фича Лиспа в том, что у него вообще нет синтаксиса.

А "программист", которого волнует синтаксис используемого им языка, а не семантика, тот не программист вовсе, а так, погулять вышел.

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

> Фича Лиспа в том, что у него вообще нет синтаксиса.

(if 1 2 3) это не синтаксис что ли? Другое дело, что он динамический, а не статический, это не привычно, но это синтаксис.

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

> (if 1 2 3) это не синтаксис что ли? Другое дело, что он динамический, а не статический, это не привычно, но это синтаксис.

Синтаксис есть у S-выражений, а не у Лиспа.

Точно так же, как синтаксис есть у XML, но нет, например, у SOAP.

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

> А почему есть название syntactic keywords?

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

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

> Можно компилировать лисп в С

Legioner, будет сборка мусора и издержки динамической типизации. Известно, что код пишется путём переделывания чужих примеров. Возникнет проблема перевода этих примеров с С на Лисп (в моём подходе эта проблема тоже есть, но её можно легко и сильно автоматизировать, т.к. нужна лишь замена синтаксиса). Касаемо нестандартных расширений, да, они есть, я знаю. Тут скорее вопрос ограниченности мозгового ресурса. В Схему нужно серьёзно погружаться, чтобы сделать выбор. Конечно, интересна и возможность встроить лисп в С, поэтому, после написания первого прототипа вопрос перехода на Scheme будет рассмотрен очень серьёзно. Тем более, что Scheme вообще более мощный язык, чем лисп, ввиду наличия call/cc.

> Ладно еще один аргумент, лиспом пользуются только вы и еще два три человека в мире

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

> Я предлагаю отказаться от списков для представления сишного кода. Строк хватит.

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

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

Laz, синтаксис и ФП/ИП - вещи ортогональные. Я согласен, что синтаксис С более читаем, но я считаю, что он менее удобен для МП. В остальном, согласен, что главное в лиспе - это макросы. А ФП - это вообще не мой конёк, я к нему совершенно холоден.

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