If a C programmer asks "do you want to see something cool?", run away.
--John Van Enk

Tuesday, November 20, 2007

Зачем мне нужен any_fun_ptr

В предыдущем посте, я высказался о том, что хочу эдакий generalized callback, который мог бы указывать на любую функцию. Возникает вопрос, а зачем это мне? Попробую для начала сделать некоторое введение, которое, надеюсь, немного прольет свет на эту проблему.
Давайте рассмотрим простенький калькулятор, поддерживающий 26 переменных (a-z), операции +, -, *, / и скобки, имлементированный при помощи парочки Flex/Bison и с целевым языком С++. Как я уже когда-то писал, для начала необходимо сделать небольшой workaround для того, чтобы состыковать парсер, сгенерированный бизоном, и лексер, сгенерированный флексом. Для этого используется класс наследник от yyFlexLexer.
файл lexer.h
#ifndef _LEXER_DERIVED_CLASS_H_
#define _LEXER_DERIVED_CLASS_H_
#ifndef __FLEX_LEXER_H
#undef yyFlexLexer
#include <FlexLexer.h>
#endif
#include <iostream>
#include <parser.h>
namespace calc{
class Lexer:public yyFlexLexer {
int yylex();
Parser::semantic_type* yylval;
Parser::location_type* yylloc;
public:
Lexer( std::istream*src = 0,std::ostream* out=0 );
virtual ~Lexer();
Parser::token_type operator()
(Parser::semantic_type* lval, Parser::location_type* lloc=0);
void LexerError(const char* msg);

};
}
#endif

файл лексического анализатора - lexer.lpp
%option 8bit
%option noyywrap
%option noyylineno
%option caseful
%option c++
%option yyclass="calc::Lexer"
%option pointer
%{
#include <lexer.h>
%}

%%

[a-z] {
yylval->var = *yytext - 'a';
return Parser::token::VARIABLE;
}

[0-9]+ {
yylval->number = atoi(yytext);
return Parser::token::INTEGER;
}

[-+()=/*\n] { return *yytext; }

[ \t] ; /* skip whitespace */

. LexerError("Unknown character");

%%
namespace calc{

Lexer::Lexer( std::istream*src,std::ostream* out ):yyFlexLexer(src,out){}

Lexer::~Lexer(){}

Parser::token_type Lexer::operator()
(Parser::semantic_type* lval, Parser::location_type* lloc){
yylval=lval; yylloc=lloc;
return Parser::token_type(yylex());
}

void Lexer::LexerError(const char* msg){
std::cerr<<"Error: "<<msg<<std::endl;
}

}

файл синтаксического анализатора - parser.ypp
%skeleton "lalr1.cc"
%name-prefix="calc"
%parse-param {calc::Lexer& yylex}
%define "parser_class_name" "Parser"
%{
#ifdef yylex
#undef yylex
#endif
namespace calc{
class Lexer;
};
%}
%union{
int number;
char var;
}
%{
#include <lexer.h>
#include <iostream>
int sym[26];
%}
%token <number> INTEGER
%token <var> VARIABLE
%type <number> expression
%left '+' '-'
%left '*' '/'

%%

program:
program statement '\n'
| /* NULL */
;

statement:
expression { printf("%d\n", $1); }
| VARIABLE '=' expression { sym[$1] = $3; }
;

expression:
INTEGER
| VARIABLE { $$ = sym[$1]; }
| expression '+' expression { $$ = $1 + $3; }
| expression '-' expression { $$ = $1 - $3; }
| expression '*' expression { $$ = $1 * $3; }
| expression '/' expression { $$ = $1 / $3; }
| '(' expression ')' { $$ = $2; }
;

%%
void calc::Parser::error (const location_type& loc, const std::string& msg){
std::cerr<<"Error: "<<msg<<std::endl;
};

main
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstdlib>
#include <lexer.h>
#include <parser.h>
using namespace std;

int main(int argc, char *argv[])
{
calc::Lexer lexer(&cin,&cout);
calc::Parser parser(lexer);
parser.parse();
return EXIT_SUCCESS;
}


А теперь допустим, что мы захотели, чтобы калькулятор поддерживал еще и некоторые функции, скажем sin, cos, tan, atan, atan2 и иже с ними.

Можно решить это в лоб:
в лексере написать

.................
sin { return Parser::token::SIN;}
.................
atan2 { return Parser::token::ATAN2;}
.................

а в парсере

.................
expression:
INTEGER
| VARIABLE { $$ = sym[$1]; }
| expression '+' expression { $$ = $1 + $3; }
| expression '-' expression { $$ = $1 - $3; }
| expression '*' expression { $$ = $1 * $3; }
| expression '/' expression { $$ = $1 / $3; }
| '(' expression ')' { $$ = $2; }
| SIN '(' expression ')' { $$=sin($3);}
| COS '(' expression ')' { $$=cos($3);}
.................
| ATAN2 '(' expression ',' expression ')' { $$=atan2($3,$5);}
;
.................


А можно и по другому:
в лексере написать

.................
func ([a-zA-z]+)([0-9]*)
%%
{func} {
yylval->func_ptr = &func_map[yytext];
return Parser::token::FUNC;}

а в парсере

.................
%union{
int number;
char var;
any_fun_ptr* func_ptr;
}
%%
.................
expression:
INTEGER
| VARIABLE { $$ = sym[$1]; }
| expression '+' expression { $$ = $1 + $3; }
| expression '-' expression { $$ = $1 - $3; }
| expression '*' expression { $$ = $1 * $3; }
| expression '/' expression { $$ = $1 / $3; }
| '(' expression ')' { $$ = $2; }
| FUNC '(' expression ')' { $$=$1($3);}
| FUNC '(' expression ',' expression ')' { $$=$1($3,$5);}
;
................



Сам же func_map может быть, например, банальным std::map<std::string, any_fun_ptr> func_map;
А адреса функций заносятся в него при старте скажем.
Вот собственно несколько упрощенное описание того, зачем это может быть нужно.

Monday, November 19, 2007

any_fun_ptr

Хочу такую вещь
any_fun_ptr pfun = &sin;
double res = pfun(M_PI);
pfun=&printf;
pfun("Result %f",res);
Пошел курить "Шаблоны С++" и Александреску, авось че нить придумается.

Thursday, November 15, 2007

Блоговщина!!!

У меня сегодня праздник - блогу исполнился 1 год. Подвести некоторые итоги надо чтоль.
Итак
  • в номинации "Самая Популярная Статья" места распределились следующим образом
    1. std::string vs. const char* . Comparison - 229 просмотров
    2. "Must Read" C++ Books - 149 просмотров
    3. Flex & Bison C++ Interoperability Continued - 95 просмотров

  • в номинации "Самый Популярный Бразуер" победила огненная лиса.

  • в номинации "Самый Популярная ОС" победила самая популярная ОС.

  • в номинации "Страна Где-Меня-Больше-Всего-Читают" победила Россия (732 посещения), за ней Украина (588 посещений) и Беларусь (66 посещений)
  • в номинации "Город Где-Меня-Больше-Всего-Читают" победила Москва (282 посещения), за ней Киев (238 посещений) и Харьков (181 посещение)
  • мне очень любопытно было узнать, что 15,46% посетителей приходит из закладок (вот уж выразился), 46,16 % по ссылкам с других блогов или сайтов и 38,37% через поисковики. Причем 34 поисковых запроса - это "linux mobile", 25 - "std::string" и 20 - "deepencpp.blogspot.com".
Ну в общем я наверное немного приврал и это нельзя назвать статистикой за год, так как Google Analitycs я прикрутил к блогу только 8 Августа. Но примерную каритину кажись обрисовал. Ах да... я завел еще один блог, на сей раз общетематический, так как чувствую, что в рамках этого блога мне тесновато, да он и так в оффтоп залез - вон сколько мыслей на сайдбаре в метках. Посему этот блог остается посвященным IT-тематике, а в этом, я буду писать обо всем.
Вотъ такъ.

Wednesday, November 7, 2007

Gphone не будет?

В блоге Google опубликовали статью Where's my Gphone? В ней говориться, что не смотря на многочисленные спекуляции по поводу Gphone в последние несколько месяцев, анонса нового телефона от Google не будет (во киберсквоттеры то расстроились небось, - зря домены регистрировали). Однако в то же время анонсируется Open Handset Alliance и открытая платформа Android для мобильных устройств на основе Linux-ядра. 12 ноября этого года обещают сделать доступным для скачивания SDK. Платформа по заверениям обещает быть довольно удобной как для разработчиков так и для конечных пользователей устройств.

Захотел проследить, а не тянется ли эта ниточка еще куда нубудь? Воспользовался все тем же поиском Google и как оказалось 17 августа 2005 года многие новостные сайты опубликовали статьи о покупке Google компании Android Inc (сейчас сайт компании редиректит на Open Handset Alliance). Сама покупка произошла вроде бы в июле, за сумму, которая не разглашается.

Вообще развитие персональных средств связи видится мне несколько по иному - я бы хотел просто иметь небольшое устройство с достаточно большим (относительно размеров самого девайса) сенсорным экраном и доступ к высокоскоростной сети в любой точке страны. Все остальное - sms, mms, протоколы и прочее - забота софта. Как звонить? Скайпом (skypephone уже есть). И всех делов то. Не было бы различных тарифов на звонки, sms, и прочую чепуху. Просто платить за трафик или покупать безлимитный пакет. Это было бы круто. А вы как думаете?

Upd: рекомендую почитать еще Google to unveil 'Android' phone software, там очень тольковые мысли приводятся...

Tuesday, November 6, 2007

О чем молчит printf

Недавно, читая книгу Диомидиса Спинеллиса "Анализ программного кода на примере проектов Open Source", узнал что функция printf возвращает результат - количество фактически выведенных символов. Посмотрел в мане и стандарте на язык С - таки да "The printf function returns the number of characters transmitted, or a negative value if an output or encoding error occurred". А я то всегда думал что она void. И практически повсеместно встречал ее использование без проверки возвращаемого значения. К чему это может привести? Это может привести к тому, что в ходе выполнения программы может возникнуть ошибка, которая пройдет незамеченной (в лучшем случае).
Вообще все функции вывода - в частности, при перенаправлении стандартного потока вывода в файл - могут завершиться аварийно по целому ряду причин:
  • на устройстве, куда перенаправляется вывод, может не хватить свободного места
  • может исчерпаться квота пользователя на объем дискового пространства
  • процесс может попытаться записать файл, который превысит максимально допустимый для этого процесса или системы объем
  • на устройстве может произойти аппаратная ошибка
  • дескриптор файла или потока, ассоциированного со стандартным потоком вывода, может оказаться не разрешенным для записи
Без проверки успешности вывода программа может тихо и незаметно рухнуть с потерей всех выводимых данных. Однако проверять результат каждой операции вывода - неудобно, поэтому зачастую используется компромиссный подход - проверка ошибок вывода в поток перед завершением программы. В языке С для этого есть функция ferror:

if (ferror(stdout))
err(1, "stdout");


Функция err - это нестандартное BSD расширение для выдачи форматированных сообщений об ошибках.

Так, что подобные очевидные моменты не стоит недооценивать...

Upd: благодаря комментарию Сергея Кондрикова - вот ссылка на очень хорошую статью в Википедии: Printf. В ней, помимо всего прочего, довольно подробно описаны уязвимости функции и возможные последствия.

Thursday, November 1, 2007

Бунтарь

Вчера прочел книгу Джеффри С. Янга и Вильяма Л. Саймона "iКона: Стив Джобс".
В аннотации говорится: "Эта книга о самом поразительном человеке в современной истории бизнеса – Стиве Джобсе – великом предпринимателе эпохи высоких технологий, известном своим индивидуализмом, инакомыслием и бунтарским характером. Авторы подробно описали головокружительный взлет молодого человека, очень рано добившегося успеха, и последовавшее за этим стремительное падение, во время которого Стив был изгнан не только из Apple, но и из компьютерной индустрии вообще. Эта книга приобрела скандальную известность еще на этапе ее подготовки к печати. Получив экземпляр рукописи для ознакомления, компания запретила продавать во всех магазинах Apple книги издательства Wiley&Son. Такая реакция не повлияла на желание издательства опубликовать это произведение. Книга будет интересна тем, кто хочет узнать, как происходило формирование, становление и развитие современной эры цифровых технологий под влиянием самой значимой фигуры современности – человека, кардинально изменившего три отрасли – индустрию кино, музыки и компьютеров, – Стивена Джобса."

А теперь мои впечатления. Если вкратце - то я остался очень доволен прочтением книги. В ней не только рассказывается об истории становлении компаний к которым приложил руки Стив - Apple, NeXT, Pixar, но и о нем самом. Причем авторы, по видимому, старались взглянуть на эту неординарную личность под разными углами. И как мне показалось им это удалось достаточно хорошо. Стив в книге приедставлен не только как бунтарь-перфекционист, оказавший огромное влияние как на развитие не только отрасли персональных компьютеров, индустрии музыки и компьютерной анимации, но и не обделены вниманием некоторые негативные моменты, имевшие место в его жизни и деятельности. Как то присвоение себе чужих заслуг и, кроме всего прочего, он долгое время отказывался от признания себя отцом (потом правда исправился). Через всю книгу красной нитью проходит становление Стива, как личности. Отдается должное его способностям очаровывать людей.

Отдельного упоминания
заслуживает перевод книги - выше всяческих похвал. Хоть мне и не довелось читать книгу в оригинале, но в переводе она читается на одном дыхании, оторваться просто не возможно. Такие книги я отношу к категории "постоянно читаемых", т.е. как только ее прочитал, хочется открыть сначала и перечитать заново. Только некоторым авторам удавалось вызвать у меня подобные ощущения. Один из них - Жюль Верн.

Странно, но факт - Билл Гейтс, оказавший, наверное, не меньшее влияние на развитие отрасли постоянно упрекается миллионами пользователей. Стив же - стал чуть ли не идолом, рок-звездой компьютерных технологий. По моему это явление имеет место и благодаря слову, написанному в заголовке данного поста. Чем в большей степени его можно применить к человеку, тем больше люди склонны его превозносить. А все почему? Человек - существо социальное, многим нужен лидер, который сможет принимать решения и вести за собой массы - эдакий Моисей современности. И человек, который своим собственным примером показал, что большинство может ошибаться, а он, считая себя правым, добивается незаурядных результатов тем самым приобретает в глазах остальных некий волшебный ореол. За ним пойдут люди. Стив однажды сказал фразу, которую назвали фразой Терминатора: "Мы вернемся". И, насколько я могу судить, это сейчас как раз и происходит. Но Apple, не просто возвращается, она уже пришла на рынки, о которых раньше и речи быть не могло. Каждый хочет быть особенным, отличаться от остальных. Пожалуй это один из факторов, заставляющий приобретать продукцию Apple, использовать Linux, BSD системы. Это позволяет выделиться, сказать "Посмотрите! Я использую Mac (Linux, BSD -нужно подчеркнуть). А не какой-то там .... (вставить нужное)". Естественно, что предоставляемый функционал тоже имеет не последнее значение. Однако принадлежность к касте "избранных", "не-таких-как-все-остальные" имела, имеет и будет иметь о-о-очень большое значение.