Скриптовый язык SSS

Начну с кода. Код тут: https://github.com/mrtrizer/LispSSS
Не смотря на то, что работу над интерпретатором я прекратил и нашел ему замену, я получил хороший опыт в процессе разработки интерпретатора. Ниже я просто опишу, как я шел, и к чему я пришел в итоге.
При работе часто требуется включить в приложение простой скриптовый язык. Вот и я столкнулся с этой необходимостью. Существуют такие популярные решения, как 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.

Комментарии

Популярные сообщения из этого блога

Siege Up! Editor (beta)

STM32F4 и программный выход в DFU

Git и Yandex.Disk