Скриптовый язык SSS
Начну с кода. Код тут: https://github.com/mrtrizer/LispSSS
Не смотря на то, что работу над интерпретатором я прекратил и нашел ему замену, я получил хороший опыт в процессе разработки интерпретатора. Ниже я просто опишу, как я шел, и к чему я пришел в итоге.
При работе часто требуется включить в приложение простой скриптовый язык. Вот и я столкнулся с этой необходимостью. Существуют такие популярные решения, как Python, Lua или JS. Но, к сожалению, интерпретаторы реализованы не для всех платформ. Так же, к недостаткам я отношу относительную сложность реализации этих языков.
Идея написать интерпретатор для Lisp у меня появилась ещё год назад, когда я столкнулся с CommonLisp. Сразу оговорюсь, я не большой знаток , и я не сталкивался с задачами, где Lisp был бы применим. Вдохновленный идеей лямбда исчисления я написал черновую версию интерпретатора lisp на Си, но дальше дело не прошло, так как у меня не было мыслей по улучшению его синтаксиса. В течении года я задумывался над возможностями улучшения синтаксиса лиспа. Вот некоторые выводы, к которым я пришел:
Не смотря на то, что работу над интерпретатором я прекратил и нашел ему замену, я получил хороший опыт в процессе разработки интерпретатора. Ниже я просто опишу, как я шел, и к чему я пришел в итоге.
При работе часто требуется включить в приложение простой скриптовый язык. Вот и я столкнулся с этой необходимостью. Существуют такие популярные решения, как Python, Lua или JS. Но, к сожалению, интерпретаторы реализованы не для всех платформ. Так же, к недостаткам я отношу относительную сложность реализации этих языков.
Идея написать интерпретатор для Lisp у меня появилась ещё год назад, когда я столкнулся с CommonLisp. Сразу оговорюсь, я не большой знаток , и я не сталкивался с задачами, где Lisp был бы применим. Вдохновленный идеей лямбда исчисления я написал черновую версию интерпретатора lisp на Си, но дальше дело не прошло, так как у меня не было мыслей по улучшению его синтаксиса. В течении года я задумывался над возможностями улучшения синтаксиса лиспа. Вот некоторые выводы, к которым я пришел:
- Если в синтаксисе вызова функции Lisp убрать скобки, получится синтаксис любой популярной консольной оболочки, таким образом можно реализовать шелл с синтаксисом лиспа, что кажется мне удобным.
- Из за однородного обрамления блоков, усложняется читаемость кода и локализация синтаксических ошибок, вроде пропуска скобок. Потому, следует ввести другой способ обрамления блоков. Чтобы подстрелить обоих зайцев, можно ввести блок пакетного выполнения команд, который заменит функцию PROG. С таким синтаксисом: {
- Так как стоит цель разработать язык общего назначения, следует уйти от рекурсии и списков, доминирующих в функциональных языках, в сторону императивного программирования. В коде скриптов должны использоваться массивы и циклы. Такой подход привычнее рядовому программисту и мне в частности.
[<выражение>[;
<выражение>... ]]
}
Так мы избавляемся от лишних скобок улучшая восприятие и даем интерпретатору возможность определять пропущенные скобки внутри пакетного блока.
И я приступил к реализации идеи создания интерпретатора. Знакомый преподаватель посоветовал для разведки почитать "Компиляторы: принципы, технологии и инструменты" под авторством Альфреда В. Ахо, Рави Сети и Джеффри Д. Ульмана. Ну я и почитал.
Оттуда я почерпнул основные идеи построения интерпретатора. Правда, не все реализовал к сожалению.
Интерпретатор двупроходный, синтаксическое дерево после построения может(!) кешироваться во временном файле, лежащем рядом с исходным кодом, и используется при повторных запусках. Таким образом, после первого запуска скрипта фазы лексического и синтаксического анализа будут пропускаться при последующих запусках для экономии времени.
Пример программы:
Пример программы:
#!/home/trizer/Hobby/lisp_v2/build/playLisp #Operations setq functions (quote ( (func (a b)(+ a b)) (func (a b)(- a b)) (func (a b)(* a b)) (func (a b)(/ a b)) )); #Operation names setq func_names (quote ( "sum" "sub" "mul" "div" ) ); defun main () { print (size (1 2 3 4 5 6)); print (foo 5 100.0); while T { setq tmp func_names; setq i 1; while (!= tmp nil) { print i ". " (car tmp); setq tmp (cdr tmp); setq i (+ i 1); }; print i ". Exit"; setq n (ask "Enter n: " ); if (|| (< n 1) (> n i)) { print "Bad number, repeat please"; continue; }; if (== n i) (return nil); setq a (ask "Enter a: "); setq b (ask "Enter b: "); setq tmp functions; while (!= n 1) { setq tmp (cdr tmp); setq n (- n 1); }; setq result ((exec (exec (car tmp))) a b); print "Result = " result; setq test result; }; }; main;Вышеприведенная программа реализует консольный, диалоговый калькулятор, причем реализация всех операторов и их названия хранятся в списках.
К сожалению (или к счастью), я прекратил работу над интерпретатором, ввиду его не очень понятного синтаксиса и набирающего обороты HTML5 и ES6. Проблема интерпретации больше не стоит, ведь все приложения теперь можно писать на JS, а там eval.
Комментарии
Отправить комментарий