ТехноСаратов → Блог

Язык TclБлогПрограммирование

Не так давно встал вопрос выбора интерпретируемого языка для встраивания в Си программы. Кандидатов было много, но в конце остался только один. О котором и пойдет речь в этой статье.

Поч… ему TCL?

Практически каждый современный скриптовый язык позволяет легко добавлять свой транслятор в вашу программу на Си. Python, Perl, Ruby, Tcl, Lisp… Этот ряд можно продолжать еще долго. Но на самом деле, выбор для программиста на Си, желающего встроить в свою программу продвинутые средства скриптования, язык для интерактивного консольного интерфейса или просто облегчить начальную инициализацию приложения, определяется более-менее однозначно — Tcl.

Можно ли сказать, что Tcl «слабее» остальных перечисленных выше языков? Возможно. Производительность ниже Python`а. Синтаксис беднее Perl`а. Средства метапрограммирования меньше чем у Lisp`а. Но когда дело доходит до практики, то оказывается, что скрипты на нем получаются короче и и гораздо проще, чем на других языках. Синтаксис похож на sh и по тому удобен для интерактивного общения с программой, а производительность скриптов в тысячи строк не приносит никаких неудобств пользователю.

Возможно, если речь идет об онлайн сервисах из десятков тысяч строк с тысячами одновременных запросов, Tcl не лучший выбор. Но ведь у нас совершенно иная проблема. И мы должны выбирать соответствующие инструменты ее решения, которые позволят сделать решение более лаконичным.

Особенности синтаксиса

Tcl чем-то напоминает sh, чем-то Lisp, чем-то Fort. Изначально он создавался в академической среде, и практически все его синтаксические особенности были заложены в него осознанно и сразу.

Программа состоит из отдельных команд. Как и команды sh (или как вызываемые из sh внешние программы) они могут иметь любые аргументы, опции, параметры опций и т.д. Например:

button .b1 -text Hello -command exit
pack .b1

В этом примере вызваны две команды библиотеки Tk. Одна из них создает кнопку как объект, а вторая размещает кнопку на форме. Нажатие на кнопке приводит к вызову команды exit, которая завершает программу.

http://technosaratov.ru/galleries/29/557.jpg

Каждая команда внутри интерпретатора реализована как Си функция, которой на манер функции main аргументы передаются в массиве char **argv, а общее количество аргументов передается в целочисленной переменной int argc. Функция интерпретирует все эти параметры так как ей самой вздумается.

Так например, если разобрать выше приведенную команду button, то ей в argv передаются ниже следующие строки:

argv[0] = «button» = имя самой команды, как в main передается имя самой программы
argv[1] = «.b1» = имя объекта создаваемой кнопки
argv[2] = «-text» = опция задающая текст на кнопке
argv[3] = «Hello» = cам текст кнопки
argv[4] = «-command» = опция задающая действие при щелчке на кнопке
argv[5] = «exit» = команда задаваемая опцией -command

То есть каждое слово отделенное от другого пробельным символом является отдельным параметром! Но часто необходимо передать несколько слов как один параметр. Ну, захочется нам написать на кнопке Hello World, а не Hello. В этом случае их как и в sh нужно объединить. Объединяются строки либо двойными кавычками «Hello World», либо фигурными скобками {Hello World}.

Различие между этими двумя подходами простое — в кавычках интерпретатор выполняет подстановку переменных и прочие преобразования (рассмотрим ниже), а в фигурных скобках нет.

set msg1 «Hello World!» ;# Устанавливаем переменные
set msg2 «Hello Myx!» ;# командой set

puts {Wow! $msg1} ;# Выводим на печать в консоль
puts «Wow! $msg2»

Первая команда puts выдаст строку:

Wow! $msg1

Так как в фигурных скобках никакие преобразования интерпретатором не проводятся.

Вторая:

Wow! Hello Myx!

Так как в кавычках производится подстановка значений переменных.

http://technosaratov.ru/galleries/29/558.jpg

И в том и в другом случае puts воспринимает {Wow! $msg1} и «Wow! $msg2» как один параметр, который в Си функции реализующей команду puts передается в одной строке массива argv. Только в первом случае интерпретатор никак не обрабатывает эту строку и передает параметры:

argv[0] = «puts»
argv[1] = «Wow! $msg1»

А во втором производит подстановку:

argv[0] = «puts»
argv[1] = «Wow! Hello Myx!»

Как и команды sh и функции Си, команды Tcl возвращают значения. Возвращаемое значение является также строкой. Например, команда button возвращает имя созданной кнопки — .b1, а команда pack возвращает пустую строку.

Возвращенное командой значение можно непосредственно использовать как аргумент другой команды, для этого она заключается в квадратные скобки:

pack [label .l1 -text «Hello World!»] ;# Создаем и размещаем текстовую метку
pack [button .b1 -text Exit! -command exit] ;# Создаем и размещаем кнопку

В этом примере команды в квадратных скобках выполняются и возвращают имена созданных ими в памяти объектов текстовой метки и кнопки команде pack, которая размещает их на форме.

http://technosaratov.ru/galleries/29/559.jpg

Встретившись среди текста в двойных кавычках, команда в квадратных скобках также выполнится, а ее значение подставится в строку вместо нее:

puts «Files in current directory:n[ls]»

Выдаст нечто похожее на:

Files in current directory:
m.tcl
m.txt
tx.tcl

Основные синтаксические конструкции (циклы, ветвления…) также не являются исключением и являются командами принимающими простые текстовые аргументы, которые обрабатывают по своему усмотрению. Например, if считает свой первый параметр логическим выражением и проверяет его на логическую истинность:

if {$x != 0} {puts «y/x == [expr $y / $x]»}

Ему собственно нет разницы, что это за выражение, если оно истино, то if запускает на исполнение второй параметр.

Что примечательно, слова elseif, else, then, которые могут использоваться в этой конструкции, сами по себе являются параметрами команды if, а не самостоятельными ключевыми словами. Они даже не подсвечиваются при вводе в консоле.

Существуют и объектноориентированные расширения языка, выполненные как отдельные библиотеки (как CLOS в Лиспе). Но их я еще не осваивал, по тому от себя ничего сказать про них не могу.

Как видно, синтаксис языка предельно прост. Странно, что Столмен его ругал именно за сложность 🙂

Кто использует Tcl

Одним из факторов, который так же повлиял на выбор этого языка мною, был список компаний использующих Tcl в своих проектах.

Tcl технологию Expect, автоматизирующую работу с консольными приложениями (Expect практически берет на себя управление интерактивной консольной программой) используют в своих продуктах и для автоматизации:

3Com, Silicon Graphics, World Bank, IBM, HP, Sun, AT&T.;

Cadence, National Semiconductor, Mentor Graphics встраивают Tcl в свои инженерные программы.

Многие софтверные компании используют его для автоматизации тестирования разрабатываемых программ.

По словам писателя и разработчика компиляторов Липпмана DewamWorks и Disney используют Tcl для скриптования в собственных анимационных системах (сами системы пишутся на С++).

Не смотря на ругательства Столмена Gnu таки использует Tcl в своих проектах. Яркий пример DejaGnu (http://www.gnu.org/software/dejagnu/).

Полезные ссылки

На русском:

http://www.opennet.ru/links/sml/36.shtml — ссылки на статьи и переводы руководств

На английском:

tcl.tk — основной сайт с ПО и документацией.
wiki.tcl.tk — Ооочень полезная и толстая wiki. Юзайте поиск.
http://wiki.tcl.tk/638 — тут можно найти программки на Tcl, чтобы поиграться и оценить язык 🙂

http://www.activestate.com/ — Наиболее продвинутая реализация + IDE Comodo.

http://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html — Туториал по Tcl
http://www.tcl.tk/doc/

http://tmml.sourceforge.net/doc/ — Документация по Tcl/Tk
http://www.invece.org/tclwise/ — Достаточно подробный мануал по Tcl
http://www.freesoftwaremagazine.com/free_issues/issue_04/software_testing_with_tcl/ — Тестирование программ с помощью Tcl

http://www.psg.com/~joem/tcl/CmdWrite.html — Написание расширений на Си

http://www.bin-co.com/tcl/tutorial/ — доступный мануал по виджетам tk
http://www.tkdocs.com/tutorial/index.html — Мануал по Tk

http://www.vim.org/htmldoc/if_tcl.html — применение Tcl в Vim (таже и Perl, Python)

http://tcl.sourceforge.net/faqs/tcl/ — Очень много ссылок. Если хочется покапаться 🙂