-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgraph.scm
More file actions
142 lines (122 loc) · 3.54 KB
/
graph.scm
File metadata and controls
142 lines (122 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
;; draw graphs of state machines
;; outputs a file in the dot format
;; They can be compiled using:
;; dot -Tpng -o out.png file.dot
(module graph
(include "nfa.sch")
(include "dfa.sch")
;(main main-graph)
(import
(nfa "nfa.scm")
(dfa "dfa.scm")
(utils "utils.scm"))
(export
(view graph)
(graph state-machine . title)
(graph-to-file state-machine file)))
(define *image-viewer* "eog")
(define *dot* "dot")
(define (graph state-machine . title)
(let ((gr (cond ((nfa? state-machine)
(graph-nfa state-machine))
((dfa? state-machine)
(graph-dfa state-machine))
(else
(error "graph" "Can only produce a graph for nfa or dfa" state-machine)))))
(if (null? title)
gr
(append-dot gr "graph[label=\"~a\"]" (car title)))))
(define (append-dot gr fmt s)
(close-dot (string-append (open-dot gr) (format fmt s))))
(define (close-dot gr)
(string-append gr "}"))
(define (open-dot gr)
(let ((sc (string-contains gr "}")))
(if sc
(string-shrink! gr sc)
gr)))
(define (graph-to-file state-machine filename)
(call-with-output-file
filename
(lambda () (graph state-machine))))
(define (graph-transition transition)
(format "\t\"~a\" -> \"~a\" [label=\"~a\"];\n"
(first transition)
(third transition)
(second transition)))
(define dot-format
"digraph G {
rankdir=LR;
node[shape=circle style=invis]
~a;
~a
node[shape=circle style=solid]
~a
}")
(define dot-final-states
"node[shape=doublecircle style=solid]
~a;")
(define (string-quote x)
(format "\"~a\"" x))
(define (graph-dfa dfa . args)
(let* ((final-states (if (null? (dfa-final-states dfa))
""
(format dot-final-states
(string-join
(map string-quote (dfa-final-states dfa)) " "))))
(pre-start (gensym "dummy"))
(transitions (map graph-transition
(append (dfa-transition-list dfa)
;; add dummy transition to the starting state
(list
(list
pre-start
""
(dfa-start-state dfa)))))))
;; fill parameters into string
(format dot-format
pre-start
final-states
(string-join transitions ""))))
(define (graph-nfa nfa . args)
(let* ((final-states (if (null? (nfa-final-states nfa))
""
(format dot-final-states
(string-join
(map string-quote (nfa-final-states nfa)) " "))))
(pre-start (gensym "dummy"))
(trans-list
(cons
;; dummy transition to the starting state
(graph-transition
(list pre-start "" (nfa-start-state nfa)))
;; make a graph edge each transition
(map (lambda (trans)
(graph-transition trans))
(nfa-transition-list nfa))))
(transitions (string-join trans-list "")))
;; fill parameters into string
(format dot-format pre-start final-states transitions)))
;; Generate a png from the graph
;; using dot. Display the graph using eog.
(define (view graph)
(let* ((tempfile (temp-filename))
(proc (run-process *dot* "-Tpng" "-o" tempfile :input :pipe))
(proc-input (process-input-port proc)))
(fprint proc-input graph)
(flush-output-port proc-input)
(close-output-port proc-input)
(process-wait proc)
(run-process *image-viewer* tempfile error: "/dev/null")))
(define (main-graph argv)
(view (graph test-dfa1))
(print (graph test-dfa1))
;(print (graph test-nfa3))
;(show-graph (graph test-dfa1))
;(show-graph (graph (complete test-dfa1)))
;(show-graph (graph (inverse test-dfa1)))
(print-nfa test-nfa3)
(print-dfa (nfa->dfa test-nfa3))
;(show-graph (graph (complete (nfa->dfa test-nfa3))))
;(show-graph (graph test-nfa3)))
)