Вчера наконец-то доставили заказаную мной две недели назад книгу Стива Макконнелла Совершенный код. Практическое руководство по разработке программного обеспечения. Это более 850 страниц в твёрдой обложке. Судя по отзывам, эту книгу определённо стоит прочитать(и соответственно стоило заказывать =) ). Как только закончу читать Александреску Современное проектирование на С++, примусь за Макконнелла.
понедельник, 24 декабря 2007 г.
вторник, 11 декабря 2007 г.
Интеграция Tcl в программу на C/C++
Есть три задачи, которые необходимо решать при работе с любым скриптовым языком:
- Вызов из основной программы скриптовых функций.
- Вызов из под скрипта функций основной программы.
- Передача данных между скриптом и основной программой.
В принципе третий пункт вполне можно реализовать через первые два.
В следующем примере создаётся инстанс интерпретатора, создаётся Tcl функция equal, которая реализуется на C и вызывается в интерпретаторе.
#include "tcl.h"
//Хэндл интерпретатора
Tcl_Interp* interp = NULL;
//функция, которая будет вызвана интерпретатором
int EqualCmd(ClientData clientData,
Tcl_Interp* interp, int argc, char** argv)
{
//устанавливаем возвращаемое значение
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(strcmp(argv[1], argv[2]) ? 0 : 1 ) );
return TCL_OK;
}
int main(int argc,char** argv)
{
//создаётся инстанс интерпретатора
interp = Tcl_CreateInterp();
int bResult;
//создаётся Tcl функция equal, которая обрабатывается в ф-ции EqualCmd
Tcl_CreateCommand(interp, "equal", (Tcl_CmdProc*)EqualCmd,
(ClientData*)NULL, (Tcl_CmdDeleteProc*)NULL);
//вызываем функцию equal для значений 10 и 10
if(TCL_OK == Tcl_Eval(interp, "equal 10 10"))
{
Tcl_Obj* pResult = Tcl_GetObjResult(interp);
Tcl_GetBooleanFromObj(interp, pResult, &bResult);
printf("result = %i\n", bResult);
}
//вызываем функцию equal для значений 20 и 10
if(TCL_OK == Tcl_Eval(interp, "equal 20 10"))
{
Tcl_Obj* pResult = Tcl_GetObjResult(interp);
Tcl_GetBooleanFromObj(interp, pResult, &bResult);
printf("result = %i\n", bResult);
}
//удалякм инстанс интерпретатора
Tcl_DeleteInterp(interp);
return 0;
}
Для обмена данными между интерпретатором и программой используются функции Tcl_SetVar и Tcl_GetVar, которые позволяют устанавливать и получать значение переменных. Кроме этих вполне ожидаемых средств в Tcl есть и другая интересная фишка - возможность линковать между собой переменную в C коде и переменную в Tcl скрипте. Когда меняется одна, меняется и другая.
Автор:
Алексей
на
13:53
0
коммент.
Ярлыки: программирование, Tcl
воскресенье, 2 декабря 2007 г.
Парсинг XML
Продолжаю экспериментировать с Ruby и Tcl. И я решил написать на каждом из этих языков парсер xhtml-документов. Задача - преобразовать все xhtml-документы в текущей директории в текстовые документы. Преобразование самое простое - в сущности оно заключается просто в удалении тэгов из документа. На обоих языках задача была выполнена.
Програма на Tcl выглядит следующим образом
package require xml
set skip_data false
set result ""
#колбэк для обработки текста xml-элемента
proc cdata {data args} {
global skip_data
global result
if {$skip_data == false } {
append result $data
}
set skip_data false
}
#колбэк для обработки начала xml-элемента.
#если встречаются тэги <style> или <title>, то мы их пропускаем
proc elem {data attlist args} {
global skip_data
if {$data == "style"} {
set skip_data true
} elseif {$data == "title"} {
set skip_data true
}
}
set l [eval glob *.html]
set b [split $l]
# b - список html-файлов в текущей директории
foreach fn $b {
#считываем содержимое файла
set f [eval open $fn]
set data [eval read $f]
close $f
#создаём парсер и указываем колбэки
set parser [::xml::parser -characterdatacommand cdata -elementstartcommand elem]
$parser parse $data
set result [string trim $result]
set ofn $fn
append ofn {.txt}
#записываем результат в файл
set res_file [open $ofn w]
puts $res_file $result
close $res_file
}
На Ruby получился следующий код
require 'rexml/parsers/PullParser'
$result = ""
#получаем список html-фалов
h_files = Dir.glob("*.html")
#обрабатываем в цикле все эти файлы
for fn in h_files
#считываем данные
f = File.open(fn, "r")
if(f.eof)
p "empty"
return
end
res = f.read
#создаём парсер
lp = REXML::Parsers::PullParser.new(res)
skip_element = 0
while(lp.has_next?)
data = lp.pull
if(skip_element > 0)
skip_element -= 1
next
end
#если попадается ненужный элемент, то пропускаем его
if(data.start_element? && (data[0] == "style" data[0] == "title"))
skip_element = 2
end
if(data.text?)
#а если нужный, то сохраняем его
$result = $result + data[0].to_s
end
end
#записываем результат в файл
res = File.open(fn.to_s + ".txt", "w")
res.write($result.strip)
end
Несмотря на то, что текст програмы на Ruby получился лаконичнее, чем на Tcl, на Ruby вариант у меня ушло значительно больше времени, большую часть из которого я потратил на то, чтобы найти и использовать подходящий xml-парсер. Кроме того результат, который выдаёт Ruby, некорректен - в тексте сохранились значки " ". Хотя конечно это недостаток парсера, а не языка... Тем не менее Tcl в данном случае показал себя гораздо лучше. Правда при этом програма на Ruby работает примерно в два раза быстрее.
Автор:
Алексей
на
22:36
0
коммент.
Ярлыки: программирование, ruby, Tcl
Сортировка на Ruby
А теперь тоже самое, но на Ruby.
a = [2, 1, 26, 14]
for i in (0..a.length - 1)
for j in (i..a.length - 1)
if a[i] > a[j]
tmp = [i]
a[i] = a[j]
a[j] = tmp
end
end
end
p a
Естественно в Ruby присутствуют и встроенные средства сортировки массивов
data = data.sort
На написание этой программы на Ruby мне потребовалось меньше времени и услилий, чем на Tcl за счёт более удобного и привычного доступа к элементам массивов в Ruby.
Автор:
Алексей
на
13:54
0
коммент.
Ярлыки: программирование, ruby
Пузырьковая сортировка на Tcl
Только что написал на Tcl сортироку пузырьком. Выглядит это следующим образом
set a {23 4 3 7 6 10}
puts $a
for { set i 0 } { $i < [llength $a] } { incr i } {
for { set j $i } { $j < [llength $a] } { incr j } {
if { [lindex $a $i] > [lindex $a $j]} {
set tmp [lindex $a $i]
lset a $i [lindex $a $j]
lset a $j $tmp
}
}
}
puts $a
Естественно того же эффекта можно добиться одной строчкой с
использованием средств языка.
set a [lsort -integer $a]
Просто хотелось написать на этом языке что-нибудь простое. Хотя конечно Tcl предназначен для решения совершенно других задач.
Автор:
Алексей
на
13:34
0
коммент.
Ярлыки: программирование, Tcl