Previous Entry Share Next Entry
MSL FL (SP) - Компилятор своими руками. Шаг 2. Легкие пути.
mikelsv
Я пожалуй повторюсь, что это интерпретатор, но компилятор звучит и лень переделывать заголовок. А у меня продолжается рад постов про разработку, в которых в частности рассказывается, что курил разработчик - один из частых вопросов при попытке писать на чужом языке, а в некоторых случаях и на своем.

Итак, наша задача выполнить <? print('Hello World!'); ?> . Поэтому вместо того, чтобы заняться переменными мы пойдем простым путем, сразу займемся парсером. Ну а че. Запарсить нужно всего ничего. Теги <??>, $переменные и очевидно funкции(), ну и 'текст всякий'.

Пока одна рука пишет код, второй расскажу о трех классах, используемых в коде, это:
VString() - класс хранящий в себе указатель на память. Это практически тоже самое как unsigned char*, только с размером. Это решает кучу проблем. Никаких проверок конуца строки по нулевому символу.  Иначе это бред, куча всевозможных дырок и падений. Очень часто нужен именно этот класс при работе с данными. Офигенная штука. Не выделяет память. На те же операции с использованием класса выделяющего память уйдет намного больше времени.
MString() - как и предыдущий, но с выделением памяти.
HLString() - класс с динамическим набором буферов памяти. Отличная штука для сложения строк. Выделяет большие блоки памяти, что позволяет уменьшить обращение к функциям выделения памяти и ускорить работу.

Так как версий будет много добавил в код дефайн USE_MSLFL_VER в котором можно указывать версию кода. Для этой статьи установить USE_MSLFL_VER равный 2.
Скачать готовый пример можно отсюда: anon:anon@svn://svn.loglist.org/usr/svn/opensource/msl-fl/ и anon:anon@svn://svn.loglist.org/usr/svn/opensource/msvlib .
Так же исходный код выложу сюда: http://pastebin.com/g7u3ry6P

Пишем код:
Меняем GetResult() на GetOutput(), SetResult() так же. Звучит лучше.
Пишем функции обработки предупреждений и ошибок SetWarning(), SetError() и SetEpic(); Разница в разрушительном эффекте от ошибок. От незначительных до ошибок при выделении памяти. Первые две для ошибок кодера, последняя для ошибок компиялтора и системы. Хотя для системы тоже надо придумать отдельную функцию.

В функции Do(code); ищется '<?' обозначающая начало программы, дальше управление передается в DoCode(). DoCode() по первому символуц определяет, что это $ - переменная, aA-zZ или _ - функция или выдает ошибку.
Обработчик $переменных пока не пишем, наша задача обработать функцию.
DoCodeFunction() определяет название функции и передает управление в функцию определения аргументов функции.

Остановимся на этом. Что такое аргумент функции? Это может быть переменная, функция, строка. Останавливаемся на строке, все строго по задаче. Пишем структуру для аргумента функции:
class msl_fl_farg{
public:
    VString val;
};

Строка, без внутренней обработки. Пока только так, строго по задаче, хотя в будущем обязательно придется переделывать для всех вариантов.
Дальше класс для списка аргументов: class msl_fl_fargs; Тут у нас динамическое выделение памяти, asz - выделено памяти, usz - испольовано под параметры. UpSize() выделяет память под еще 16 параметров, Add(val) - добавляет параметр, Sz() - возвращает количество параметров, operator[id] - возвращает параметр с указанным номером.

Переходим к функци DoCodeFunctionArgs(), которая занимается той самой обработкой параметров нашей функции. Сейчас она умеет определять строки и переменные, а так же разбирает запятые и закрывающую скобку.
После обработки параметров нас снова возвращает в DoCodeFunction(), откуда вызывается DoCodeFunctionExec().
Ее код:
    int DoCodeFunctionExec(VString name, msl_fl_fargs &args){
        if(name=="print" || name=="echo"){
            for(int i=0; i<args.Sz(); i++){
                print(args[i].val);
            }
            return 1;
        }

        SetError(HLString()+"Function: '"+name"' not found");
        return 0;
    }

Вот и все. Немного отладки... И "Hello World!" выводится в консоле. Попробуте добавить свою функцию в DoCodeFunctionExec(); Можно добавить проверку количества параметров в args.Sz() и выдавать ошибку. Развлекайтесь.

Что дальше? Полагаю: <? $hello="Hello World!"; print($hello); ?> Переменные, куда ж без них.

?

Log in

No account? Create an account