графическое построение кода LISP - PullRequest
1 голос
/ 16 января 2012

Относительно проекта GP У меня есть много автоматически сгенерированных фрагментов lisp, которые могут выглядеть примерно так:

(+ 2 (f1 (f2 x y) (f2 x y)))

Короче говоря: загрузка однострочников.

Какможно было бы построить это графически в дереве функций?Желательно генерировать графики в точках или что-то подобное, что можно легко протолкнуть через graphviz, чтобы я мог преобразовать его в нечто вроде этого:

       +
      / \
     /   \
    2     f1
         /  \
        /    \
       /      \
      /        \
     f2         f2
    /  \       /  \
   /    \     /    \
  x      y   x      y

Ответы [ 2 ]

2 голосов
/ 17 января 2012

Как это (в схеме [Доктор Ракет]):

(define (as-string elm)
  (cond
    ((string? elm) (string-append "\\\"" elm "\\\""))
    ((number? elm) (number->string elm))
    ((symbol? elm) (symbol->string elm))
    ((null? elm) "*empty-list*")
    (else (error "Unrecognized type"))))

(define (node-name-label names labels)
  (apply append (map (lambda (a b)
                       (if (list? a)
                           (node-name-label a b)
                           (list (cons a b))))
                     names labels)))

(define (node-txt names labels)
  (apply string-append (map (lambda (x)
                              (let ((name (car x)) (label (cdr x)))
                                (string-append name " [label=\"" (as-string label) "\"];\n")))
                            (node-name-label names labels))))

(define (graph-txt lst)
  (apply string-append (map (lambda (x)
                              (let ((a (car x)) (b (cdr x)))
                                (string-append a " -- " b ";\n")))
                            (get-relationships lst))))

(define (declare-nodes lst (basename "node"))
  (map (lambda (x n)
         (if (and (list? x) (not (empty? x)))
             (declare-nodes x (string-append basename "_" (number->string n)))
             (string-append basename "_" (number->string n))))
       lst
       (range 0 (length lst))))

(define (get-relationships lst)
  (if (< (length lst) 2)
      null
      (apply append (map (lambda (x)
                           (if (list? x)
                               (cons (cons (car lst) (car x)) (get-relationships x))
                               (list (cons (car lst) x))))
                         (cdr lst)))))

(define (range start end)
  (if (>= start end)
      '()
      (cons start (range (+ 1 start) end))))

(define (get-graph code graph-title)
  (let ((names (declare-nodes code)))
    (string-append
     "graph "
     graph-title
     " {\n"
     (node-txt names code)
     "\n"
     (graph-txt names)
     "}")))

Использование: (display (get-graph '(+ 2 (f1 (f2 () y) (f2 x y))) "simple_graph")) производит:

graph simple_graph {
node_0 [label="+"];
node_1 [label="2"];
node_2_0 [label="f1"];
node_2_1_0 [label="f2"];
node_2_1_1 [label="*empty-list*"];
node_2_1_2 [label="y"];
node_2_2_0 [label="f2"];
node_2_2_1 [label="x"];
node_2_2_2 [label="y"];

node_0 -- node_1;
node_0 -- node_2_0;
node_2_0 -- node_2_1_0;
node_2_1_0 -- node_2_1_1;
node_2_1_0 -- node_2_1_2;
node_2_0 -- node_2_2_0;
node_2_2_0 -- node_2_2_1;
node_2_2_0 -- node_2_2_2;
}
1 голос
/ 17 января 2012

Я сделал быстрый и грязный Perl-скрипт, который делает то, что мне нужно. Разместите его здесь на случай, если кто-то еще сможет его использовать: Ссылка: http://jarmund.net/stuff/lisp2svg.pl.txt

Пример вывода: http://jarmund.net/graphs/lisp.svg

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

...