Sophie

Sophie

distrib > Mageia > 4 > x86_64 > by-pkgid > ffa379e674c6e907833924c14996ed7e > files > 86

geda-docs-1.8.1-6.mga4.x86_64.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
  <title></title>
  <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
  <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
  <link rel="stylesheet" media="print" type="text/css" href="./print.css" />

  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>


<h1 class="sectionedit1426"><a name="написание_скриптов_драйверов_gnetlist_на_scheme" id="написание_скриптов_драйверов_gnetlist_на_scheme">Написание скриптов драйверов gnetlist на Scheme</a></h1>
<div class="level1">

<p>
<strong>Автор: <em>John Doty</em></strong>
</p>

<p>
(первоначально это было
<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> в
список рассылки gEDA-user в июле 2009 г.)
</p>

<p>
Не паникуй!
</p>

<p>
Если ты никогда не писал программы на <strong>Lisp</strong>, это выглядит страшновато. Но
это намного легче, чем кажется. Добавь в <strong>Lisp</strong> чуть-чуть синтаксического
сахара<sup><a href="#fn__1" name="fnt__1" id="fnt__1" class="fn_top">1)</a></sup> и он превращается в
<strong>Logo</strong>, который могут изучить даже дети из начальной школы.
</p>

<p>
И просто для объяснения значения некоторых из этих странных слов:
<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> — компьютерный язык,
<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;а,
и <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>.
<strong>Guile</strong> в gEDA используется для написания скриптов. В частности,
оболочка <strong>gnetlist</strong>, написанная на <strong>C</strong>, выделяет из схем информацию о
топологии и атрибутах, а затем отдаёт данные низкоуровневым скриптам
(драйверам) на <strong>Guile</strong> для обработки и вывода.
</p>

<p>
Это руководство именно по программированию драйверов
<strong>gnetlist</strong> на <strong>Scheme</strong>. Если ты ещё не знаешь <strong>Scheme</strong>, тебе, наверно,
стоит взглянуть и на другие материалы, такие как:
</p>

<p>
<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>
</p>

<p>
Или поищи “Учебник по Scheme” в своём любимом поисковике: их много.
</p>

<p>
Также может пригодиться справочный документ по адресу:
</p>

<p>
<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>
</p>

<p>
Итак, начнём. Вот очень простой драйвер:
</p>
<pre class="code scheme"><span class="co1">;; gnetlist development playground</span>
&nbsp;</pre>

<p>
Чтобы это применить, сохрани всё в файле <em><code>gnet-devel.scm</code></em>. Скопируй этот
файл туда, где в твоей системе хранятся файлы <strong>Scheme</strong>. На машине, на
которой я сейчас работаю, команда такова:
</p>
<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>

<p>
<em><code>/sw/</code></em> для многих устанавливаемых в Linux пакетов надо
заменить на <em><code>/usr/</code></em>, может быть на <em><code>/usr/local</code></em>, или — при
установке из tar-архива — на <em><code>~/mygeda/</code></em>. Это нужно выяснить. Если ты
можешь записывать в целевой каталог без прав суперпользователя, <strong><code>sudo</code></strong>
не нужно.
</p>

<p>
Теперь, изменив нужным образом <em><code>/sw/</code></em>, набери:
</p>
<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>

<p>
Ты должен увидеть обычный текст стандартного приглашения, за которым следует:
</p>
<pre class="code">guile&gt;</pre>

<p>
Попробуй:
</p>
<pre class="code">guile&gt; packages</pre>

<p>
Ты должен увидеть:
</p>
<pre class="code scheme"><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></pre>

<p>
<code>packages</code> — удобная переменная, содержащая список всех уникальных
значений атрибутов <code>refdes=</code>. Набрав её, ты скормил её “REPL” — циклу
чтения, оценки, вывода (Read, Evaluate, Print Loop). Итак,
REPL считал её, оценил (создав список) и вывел.
</p>

<p>
Теперь попробуй:
</p>
<pre class="code">guile&gt; (length packages)
25</pre>

<p>
Что здесь произошло? Здесь REPL оценил список.
</p>
<pre class="code scheme">&nbsp;</pre>

<p>
В большинстве языков программирования ты бы написал это выражение в более
традиционной функциональной записи: <code>length(packages)</code>. <code>length</code> — это
функция, которая сообщит тебе длину списка.
</p>

<p>
Такая же запись используется для арифметических вычислений. Например, “2+3”
вычисляется так:
</p>
<pre class="code">guile&gt; (+ 2 3)
5</pre>

<p>
Учти, что процедура &quot;+&quot; может использоваться для сложения любого
количества величин, в том числе и совсем ни одной:
</p>
<pre class="code">guile&gt; (+)
0
guile&gt; (+ 1 2 3)
6</pre>

<p>
Это мы используем позже.
</p>

<p>
Строки про <code>readline</code> в нашем драйвере <em><code>gnet-devel.scm</code></em> позволят тебе
пользоваться стрелками на клавиатуре для перемещения по истории и для
редактирования вводимых строк. Очень удобно в интерактивном режиме. Попробуй.
</p>

<p>
Другая полезная переменная, определённая в <strong>gnetlist</strong>, это
<code>all-unique-nets</code> (набери это). Точно так же как <code>(length packages)</code>
говорит тебе, сколько у тебя компонентов, <code>(length all-unique-nets)</code>
подскажет, сколько у тебя соединений.
</p>

<p>
Ещё есть <code>all-pins</code>:
</p>
<pre class="code">guile&gt; all-pins
((&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>

<p>
Заметь, это немного сложнее, чем в предыдущих примерах: это список списков, а
не просто список строк. Каждый из списков соответствует выводам компонента.
Есть одна штука, которую мы могли бы вытащить отсюда, — это подсчёт
количества выводов. Мы не можем просто взять длину <code>all-pins</code>, чтобы
получить его: это даст нам только количество списков, содержащихся там, равное
количеству компонентов:
</p>
<pre class="code">guile&gt; (length all-pins)
25</pre>

<p>
Чтобы посчитать количество выводов, сначала посчитаем их количество для
каждого из компонентов в отдельности:
</p>
<pre class="code">guile&gt; (map length all-pins)
(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>

<p>
Это один из простых способов сделать “цикл” на <strong>Scheme</strong>; <code>(map p x)</code>
выдаёт список результатов вызываемой процедуры <code>p</code> отдельно для каждого
элемента из <code>x</code>. Затем мы можем их сложить с помощью “цикла” несколько иного
типа:
</p>
<pre class="code">guile&gt; (apply + (map length all-pins))
50</pre>

<p>
<code>(apply p x)</code> вызывает процедуру <code>p</code> один раз, с аргументами из всех
элементов из <code>x</code>. Поэтому вышеуказанное выражение в конце концов посчитает
следующее:
</p>
<pre class="code scheme">&nbsp;</pre>

<p>
До сих пор мы использовали предопределённые переменные и процедуры. Но мы бы
хотели иметь возможность определять свои. Это просто:
</p>
<pre class="code">guile&gt; (define the-answer 42)
guile&gt; the-answer
42</pre>

<p>
Это определяет переменную <code>the-answer</code> и задаёт ей значение 42.
</p>

<p>
Можно также определять процедуры:
</p>
<pre class="code">guile&gt; (define add1 (lambda (x) (+ x 1)))
guile&gt; (add1 100)
101</pre>

<p>
Когда видишь <code>lambda</code>, думай — “процедура”. Сразу следом за <code>lambda</code> идёт
первый элемент (технический термин — “выражение”<sup><a href="#fn__2" name="fnt__2" id="fnt__2" class="fn_top">2)</a></sup>) — список аргументов процедуры, в данном случае
<code>(x)</code>. Когда вызывается процедура, <strong>Guile</strong> оценивает оставшиеся выражения,
в данном случае только одно, <code>(+ x 1)</code>, с подстановкой текущих аргументов.
Результат процедуры — это результат оценки последнего выражения. Так,
<code>(add1 100)</code> становится <code>(+ 100 1)</code>, что даёт 101.
</p>

<p>
Теперь мы можем объединить наш сбор статистики в драйвер.
Сначала определим процедуру для записи выходной строки:
</p>
<pre class="code scheme">&nbsp;</pre>

<p>
Здесь мы используем две новых встроенных процедуры, <code>display</code> и <code>newline</code>,
названия которых говорят сами за себя. Теперь:
</p>
<pre class="code scheme"><span class="co1">; без аргументов</span>
<span class="st0">&quot;pins:     &quot;</span><span class="st0">&quot;packages: &quot;</span><span class="st0">&quot;nets:     &quot;</span></pre>
<pre class="code">guile&gt; (display-stats)
pins:     50
packages: 25
nets:     13</pre>

<p>
Чтобы завершить драйвер, нам нужна “основная программа”. По соглашению она
называется так же, как и сам драйвер. Также она отвечает за открывание выходного файла.
Итак, целиком файл драйвера сбора статистики “stats” будет выглядеть
примерно так:
</p>
<pre class="code scheme"><span class="co1">;; драйвер gnetlist для получения статистики по проекту</span>
<span class="co1">;;</span>
<span class="co1">;; Стандартный текст лицензии, как положено</span>
<span class="co1">;; Сбор и вывод статистики</span>
<span class="co1">; без аргументов</span>
<span class="st0">&quot;pins:     &quot;</span><span class="st0">&quot;packages: &quot;</span><span class="st0">&quot;nets:     &quot;</span><span class="co1">;; Простой формат вывода</span>
&nbsp;</pre>

<p>
Сохрани это в файле с именем <code>gnet-stats.scm</code>, скопируй его в надлежащее
место, например так:
</p>
<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>

<p>
и затем <strong><code>gnetlist -g stats</code></strong> с другими обычными аргументами и именами
схем выдаст статистику твоего проекта в выходной файл (по умолчанию
<em><code>output.net</code></em>).
</p>

<p>
Довольно просто, а? А также полезно. Недавно я проектировал системы, состоящие
из множества плат: статистика, подобная этой, помогает мне выяснить, какие
подсистемы лучше скомбинировать на каждой из плат.
</p>

</div>
<div class="footnotes">
<div class="fn"><sup><a href="#fnt__1" id="fn__1" name="fn__1" class="fn_bot">1)</a></sup> 
“Синтаксический сахар” — конструкция языка программирования,
полностью эквивалентная другой его конструкции, но имеющая более естественную
запись (Компьютерный словарь). — <em>Прим. перев.</em></div>
<div class="fn"><sup><a href="#fnt__2" id="fn__2" name="fn__2" class="fn_bot">2)</a></sup> 
Англоязычный термин —
“form”. — <em>Прим. перев.</em></div>
</div>
</body>
</html>