gaf: Fix memory leak
[geda-gaf.git] / docs / wiki / geda-gnetlist_scheme_tutorial.ru.html
blob29821c51acf0b9518b4bbe1e7013200cc74d76d0
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 <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
6 <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
7 <link rel="stylesheet" media="print" type="text/css" href="./print.css" />
9 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
10 </head>
11 <body>
13 <p>
14 <em>Это руководство доступно также на следующих языках:</em>
15 <a href="geda-gnetlist_scheme_tutorial.html" class="wikilink1" title="geda-gnetlist_scheme_tutorial.html">English</a>
16 </p>
18 <h1 id="написаниескриптовдрайверовgnetlistнаscheme">Написание скриптов драйверов gnetlist на Scheme</h1>
19 <div class="level1">
21 <p>
22 <strong>Автор: <em>John Doty</em></strong>
23 </p>
25 <p>
26 (первоначально это было
27 отправлено в
28 список рассылки gEDA-user в июле 2009 г.)
29 </p>
31 <p>
32 Не паникуй!
33 </p>
35 <p>
36 Если ты никогда не писал программы на <strong>Lisp</strong>, это выглядит страшновато. Но
37 это намного легче, чем кажется. Добавь в <strong>Lisp</strong> чуть-чуть синтаксического
38 сахара<sup><a href="#fn__25" id="fnt__25" class="fn_top">25)</a></sup> и он
39 превращается в <strong>Logo</strong>, который могут изучить даже дети из начальной школы.
40 </p>
42 <p>
43 И просто для объяснения значения некоторых из этих странных слов:
44 <a href="https://www.google.com/search?q=Lisp_%28programming_language%29&amp;btnI=lucky" class="interwiki iw_go" title="https://www.google.com/search?q=Lisp_%28programming_language%29&amp;btnI=lucky">Lisp</a> --- компьютерный язык,
45 <a href="https://www.google.com/search?q=Scheme_%28programming_language%29&amp;btnI=lucky" class="interwiki iw_go" title="https://www.google.com/search?q=Scheme_%28programming_language%29&amp;btnI=lucky">Scheme</a> --- диалект <strong>Lisp</strong>&#039;а, и
46 <a href="https://www.google.com/search?q=GNU_Guile&amp;btnI=lucky" class="interwiki iw_go" title="https://www.google.com/search?q=GNU_Guile&amp;btnI=lucky">Guile</a> --- реализация <strong>Scheme</strong>. <strong>Guile</strong> в gEDA
47 используется для написания скриптов. В частности, оболочка <strong>gnetlist</strong>,
48 написанная на <strong>C</strong>, выделяет из схем информацию о топологии и атрибутах, а
49 затем отдаёт данные низкоуровневым скриптам (драйверам) на <strong>Guile</strong> для
50 обработки и вывода.
51 </p>
53 <p>
54 Это руководство именно по программированию драйверов <strong>gnetlist</strong> на
55 <strong>Scheme</strong>. Если ты ещё не знаешь <strong>Scheme</strong>, тебе, наверно, стоит взглянуть
56 и на другие материалы, такие как:
57 </p>
59 <p>
60 http:<em>www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html
62 Или поищи «Учебник по Scheme» в своём любимом поисковике: их много.
64 Также может пригодиться справочный документ по адресу:
66 http:</em>www.gnu.org/software/guile/manual/html_node/index.html
67 </p>
69 <p>
70 Итак, начнём. Вот очень простой драйвер:
71 </p>
72 <pre class="code lisp"><span class="co1">;; gnetlist development playground</span>
73 &nbsp;
74 <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>
75 <span class="br0">&#40;</span>activate-readline<span class="br0">&#41;</span>
76 &nbsp;
77 <span class="br0">&#40;</span>define <span class="br0">&#40;</span>devel output-filename<span class="br0">&#41;</span>
78 <span class="br0">&#40;</span>scm-style-repl<span class="br0">&#41;</span>
79 <span class="br0">&#41;</span></pre>
81 <p>
82 Чтобы это применить, сохрани всё в файле <em><code>gnet-devel.scm</code></em>. Скопируй
83 этот файл туда, где в твоей системе хранятся файлы <strong>Scheme</strong>. На машине, на
84 которой я сейчас работаю, команда такова:
85 </p>
86 <pre class="code bash"><span class="co4">$ </span><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>
88 <p>
89 <em><code>/sw/</code></em> для многих устанавливаемых в Linux пакетов надо заменить на
90 <em><code>/usr/</code></em>, может быть на <em><code>/usr/local</code></em>, или --- при установке из
91 tar-архива --- на <em><code>~/mygeda/</code></em>. Это нужно выяснить. Если ты можешь
92 записывать в целевой каталог без прав суперпользователя, <strong><code>sudo</code></strong> не
93 нужно.
94 </p>
96 <p>
97 Теперь, изменив нужным образом <em><code>/sw/</code></em>, набери:
98 </p>
99 <pre class="code bash"><span class="co4">$ </span>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>
102 Ты должен увидеть обычный текст стандартного приглашения, за которым
103 следует:
104 </p>
105 <pre class="code">guile&gt;</pre>
108 Попробуй:
109 </p>
110 <pre class="code">guile&gt; packages</pre>
113 Ты должен увидеть:
114 </p>
115 <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>
118 <code>packages</code> --- удобная переменная, содержащая список всех уникальных
119 значений атрибутов <code>refdes=</code>. Набрав её, ты скормил её «REPL» --- циклу
120 чтения, вычисления, вывода (Read, Evaluate, Print Loop). Итак, REPL считал
121 её, вычислил (получив список) и вывел.
122 </p>
125 Теперь попробуй:
126 </p>
127 <pre class="code">guile&gt; (length packages)
128 25</pre>
131 Что здесь произошло? Здесь REPL вычислил список.
132 </p>
133 <pre class="code lisp"><span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span></pre>
136 В большинстве языков программирования ты бы написал это выражение в более
137 традиционной функциональной записи: <code>length(packages)</code>. <code>length</code> --- это
138 функция, которая сообщит тебе длину списка.
139 </p>
142 Такая же запись используется для арифметических вычислений. Например, «2+3»
143 вычисляется так:
144 </p>
145 <pre class="code">guile&gt; (+ 2 3)
146 5</pre>
149 Учти, что процедура &quot;+&quot; может использоваться для сложения любого
150 количества величин, в том числе и совсем ни одной:
151 </p>
152 <pre class="code">guile&gt; (+)
154 guile&gt; (+ 1 2 3)
155 6</pre>
158 Это мы используем позже.
159 </p>
162 Строки про <code>readline</code> в нашем драйвере <em><code>gnet-devel.scm</code></em> позволят
163 тебе пользоваться стрелками на клавиатуре для перемещения по истории и для
164 редактирования вводимых строк. Очень удобно в интерактивном
165 режиме. Попробуй.
166 </p>
169 Другая полезная переменная, определённая в <strong>gnetlist</strong>, это
170 <code>all-unique-nets</code> (набери это). Точно так же как <code>(length packages)</code>
171 говорит тебе, сколько у тебя компонентов, <code>(length all-unique-nets)</code>
172 подскажет, сколько у тебя соединений.
173 </p>
176 Ещё есть <code>all-pins</code>:
177 </p>
178 <pre class="code">guile&gt; all-pins
179 ((&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>
182 Заметь, это немного сложнее, чем в предыдущих примерах: это список списков,
183 а не просто список строк. Каждый из списков соответствует выводам
184 компонента. Есть одна штука, которую мы могли бы вытащить отсюда, --- это
185 подсчёт количества выводов. Мы не можем просто взять длину <code>all-pins</code>,
186 чтобы получить его: это даст нам только количество списков, содержащихся
187 там, равное количеству компонентов:
188 </p>
189 <pre class="code">guile&gt; (length all-pins)
190 25</pre>
193 Чтобы посчитать количество выводов, сначала посчитаем их количество для
194 каждого из компонентов в отдельности:
195 </p>
196 <pre class="code">guile&gt; (map length all-pins)
197 (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>
200 Это один из простых способов сделать «цикл» на <strong>Scheme</strong>; <code>(map p x)</code>
201 выдаёт список результатов вызываемой процедуры <code>p</code> отдельно для каждого
202 элемента из <code>x</code>. Затем мы можем их сложить с помощью «цикла» несколько
203 иного типа:
204 </p>
205 <pre class="code">guile&gt; (apply + (map length all-pins))
206 50</pre>
209 <code>(apply p x)</code> вызывает процедуру <code>p</code> один раз, с аргументами из всех
210 элементов из <code>x</code>. Поэтому вышеуказанное выражение в конце концов посчитает
211 следующее:
212 </p>
213 <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>
216 До сих пор мы использовали предопределённые переменные и процедуры. Но мы бы
217 хотели иметь возможность определять свои. Это просто:
218 </p>
219 <pre class="code">guile&gt; (define the-answer 42)
220 guile&gt; the-answer
221 42</pre>
224 Это определяет переменную <code>the-answer</code> и задаёт ей значение 42.
225 </p>
228 Можно также определять процедуры:
229 </p>
230 <pre class="code">guile&gt; (define add1 (lambda (x) (+ x 1)))
231 guile&gt; (add1 100)
232 101</pre>
235 Когда видишь <code>lambda</code>, думай --- «процедура». Сразу следом за <code>lambda</code>
236 идёт первый элемент (технический термин --- «выражение»<sup><a href="#fn__26" id="fnt__26" class="fn_top">26)</a></sup>) --- список аргументов процедуры, в
237 данном случае <code>(x)</code>. Когда вызывается процедура, <strong>Guile</strong> вычисляет
238 оставшиеся выражения, в данном случае только одно, <code>(+ x 1)</code>, с
239 подстановкой текущих аргументов. Результат процедуры --- это результат
240 вычисления последнего выражения. Так, <code>(add1 100)</code> становится <code>(+ 100
241 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> и
258 <code>newline</code>, названия которых говорят сами за себя. Теперь:
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="co4">$ </span><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__25" id="fn__25" class="fn_bot">25)</a></sup>
330 <div class="content">«Синтаксический сахар» --- конструкция языка программирования,
331 полностью эквивалентная другой его конструкции, но имеющая более
332 естественную запись (Компьютерный словарь). --- <em>Прим. перев.</em></div></div>
333 <div class="fn"><sup><a href="#fnt__26" id="fn__26" class="fn_bot">26)</a></sup>
334 <div class="content">Англоязычный термин
335 --- «form». --- <em>Прим. перев.</em></div></div>
336 </div>
337 </body>
338 </html>