Automatic wiki import (Sat Mar 8 21:51:23 UTC 2014)
[geda-gaf.git] / docs / wiki / geda-gnetlist_scheme_tutorial.ru.html
blob986557a4f24b76c7a3e99aa0fe81518dffb22250
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html>
4 <head>
5 <title></title>
6 <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
7 <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
8 <link rel="stylesheet" media="print" type="text/css" href="./print.css" />
10 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
11 </head>
12 <body>
15 <h1 class="sectionedit1452"><a name="написание_скриптов_драйверов_gnetlist_на_scheme" id="написание_скриптов_драйверов_gnetlist_на_scheme">Написание скриптов драйверов gnetlist на Scheme</a></h1>
16 <div class="level1">
18 <p>
19 <strong>Автор: <em>John Doty</em></strong>
20 </p>
22 <p>
23 (первоначально это было
24 <a href="http://archives.seul.org/geda/user/Jul-2009/msg00235.html" class="urlextern" title="http://archives.seul.org/geda/user/Jul-2009/msg00235.html" rel="nofollow">отправлено</a> в
25 список рассылки gEDA-user в июле 2009 г.)
26 </p>
28 <p>
29 Не паникуй!
30 </p>
32 <p>
33 Если ты никогда не писал программы на <strong>Lisp</strong>, это выглядит страшновато. Но
34 это намного легче, чем кажется. Добавь в <strong>Lisp</strong> чуть-чуть синтаксического
35 сахара<sup><a href="#fn__1" name="fnt__1" id="fnt__1" class="fn_top">1)</a></sup> и он превращается в
36 <strong>Logo</strong>, который могут изучить даже дети из начальной школы.
37 </p>
39 <p>
40 И просто для объяснения значения некоторых из этих странных слов:
41 <a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp</a> — компьютерный язык,
42 <a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/Scheme_(programming_language)">Scheme</a> — диалект <strong>Lisp</strong>&#039;а,
43 и <a href="http://en.wikipedia.org/wiki/GNU_Guile" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/GNU_Guile">Guile</a> — реализация <strong>Scheme</strong>.
44 <strong>Guile</strong> в gEDA используется для написания скриптов. В частности,
45 оболочка <strong>gnetlist</strong>, написанная на <strong>C</strong>, выделяет из схем информацию о
46 топологии и атрибутах, а затем отдаёт данные низкоуровневым скриптам
47 (драйверам) на <strong>Guile</strong> для обработки и вывода.
48 </p>
50 <p>
51 Это руководство именно по программированию драйверов
52 <strong>gnetlist</strong> на <strong>Scheme</strong>. Если ты ещё не знаешь <strong>Scheme</strong>, тебе, наверно,
53 стоит взглянуть и на другие материалы, такие как:
54 </p>
56 <p>
57 <a href="http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html" class="urlextern" title="http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html" rel="nofollow">http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html</a>
58 </p>
60 <p>
61 Или поищи “Учебник по Scheme” в своём любимом поисковике: их много.
62 </p>
64 <p>
65 Также может пригодиться справочный документ по адресу:
66 </p>
68 <p>
69 <a href="http://www.gnu.org/software/guile/manual/html_node/index.html" class="urlextern" title="http://www.gnu.org/software/guile/manual/html_node/index.html" rel="nofollow">http://www.gnu.org/software/guile/manual/html_node/index.html</a>
70 </p>
72 <p>
73 Итак, начнём. Вот очень простой драйвер:
74 </p>
75 <pre class="code lisp"><span class="co1">;; gnetlist development playground</span>
76 &nbsp;
77 <span class="br0">&#40;</span>use-modules <span class="br0">&#40;</span>ice-<span class="nu0">9</span> readline<span class="br0">&#41;</span><span class="br0">&#41;</span>
78 <span class="br0">&#40;</span>activate-readline<span class="br0">&#41;</span>
79 &nbsp;
80 <span class="br0">&#40;</span>define <span class="br0">&#40;</span>devel output-filename<span class="br0">&#41;</span>
81 <span class="br0">&#40;</span>scm-style-repl<span class="br0">&#41;</span>
82 <span class="br0">&#41;</span></pre>
84 <p>
85 Чтобы это применить, сохрани всё в файле <em><code>gnet-devel.scm</code></em>. Скопируй этот
86 файл туда, где в твоей системе хранятся файлы <strong>Scheme</strong>. На машине, на
87 которой я сейчас работаю, команда такова:
88 </p>
89 <pre class="code bash">$ <span class="kw2">sudo</span> <span class="kw2">cp</span> gnet-devel.scm <span class="sy0">/</span>sw<span class="sy0">/</span>share<span class="sy0">/</span>gEDA<span class="sy0">/</span>scheme<span class="sy0">/</span></pre>
91 <p>
92 <em><code>/sw/</code></em> для многих устанавливаемых в Linux пакетов надо
93 заменить на <em><code>/usr/</code></em>, может быть на <em><code>/usr/local</code></em>, или — при
94 установке из tar-архива — на <em><code>~/mygeda/</code></em>. Это нужно выяснить. Если ты
95 можешь записывать в целевой каталог без прав суперпользователя, <strong><code>sudo</code></strong>
96 не нужно.
97 </p>
99 <p>
100 Теперь, изменив нужным образом <em><code>/sw/</code></em>, набери:
101 </p>
102 <pre class="code bash">$ gnetlist <span class="re5">-g</span> devel <span class="sy0">/</span>sw<span class="sy0">/</span>share<span class="sy0">/</span>gEDA<span class="sy0">/</span>examples<span class="sy0">/</span>lightning_detector<span class="sy0">/</span>lightning.sch</pre>
105 Ты должен увидеть обычный текст стандартного приглашения, за которым следует:
106 </p>
107 <pre class="code">guile&gt;</pre>
110 Попробуй:
111 </p>
112 <pre class="code">guile&gt; packages</pre>
115 Ты должен увидеть:
116 </p>
117 <pre class="code lisp"><span class="br0">&#40;</span><span class="st0">&quot;Q3&quot;</span> <span class="st0">&quot;R5&quot;</span> <span class="st0">&quot;Q2&quot;</span> <span class="st0">&quot;R4&quot;</span> <span class="st0">&quot;Q1&quot;</span> <span class="st0">&quot;C6&quot;</span> <span class="st0">&quot;R3&quot;</span> <span class="st0">&quot;L2&quot;</span> <span class="st0">&quot;A1&quot;</span> <span class="st0">&quot;bat(+3v)&quot;</span> <span class="st0">&quot;lamp(1)&quot;</span> <span class="st0">&quot;R2&quot;</span> <span class="st0">&quot;C5&quot;</span> <span class="st0">&quot;L1&quot;</span> <span class="st0">&quot;R1&quot;</span> <span class="st0">&quot;C4&quot;</span> <span class="st0">&quot;lamp(2)&quot;</span> <span class="st0">&quot;C3&quot;</span> <span class="st0">&quot;C2&quot;</span> <span class="st0">&quot;C1&quot;</span> <span class="st0">&quot;D1&quot;</span> <span class="st0">&quot;bat(0v)&quot;</span> <span class="st0">&quot;R7&quot;</span> <span class="st0">&quot;Q4&quot;</span> <span class="st0">&quot;R6&quot;</span><span class="br0">&#41;</span></pre>
120 <code>packages</code> — удобная переменная, содержащая список всех уникальных
121 значений атрибутов <code>refdes=</code>. Набрав её, ты скормил её “REPL” — циклу
122 чтения, оценки, вывода (Read, Evaluate, Print Loop). Итак,
123 REPL считал её, оценил (создав список) и вывел.
124 </p>
127 Теперь попробуй:
128 </p>
129 <pre class="code">guile&gt; (length packages)
130 25</pre>
133 Что здесь произошло? Здесь REPL оценил список.
134 </p>
135 <pre class="code lisp"><span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span></pre>
138 В большинстве языков программирования ты бы написал это выражение в более
139 традиционной функциональной записи: <code>length(packages)</code>. <code>length</code> — это
140 функция, которая сообщит тебе длину списка.
141 </p>
144 Такая же запись используется для арифметических вычислений. Например, “2+3
145 вычисляется так:
146 </p>
147 <pre class="code">guile&gt; (+ 2 3)
148 5</pre>
151 Учти, что процедура &quot;+&quot; может использоваться для сложения любого
152 количества величин, в том числе и совсем ни одной:
153 </p>
154 <pre class="code">guile&gt; (+)
156 guile&gt; (+ 1 2 3)
157 6</pre>
160 Это мы используем позже.
161 </p>
164 Строки про <code>readline</code> в нашем драйвере <em><code>gnet-devel.scm</code></em> позволят тебе
165 пользоваться стрелками на клавиатуре для перемещения по истории и для
166 редактирования вводимых строк. Очень удобно в интерактивном режиме. Попробуй.
167 </p>
170 Другая полезная переменная, определённая в <strong>gnetlist</strong>, это
171 <code>all-unique-nets</code> (набери это). Точно так же как <code>(length packages)</code>
172 говорит тебе, сколько у тебя компонентов, <code>(length all-unique-nets)</code>
173 подскажет, сколько у тебя соединений.
174 </p>
177 Ещё есть <code>all-pins</code>:
178 </p>
179 <pre class="code">guile&gt; all-pins
180 ((&quot;1&quot; &quot;2&quot; &quot;3&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;1&quot;) (&quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot;) (&quot;1&quot;))</pre>
183 Заметь, это немного сложнее, чем в предыдущих примерах: это список списков, а
184 не просто список строк. Каждый из списков соответствует выводам компонента.
185 Есть одна штука, которую мы могли бы вытащить отсюда, — это подсчёт
186 количества выводов. Мы не можем просто взять длину <code>all-pins</code>, чтобы
187 получить его: это даст нам только количество списков, содержащихся там, равное
188 количеству компонентов:
189 </p>
190 <pre class="code">guile&gt; (length all-pins)
191 25</pre>
194 Чтобы посчитать количество выводов, сначала посчитаем их количество для
195 каждого из компонентов в отдельности:
196 </p>
197 <pre class="code">guile&gt; (map length all-pins)
198 (3 3 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 3 3 1 2 3 2 1 1)</pre>
201 Это один из простых способов сделать “цикл” на <strong>Scheme</strong>; <code>(map p x)</code>
202 выдаёт список результатов вызываемой процедуры <code>p</code> отдельно для каждого
203 элемента из <code>x</code>. Затем мы можем их сложить с помощью “цикла” несколько иного
204 типа:
205 </p>
206 <pre class="code">guile&gt; (apply + (map length all-pins))
207 50</pre>
210 <code>(apply p x)</code> вызывает процедуру <code>p</code> один раз, с аргументами из всех
211 элементов из <code>x</code>. Поэтому вышеуказанное выражение в конце концов посчитает
212 следующее:
213 </p>
214 <pre class="code lisp"><span class="br0">&#40;</span>+ <span class="nu0">3</span> <span class="nu0">3</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">3</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">2</span> <span class="nu0">1</span> <span class="nu0">1</span><span class="br0">&#41;</span></pre>
217 До сих пор мы использовали предопределённые переменные и процедуры. Но мы бы
218 хотели иметь возможность определять свои. Это просто:
219 </p>
220 <pre class="code">guile&gt; (define the-answer 42)
221 guile&gt; the-answer
222 42</pre>
225 Это определяет переменную <code>the-answer</code> и задаёт ей значение 42.
226 </p>
229 Можно также определять процедуры:
230 </p>
231 <pre class="code">guile&gt; (define add1 (lambda (x) (+ x 1)))
232 guile&gt; (add1 100)
233 101</pre>
236 Когда видишь <code>lambda</code>, думай — “процедура”. Сразу следом за <code>lambda</code> идёт
237 первый элемент (технический термин — “выражение”<sup><a href="#fn__2" name="fnt__2" id="fnt__2" class="fn_top">2)</a></sup>) — список аргументов процедуры, в данном случае
238 <code>(x)</code>. Когда вызывается процедура, <strong>Guile</strong> оценивает оставшиеся выражения,
239 в данном случае только одно, <code>(+ x 1)</code>, с подстановкой текущих аргументов.
240 Результат процедуры — это результат оценки последнего выражения. Так,
241 <code>(add1 100)</code> становится <code>(+ 100 1)</code>, что даёт 101.
242 </p>
245 Теперь мы можем объединить наш сбор статистики в драйвер.
246 Сначала определим процедуру для записи выходной строки:
247 </p>
248 <pre class="code lisp"><span class="br0">&#40;</span>define format-line
249 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="kw1">name</span> <span class="kw1">value</span><span class="br0">&#41;</span>
250 <span class="br0">&#40;</span>display <span class="kw1">name</span><span class="br0">&#41;</span>
251 <span class="br0">&#40;</span>display <span class="kw1">value</span><span class="br0">&#41;</span>
252 <span class="br0">&#40;</span>newline<span class="br0">&#41;</span>
253 <span class="br0">&#41;</span>
254 <span class="br0">&#41;</span></pre>
257 Здесь мы используем две новых встроенных процедуры, <code>display</code> и <code>newline</code>,
258 названия которых говорят сами за себя. Теперь:
259 </p>
260 <pre class="code lisp"><span class="br0">&#40;</span>define display-stats
261 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="co1">; без аргументов</span>
262 <span class="br0">&#40;</span>format-line <span class="st0">&quot;pins: &quot;</span> <span class="br0">&#40;</span><span class="kw1">apply</span><span class="sy0"> + </span><span class="br0">&#40;</span>map <span class="kw1">length</span> all-pins<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
263 <span class="br0">&#40;</span>format-line <span class="st0">&quot;packages: &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span><span class="br0">&#41;</span>
264 <span class="br0">&#40;</span>format-line <span class="st0">&quot;nets: &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> all-unique-nets<span class="br0">&#41;</span><span class="br0">&#41;</span>
265 <span class="br0">&#41;</span>
266 <span class="br0">&#41;</span></pre>
267 <pre class="code">guile&gt; (display-stats)
268 pins: 50
269 packages: 25
270 nets: 13</pre>
273 Чтобы завершить драйвер, нам нужна “основная программа”. По соглашению она
274 называется так же, как и сам драйвер. Также она отвечает за открывание выходного файла.
275 Итак, целиком файл драйвера сбора статистики “stats” будет выглядеть
276 примерно так:
277 </p>
278 <pre class="code lisp"><span class="co1">;; драйвер gnetlist для получения статистики по проекту</span>
279 <span class="co1">;;</span>
280 <span class="co1">;; Стандартный текст лицензии, как положено</span>
281 &nbsp;
282 <span class="br0">&#40;</span>define stats
283 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>filename<span class="br0">&#41;</span>
284 <span class="br0">&#40;</span>set-current-output-port <span class="br0">&#40;</span>open-output-file filename<span class="br0">&#41;</span><span class="br0">&#41;</span>
285 <span class="br0">&#40;</span>display-stats<span class="br0">&#41;</span>
286 <span class="br0">&#41;</span>
287 <span class="br0">&#41;</span>
288 &nbsp;
289 <span class="co1">;; Сбор и вывод статистики</span>
290 &nbsp;
291 <span class="br0">&#40;</span>define display-stats
292 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="co1">; без аргументов</span>
293 <span class="br0">&#40;</span>format-line <span class="st0">&quot;pins: &quot;</span> <span class="br0">&#40;</span><span class="kw1">apply</span><span class="sy0"> + </span><span class="br0">&#40;</span>map <span class="kw1">length</span> all-pins<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
294 <span class="br0">&#40;</span>format-line <span class="st0">&quot;packages: &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span><span class="br0">&#41;</span>
295 <span class="br0">&#40;</span>format-line <span class="st0">&quot;nets: &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> all-unique-nets<span class="br0">&#41;</span><span class="br0">&#41;</span>
296 <span class="br0">&#41;</span>
297 <span class="br0">&#41;</span>
298 &nbsp;
299 <span class="co1">;; Простой формат вывода</span>
300 &nbsp;
301 <span class="br0">&#40;</span>define format-line
302 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="kw1">name</span> <span class="kw1">value</span><span class="br0">&#41;</span>
303 <span class="br0">&#40;</span>display <span class="kw1">name</span><span class="br0">&#41;</span>
304 <span class="br0">&#40;</span>display <span class="kw1">value</span><span class="br0">&#41;</span>
305 <span class="br0">&#40;</span>newline<span class="br0">&#41;</span>
306 <span class="br0">&#41;</span>
307 <span class="br0">&#41;</span></pre>
310 Сохрани это в файле с именем <code>gnet-stats.scm</code>, скопируй его в надлежащее
311 место, например так:
312 </p>
313 <pre class="code bash">$ <span class="kw2">sudo</span> <span class="kw2">cp</span> gnet-stats.scm <span class="sy0">/</span>sw<span class="sy0">/</span>share<span class="sy0">/</span>gEDA<span class="sy0">/</span>scheme<span class="sy0">/</span></pre>
316 и затем <strong><code>gnetlist -g stats</code></strong> с другими обычными аргументами и именами
317 схем выдаст статистику твоего проекта в выходной файл (по умолчанию
318 <em><code>output.net</code></em>).
319 </p>
322 Довольно просто, а? А также полезно. Недавно я проектировал системы, состоящие
323 из множества плат: статистика, подобная этой, помогает мне выяснить, какие
324 подсистемы лучше скомбинировать на каждой из плат.
325 </p>
327 </div>
328 <div class="footnotes">
329 <div class="fn"><sup><a href="#fnt__1" id="fn__1" name="fn__1" class="fn_bot">1)</a></sup>
330 “Синтаксический сахар” — конструкция языка программирования,
331 полностью эквивалентная другой его конструкции, но имеющая более естественную
332 запись (Компьютерный словарь). — <em>Прим. перев.</em></div>
333 <div class="fn"><sup><a href="#fnt__2" id="fn__2" name="fn__2" class="fn_bot">2)</a></sup>
334 Англоязычный термин —
335 “form”. — <em>Прим. перев.</em></div>
336 </div>
337 </body>
338 </html>