missing NULL terminator in set_config_x
[geda-gaf.git] / docs / wiki / geda-gnetlist_scheme_tutorial.ru.html
blobaaaf6ea4dbd062bd18b64dffa393c9d35e5388c8
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 class="sectionedit1" 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 <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> в
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__26" id="fnt__26" class="fn_top">26)</a></sup> и он
39 превращается в <strong>Logo</strong>, который могут изучить даже дети из начальной школы.
40 </p>
42 <p>
43 И просто для объяснения значения некоторых из этих странных слов:
44 <a href="https://en.wikipedia.org/wiki/Lisp_(programming_language)" class="interwiki iw_wp" title="https://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp</a> — компьютерный язык,
45 <a href="https://en.wikipedia.org/wiki/Scheme_(programming_language)" class="interwiki iw_wp" title="https://en.wikipedia.org/wiki/Scheme_(programming_language)">Scheme</a> — диалект <strong>Lisp</strong>&#039;а, и
46 <a href="https://en.wikipedia.org/wiki/GNU_Guile" class="interwiki iw_wp" title="https://en.wikipedia.org/wiki/GNU_Guile">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 <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>
61 </p>
63 <p>
64 Или поищи «Учебник по Scheme» в своём любимом поисковике: их много.
65 </p>
67 <p>
68 Также может пригодиться справочный документ по адресу:
69 </p>
71 <p>
72 <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>
73 </p>
75 <p>
76 Итак, начнём. Вот очень простой драйвер:
77 </p>
78 <pre class="code lisp"><span class="co1">;; gnetlist development playground</span>
79 &nbsp;
80 <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>
81 <span class="br0">&#40;</span>activate-readline<span class="br0">&#41;</span>
82 &nbsp;
83 <span class="br0">&#40;</span>define <span class="br0">&#40;</span>devel output-filename<span class="br0">&#41;</span>
84 <span class="br0">&#40;</span>scm-style-repl<span class="br0">&#41;</span>
85 <span class="br0">&#41;</span></pre>
87 <p>
88 Чтобы это применить, сохрани всё в файле <em><code>gnet-devel.scm</code></em>. Скопируй
89 этот файл туда, где в твоей системе хранятся файлы <strong>Scheme</strong>. На машине, на
90 которой я сейчас работаю, команда такова:
91 </p>
92 <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>
94 <p>
95 <em><code>/sw/</code></em> для многих устанавливаемых в Linux пакетов надо заменить на
96 <em><code>/usr/</code></em>, может быть на <em><code>/usr/local</code></em>, или — при установке из
97 tar-архива — на <em><code>~/mygeda/</code></em>. Это нужно выяснить. Если ты можешь
98 записывать в целевой каталог без прав суперпользователя, <strong><code>sudo</code></strong> не
99 нужно.
100 </p>
103 Теперь, изменив нужным образом <em><code>/sw/</code></em>, набери:
104 </p>
105 <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>
108 Ты должен увидеть обычный текст стандартного приглашения, за которым
109 следует:
110 </p>
111 <pre class="code">guile&gt;</pre>
114 Попробуй:
115 </p>
116 <pre class="code">guile&gt; packages</pre>
119 Ты должен увидеть:
120 </p>
121 <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>
124 <code>packages</code> — удобная переменная, содержащая список всех уникальных
125 значений атрибутов <code>refdes=</code>. Набрав её, ты скормил её «REPL» — циклу
126 чтения, вычисления, вывода (Read, Evaluate, Print Loop). Итак, REPL считал
127 её, вычислил (получив список) и вывел.
128 </p>
131 Теперь попробуй:
132 </p>
133 <pre class="code">guile&gt; (length packages)
134 25</pre>
137 Что здесь произошло? Здесь REPL вычислил список.
138 </p>
139 <pre class="code lisp"><span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span></pre>
142 В большинстве языков программирования ты бы написал это выражение в более
143 традиционной функциональной записи: <code>length(packages)</code>. <code>length</code> — это
144 функция, которая сообщит тебе длину списка.
145 </p>
148 Такая же запись используется для арифметических вычислений. Например, «2+3»
149 вычисляется так:
150 </p>
151 <pre class="code">guile&gt; (+ 2 3)
152 5</pre>
155 Учти, что процедура &quot;+&quot; может использоваться для сложения любого
156 количества величин, в том числе и совсем ни одной:
157 </p>
158 <pre class="code">guile&gt; (+)
160 guile&gt; (+ 1 2 3)
161 6</pre>
164 Это мы используем позже.
165 </p>
168 Строки про <code>readline</code> в нашем драйвере <em><code>gnet-devel.scm</code></em> позволят
169 тебе пользоваться стрелками на клавиатуре для перемещения по истории и для
170 редактирования вводимых строк. Очень удобно в интерактивном
171 режиме. Попробуй.
172 </p>
175 Другая полезная переменная, определённая в <strong>gnetlist</strong>, это
176 <code>all-unique-nets</code> (набери это). Точно так же как <code>(length packages)</code>
177 говорит тебе, сколько у тебя компонентов, <code>(length all-unique-nets)</code>
178 подскажет, сколько у тебя соединений.
179 </p>
182 Ещё есть <code>all-pins</code>:
183 </p>
184 <pre class="code">guile&gt; all-pins
185 ((&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>
188 Заметь, это немного сложнее, чем в предыдущих примерах: это список списков,
189 а не просто список строк. Каждый из списков соответствует выводам
190 компонента. Есть одна штука, которую мы могли бы вытащить отсюда, — это
191 подсчёт количества выводов. Мы не можем просто взять длину <code>all-pins</code>,
192 чтобы получить его: это даст нам только количество списков, содержащихся
193 там, равное количеству компонентов:
194 </p>
195 <pre class="code">guile&gt; (length all-pins)
196 25</pre>
199 Чтобы посчитать количество выводов, сначала посчитаем их количество для
200 каждого из компонентов в отдельности:
201 </p>
202 <pre class="code">guile&gt; (map length all-pins)
203 (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>
206 Это один из простых способов сделать «цикл» на <strong>Scheme</strong>; <code>(map p x)</code>
207 выдаёт список результатов вызываемой процедуры <code>p</code> отдельно для каждого
208 элемента из <code>x</code>. Затем мы можем их сложить с помощью «цикла» несколько
209 иного типа:
210 </p>
211 <pre class="code">guile&gt; (apply + (map length all-pins))
212 50</pre>
215 <code>(apply p x)</code> вызывает процедуру <code>p</code> один раз, с аргументами из всех
216 элементов из <code>x</code>. Поэтому вышеуказанное выражение в конце концов посчитает
217 следующее:
218 </p>
219 <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>
222 До сих пор мы использовали предопределённые переменные и процедуры. Но мы бы
223 хотели иметь возможность определять свои. Это просто:
224 </p>
225 <pre class="code">guile&gt; (define the-answer 42)
226 guile&gt; the-answer
227 42</pre>
230 Это определяет переменную <code>the-answer</code> и задаёт ей значение 42.
231 </p>
234 Можно также определять процедуры:
235 </p>
236 <pre class="code">guile&gt; (define add1 (lambda (x) (+ x 1)))
237 guile&gt; (add1 100)
238 101</pre>
241 Когда видишь <code>lambda</code>, думай — «процедура». Сразу следом за <code>lambda</code>
242 идёт первый элемент (технический термин — «выражение»<sup><a href="#fn__27" id="fnt__27" class="fn_top">27)</a></sup>) — список аргументов процедуры, в
243 данном случае <code>(x)</code>. Когда вызывается процедура, <strong>Guile</strong> вычисляет
244 оставшиеся выражения, в данном случае только одно, <code>(+ x 1)</code>, с
245 подстановкой текущих аргументов. Результат процедуры — это результат
246 вычисления последнего выражения. Так, <code>(add1 100)</code> становится <code>(+ 100
247 1)</code>, что даёт 101.
248 </p>
251 Теперь мы можем объединить наш сбор статистики в драйвер. Сначала определим
252 процедуру для записи выходной строки:
253 </p>
254 <pre class="code lisp"><span class="br0">&#40;</span>define format-line
255 <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>
256 <span class="br0">&#40;</span>display <span class="kw1">name</span><span class="br0">&#41;</span>
257 <span class="br0">&#40;</span>display <span class="kw1">value</span><span class="br0">&#41;</span>
258 <span class="br0">&#40;</span>newline<span class="br0">&#41;</span>
259 <span class="br0">&#41;</span>
260 <span class="br0">&#41;</span></pre>
263 Здесь мы используем две новых встроенных процедуры, <code>display</code> и
264 <code>newline</code>, названия которых говорят сами за себя. Теперь:
265 </p>
266 <pre class="code lisp"><span class="br0">&#40;</span>define display-stats
267 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="co1">; без аргументов</span>
268 <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>
269 <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>
270 <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>
271 <span class="br0">&#41;</span>
272 <span class="br0">&#41;</span></pre>
273 <pre class="code">guile&gt; (display-stats)
274 pins: 50
275 packages: 25
276 nets: 13</pre>
279 Чтобы завершить драйвер, нам нужна «основная программа». По соглашению она
280 называется так же, как и сам драйвер. Также она отвечает за открывание
281 выходного файла. Итак, целиком файл драйвера сбора статистики «stats» будет
282 выглядеть примерно так:
283 </p>
284 <pre class="code lisp"><span class="co1">;; драйвер gnetlist для получения статистики по проекту</span>
285 <span class="co1">;;</span>
286 <span class="co1">;; Стандартный текст лицензии, как положено</span>
287 &nbsp;
288 <span class="br0">&#40;</span>define stats
289 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>filename<span class="br0">&#41;</span>
290 <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>
291 <span class="br0">&#40;</span>display-stats<span class="br0">&#41;</span>
292 <span class="br0">&#41;</span>
293 <span class="br0">&#41;</span>
294 &nbsp;
295 <span class="co1">;; Сбор и вывод статистики</span>
296 &nbsp;
297 <span class="br0">&#40;</span>define display-stats
298 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="co1">; без аргументов</span>
299 <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>
300 <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>
301 <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>
302 <span class="br0">&#41;</span>
303 <span class="br0">&#41;</span>
304 &nbsp;
305 <span class="co1">;; Простой формат вывода</span>
306 &nbsp;
307 <span class="br0">&#40;</span>define format-line
308 <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>
309 <span class="br0">&#40;</span>display <span class="kw1">name</span><span class="br0">&#41;</span>
310 <span class="br0">&#40;</span>display <span class="kw1">value</span><span class="br0">&#41;</span>
311 <span class="br0">&#40;</span>newline<span class="br0">&#41;</span>
312 <span class="br0">&#41;</span>
313 <span class="br0">&#41;</span></pre>
316 Сохрани это в файле с именем <code>gnet-stats.scm</code>, скопируй его в надлежащее
317 место, например так:
318 </p>
319 <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>
322 и затем <strong><code>gnetlist -g stats</code></strong> с другими обычными аргументами и именами
323 схем выдаст статистику твоего проекта в выходной файл (по умолчанию
324 <em><code>output.net</code></em>).
325 </p>
328 Довольно просто, а? А также полезно. Недавно я проектировал системы,
329 состоящие из множества плат: статистика, подобная этой, помогает мне
330 выяснить, какие подсистемы лучше скомбинировать на каждой из плат.
331 </p>
333 </div>
334 <!-- EDIT1 SECTION "Написание скриптов драйверов gnetlist на Scheme" [139-] --><div class="footnotes">
335 <div class="fn"><sup><a href="#fnt__26" id="fn__26" class="fn_bot">26)</a></sup>
336 <div class="content">«Синтаксический сахар» — конструкция языка программирования,
337 полностью эквивалентная другой его конструкции, но имеющая более
338 естественную запись (Компьютерный словарь). — <em>Прим. перев.</em></div></div>
339 <div class="fn"><sup><a href="#fnt__27" id="fn__27" class="fn_bot">27)</a></sup>
340 <div class="content">Англоязычный термин
341 — «form». — <em>Прим. перев.</em></div></div>
342 </div>
343 </body>
344 </html>