Рубрика «интерпретатор» - 3

В первой части был написан лексер. Далее будет рассмотрена разработка парсера.

Парсер

Парсер будет реализован по алгоритму сортировочной станции, так как он достаточно прост и не нуждается в рекурсии. Сам алгоритм таков:

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

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

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

Прикинем, какие тесты могут понадобиться для начала.

  • При получении пустого списка, возвращается пустой список.
  • При получении списка с одним числом, возвращается список с этим числом.
  • При получении [1 + 2], возвращается [1 2 +].
  • При получении [1 + 2 + 3], возвращается [1 2 + 3 +], так как оператор + является лево ассоциативным.
  • При получении [1 * 2 + 3], возвращается [1 2 * 3 +].
  • При получении [1 + 2 * 3], возвращается [1 2 3 * +], так как оператор * имеет больший приоритет.

Со скобками и ошибками разберёмся позднее. Итак, напишем первый тест из списка.

TEST_CLASS(ParserTests) {
public:
    TEST_METHOD(Should_return_empty_list_when_put_empty_list) {
        Tokens tokens = Parser::Parse({});
        Assert::IsTrue(tokens.empty());
    }
};

Читать полностью »

Введение

Пишем простой интерпретатор на C++ с помощью TDD, часть 1
Многие C++ программисты слышали про разработку через тестирование. Но почти все материалы по данной теме касаются более высокоуровневых языков и сосредоточены больше на общей теории, чем на практике. Итак, в данной статье я попробую привести пример пошаговой разработки через тестирование небольшого проекта на C++. А именно, как можно предположить из названия, простого интерпретатора математических выражений. Такой проект также является неплохой code kata, так как на его выполнение затрачивается не более часа (если не писать параллельно статью об этом).

Архитектура

Несмотря на то, что при использовании TDD архитектура приложения постепенно проявляется сама собой, начальная её проработка всё же необходима. Благодаря этому может значительно снизиться общее время, затраченное на реализацию. Это особенно эффективно в тех случаях, когда существуют готовые примеры подобных систем, которые можно взять за образец. В данном случае, существует вполне устоявшееся мнение о том, как должны быть устроены компиляторы и интерпретаторы, чем и можно воспользоваться.

Для начала, составим список того, что должен уметь наш простой интерпретатор, в порядке убывания приоритета:

  • Вычислять значение математического выражения, состоящего из чисел с плавающий точкой и математических операторов (-+/*).
  • Учёт приоритета операторов.
  • Учёт скобок.
  • Унарные плюс и минус.
  • Вычисление нескольких выражений, разделённых точкой с запятой (;).
  • Встроенные константы (pi, e).
  • Создание собственных констант с помощью оператора присваивания (=).
  • Встроенные функции с переменным числом аргументов.
  • Задание новых функций.

В данной статье будет реализация только первых трёх пунктов. Сам проект концептуально будет состоять из четырёх частей:

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

Инструментарий

Программа будет писаться в Visual Studio 2013 с установленным Visual C++ Compiler Nov 2013 CTP. Тесты будут на основе встроенного в студию тестового фреймворка для C++ проектов CppUnitTestFramework. Он предоставляет минимальную поддержку для написания модульных тестов (по сравнению с Boost.Test, или CppUTest), но, с другой стороны, хорошо интегрирован в среду разработки.

Итак, создадим новый проект типа «Native Unit Test Project» и удостоверимся, что всё компилируется.
Читать полностью »

В очередной раз используя этот скрипт в одном из учебных классов, я поискал материалы и обнаружил, что здесь давно не вспоминали об expect. Это замечательный альтернативный интерпретатор для командной строки Linux, который может общаться с ней вместо живого человека, и я добавлю сюда лишь ещё один пример его применения.

Автовход с паролем и управление по ssh «в гостях» при помощи expect

Картинок на эту тему особо нет, а в статье и вообще не будет, поэтому привлечём ваше внимание обложкой замечательной книги

Читать полностью »

Простой интерпретатор с нуля на Python #4

В предыдущих трех частях мы создали лексер, парсер и AST для нашего игрушечного языка IMP. Мы даже написали нашу собственную библиотеку парсеров комбинаторов. В этой, финальной статье мы напишем последний компонент интерпретатора — исполнитель.

Давайте подумаем, как обычно исполняются программы. В любой момент времени есть некоторые «точки контроля», которые указывает на то, какое выражение программа собирается выполнить дальше. Когда следующее выражение исполняется, оно модифицирует состояние программы, путем улучшения «точки контроля» и изменения значений переменных.
Читать полностью »

Простой интерпретатор с нуля на Python (часть 3)

Содержание

Простой интерпретатор с нуля на Python #1
Простой интерпретатор с нуля на Python #2
Простой интерпретатор с нуля на Python #3
Простой интерпретатор с нуля на Python #4

Разъяснение к публикации

Пользователь duse ранее выкладывал переводы двух предыдущих статей, явно намереваясь перевести всю серию. Так как тема меня очень интересует, а новых переводов нет, обратился к первоисточнику. С английским не очень силён, чтобы не терять суть, стал переводить на русский. Так и родился этот перевод. Прошу прощения у duse в случае, если мне стоило ещё чуточку потерпеть. Но для сообщества в любом случае должна быть польза.

Таким образом, мы написали лексер библиотеку комбинатора парсеров для нашего интерпретатора. В этой части, мы создадим структурные данные абстрактного синтаксического дерева (AST), и напишем парсер, используя нашу библиотеку комбинаторов, которые переводят список токенов, возвращенных лексером, в абстрактное синтаксическое дерево (AST). После того, как мы распарсим AST, запустить программу будет очень просто.

Читать полностью »

Простой интерпретатор с нуля на Python #2

Содержание

Простой интерпретатор с нуля на Python #1
Простой интерпретатор с нуля на Python #2
Простой интерпретатор с нуля на Python #3
Простой интерпретатор с нуля на Python #4

В предыдущей статье мы рассматривали сам язык IMP и основную структуру интерпретатора. Также, мы тщательно рассмотрели лексер. В этой статье мы будем писать небольшой парсер для нашего языка. Он будет извлекать AST (abstract syntax tree) из списка токенов, сгенерированных лексером. Библиотека комбинатора будет независимая, то есть с помощью нее можно будет написать парсер для любого языка.

Что такое комбинаторы парсеров?

Есть очень много способов написать парсер. Самым простым и быстрым способом сделать это являются комбинаторы.

Вы можете считать парсер функцией, которая принимает поток токенов. Если успешно, то парсер будет «съедать» немного токенов из потока. Функция вернет часть финального AST вместе с остальными токенами. Комбинатор — это функция, которая производит парсер, как его результат, обычно после приема одного или нескольких анализаторов (парсеров) в качестве входных данных, отсюда и название — «комбинатор». Вы можете использовать комбинаторы для создания законченного парсера для языка, как IMP, путем создания множества маленьких парсеров для каждой части языка.
Читать полностью »

image

От переводчика

Весьма вольный перевод серии из трёх статей об устройстве питоновского интерпретатора. Автор занимается разработкой собственного велосипеда по этой теме и решил поделиться знаниями, появившимися в процессе. Посмотрим, что у него из этого получилось.

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

Небольшой дисклеймер: свой рассказ я буду вести на примере интерпретатора python 2.7. Всё, о чем пойдёт речь далее, можно повторить и на python 3.x с поправкой на некоторые различия в синтаксисе и именование некоторых функций.

Итак, начнём.
Читать полностью »

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

В этом цикле статей я попытаюсь захватить часть этой простоты путем написания простого интерпретатора для обычного императивного языка IMP (IMperative Language). Интерпретатор будет написан на Питоне, потому что это простой и широко известный язык. Также, питон-код похож на псевдокод, и даже если вы не знаете его [питон], у вас получится понять код. Парсинг будет выполнен с помощью простого набора комбинаторов, написанных с нуля (подробнее расскажу в следующей части). Никаких дополнительных библиотек не будет использовано, кроме sys (для I/O), re (регулярные выражения в лексере) и unittest (для проверки работоспособности нашей поделки).
Читать полностью »

Программная симуляция микропроцессора. Коробка передачВ этой статье я хочу рассказать о том, как создатели симуляторов добиваются максимальной производительности моделей процессоров, при этом не жертвуя гибкостью и расширяемостью полного решения. Если кратко, то решение состоит в сосуществовании нескольких движков, наилучшие качества которых используются на различных этапах работы модели.
Содержимое данной заметки будет основываться на моём опыте разработки функциональных симуляторов, а также на публикациях и технических статьях, описывающих различные симуляторы и виртуальные машины: Wind River Simics, VMWare, Qemu, Bochs и другим. Слово «функциональный» в контексте данной статьи обозначает то, что точность моделей ограничена уровнем набора команд (instruction set architecture, ISA).
Читать полностью »

Вдохновившись проектом Google Glass, я подумал, как хорошо было бы сделать крайне простой, но мощный инструмент дополненной реальности специально для таких очков. И почему бы не сделать его на основе такой широко используемой технологии как QR-коды. Так родилась задумка языка QuRava — набора байтов, записанных в QR-коде и интерпретируемого в полноценную программу, реализующую часть возможностей языка Java.

Хочу сразу предупредить, что все нижеизложенное — альфа-версия, сделано за несколько вечеров. Поэтому по поводу маленьких возможностей сильно не ругайтесь и вопросов про отсутствие лямбда-исчисления не задавайте.
Пишем свой интерпретируемый шестнадцатиричный язык программирования для QR кодов
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js