Ссылки, необходимые для реализации интерпретатора в C / C ++ - PullRequest
36 голосов
/ 17 ноября 2008

Я привязан к проекту, чтобы встроить переводчика в существующее приложение. Интерпретируемый язык является производным от Lisp со встроенными в него приложениями. Отдельные «программы» будут запускаться пакетно в приложении.

Я удивлен, что за эти годы я написал пару компиляторов и несколько переводчиков / анализаторов языка данных, но я никогда раньше не писал интерпретатор. Прототип довольно далеко, реализован как обходчик синтаксического дерева, в C ++. Я, вероятно, могу влиять на архитектуру за пределами прототипа, но не на язык реализации (C ++). Итак, ограничения:

  • реализация будет в C ++
  • синтаксический анализ, вероятно, будет обрабатываться грамматикой yacc / bison (сейчас)
  • предложения полной экологии VM / Interpreter, таких как NekoVM и LLVM, вероятно, не практичны для этого проекта. Автономный лучше, даже если это звучит как NIH.

Что я действительно ищу, так это материалы для чтения по основам реализации переводчиков. Я немного просмотрел SO и другой сайт, известный как Lambda the Ultimate , хотя они больше ориентированы на теорию языка программирования.

Некоторые лакомые кусочки, которые я до сих пор собирал:

  • Лисп в маленьких кусочках , Кристиан Квиннек. Человек, рекомендовавший это, сказал, что он «переходит от тривиального интерпретатора к более продвинутым методам и заканчивает представлять байт-код и компиляторы« Схема С »».

  • NekoVM . Как я упоминал выше, я сомневаюсь, что нам будет позволено включить всю инфраструктуру VM для поддержки этого проекта.

  • Структура и интерпретация компьютерных программ . Первоначально я предположил, что это может быть излишним, но, проработав здоровый кусок, я согласен с @JBF. Очень информативно и расширяет кругозор.

  • На Лиспе Пол Грэм. Я читал это, и хотя это информативное введение в принципы Lisp, его недостаточно для быстрого создания интерпретатора.

  • Реализация попугая . Это похоже на забавное чтение. Не уверен, что это даст мне основы.

  • Схема с нуля . Питер Мишо атакует различные реализации Scheme, от быстрого и грязного интерпретатора Scheme, написанного на C (для использования в качестве начальной загрузки в более поздних проектах), до скомпилированного кода Scheme. Пока очень интересно.

  • Шаблоны языковой реализации: создание собственных доменных и общих языков программирования , рекомендуется в ветке комментариев для Книги по созданию интерпретируемых языков . Книга содержит две главы, посвященные практике построения переводчиков, поэтому я добавляю ее в очередь на чтение.

  • Новый (и все же Старый , т.е. 1979): Написание интерактивных компиляторов и интерпретаторов П. Дж. Брауна. Это давно вышло из печати, но интересно в плане краткого описания различных задач, связанных с реализацией интерпретатора Basic. Я видел смешанные обзоры для этого, но так как он дешевый (у меня он используется по цене около $ 3,50), я сделаю это.

Так как насчет этого? Есть ли хорошая книга, которая берет неофита за руку и показывает, как построить интерпретатор в C / C ++ для Lisp-подобного языка? У вас есть предпочтения для обходчиков синтаксического дерева или интерпретаторов байт-кода?

Чтобы ответить @JBF:

  • текущий прототип является интерпретатором, и для меня это имеет смысл, поскольку мы принимаем путь к файлу произвольного кода и выполняем его в нашей прикладной среде. Встроенные функции влияют на представление данных в памяти.

  • это не должно быть ужасно медленным. Текущий ходок по дереву кажется приемлемым.

  • Язык основан на на Лиспе, но не на Лиспе, поэтому соответствие стандартам не требуется.

  • Как упомянуто выше, маловероятно, что нам будет разрешено добавить полностью внешний проект виртуальной машины / интерпретатора для решения этой проблемы.

На других постерах я тоже буду проверять ваши цитаты. Спасибо всем!

Ответы [ 5 ]

12 голосов
/ 17 ноября 2008

Краткий ответ:

Основной список чтения для интерпретатора lisp - SICP. Я бы не стал называть это излишним, если вы чувствуете, что вы слишком квалифицированы для первых частей книги, перейдите к главе 4 и начнете переводить прочь (хотя я чувствую, что это потеря, поскольку главы 1-3 действительно хороши!) .

Добавить LISP маленькими кусочками (LISP отныне), главы 1-3. Особенно глава 3, если вам нужно реализовать какие-либо нетривиальные формы контроля.

См. Этот пост Jens Axel Søgaard на минимальной схеме самостоятельного хостинга: http://www.scheme.dk/blog/2006/12/self-evaluating-evaluator.html.

Немного более длинный ответ:

Трудно дать совет, не зная, что вам требуется от вашего переводчика.

  • действительно ли это действительно должен быть интерпретатор, или вам действительно нужно иметь возможность выполнять код lisp?
  • это должно быть быстро?
  • нужно ли соответствие стандартам? Общие губы? R5RS? R6RS? Какие SFRI вам нужны?

Если вам нужно что-то более интересное, чем простой обходчик синтаксического дерева, я настоятельно рекомендую встроить подсистему быстрой схемы. На ум приходит схема гамбита: http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page.

Если это не вариант главы 5 в SICP и глав 5 - в целевой компиляции LISP для более быстрого выполнения.

Для более быстрой интерпретации я бы взглянул на самые последние интерпретаторы / компиляторы JavaScript. Похоже, что быстрое выполнение JavaScript заставляет задуматься, и вы, вероятно, сможете поучиться у них. В V8 приводятся два важных документа: http://code.google.com/apis/v8/design.html, а рыба-белок цитирует пару: http://webkit.org/blog/189/announcing-squirrelfish/.

Существует также каноническая схема работы: http://library.readscheme.org/page1.html для компилятора RABBIT.

Если я начну заниматься преждевременными спекуляциями, управление памятью может стать крепким орешком. Нильс М. Холм опубликовал книгу «Схема 9 из пустого пространства» http://www.t3x.org/s9fes/, которая включает в себя простую метку «Останови мир» и сборщик мусора. Источник включен.

Джон Роуз (из более новой известности JVM) написал статью об интеграции Схемы в C: http://library.readscheme.org/servlets/cite.ss?pattern=AcmDL-Ros-92.

7 голосов
/ 17 ноября 2008

Да на SICP.

Я выполнил эту задачу несколько раз, и вот что я бы сделал на вашем месте:

Сначала создайте модель памяти. Вы будете хотеть систему GC некоторого вида. Сначала проще сделать это, чем потом прикрутить.

Дизайн ваших структур данных. В моих реализациях у меня был базовый минус с несколькими базовыми типами: атом, строка, число, список, bool, примитивная функция.

Создайте свою виртуальную машину и не забывайте поддерживать API в чистоте. В моей последней реализации это было API-интерфейсом верхнего уровня (простите за форматирование - так что мой просмотр превосходит)

ConsBoxFactory &GetConsBoxFactory() { return mConsFactory; }
AtomFactory &GetAtomFactory() { return mAtomFactory; }
Environment &GetEnvironment() { return mEnvironment; }
t_ConsBox *Read(iostream &stm);
t_ConsBox *Eval(t_ConsBox *box);
void Print(basic_ostream<char> &stm, t_ConsBox *box);
void RunProgram(char *program);
void RunProgram(iostream &stm);

RunProgram не нужен - он реализован в терминах Read, Eval и Print. REPL - это общая схема для переводчиков, особенно LISP.

Доступен ConsBoxFactory для создания новых коробок с минусами и работы с ними. AtomFactory используется так, чтобы эквивалентные символические атомы отображались точно на один объект. Среда используется для поддержания привязки символов к минусам.

Большая часть вашей работы должна идти в эти три шага. Тогда вы обнаружите, что ваш клиентский код и код поддержки начинают очень похожи на LISP:

t_ConsBox *ConsBoxFactory::Cadr(t_ConsBox *list)
{
    return Car(Cdr(list));
}

Вы можете написать анализатор в yacc / lex, но зачем? Lisp - невероятно простая пара грамматики и сканера / рекурсивного спуска, для которой требуется около двух часов работы. Хуже всего - написание предикатов для идентификации токенов (т. Е. IsString, IsNumber, IsQuotedExpr и т. Д.), А затем написание подпрограмм для преобразования токенов в блоки cons.

Упростите написание клея в коде C и из него и упростите отладку проблем, когда что-то пойдет не так.

5 голосов
/ 17 ноября 2008

Переводчики Камина из книги Самуила Камина Языки программирования, подход, основанный на переводчике , переведенный на C ++ Тимоти Баддом. Я не уверен, насколько полезным будет голый исходный код, как это было задумано в книге, но это хорошая книга, в которой рассматриваются основы реализации Lisp на языке более низкого уровня, включая сборку мусора и т. Д. ( Это не тема книги, в которой речь идет вообще о языках программирования, но она рассматривается.)

Лисп в маленьких кусочках углубляется, но это хорошо и плохо для вашего случая. Существует много материалов по компиляции и тому подобного, которые не будут иметь отношения к вам, и его более простые интерпретаторы находятся в Scheme, а не в C ++.

SICP это хорошо, определенно. Не слишком много, но, конечно, написание переводчиков - это лишь малая часть книги.

Предложение JScheme тоже хорошее (и оно включает в себя некоторый код мной), но оно не поможет вам с такими вещами, как GC.

Я мог бы дополнить это несколькими предложениями позже.

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

3 голосов
/ 17 ноября 2008

Выезд JScheme от Питера Норвига . Я нашел это удивительно простым для понимания и портирования на C ++. Не знаю, как использовать схему в качестве языка сценариев - обучение ее jnrs громоздко и устарело (привет 1980-е).

2 голосов
/ 26 ноября 2008

Я хотел бы расширить мою рекомендацию для Языки программирования: применение и интерпретация . Если вы хотите написать переводчика, эта книга приведет вас туда очень коротким путем. Если вы перечитываете написание кода, который читаете, и выполняете упражнение, вы получаете кучу похожих интерпретаторов, но разных (один стремится, другой ленив, один динамичен, другой имеет некоторую типизацию, один имеет динамический охват, у других есть лексическая область и т. д.).

...