Обзор интерпретатора 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]; - интерактивная консоль - передача параметров через ARGV В библиотеке menuetlibc процедура разбора параметров командной строки пока не адаптирована для КолибриОС, поэтому при запуске TinyPy приходится вводить имя файла вручную, также нельзя передавать параметры в командной строке. И конечно, не хватает основной силы 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. В последнем случае нужно указать глобальный массив ARGV=[0, 'math.py', 'math.tpc'], так как передать параметры через командную строку пока нельзя. После этого можно запустить prog.py из TinyPy. Синтаксис "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. Продолжение следует.