Скриптовый язык 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.

Комментарии
Отправить комментарий