LINUX.ORG.RU

Кодогенерация LISP → C


1

3

Вот тут все говорят, что дескать лисп не предназначен для крутых вычислений, что лучше дескать «программа на лиспе напишет программу на Си/Фортране/whatever». Интересно знать, а как это реализуется на практике? Вот, скажем, есть выражение (sin (+ (* x x) 1). Как будет выглядеть макрос, переводящий эту форму в строку «sin(x*x+1)»? Пускай рассматривается коммон лисп и его подмножество: арифметика, векторы (aref должно переводится в сишную индексацию с квадратными скобками), а также функции соответствующие сишному <math.h>.


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

Им жалко потратить пять минут, чтобы хотя бы описать основные идеи для решения? Или эта задачка на самом деле не такая тривиальная, как кажется?

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

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

Я тут могу и ошибаться, сам никогда его не юзал. Но говорят, что годогенерирует.

http://risupu.blogspot.com/2009/05/cffi-rocks.html

Самому проверять влом, конечно же. Про VOP'ы:

http://lisper.ru/articles/sbcl-add-vop

Меряться скоростью тоже влом, но сама возможность писать низкоуровневый код и создавать на их основе примитивы в sbcl есть, в статье проиллюстрировано.

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

Пойми, что ты просишь за тебя написать комплиятор лиспа в C.

А что, неужели это так сложно?

Есть библиотека Parenscript, которая код, похожий на CL, транслирует в код на JavaScript. Задача похожа на трансляцию код в C, но только без учёта типизации и сборки мусора. Т.е. можно взять Parenscript, добавить туда какой-то вывод типов, добавить реализацию сборки мусора, допилить и получиться компилятор из лиспа с C. Ну и да, Parenscript это примерно 5000 строк кода.

archimag ★★★
()

Lisp есть святая корова местечковых хомячков. Lisp — это православно. Lisp — это кошерно. Короче годный наброс. Зачот.

По делу, забей ты на этот лисп. Тривиальные вещи, как твой пример решаются просто: http://lmgtfy.com/?q=lisp infix prefix Ежели нужны преобразования выражений, бери вольфрамову математику и не парься. Если седьмая, то есть винарнейший CFormat http://library.wolfram.com/infocenter/Demos/60/ Восьмерка вроде как аут оф тхе бокс умеет.

ebantrop
()

На первый взгляд кажется, что такие вещи удобнее всего делать в Racket с его переключаемыми языками. Включаешь обычный лисп — и прога просто работает как лисповая. Переключил на свой язык под названием «compileToC» - и прога компилируется в C. Поскольку синтаксис двух языков совпадает, то reader не потребуется переписывать. Вот дискуссия по теме: на чём реализовать DSL?

Сам намереваюсь для Racket сделать (или найти) что-то подобное в этом году. Для Racket это даже актуальнее, чем для CL, потому что Racket, в отличие от CL, не компилируется в машинный код.

Но если твоя платформа CL, то тоже никаких проблем с компиляцией в C, в общем, нет, кроме чисто технических. Писать парсер S-выражений не нужно. См. также посты antares0 по ссылке.

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

и после этого вы все будете выглядеть очень глупо

пока очень глупо выглядишь ты, особенно с учётом того, что тебе уже дали несколько ответов и гугл тебе в помощь работает круглосуточно

shty ★★★★★
()

Я такое делаю на питоне. Могу рассказать как, если интересно.

ЗЫ «ответить на задачу» - что, ЕГЭ по русскому 100 из 100? Отвечают на ВОПРОСЫ, задачи РЕШАЮТ;-)

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

Я хочу уметь это делать самостоятельно.

Пойми, что ты просишь за тебя написать комплиятор лиспа в C.

А что, неужели это так сложно?

что студентота, сессия заканчивается и гранит грызть уже некогда?

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

ЗЫ «ответить на задачу»

«ТЫ НЕ ОТВЕЧАЕШЬ НА МОЙ ОТВЕТ!» (с)

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

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

А может, гуру просто «не осилили», а? Демагогией о «вызывающем поведении и отсутствии понимания» можно прикрыть любую свою некомпетентность. У меня пока только такое впечатление складывается.

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

Есть библиотека Parenscript, которая код, похожий на CL, транслирует в код на JavaScript. Задача похожа на трансляцию код в C, но только без учёта типизации и сборки мусора. Т.е. можно взять Parenscript, добавить туда какой-то вывод типов, добавить реализацию сборки мусора, допилить и получиться компилятор из лиспа с C. Ну и да, Parenscript это примерно 5000 строк кода.

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

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

По делу, забей ты на этот лисп.

На «этом лиспе» написана неплохая модель, которую надо оттранслировать в другой язык. Тогда об «этом лиспе», вероятно, и можно будет забыть.

Тривиальные вещи, как твой пример решаются просто: http://lmgtfy.com/?q=lisp infix prefix

Моя задача несколько сложнее, чем просто преобразование infix/prefix. Но по ссылке кое-что интересное по теме нашлось, например Infpre, спасибо.

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

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

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

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

Я такое делаю на питоне. Могу рассказать как, если интересно.

Да, с удовольствием послушаю. Через AST library, как указал archimag?

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

Эээ, современных лиспов три штуки: CL, Racket/Scheme, Clojure. Макросы есть во всех трёх языках, но языки между собой несовместимы, и транслятор для всех лиспов сразу у тебя сделать не получится. И вообще, как можно на «абстрактном» лиспе решать чисто техническую задачу. Платформы разные, и технические аспекты разные.

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

Lisp есть святая корова местечковых хомячков. Lisp — это православно. Lisp — это кошерно. Короче годный наброс. Зачот.

Что на Лиспе, что на Си, что на ассемблере можно научить программировать хоть обезьяну. Ничего выдающегося в его знании нет.

ttnl ★★★★★
()

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

Для приведенного тобой примера все решается простым пробегом по дереву и переписыванию его в строку.

(defvar *translate* (make-hash-table))

(defun get-si-form (x)
 (let ((out (gethash x *translate*)))
  (if out out
      (error "Wrong lisp construction"))))

(defun lisp-2-si (in)
 (cond
   ((listp in) (process-function
		(get-si-form (car in))
		(cdr in)))
   (t in)))

(defun process-function (f-info args)
 (case (getf f-info :type)
   (function
    (format nil "~a(~{~a~^, ~})"
	    (getf f-info :name)
	    (mapcar 'lisp-2-si args)))
   (operator-binary
    (format nil "(~a~a~a)"
	    (lisp-2-si (first args))
	    (getf f-info :name)
	    (lisp-2-si (second args))))
   (otherwise
    (error "Unsupported function type"))))

(defmacro translate (&rest args)
 `(progn
   ,@(loop for x in args collect
	  `(setf (gethash ,(car x) *translate*) ,(cadr x)))))

(translate
 ('sin '(:type function :name "sin"))
 ('+ '(:type operator-binary :name "+"))
 ('* '(:type operator-binary :name "*")))

(format t "~a~%"
	(lisp-2-si '(sin (+ (* x x) 1))))

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

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

Принципиально она решается везде одинаково, конечно: вызываешь стандартный reader для парсинга своего файла, затем рекурсивно обходишь полученное AST, преобразовывая '(sin x y) в «sin(x,y)» и т.д.

В Racket это выглядит так:

(define-syntax (sin x y)
  (format "sin(~a,~a)" x y))

Вся разница, короче, в технических деталях для разных платформ.

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

Неужели такая простая задача будет решаться на всех этих лиспах принципиально по-разному?

Это всё равно, что писать код, одинаково работающий с компиляторами C++, C# и Java. Сточки зрения синтаксиса и набора фич разница, плюс-минус трамвайная остановка, непринципиальна.

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

написана неплохая модель, которую надо оттранслировать в другой язык

Ежели это одноразовая проблема стоит ли париться с транслятором? Как уже говорили есть например clojure, которая оттранслирует в Яву или дотнет.

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

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

(defun process-function (f-info args)
 (case (getf f-info :type)
   (function
    (format nil "~a(~{~a~^, ~})"
	    (getf f-info :name)
	    (mapcar 'lisp-2-si args)))
   (operator-binary
    (format nil "(~a~a~a)"
	    (lisp-2-si (first args))
	    (getf f-info :name)
	    (if (> (length args) 2)
		(process-function f-info (cdr args))
		(lisp-2-si (second args)))))
   (otherwise
    (error "Unsupported function type"))))
staseg ★★★★★
()
Ответ на: комментарий от ttnl

Что на Лиспе, что на Си, что на ассемблере можно научить программировать хоть обезьяну. Ничего выдающегося в его знании нет.

Не, лисп это генератор лулзов. Автор, похоже, весьма не в теме и начал грубить на третьем каменте. Вообще, если любой топик сдесь содержит слово LISP, то мерянье монадами будет непременно жарким.

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

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

Понятно, что на провокацию ТС можно поддаться только в состоянии сильного алкогольного опьянения, но зачем же постить неработающую программу?

....

(translate
 ('sin '(:type function        :name «sin»))
 ('+   '(:type operator-binary :name «+»))
 ('-   '(:type operator-binary :name "-"))
 ('*   '(:type operator-binary :name «*»)))

TEST> (format t «~a~%»
	(lisp-2-si '(sin (- 30 20 5))))
sin((30-(20-5)))
NIL

Как насчёт равенства (- 30 20 5) и (30-(20-5)) ?

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

зафрендил

так ты, мбванга, мелкопупочный?

//какая драма

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

Какая разница? Если хочешь, то можешь парсить на Python и s-выражения.

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

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

зачем же постить неработающую программу?

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

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

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

Кстати. На лиспе я пишу много, но догадываюсь, что мой стиль хромает. Любая критика крайне приветствуется. Например (if out out ...) выглядит как говно - как исправить? Может что-нибудь еще?

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

ну (if out out ...) можно использовать (or out ...)

и translate наверное лучше переписать как-то так:

(defmacro translate (&body args)
  `(progn
    ,@(loop for x in args collect
	`(setf (gethash ',(first x) *translate*)
               ',(rest x)))))

(translate
  (sin :type function        :name "sin"))
  (+   :type operator-binary :name "+"  ))
  (*   :type operator-binary :name "*"  )))

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

Например (if out out ...) выглядит как говно

Скорее «cond» в lisp-2-si

Общее правило:

1 условие - when, unless

2 условия - if

3 и больше - cond

посмотри

http://www.mit.edu/~mkgray/stuff/ath/afs/oldfiles/project/silk/root/afs/sipb....

http://www.faqs.org/faqs/lisp-faq/part1/section-4.html

http://labs.ariel-networks.com/cl-style-guide.html

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

зачем же постить неработающую программу?

Чтобы препод схватил топикстартера за яйца.

Так предупреждать надо, а то лиспоненавистники за@#ут.

А ТС-у твой код не поможет - Кодогенерация LISP → C (комментарий) - не знать, что любая функция должна быть правильным s-exp-ом и рассуждать о лиспе, это как не зная арифметики рассуждать о диффурах.

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

могу потратить несколько минут, чтобы подробно обосновать, зачем мне это нужно, и после этого вы все будете выглядеть очень глупо

То что ты можешь — никого не волнует. Или обосновывай или сваливай.

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

Им жалко потратить пять минут, чтобы хотя бы описать основные идеи для решения?

Тебе никто ничего не должен, запомни это. Самое большее что ты можешь — вежливо просить помочь, и если тебя послали, молча согласиться и заткнуться. Когда ты начинаешь что-то требовать, ты автоматически становишься школьником-клоуном.

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

Да, с удовольствием послушаю. Через AST library, как указал archimag?

.Нет, я не знаю что такое AST;-(

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

Дальше это дерево рекурсивно может приведено к любому формату (у меня актуальных штук пять - питон, С, гнуплот для использования в using, eps и ес-но tex). Приводится с учетом приоритетов операций, что бы лишних скобок не лепить. Ядро это хозяйства занимает на питоне 167 строк. Еще 45 строк для преобразования имен переменных в tex-eps и парсинга пользовательских скобок (бывает удобно в сложных выражениях юзать {}[]<>|| - фактически небольшое расширение синтаксиса).

PS shty зря зафрендил, он обычно очень по делу говорит. В итоге ты себя наказал, а не его;-)

AIv ★★★★★
()

Уже создали суперкомпилятор?

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

Это то я по ссылке прочитал. Но я не программист, так что вполне может оказаться что то, чем я уже 8 лет активно пользуюсь, называется AST;-)

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

.Нет, я не знаю что такое AST;-(

Я тебя расстрою ещё больше - от слов «Создается объект с...» до слов «на аргументы ф-ии.» - это построение АСТ. У ТС оно есть по условию задачи - на лиспе программы по другому не записать.

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