Если хотите подробностей — прошу под кат. Если же нет — можно идти напрямую к переводу, он на гитхабе.
Что это, зачем это, почему это
Для тех кто не знает об этом проекте — это работающий компилятор Lisp-подобного языка в Си-подобный, написанный на JS. Процентов 90 кода покрыто подробными комментариями, и самих комментариев, в общем то, в 4 раза больше чем кода. В начале объясняются основы, терминология, а потом сам код.
А зачем это переводить? Английский же — язык программистов!
Всё началось с того что ссылка на этот проект у меня больше года провалялась в папке «на почитать». И вроде и штука интересная (10к+ звёзд на гитхабе, шутка ли), и мне интересно, но как как-то всё не находилось сил посмотреть и вникнуть. Почему? Да потому что оно на английском. А тут дело не в сложности, а в том что после 8-ми часового рабочего дня мозг напрочь отказывается читать на не родном языке что-то ещё. Вот протестует и всё тут. Поэтому решено было сделать перевод — и себе прочитать заодно, и другим помочь.
800+ форков. Из них — много попыток перевести на китайский, но на русском я ничего не нашёл (может оно и есть). Кстати, объясните, вот зачем люди форкают проекты а потом ничего в них не меняют?
А ты переводчик?
Нет, вообще ни разу. Но проект написан вполне доступным языком, который, по-идее, осилит практически любой человек который способен читать тех. документацию. Но, опять таки, для многих (в том числе для меня) изучать что-то новое гораздо проще на родном языке, даже если отлично понимаешь язык оригинала.
Что же касается перевода — он не дословный, незначительные слова могли быть упущены, кое-что добавлено от себя. Но при этом я старался передать суть на все 100%, так что в плане информативности перевод, вроде, получился равнозначным оригиналу.
Пример перевода. Скриншот кликабельный.
Так как оригинальный проект выложен на гитхабе — то и перевод я не стал закидывать целиком сюда. Для желающих ознакомиться: ссылка на перевод, ссылка на оригинал.
Приятного чтения!
P. S. Замечания принимаю хоть в комментариях, хоть в виде pull-реквестов, хоть в личку. Можете вообще делать форк и вносить изменения :)
По посту — надо ли (и как?) вешать плашку «перевод» на этот пост?
Комментарии (10)
ilammy
10.08.2018 12:52Я когда-то перевёл целую книгу о том, как реализовывать Лиспы на Лиспе. Там есть и глава о том, как их компилировать в Си. Извиняюсь за саморекламу, но темы пересекаются.
bgnx
10.08.2018 13:24В этом примере компилятора объясняется как написать конкретный парсер но совершенно не объясняется почему автор решил делать так и так. А ведь у тех кто не знаком с теорией компиляторов обязательно возникнет вопрос почему автор решил сделать отдельно токинизатор и отдельно парсер токенов для получения синтаксического дерева когда можно было например сделать все в одном проходе.
пример однопроходного парсераconst Code = '(substract (add 4 21) (mul 2 2))'; let Position = 0; function parseExpr() { let number; if (parseSpace() && (number = parseNumber()) && parseSpace()) { return number; } let callExpr; if(callExpr = parseCallExpr()){ return callExpr; } } function parseCallExpr(){ let name; let args; if (parseSpace() && parseToken('(') && parseSpace() && (name = parseName()) && parseSpace() && (args = parseArguments()) && parseSpace() && parseToken(')') && parseSpace()) { return { type: 'CallExpression', name, args }; } return null; } function parseArguments() { let expr; let args; if ((expr = parseExpr()) && ((args = parseArguments()) || true)) { return [expr, ...(args || [])]; } return null; } function parseSpace(){ let char = Code[Position]; while (/ /.test(char)) char = Code[++Position]; return true; } function parseNumber() { let current = Position let char = Code[current]; var value = ""; while (/[0-9]/.test(char)) { value += char; char = Code[++current]; } if (value.length === 0) { return null; } else { Position = current; return { type: "NumberLiteral", value: value }; } } function parseName() { let current = Position let char = Code[current]; var value = ""; while (/[a-zA-Z]/.test(char)) { value += char; char = Code[++current]; } if (value.length === 0) { return null; } else { Position = current; return { type: 'Identifier', value: value }; } } function parseToken(token) { let current = Position; let char = Code[current]; let i = 0; char = token[i]; while (Code[current] === char && i < token.length) { i++; current++; char = token[i]; } if (i !== token.length) { return false; } else { Position = current; return true; } } console.log(JSON.stringify(parseExpr()));
vlreshet Автор
10.08.2018 13:38Ну, никто не утверждает что это лучший в мире пример. Но это сильно лучше чем ничего, или чем сухие формулы и объяснения.
true-grue
10.08.2018 16:51Спасибо за ссылку на проект и за перевод. Я стараюсь отслеживать появление ресурсов по разработке компиляторов для начинающих, но этот проект по какой-то причине упустил из виду. Позволю себе небольшую критику английского варианта.
На мой взгляд, разумно начать с причин, по которым с построением компиляторов важно знакомиться неспециалистам. Причины эти сегодня не так уж очевидны, помимо совсем уж тривиального — “изучение устройства инструмента может помочь в практической с ним работе”. Казалось бы, языков и компиляторов уже и так существует великое множество. А для исключительных случаев есть перенацеливаемые системы gcc и LLVM.
Подробный ответ включал бы в себя DSL и порождение кода для экзотических архитектур (бытует расхожее мнение, что архитектура команд это нечто неизменное, и если хочется нового — следует брать RISCV, созданную специалистами мирового класса. В качестве возражения можно привести подходы с синтезируемой системой команд, ASIP, CGRA, HLS).
Новые подходы к компиляции часто требуют перестройки архитектуры существующего компилятора. Так произошло, например, с популяризацией SSA. И, скорее всего, именно по такой причине в gcc и LLVM до сих пор отсутствует работа с графовым представлением, подобным sea of nodes, не говоря уже о более нишевых и более современных представлениях программы. Реализации современных подходов, и пусть это не кажется теперь странным, чаще можно найти в небольшом DSL-компиляторе.
В коде данного проекта учебного компилятора можно встретить visitors. На мой взгляд, это неоднозначный выбор. Разумеется, использование данного шаблона проектирования — данность, обусловленная, во многом, преподаванием ООП/Java. Более того, visitors до сих пор можно встретить в реализациях некоторых “промышленных” компиляторов. Но начинающим, и это мое убеждение, следует демонстрировать вещи в наиболее прозрачной и естественной для соответствующего предмета изучения нотации. В хорошем учебнике по компиляторам вы не найдёте visitors. Сопоставление с образцом, которое этот шаблон с успехом заменяет, используется в наши дни даже в таких популярных и практичных языках, как Scala.
Любопытно, что автор так и не воспользовался в своей реализации visitors методом exit, который соответствует обходу дерева снизу вверх. А ведь именно такой порядок обхода используется в проекте для реализации генератора кода. Здесь автор обошёлся лишь рекурсией и switch. Почему же не сделать того же и в остальных частях программы?
Для знакомых с Лисп-подобными языками в качестве возможной альтернативы данному проекту я бы посоветовал очень хорошее введение Essentials of Compilation An Incremental Approach (https://jeapostrophe.github.io/courses/2017/spring/406/notes/book.pdf ). Не теряют актуальности и сегодня известные учебники Вирта (https://www.ozon.ru/context/detail/id/4803779/ ) и Эппеля (https://www.cs.princeton.edu/~appel/modern/ml/ ).
Комментарий получается слишком пространным, но мне все еще не даёт покоя вопрос: а где же подобные введения на русском языке, оригиналы, а не переводы? Ведь предположение о том, что русскоязычные разработчики менее компетентны в области компиляторов, чем автор рассмотренного учебного компилятора, является абсолютно несостоятельным…vlreshet Автор
10.08.2018 17:09+1Спасибо, рад что мой труд не прошёл даром.
а где же подобные введения на русском языке, оригиналы, а не переводы
ИМХО, вопрос менталитета. Американцы: «я выучил крутую штуку. пойду напишу в блог, расскажу всем что оно такое». Наши (СНГ): «я выучил крутую штуку. хрен я что кому подскажу, я мучился с документацией — вот и все остальные пусть мучаются». Как-то так. Не зря же есть шутка о зарубежных форумах и о наших — мол на зарубежном тебе всё подскажут и разжуют, а на наших назовут 10 причин почему ты дебил и вопрос твой говно.mihacoder
12.08.2018 14:39Тут еще от форума зависит. Например, на форум CMS Opencart, как и везде, заходят новички с вопросами "как сделать...". И большинство ответов звучат типа "купи у меня вот этот модуль (ссылка), там это сделано". Хотя, если объяснить, там дел на 10 минут. На форумах по WordPress такого намного меньше, хотя они оба бесплатные, к обоим есть и платные, и бесплатные модули и плагины.
rraderio
pewpew
Ещё вариант — кнопкой ошибаются в гитхабе.