Обзор интерпретатора TinyPy и заметки по его адаптации к работе в КолибриОС. 1. Что такое TinyPy и чем он хорош в плане портирования TinyPy - интерпретатор Python-подобного языка, созданный Филом Хэсси (Phil Hassey), отличающийся очень небольшими размерами: выбором опций компиляции можно добиться размеров исполняемого модуля в пределах 64 килобайт. При разработке приложений для Колибри в других операционных системах доступен довольно широкий выбор кросс-компиляторов. Набор средств разработки в самой Колибри до недавнего времени был ограничен FASM. Можно предположить, что возможность создавать программы в самой системе на таком легкоизучаемом и распространённом языке, как Python, повышает привлекательность системы для пользователя, далёкого от программирования на ассемблере. TinyPy оказался лёгок в портировании: значительная часть его написана на самом Python, а остальная часть - на C, исходные тексты занимают чуть больше 200 Кб. Для компиляции нужна только стандартная библиотека libc. Из неё используется всего около полутора десятков функций (vsnprintf/vsprintf, malloc/memcpy/memmove/free, fopen/fread/fwrite/fclose). В итоге работа по портированию TinyPy состояла из следующих частей: 1. Написание Makefile для сборки компилятором GCC с использованием menuetlibc. 2. Добавление в menuetlibc недостающих функций vsnprintf/vsprintf. 3. Подключение библиотеки Колибри для работы с консолью. 4. И конечно, отлов разнообразных мелких багов (как же без этого!). 2. Возможности TinyPy. 2.1. Типы данных. Каждый объект в среде TinyPy представляется 16-байтовой структурой tp_obj. Первые 4 байта занимает тип, и назначение последующих 12 байт зависит от него. Доступны следующие типы: TP_NONE, TP_NUMBER, TP_STRING, TP_DICT, TP_LIST, TP_FNC, TP_DATA. TP_NONE - соответствует единственному объекту None. Больше про него сказать нечего. TP_NUMBER - число, хранится как float. Если число отличается от ближайшего целого меньше, чем на 10^(-6), оно считается целым, и при печати выводится как целое. Также к этому типу относятся логические True и False. Поддерживаются арифметические операции +,-,*,/,%, битовые << и >>, логические |, &. Пример: print(2+2*2, 7/3, (-7)%3, 1==True, 0==False) Выводит: 6 2.333333 -1 1 1 Заметим сразу, что print является функцией (как в Python 3), то есть параметры обязательно указывать в скобках. TP_STRING - строка. Поддерживаются: проверка вхождения ("str1" in "str2"), срезы s[:b], s[a:b], s[a:], функции len, index, join, split, find, strip, replace. TP_DICT - словарь, он же ассоциативный массив. Поддерживается добавление нового элемента и всех элементов другого словаря. Перебор по всем ключам и удаление элементов пока не поддерживается. Словари также являются удобным способом представления объектов, в частности, если d словарь, то записи d.key и d['key'] равнозначны. В этом TinyPy немного напоминает JavaScript. TP_LIST - список. Поддерживаются: перебор по элементам (for el in list), функции len, append/appendx, extend, insert/insertx, pop, find, index, sort. Также поддерживается функция range. reverse() пока не поддерживается. TP_FNC - функция. Бывает 2 типов - обычная функция и метод, отличаются порядком вызова. TP_DATA - внутренние структуры TinyPy. 2. Возможности TinyPy в сравнении с "большим" Python "what tinypy won't be: - a full implementation of Python; - totally compatible with Python" "roadmap.txt", tinypy sources Синтаксис языка TinyPy очень похож на Python, но многие существенные возможности Python не поддерживаются: - итераторы и сопрограмм; - синтаксический "сахар" для объявления списков и словарей, наподобие odd_squares = [a*a for a in range(100) if a%2]; - интерактивная консоль. И конечно, не хватает основной силы Python - его стандартной библиотеки. 3. Расширение TinyPy. Набор встроенных функций в TinyPy достаточно беден, но зато добавление новых модулей достаточно просто. Рассмотрим создание модулей на самом TinyPy, на C и на FASM. 3.1. Модули на TinyPy. TinyPy поддерживает модульное программирование, создание модулей принципиально ничем не отличается от Python. Пусть, у нас есть простая программа из двух файлов: Файл math.py: def square(a): return a*a Файл prog.py: import math if __name__=="__main__": math.square(12) Вначале нужно скомпилировать модуль math.py в байт-код при помощи программы py2bc.py, она работает как в Python, так и в TinyPy. Запускаем shell и выполняем команду # tinypy py2bc.py math.py math.tpc После этого можно запустить prog.py из TinyPy. # tinypy prog.py 144 Замечание: синтаксис "from module import function" пока не поддерживается. 3.2 Модули на C. Пример создания модулей на C можно посмотреть в каталоге modules/kolibri. Такие модули статически линкуются с самим интерпретатором и, соответственно, увеличивают его размер. Для снижения накладных расходов компоненты TinyPy компилируются в один объектный модуль, а файлы исходных текстов включаются с помощью директивы #include. Дополнительные модули могут компилироваться как в отдельные объектные файлы, в этом случае нужно дописать их в Makefile, или точно так же подключаться директивой include. В модуле должна присутствовать функция инициализации обычно она называется _init. Она вызывается в tpmain сразу после инициализации виртуальной машины, создаёт словарь экспортируемых объектов и добавляет его в предопределённый словарь modules. Чтобы определить TinyPy-функцию, нужно создать обычную функцию на C вида tp_obj myfunc(tp_vm *tp); 3.3 Модули на FASM. Модуль на FASM пишется аналогично, но всегда компилируется в отдельный объектный файл. Пример можно посмотреть в каталоге fasm_modules. Модуль kolibri_dbg экспортирует одну функцию debug_print, выводящую строку на доску отладки. 4. Обзор модуля kolibri. Продолжение следует.