Редактирование: Практика мультипарадигмального программирования, 03 лекция (от 12 марта)

Материал из eSyr's wiki.

Перейти к: навигация, поиск

Внимание: Вы не представились системе. Ваш IP-адрес будет записан в историю изменений этой страницы.

Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.

Текущая версия Ваш текст
Строка 1: Строка 1:
-
[[Практика мультипарадигмального программирования, 02 лекция (от 19 февраля)|Предыдущая лекция]] | [[Практика мультипарадигмального программирования, 04 лекция (от 19 марта)|Следующая лекция]]
+
== From Ebaums Inc to MurkLoar. ==
-
 
+
We at EbaumsWorld consider you as disgrace of human race.
-
= Tcl (продолжение) =
+
Your faggotry level exceeded any imaginable levels, and therefore we have to inform you that your pitiful resourse should be annihilated.
-
 
+
Dig yourself a grave - you will need it.
-
Это хороший пример языка, который встраивается, и в него можно встроить. В прошлый раз был рассмотрен пример встраивания Tcl в C-шное приложение. В этот раз рассмотрим одну интересную C-шную функцию (в прошлый раз были Tcl_CreateInterp, Tcl_Eval, Tcl_GetStringResult): ... . Нужно было компилировать с библиотекой, компоновать... Но эта библиотека не ограничена этими тремя функциями. Рассмотрим новые функции:
+
-
* Tcl_CreateCommand(Tcl_Interp * interp, char * cmdName, cmdProc * proc, 0, 0 )
+
-
** interp — интерпретатор, в котором хотим создать команду
+
-
** cmdName — имя команды
+
-
** proc — указатель на функцию, которая возвращает инт, получает ClientData, интерпретатор и argc, argv
+
-
Два последних параметра не обязательно нули, один из них вроде бы ClientData, но обычно ставят туда именно нули.
+
-
typedef int (* cmdProc)(ClientData, Tcl_Interp *, int /* argc */, const char ** /* argv */);
+
-
Позволяет встроить в Tcl команду, написанную на Си или Си++. Так обычно и делают: создают интерпретатор, погружают в него проблемно-ориентированные вещи, так как просто интерпретатор неинтересен. Мало того, можно сделать интерпретатор главной программой. То есть программа написана на Tcl и дополнена функциями, которые загнаны в библиотеку, а в интерпретаторе скажем load. Более того, можно расширить уже встроенный интерпретатор.
+
-
 
+
-
<div class="comment">Если вы хотите запретить load, то надо не бросаться искать, как её запретить, а разобраться, действительно ли вы этого хотите, потому что я уверен, что вы этого не хотите.</div>
+
-
 
+
-
== Пример. Функция, которая делает реверс слова ==
+
-
reverse: abcde &rarr; edcba
+
-
 
+
-
#include <tcl.h>
+
-
 
+
-
int ReverseString(ClientData ignored, Tcl_Interp * interp, int argc, char * argv[])
+
-
{
+
-
int len = 0;
+
-
char * result = 0;
+
-
int i = 0;
+
-
+
-
if (argc != 2)
+
-
{
+
-
Tcl_SetResult(interp, "sampleReverseString", TCL_STATIC);
+
-
return TCL_ERROR;
+
-
/* TCL_STATIC — результат есть статическая константа,
+
-
* то есть копировать и удалять её не надо, мы гарантируем,
+
-
* что эта строка никуда не денется и можно просто поставить
+
-
* на неё указатель */
+
-
}
+
-
+
-
len = strlen(argv[1]);
+
-
res = (char *)malloc(len + 1);
+
-
for (i = 0; i < len; i++)
+
-
{
+
-
res[i] = argv[1][len – 1 – i];
+
-
}
+
-
res[len] = 0;
+
-
Tcl_SetResult(interp, res, TCL_VOLATILE);
+
-
/* TCL_VOLATILE — вот тебе строка, сними с неё копию прямо сейчас */
+
-
free(res);
+
-
return TCL_OK;
+
-
}
+
-
 
+
-
Эту функцию можно встроить в любой интерпретатор Tcl с помощью Tcl_CreateCommand. Как это встроить в отдельно стоящий интерпретатор: общая идея в следующем: мы должны создать разделяемую библиотеку (tcl_sample.so), в которой будет несколько функций, которые прилинкованы как static, и одна нестатическая, которая будет называться аналогично имени библиотеки:
+
-
Tcl_sample_Init
+
-
 
+
-
/* Библиотека может подгружать несколько функций, ибо делать
+
-
* библиотеку ради одной функции обычно смысла не имеет */
+
-
int Tcl_sample_Init(Tcl_Interp * interp)
+
-
{
+
-
struct {
+
-
char * cmdname;
+
-
cmdProc cmdp;
+
-
} funcs[] = {
+
-
{ "sampleReverseString". sampleReverseString }
+
-
...
+
-
{0, 0}
+
-
};
+
-
+
-
int i = 0;
+
-
+
-
for (i = 0; funcs[i].cmdp; i++)
+
-
{
+
-
Tcl_CreateCommand(interp, funcs[i].cmdname, funcs[i].cmdp, 0, 0);
+
-
}
+
-
}
+
-
 
+
-
Что такое mangling — в С++ есть перегрузка функций. Там может быть много функций с одинаковым именем и разными типами. Загрузчик этого не умеет, поэтому компилятор вынужден информацию о типах сохранять в имени функции. Но Tcl ищет конкретную функцию. Добиться неприменения mangling просто:
+
-
 
+
-
#ifdef _cplusplus
+
-
extern "C"
+
-
{
+
-
int Tcl_sample_Init(Tcl_Interp *);
+
-
}
+
-
#endif
+
-
 
+
-
В самом интерпретаторе:
+
-
load "tcl_sample.so"
+
-
 
+
-
Где это нужно: например, в Tcl/Tk (Tk — Toolkit, набор виджетов)
+
-
 
+
-
Есть wish. Что он собой представляет: Сишное приложение с встроенным интерпретатором тикля, каковой интерпретатор расширен командами тикля для работы с графическими элементами.
+
-
 
+
-
Пример на Tcl/Tk: небольшое приложение, которое будет собой представлять 4 элемента диалогового окна — 3 кнопки и лэйбл.
+
-
Есть главное окно, которое обозначается точкой. Под ним будут дочерние окна:
+
-
* .lab
+
-
* .buttons.left
+
-
* .buttons.right
+
-
* .quit
+
-
 
+
-
почему это происходит быстро? В wish есть возможность автоматически рапролагать новые элементы. Изначально есть пустое окно. Новые элементы можно паковать (pack) на форме — прижимать их к краю окна. В Windows же нужно использовать файлы ресурсов, и т. д. Здесь таких проблем нет вообще. wish может работать с ncurses, в иксах, и т. д.
+
-
 
+
-
#!/usr/bin/wish
+
-
Нехорошо, так как в разных системах лежит в разных местах.
+
-
 
+
-
Особенности wish: если в конце комментария бэкслеш, то комментарий продолжается. В связи с этим используем следующий хак:
+
-
+
-
#!/bin/sh
+
-
#\
+
-
export PATH=/opt/bin:$PATH
+
-
exec wish "$0" -name mydemo "$@"
+
-
 
+
-
Команды Tk:
+
-
* label
+
-
* frame
+
-
* button
+
-
* pack
+
-
* wm
+
-
 
+
-
set w "" ;#root window
+
-
label $w.lab -text {Just a label}
+
-
pack $w.lab -side top
+
-
frame $w.buttons
+
-
button $w.buttons.left -text Left -command
+
-
{
+
-
$w.lab configure -text {Left pressed}
+
-
}
+
-
button $w.buttons.right -text Right -command
+
-
{
+
-
$w.lab configure -text {Right pressed}
+
-
}
+
-
pack $w.buttons.left $w.buttons.right -side left
+
-
pack $w.buttons -side top
+
-
button $w.quit -text {Quit program} -command exit
+
-
wm title . {This is a demo }
+
-
 
+
-
Здесь есть аналоги виндовых файлов ресурсов, но предназначены они немного для другого. Например, мы хотим сделать приложение, в котором можно менять язык. С символами нацкодировок всё, в принципе, неплохо. Но есть Юникод. Это в принципе плохо, но не так, как если бы пришлось вставлять это в код программы. Как это сделать:
+
-
* Выкидываем все -text
+
-
* Добавляем файл опций sample.rc
+
-
set w "" ;#root window
+
-
option readfile "sample.rc"
+
-
...
+
-
+
-
(sample.rc)
+
-
mydemo.lab.text: Just a label
+
-
mydemo.buttons.left.text : Left Button
+
-
mydemo.buttons.right.text : Right Button
+
-
mydemo.quit.text : Quit Program
+
-
 
+
-
== Как компилировать .so ==
+
-
Тайное знание: в расширяемых библиотеках код должен обладать свойством переносимости, то есть код должен быть с относительными адресами. Всё, что нужно сказать компилятору, — компилировать сошку с определёнными ключами. Для С:
+
-
* Из файла объектный файл
+
-
gcc -Wall -g -fpic -c tcl_sample.c
+
-
* Как собрать библиотеку
+
-
gcc -shared tcl_sample.o ... -o tcl_sample.so
+
-
 
+
-
{{Практика мультипарадигмального программирования}}
+
-
{{Lection-stub}}
+

Пожалуйста, обратите внимание, что все ваши добавления могут быть отредактированы или удалены другими участниками. Если вы не хотите, чтобы кто-либо изменял ваши тексты, не помещайте их сюда.
Вы также подтверждаете, что являетесь автором вносимых дополнений, или скопировали их из источника, допускающего свободное распространение и изменение своего содержимого (см. eSyr's_wiki:Авторское право).
НЕ РАЗМЕЩАЙТЕ БЕЗ РАЗРЕШЕНИЯ ОХРАНЯЕМЫЕ АВТОРСКИМ ПРАВОМ МАТЕРИАЛЫ!

Личные инструменты
Разделы