Месяц назад я написал интерпретатор chip8 с адаптерами командной строки и дисплея SDL2 (даже я начал писать адаптер на основе Web-cavas для экспериментов). Затем я сделал то же самое для NES. Это было похоже на Java VM, в смысле интерпретации инструкций байт-кода. У каждого байта есть цель. Но потом я подумал, почему бы не написать простой интерпретируемый язык, который я мог бы программировать на английском, а не на asm конкретной машины. Я не проходил формальный курс по проектированию компиляторов. Так что написать лексер и A-S-T с нуля было сложной задачей для языка C-стиля. Итак, самым простым языком, который пришел мне на ум, был Lisp. Я использую Emacs около 3 лет. Написав свои собственные функции и настройки, я познакомился с этим языком.

В основном имена функций и аргументы разделяются пробелом и заключаются в пару квадратных скобок. Токенизировать это было легко. Токены вызова простых функций будут иметь имя функции в 0-м индексе и их аргументы в последующих индексах.

Теперь структура VM: обычно lisp (по крайней мере, emacs lisp) — это язык без области видимости, работающий в глобальном пространстве имен. т. е., если вы устанавливаете значение в функции, оно существует в памяти виртуальной машины на протяжении всего времени жизни виртуальной машины, если только мы не удалим переменную явным образом. Но я попытался реализовать ligo как язык с ограниченной областью действия. Таким образом, локальные для данной области видимости переменные будут удалены после завершения функции. Но по-прежнему может получать доступ и изменять переменные родительской области. Виртуальной машине требуется 4 основных члена для операции с заданной областью. А именно,

  • указатель на родительскую область (другая структура виртуальной машины)
  • Vars: сопоставление строки с другой структурой, переменная
  • Funcs : сопоставление строки с типом функции InBuilt (т. е. функции, определенные в go)
  • LFuncs: отображение строки в структуру, обозначающую определенную функцию (т. е. функции, определенные в ligo)

У этого есть много методов для обработки вызовов языка, таких как циклы(loop,in), условные выражения(if..else), forks, returns, progns и т. д. Одним из таких основных методов является метод GetVariable. GetVariable используется для получения значения токена (строки) по отношению к виртуальной машине.

В приведенной выше структуре виртуальной машины новые функции go можно определить, написав и добавив на карту новые нативные функции go. Обратитесь к этому документу для более подробной информации.

И это просто эксперимент того, как вообще работает интерпретатор.

Где я использовал это

  • Я использовал это для своих внутренних проектов в качестве языка файла конфигурации.
  • Написал экспериментальный интерактивный веб-интерпретатор. То есть в репо. Запустите ligo с флагом web, т.е. (стиль GNU: 2 дефиса)
  • Я использовал его для простых сценариев вместо Python или оболочки в качестве вызова: P

Кстати, это — пример синтаксиса того, как делать что-то на этом языке.

Не стесняйтесь сообщать о проблемах и делать запрос на включение. Вот проект: github://aki237/ligo.