Wednesday, November 21, 2007

vim

В последнее время пытаюсь освоить Vim. Редактор очень мощный и интересный. Прочитал кучу доков и мануалов и с нетерпением хочу начать его использовать... Но, к сожалению, наткнулся на одну проблему, которую решить не могу и которая нигде не описывается.
Мне не понятно, как в этом редакторе поменять текущий путь. !cd -- не помогает. shell/cd также не помогает. После выхода из командного режима путь остаётся прежним.
Обидно. Проблема настолько тривиальная, видимо, что никто не стал её описывать. А с этим ни программу сбилдить, ни теги построить, да и вообще работать нельзя.

Приходится пока оставаться в KDevelop

Friday, November 16, 2007

Деликатес

Создал себе аккаунт на деликатесе - http://del.icio.us/cyberzx
Буду туда добавлять ссылки IT тематики. Удобная штука, как оказалось.

Monday, November 05, 2007

О кошерном

* Messages for package sys-libs/glibc-2.6.1:

* You still haven't deleted //etc/locales.build.
* Do so now after making sure //etc/locale.gen is kosher.

Хаха. Юмор оценил :)

Saturday, November 03, 2007

былое

Вот разгребал я тут старые программы свои. Эдак готов 2002-2005го. На некоторый код смотрю и думаю: "OMG!!! Что за ламер писал такой ужасный код!?". На другие же программки наоборот вызывают мысль: "ну ничего себе, неужели это я такое сделал? круто!".
Ну это уже ближе к нашему времени.

Вообще полезно. Смотришь как ты рос в профессиональном плане, как менялись твои навыки, философия программирования и, даже, мировоззрение. Это очень полезно.

Но заметил одну странную вещь. Раньше была куча идей, но не хватало умения для их реализовывания. Сейчас умений выше крыши, но вот с идеями туговато... Надо как-то выходить из этой стагнации.

Friday, November 02, 2007

Реализация

Вот написал реализации калькуляторов к прошлому посту.
на Хаскелле и на С

Сейчас ещё напишу его на питоне. Ну а потом, если будет настроение, сделаю это на С++ без буста. Хотя это мне не особо интересно, так как С++ мой родной язык.

upd:
http://pastebin.com/f2e155cae - программа на петоне.
http://pastebin.com/f356d13b0 - реализация на хаскелле от VoidEx. с использованием монад.

Об ассоциативностях

Вообщем, почитал я немного Книгу Дракона. Думал, что это нечто страшное типа "Искусства Программирования" Кнута. Оказалось, что совсем не так, книга написа довольно внятным языком и легка для восприятия, жалею что раньше не прочитал её.

Я понял, почему мне так не удалось сходу написать калькулятор. Проблема, как я и думал, лежала в математической области. О ней и хочу поговорить. Но обо всём по порядку. Начну я с ассоциативности.

И так, что такое ассоциативность и зачем она нам нужна?

Пусть есть некоторая бинарная операция @
Значит некоторой сущности x мы можем поставить в соответсвие y @ z
x = y @ z

Но y и z сами могут быть результатами выполнения операции @.

y = a @ b

x = (a @ b) @ z

или

z = b @ c

x = y @ (b @ c)


Ну и дальше по индукции, рекурсивно расширяя до какого угодно количества членов в выражении.

Назовём операцию @ лево-ассоциативной, если запись a @ b @ c эквивалентна выражению (a @ b) @ c. Если же a @ b @ c эквивалентно выражению a @ (b @ c), то операция @ является право-ассоциативной.

Можно запомнить, что если оператор стоит слева от терминального операнда(того, который нельзя разбить на под-выражения), то операция — лево-ассоциативная, иначе она право-ассоциативная. То есть, с какой стороны операция прилепливается к терминальному операнду, такая и ассоциативность у неё.

Пример.
Во многих языках программирования операция присваивания является право-ассоциативной. То есть a = b = c => a = (b = c). Это вполне резонно, так как вычесление операндов идёт справа и в конечном итоге доходит до самого левого.


Но арифметические операции являются лево-ассоциативными.

a - b - c => (a - b) - c.

Тут вычесление идет начиная с самого левого операнда.


Перейдёт к собственно проблеме.

Вот как выглядят грамматики для выражений с операторами с разной ассоциативностью.


expr -> term op expr — право-ассоциативная операция

expr -> expr op term — лево-ассоциативная операция

Тут term это операнд, который в контексте данной операции не разбивается на составные части, хотя он может разбиваться на них для операции с более высоким приоритетом.


Вот тут-то уже можно увидеть проблему. Заметим, что грамматика для лево-ассоциативной операции образует, так называемую, левую рекурсию. Но я хотел реализовть парсинг выражений за один проход слева направо. То есть predictive parser.


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

Так что делать? Неужели для такой простой задачки, как разбор арифмитических выражений придётся писать сложный bottom-up парсер с бэктрейсингом? Ну уж нет. Я так просто не сдамся!


Тут нам на помощь приходит математика. Оказывается есть простой способ избавления от левой рекурсии путём добавления новых нетреминальных символов в грамматику.


Если есть грамматика вида

A -> Aa | Ab | c


то мы можем трансформировать её в грамматику с правой рекурсией

A -> cR

R -> aR | bR | eps


Вот пример:

expr -> expr + term |

expr - term |

term


заменяется на

expr -> term rest

rest -> +term rest |

-term rest |

eps


А эта грамматика очень легко парсится на predictive parser.


Ну и приведу полную грамматика для арифметических выражений.


expr -> term rest_e

rest_e -> (+ | -) term rest_e | eps


term -> factor rest_t

rest_t -> (* | / | ^) factor rest_t | eps


factor -> -factor | +factor | (expr) | function | number


function -> unary_func_name (expr) |

binary_func_name(expr, expr)


Очень маленькая, простенькая и без левых рекурсий!