LINUX.ORG.RU

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


1

3

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


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

В принципе могу и кодом поделится. В частности, мы на этом деле пилим шнягу для кодогенерации в числ. моделировании.

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

Мда, написал на ночь глядя синус от двух аргументов и define-syntax вместо define-syntax-rule.

Вот как правильно:

#lang racket

(define-syntax-rule (sin x)
  (format "sin(~a)" x))

(define-syntax-rule (set! x y)
  (format "~a = ~a" 'x y))

(define-syntax-rule (+ x y ...)
  (string-append
   x
   (apply string-append
          (map (lambda (arg) (string-append "+" arg))
               (list y ...)))))

(define-for-syntax (process-body var-symbols body)
  (let ((body-e (syntax-e body)))
    (if (list? body-e)
        (datum->syntax body
                       (map (lambda (s)
                              (process-body var-symbols s)) body-e))
        (if (member body-e var-symbols)
            (symbol->string body-e)
            (if (number? body-e)
                (number->string body-e)
                body)))))

(define-syntax (let stx)
  (syntax-case stx ()
    ((_ ((var-name var-value ...) ...) body ...)
     (let ((var-names (syntax->datum #'(var-name ...))))
     #`(string-append
        "{\n"
        (apply string-append 
               (map (lambda (name value)
                      (if (empty? value)
                          (format "double ~a;\n" name)
                          (format "double ~a = ~a;\n" name (car value))))
                    '(var-name ...) `#,(process-body
                                        var-names
                                        #'((,var-value ...) ...))))
        #,@(process-body var-names #'((string-append body ";\n") ...))
        "}\n")))))

Пример использования:

> (printf (let ((x) (y 2) (z (+ y 4)) (w)) (set! x (+ y 10)) (set! w (+ x y (sin z)))))
{
double x;
double y = 2;
double z = y+4;
double w;
x = y+10;
w = x+y+sin(z);
}

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

Скорее всего прост лютый говнокод.

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

лучше так:

#lang racket
(require syntax/parse/define)

(begin-for-syntax
  (define-syntax-class arg
    (pattern (x ...)
             #:with expr #'(x ...))
    (pattern y
             #:with expr #'(format "~a" 'y))))

(define-simple-macro (binary-ops [op:id name:str] ...)  
  (begin 
    (define-simple-macro (op arg:arg (... ...))
      (string-join `(,arg.expr (... ...)) (format " ~a " name))) ...))

(define-simple-macro (functions [fun:id name:str] ...)  
  (begin 
    (define-simple-macro (fun arg:arg (... ...))
      (format "~a(~a)" name (string-join `(,arg.expr (... ...)) ", "))) ...))

(define-simple-macro (set! x:arg e:arg)
  (format "~a = ~a;~n" x.expr e.expr))

(define-simple-macro (let ([x:arg e:arg] ...) body:arg ...)
  (format "{~n~a}" (string-append (format "double ~a = ~a;~n" x.expr e.expr) ... 
                                  body.expr ...)))

(binary-ops [+ "+"] 
            [- "-"] 
            [/ "/"] 
            [* "*"])

(functions [sin "sin"])

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

Мне лениво слушать анонимусов и проч. школоту про несоблюдение PEP8, неоптимальный с их точки зрения дизайн и т.д. Если кому то правда нужно/интересно - могу тоже кинуть в мыло, а так ЛОР это последнее место, где я бы стал выкладывать свой код как просто код (без описания, постановки задачи и проч.).

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

ЛОР это последнее место, где я бы стал выкладывать свой код

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

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

Вот когда этот проект дойдет до той стадии, что бы его выпускать в массы, тогда я его где нить выложу и тисну статейку на главной ЛОР-а. А пока мы обсуждали какую то очень частную задачу, и я просто описал одну из возможностей ее решения. Если кому то правда нужен этот код в качестве иллюстрации - стучитесь на мыло aivanov(злая собака)keldysh(жирная точка)ru, представляйтесь (фамилия-имя, где работаете, зачем оно вам;-)), вышлю и отвечу на все вопросы.

Я во первых не люблю анонимов, во вторых незаконченную работу не всем показывают;-)

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

Мне лениво слушать анонимусов и проч. школоту (...)

Боишься критики? Думаешь, что потеряешь от этого мнимый авторитет?

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

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

Такими темпами (после 8 лет разработки кодогенератора узнать, что такое синтаксическое дерево!) этого не случится никогда.

Я во первых не люблю анонимов (...)

А кто их любит-то? Я тоже не переношу.

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

Нет, ну надо же! Какой я умный, это что то - сам AST придумал... ;-)

российские математики настолько суровы... (с)

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

значит ребятки вам придется критиковать и отнимать мнимый авторитет друг у друга;-)

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

AIv

наверное... не знаю, я не матетматик;-)

российские физики... WAIT, OH SHI~ :)

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

(сказать честно, не проверял, есть ли в ней данная фича, но раз она есть в Mathematica, то почему бы ей не быть в Octave?)

den73 ★★★★★
()

Ты хочешь создать что-то очередное принципиально новое с нескучным кодогенератором?

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

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

(сказать честно, не проверял, есть ли в ней данная фича, но раз она есть в Mathematica, то почему бы ей не быть в Octave?)

Потому что это разные пакеты с разным назначением?

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

Этих трех составляющих достаточно для истории успеха через месяцок.

Ну это ты загнул на счет месяца.

anonymous
()

Интересно знать, а как это реализуется на практике?

sbcl/src/compiler/srctran.lisp?

Пускай рассматривается коммон лисп и его подмножество: арифметика, векторы (aref должно переводится в сишную индексацию с квадратными скобками), а также функции соответствующие сишному <math.h>.

В CL числа неограниченного размера, в си - фиксированные. Так что нужно генерировать код для (g)mp, а для этого - переводить эти скобочки в SSA.

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

В CL числа неограниченного размера, в си - фиксированные.

Если известно, что размер не выходит за int, например, то никаких проблем нет.

anonymous
()

Что за бред, транслировать элементарную математику с CL на C для какого-то эфемерного прироста производительности - это как писать сложение асемблерными вставками потому что «асемблер эта крута, асемблер быстрее чем си!». Компилируешь, профилируешь, смотришь низкоуровневый код (асемблер а CL, java-байткод в Clojure) в боттлнеках, оптимизируешь. Вот тебе совет на практике, вот тебе независимость от платформы.

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

Я скобочками деревья назвал - у GMP такое API, он не понимает вложенных выражений, ему нужно расписать готовую секвенцию (3-operand instructions, фактически).

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

quasimoto

у GMP такое API, он не понимает вложенных выражений, ему нужно расписать готовую секвенцию (3-operand instructions, фактически).

трёхадресный код - это понятно, но таки static single assignment - это совсем про другое, SSA - это то как конпелятор представляет себе присваивания

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

это совсем про другое

Оговорился - переводить вложенную арифметику в секвенции (2/3-operand instructions, etc, не обязательно SSA).

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

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

malbolge ★★
()
16 января 2013 г.

Интересно знать, а как это реализуется на практике?

Смотри на Wolfram Mathematica, там для такой кодогенерации есть CForm (и аналогичная FortranForm).

Пускай рассматривается коммон лисп и его подмножество:

Никому обычно не надо генерить код из самого Лиспа в Си. Исходником служит обычно какой-либо DSL.

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

Лол, онанимному лиспофанбою так БОМБАНУЛО от ТСа, что он решил распечатать годовалую тему. Лол.

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