Bash как mainstream-язык
Нет, я не буду здесь расползаться пространными рассуждениями, как я обычно это делаю. Просто две ссылки:
- Объектно-ориентированный bash.
- Bash on Balls — web-framework на bash.
Архив автора
Нет, я не буду здесь расползаться пространными рассуждениями, как я обычно это делаю. Просто две ссылки:
В студенческие годы мне пришлось столкнуться с одной интересной образовательной проблемой. Она имеет две стороны, кажду из которых проще всего проиллюстрировать на примерах:
Интересно то, что многие считают второй случай вопиющей халатностью при составлении учебного плана, а первый — неизбежным злом. Некоторые даже добавят что-то в духе «учиться надо было лучше». Так вот, я учился хорошо. Местами даже отлично. И получил красный диплом. Но сейчас, в аспирантуре, мне приходится изучать математику заново, иногда даже по тем же самым учебникам.
Мне придумалась образное объяснение, почему так происходит — теория крючков. Она состоит из следующих постулатов:
Попробую продемонстрировать эту теорию на ней же самой. Эти постулаты сами по себе не очень ценны — какие-то утверждения, сделанные неизвестно кем непонятно с какой целью. Если трактовать их именно так, то на следующий день после прочтения они из головы сотрутся. Но можно прицепить их крючками к уже известным фактам, наведя между ними «знания-мосты». Такими мостами могут быть, например, следующие факты:
В общем, берегите свои крючки и не цепляйте на них всякую гадость.
Такая вот классическая задача, которая которую я когда-то увидел в книжке «C Traps and Pitfalls». Для современных компиляторов ответ однозначен: вложенные комментарии вида /*…/*…*/…*/ не поддерживаются, см. п. 6.4.9-1 стандарта C99. Но во времена динозавров, говорят, некоторые компиляторы все-таки поддерживали. Собственно, задача формулируется так:
Написать программу на C, компилирующуюся без ошибок (warning-и не в счет), которая при запуске выводит «YES», если вложенные комментарии поддерживаются, и «NO», если это не так.
Механизм, вокруг которого должна строиться такая программа, очевиден — вложенные комментарии:
/* всегда в комментарии /* всегда в комментарии */ какой-то-код */
Если вложенность поддерживается, какой-то-код — всего лишь часть комментария. Но если вложенности нет, то комментарий кончается на первом же «*/», а какой-то-код будет выполнен. Проблема только в одном: что делать с остающимися в хвосте «*/»? Наверное, нужно где-то раньше поместить парные «/*», но тогда код станет некорректным в случае, если вложенность поддерживается. Нетрудно видеть, что написание комментариев с еще большей глубиной вложенности лишь усугубляет проблему.
(Здесь самое время прекратить читать и попытаться придумать решение самостоятельно.)
Ключ к решению — различная лексическая трактовка символов в зависимости от контекста. Я придумал три способа:
Код выглядит немного странно, но разобраться несложно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // file: nestcomm.c? #include <stdio.h> void method1(){ printf("Method 1: "); printf("%s\n", /*/**/" NO\0*/"/*YES\0"/**/"*/"+2); } void method2(){ int a = 1; printf("Method 2: "); printf("%s\n", /*/**/2*/*(&a)+/**/2==4?"NO":"YES"); } void method3(){ printf("Method 3: "); /*/**/#define A */ printf("%s\n", #ifdef A "NO" #else "YES" #endif ); } int main(){ method1(); method2(); method3(); return 0; } |
Компилятор с поддержкой вложенных комментариев уже не найдешь, но можно его сымитировать, написав на flex небольшой препроцессор:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // file: snc.lex
%option noyywrap
%{
int comm = 0;
%}
%x STRING COMMENT
%%
<INITIAL>{
\" { BEGIN(STRING); ECHO; }
"/*" { comm++; BEGIN(COMMENT); }
. { ECHO; }
}
<COMMENT>{
"/*" { comm++; }
. { }
"*/" { comm--; if (!comm) BEGIN(INITIAL); }
}
<STRING>{
\" { BEGIN(INITIAL); ECHO; }
. { ECHO; }
}
%%
int main()
{
yylex();
return 0;
} |
Ну, и чтобы два раза не вставать, Makefile для автоматического прогона:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | .PHONY: all all: nest_yes nest_no @echo "With nested comments support:" ./nest_yes @echo "Without nested comments support:" ./nest_no nest_yes: nestcomm.c snc ./snc < $< > tmp.c cc -o $@ tmp.c rm -f tmp.c snc: snc.lex flex -o $(subst .lex,.c,$<) $< cc -o $@ $(subst .lex,.c,$<) nest_no: nestcomm.c cc -o $@ $< .PHONY: clean clean: rm -f snc.c snc nest_yes nest_no |
Многие считают подобные упражнения напрасной тратой времени, но на самом деле таким образом можно узнать удивительно много нового о тонкостях языка.
Уличил сам себя в бессовестном разбазаривании вычислительных ресурсов. У меня запущен urxvt, в котором запущен tmux, в котором через ssh запущен screen, в котором запущен minicom, в котором видна консоль суровой отечественной железки. Остается только запустить это все в виртуальной машине.
Стоило мне впервые успешно решить 1000-бальную задачу из SRM 504 Div 2, как результаты матча аннулировали из-за технических неполадок на сервере. Я, конечно, горжусь собой, но моя радость была бы более полной, если бы мои успехи отразились в рейтинге.
А первые две задачи во втором дивизионе вот уже второй матч подряд совсем простые. Или дело во мне?..
Еду, стало быть, в метро. Изучаю налепленные на стены вагонов творения неизвестных рекламщиков. Оказывается, средство от аллергии N не вызывает сонливости! Волшебно! Но впечатление смазывается циферками-сносками. Что обычно пишут в сносках к рекламному тексту? Например, что N не вызывает сонливости, если его не принимать. Или что сонливостью считается только мгновенное погружение в сон не менее чем на 10 часов. Но нет!
В сносках были ссылки на научные статьи. Такие дела.
Я аж всплакнул от счастья.