This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
geda:gnetlist_scheme_tutorial.ru [2012/11/21 15:20] vzh Updated |
geda:gnetlist_scheme_tutorial.ru [2015/08/25 07:41] vzh Little review |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | //Это руководство доступно также на следующих языках:// | ||
+ | [[gnetlist_scheme_tutorial|English]] | ||
+ | |||
====== Написание скриптов драйверов gnetlist на Scheme ====== | ====== Написание скриптов драйверов gnetlist на Scheme ====== | ||
Line 11: | Line 14: | ||
Если ты никогда не писал программы на **Lisp**, это выглядит страшновато. Но | Если ты никогда не писал программы на **Lisp**, это выглядит страшновато. Но | ||
это намного легче, чем кажется. Добавь в **Lisp** чуть-чуть синтаксического | это намного легче, чем кажется. Добавь в **Lisp** чуть-чуть синтаксического | ||
- | сахара(("Синтаксический сахар" --- конструкция языка программирования, | + | сахара((«Синтаксический сахар» --- конструкция языка программирования, |
- | полностью эквивалентная другой его конструкции, но имеющая более естественную | + | полностью эквивалентная другой его конструкции, но имеющая более |
- | запись (Компьютерный словарь). --- //Прим. перев.//)) и он превращается в | + | естественную запись (Компьютерный словарь). --- //Прим. перев.//)) и он |
- | **Logo**, который могут изучить даже дети из начальной школы. | + | превращается в **Logo**, который могут изучить даже дети из начальной школы. |
И просто для объяснения значения некоторых из этих странных слов: | И просто для объяснения значения некоторых из этих странных слов: | ||
[[wp>Lisp_(programming_language)|Lisp]] --- компьютерный язык, | [[wp>Lisp_(programming_language)|Lisp]] --- компьютерный язык, | ||
- | [[wp>Scheme_(programming_language)|Scheme]] --- диалект **Lisp**'а, | + | [[wp>Scheme_(programming_language)|Scheme]] --- диалект **Lisp**'а, и |
- | и [[wp>GNU_Guile|Guile]] --- реализация **Scheme**. | + | [[wp>GNU_Guile|Guile]] --- реализация **Scheme**. **Guile** в gEDA |
- | **Guile** в gEDA используется для написания скриптов. В частности, | + | используется для написания скриптов. В частности, оболочка **gnetlist**, |
- | оболочка **gnetlist**, написанная на **C**, выделяет из схем информацию о | + | написанная на **C**, выделяет из схем информацию о топологии и атрибутах, а |
- | топологии и атрибутах, а затем отдаёт данные низкоуровневым скриптам | + | затем отдаёт данные низкоуровневым скриптам (драйверам) на **Guile** для |
- | (драйверам) на **Guile** для обработки и вывода. | + | обработки и вывода. |
- | Это руководство именно по программированию драйверов | + | Это руководство именно по программированию драйверов **gnetlist** на |
- | **gnetlist** на **Scheme**. Если ты ещё не знаешь **Scheme**, тебе, наверно, | + | **Scheme**. Если ты ещё не знаешь **Scheme**, тебе, наверно, стоит взглянуть |
- | стоит взглянуть и на другие материалы, такие как: | + | и на другие материалы, такие как: |
http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html | http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html | ||
- | Или поищи "Учебник по Scheme" в своём любимом поисковике: их много. | + | Или поищи «Учебник по Scheme» в своём любимом поисковике: их много. |
Также может пригодиться справочный документ по адресу: | Также может пригодиться справочный документ по адресу: | ||
Line 37: | Line 40: | ||
http://www.gnu.org/software/guile/manual/html_node/index.html | http://www.gnu.org/software/guile/manual/html_node/index.html | ||
+ | %%%% | ||
Итак, начнём. Вот очень простой драйвер: | Итак, начнём. Вот очень простой драйвер: | ||
+ | |||
<code lisp> | <code lisp> | ||
;; gnetlist development playground | ;; gnetlist development playground | ||
Line 50: | Line 55: | ||
</code> | </code> | ||
- | Чтобы это применить, сохрани всё в файле //''gnet-devel.scm''//. Скопируй этот | + | Чтобы это применить, сохрани всё в файле //''gnet-devel.scm''//. Скопируй |
- | файл туда, где в твоей системе хранятся файлы **Scheme**. На машине, на | + | этот файл туда, где в твоей системе хранятся файлы **Scheme**. На машине, на |
которой я сейчас работаю, команда такова: | которой я сейчас работаю, команда такова: | ||
+ | |||
<code bash> | <code bash> | ||
$ sudo cp gnet-devel.scm /sw/share/gEDA/scheme/ | $ sudo cp gnet-devel.scm /sw/share/gEDA/scheme/ | ||
</code> | </code> | ||
- | //''/sw/''// для многих устанавливаемых в Linux пакетов надо | + | //''/sw/''// для многих устанавливаемых в Linux пакетов надо заменить на |
- | заменить на //''/usr/''//, может быть на //''/usr/local''//, или --- при | + | //''/usr/''//, может быть на //''/usr/local''//, или --- при установке из |
- | установке из tar-архива --- на //''~/mygeda/''//. Это нужно выяснить. Если ты | + | tar-архива --- на //''~/mygeda/''//. Это нужно выяснить. Если ты можешь |
- | можешь записывать в целевой каталог без прав суперпользователя, **''sudo''** | + | записывать в целевой каталог без прав суперпользователя, **''sudo''** не |
- | не нужно. | + | нужно. |
Теперь, изменив нужным образом //''/sw/''//, набери: | Теперь, изменив нужным образом //''/sw/''//, набери: | ||
Line 68: | Line 74: | ||
</code> | </code> | ||
- | Ты должен увидеть обычный текст стандартного приглашения, за которым следует: | + | %%%% |
+ | |||
+ | Ты должен увидеть обычный текст стандартного приглашения, за которым | ||
+ | следует: | ||
<code> | <code> | ||
guile> | guile> | ||
Line 74: | Line 84: | ||
Попробуй: | Попробуй: | ||
+ | |||
<code> | <code> | ||
guile> packages | guile> packages | ||
Line 82: | Line 93: | ||
("Q3" "R5" "Q2" "R4" "Q1" "C6" "R3" "L2" "A1" "bat(+3v)" "lamp(1)" "R2" "C5" "L1" "R1" "C4" "lamp(2)" "C3" "C2" "C1" "D1" "bat(0v)" "R7" "Q4" "R6") | ("Q3" "R5" "Q2" "R4" "Q1" "C6" "R3" "L2" "A1" "bat(+3v)" "lamp(1)" "R2" "C5" "L1" "R1" "C4" "lamp(2)" "C3" "C2" "C1" "D1" "bat(0v)" "R7" "Q4" "R6") | ||
</code> | </code> | ||
+ | |||
+ | %%%% | ||
''packages'' --- удобная переменная, содержащая список всех уникальных | ''packages'' --- удобная переменная, содержащая список всех уникальных | ||
- | значений атрибутов ''refdes=''. Набрав её, ты скормил её "REPL" --- циклу | + | значений атрибутов ''refdes=''. Набрав её, ты скормил её «REPL» --- циклу |
- | чтения, оценки, вывода (Read, Evaluate, Print Loop). Итак, | + | чтения, вычисления, вывода (Read, Evaluate, Print Loop). Итак, REPL считал |
- | REPL считал её, оценил (создав список) и вывел. | + | её, вычислил (получив список) и вывел. |
Теперь попробуй: | Теперь попробуй: | ||
+ | |||
<code> | <code> | ||
guile> (length packages) | guile> (length packages) | ||
Line 94: | Line 108: | ||
</code> | </code> | ||
- | Что здесь произошло? Здесь REPL оценил список. | + | Что здесь произошло? Здесь REPL вычислил список. |
<code lisp> | <code lisp> | ||
(length packages) | (length packages) | ||
Line 103: | Line 118: | ||
функция, которая сообщит тебе длину списка. | функция, которая сообщит тебе длину списка. | ||
- | Такая же запись используется для арифметических вычислений. Например, "2+3" | + | Такая же запись используется для арифметических вычислений. Например, «2+3» |
вычисляется так: | вычисляется так: | ||
+ | |||
<code> | <code> | ||
guile> (+ 2 3) | guile> (+ 2 3) | ||
Line 112: | Line 128: | ||
Учти, что процедура %%"+"%% может использоваться для сложения любого | Учти, что процедура %%"+"%% может использоваться для сложения любого | ||
количества величин, в том числе и совсем ни одной: | количества величин, в том числе и совсем ни одной: | ||
+ | |||
<code> | <code> | ||
guile> (+) | guile> (+) | ||
Line 121: | Line 138: | ||
Это мы используем позже. | Это мы используем позже. | ||
- | Строки про ''readline'' в нашем драйвере //''gnet-devel.scm''// позволят тебе | + | Строки про ''readline'' в нашем драйвере //''gnet-devel.scm''// позволят |
- | пользоваться стрелками на клавиатуре для перемещения по истории и для | + | тебе пользоваться стрелками на клавиатуре для перемещения по истории и для |
- | редактирования вводимых строк. Очень удобно в интерактивном режиме. Попробуй. | + | редактирования вводимых строк. Очень удобно в интерактивном |
+ | режиме. Попробуй. | ||
Другая полезная переменная, определённая в **gnetlist**, это | Другая полезная переменная, определённая в **gnetlist**, это | ||
Line 131: | Line 149: | ||
Ещё есть ''all-pins'': | Ещё есть ''all-pins'': | ||
+ | |||
<code> | <code> | ||
guile> all-pins | guile> all-pins | ||
Line 136: | Line 155: | ||
</code> | </code> | ||
- | Заметь, это немного сложнее, чем в предыдущих примерах: это список списков, а | + | Заметь, это немного сложнее, чем в предыдущих примерах: это список списков, |
- | не просто список строк. Каждый из списков соответствует выводам компонента. | + | а не просто список строк. Каждый из списков соответствует выводам |
- | Есть одна штука, которую мы могли бы вытащить отсюда, --- это подсчёт | + | компонента. Есть одна штука, которую мы могли бы вытащить отсюда, --- это |
- | количества выводов. Мы не можем просто взять длину ''all-pins'', чтобы | + | подсчёт количества выводов. Мы не можем просто взять длину ''all-pins'', |
- | получить его: это даст нам только количество списков, содержащихся там, равное | + | чтобы получить его: это даст нам только количество списков, содержащихся |
- | количеству компонентов: | + | там, равное количеству компонентов: |
<code> | <code> | ||
guile> (length all-pins) | guile> (length all-pins) | ||
Line 149: | Line 169: | ||
Чтобы посчитать количество выводов, сначала посчитаем их количество для | Чтобы посчитать количество выводов, сначала посчитаем их количество для | ||
каждого из компонентов в отдельности: | каждого из компонентов в отдельности: | ||
+ | |||
<code> | <code> | ||
guile> (map length all-pins) | guile> (map length all-pins) | ||
Line 154: | Line 175: | ||
</code> | </code> | ||
- | Это один из простых способов сделать "цикл" на **Scheme**; ''(map p x)'' | + | Это один из простых способов сделать «цикл» на **Scheme**; ''(map p x)'' |
выдаёт список результатов вызываемой процедуры ''p'' отдельно для каждого | выдаёт список результатов вызываемой процедуры ''p'' отдельно для каждого | ||
- | элемента из ''x''. Затем мы можем их сложить с помощью "цикла" несколько иного | + | элемента из ''x''. Затем мы можем их сложить с помощью «цикла» несколько |
- | типа: | + | иного типа: |
<code> | <code> | ||
guile> (apply + (map length all-pins)) | guile> (apply + (map length all-pins)) | ||
Line 166: | Line 188: | ||
элементов из ''x''. Поэтому вышеуказанное выражение в конце концов посчитает | элементов из ''x''. Поэтому вышеуказанное выражение в конце концов посчитает | ||
следующее: | следующее: | ||
+ | |||
<code lisp> | <code lisp> | ||
(+ 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) | (+ 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) | ||
Line 172: | Line 195: | ||
До сих пор мы использовали предопределённые переменные и процедуры. Но мы бы | До сих пор мы использовали предопределённые переменные и процедуры. Но мы бы | ||
хотели иметь возможность определять свои. Это просто: | хотели иметь возможность определять свои. Это просто: | ||
+ | |||
<code> | <code> | ||
guile> (define the-answer 42) | guile> (define the-answer 42) | ||
Line 181: | Line 205: | ||
Можно также определять процедуры: | Можно также определять процедуры: | ||
+ | |||
<code> | <code> | ||
guile> (define add1 (lambda (x) (+ x 1))) | guile> (define add1 (lambda (x) (+ x 1))) | ||
Line 187: | Line 212: | ||
</code> | </code> | ||
- | Когда видишь ''lambda'', думай --- "процедура". Сразу следом за ''lambda'' идёт | + | Когда видишь ''lambda'', думай --- «процедура». Сразу следом за ''lambda'' |
- | первый элемент (технический термин --- "выражение"((Англоязычный термин --- | + | идёт первый элемент (технический термин --- «выражение»((Англоязычный термин |
- | "form". --- //Прим. перев.//))) --- список аргументов процедуры, в данном случае | + | --- «form». --- //Прим. перев.//))) --- список аргументов процедуры, в |
- | ''(x)''. Когда вызывается процедура, **Guile** оценивает оставшиеся выражения, | + | данном случае ''(x)''. Когда вызывается процедура, **Guile** вычисляет |
- | в данном случае только одно, ''(+ x 1)'', с подстановкой текущих аргументов. | + | оставшиеся выражения, в данном случае только одно, ''(+ x 1)'', с |
- | Результат процедуры --- это результат оценки последнего выражения. Так, | + | подстановкой текущих аргументов. Результат процедуры --- это результат |
- | ''(add1 100)'' становится ''(+ 100 1)'', что даёт 101. | + | вычисления последнего выражения. Так, ''(add1 100)'' становится ''(+ 100 |
+ | 1)'', что даёт 101. | ||
+ | |||
+ | Теперь мы можем объединить наш сбор статистики в драйвер. Сначала определим | ||
+ | процедуру для записи выходной строки: | ||
- | Теперь мы можем объединить наш сбор статистики в драйвер. | ||
- | Сначала определим процедуру для записи выходной строки: | ||
<code lisp> | <code lisp> | ||
(define format-line | (define format-line | ||
Line 207: | Line 234: | ||
</code> | </code> | ||
- | Здесь мы используем две новых встроенных процедуры, ''display'' и ''newline'', | + | Здесь мы используем две новых встроенных процедуры, ''display'' и |
- | названия которых говорят сами за себя. Теперь: | + | ''newline'', названия которых говорят сами за себя. Теперь: |
<code lisp> | <code lisp> | ||
(define display-stats | (define display-stats | ||
Line 226: | Line 254: | ||
</code> | </code> | ||
- | Чтобы завершить драйвер, нам нужна "основная программа". По соглашению она | + | Чтобы завершить драйвер, нам нужна «основная программа». По соглашению она |
- | называется так же, как и сам драйвер. Также она отвечает за открывание выходного файла. | + | называется так же, как и сам драйвер. Также она отвечает за открывание |
- | Итак, целиком файл драйвера сбора статистики "stats" будет выглядеть | + | выходного файла. Итак, целиком файл драйвера сбора статистики «stats» будет |
- | примерно так: | + | выглядеть примерно так: |
<code lisp> | <code lisp> | ||
;; драйвер gnetlist для получения статистики по проекту | ;; драйвер gnetlist для получения статистики по проекту | ||
Line 272: | Line 301: | ||
//''output.net''//). | //''output.net''//). | ||
- | Довольно просто, а? А также полезно. Недавно я проектировал системы, состоящие | + | Довольно просто, а? А также полезно. Недавно я проектировал системы, |
- | из множества плат: статистика, подобная этой, помогает мне выяснить, какие | + | состоящие из множества плат: статистика, подобная этой, помогает мне |
- | подсистемы лучше скомбинировать на каждой из плат. | + | выяснить, какие подсистемы лучше скомбинировать на каждой из плат. |