По работе пришлось писать встраиваемый парсер для скриптового языка. Lua и иже с ним не пошёл так как нужно было для разных пользователей разную функциональность, а стандартные функции Lua не так уж просто из него убрать. В общем попробовал написать свой и оказалось, что дело несложное. Идею взял здесь. Парсер состоит из управляющего модуля и модулей занимающих парсингом. Можно сделать очень простой язык, можно сложный, зависит от набора модулей для парсинга. Обычно модуль это один файл содержащий в среднем 200 строк С-кода. В общем вещь достаточно тривиальная однако с её помощью можно делать сложные вещи (в моём случае даже лямбда-функции поддерживаются), самое приятное в том, что парсер самодокументирующийся. В сложных проектах документация постоянно отстаёт от кода, а здесь парсер всегда может выдать текущий синтаксис языка.
Начальство не возражало против выкладывания исходников для парсера в открытый доступ, так что я его кинул на sourceforge. Лежит здесь. Чтобы совсем уж не было всё голым слепил интерпретатор читающий скрипты из файла и выполняющий их. Для иллюстрации возможностей удалённого запуска процедур (RPC) сделал сервер для хранения файлов. Получение или загрузка файлов делается с помощью скриптов. Это значит, что можно запросить файл сжатый в bzip2 а затем закодированный MIME::Base64 или зашифрованный с помощью AES. В общем, игрушка
Код написан на С, под Линукс. Документация кое-какая есть, правда на английском (писано для работодателя). В общем, может кому пригодится.
Обязательно поиграюсь с вашей игрушкой.
Скажите, а производительность как-то тестировали?
Возможности встраивания насколько широки? Например можно ли его прикрутить к java апплетам или к ruby коду?
Здравствуйте, -n1l-, Вы писали:
N>Обязательно поиграюсь с вашей игрушкой. N>Скажите, а производительность как-то тестировали? N>Возможности встраивания насколько широки? Например можно ли его прикрутить к java апплетам или к ruby коду?
Специальных тестов не делал. Сейчас он используется в системе обработки SMS для адресации (routing) и модификации сообщений, если это необходимо. Пропускная способность этой системы выше, чем у обычного SMSC (до 1000 сообщений в секунду), при этом система гораздо более гибкая. Собственно, парсер создавался для того, чтобы иметь возможность создавать опкоды заточенные под конкретные действия системы. За счёт этого можно делать оптимизацию. Сам парсер почти ничего не добавляет. Можно, конечно, попытаться и его оптимизировать, только это лишние усложнения, а значит баги.
Ограничения по встраиванию минимальны. Парсер не может остановиться на пол-пути. То есть, для работы ему требуется полный текст скрипта и время чтобы разобрать его от начала до конца. То же самое относится к выполнению опкодов. Сделать для него обёртку например в JNI не составит труда. (Надеюсь речь не идёт о том, чтобы добавлять к этому парсеру модули написанные на Java Если скрипты очень большие, то их выполнение и обработку можно выносить в отдельный поток.
Была у меня задумка, вместо уродского описания интерфейса с помощью XML, слепить скрипт-язык позволяющий делать то же самое, только более эффективным способом. Да и писать скрипты гораздо проще, чем трахаться с XML. Только для работы мне это не нужно, а для себя мне GUI редко приходится делать. Так что дальше пары пробных видгетов дело не пошло.
Здравствуйте, v_andal, Вы писали:
_>Lua и иже с ним не пошёл так как нужно было для разных пользователей разную функциональность, а стандартные функции Lua не так уж просто из него убрать.
Нет ничего проще, чем убрать из Луа стандартные функции. Просто не подключайте соответствующую библиотеку и всего делов:
L = luaL_newstate();
luaL_requiref( L, "_G", luaopen_base, 1 ); // или не подключаем
lua_pop( L, 1 );
luaL_requiref( L, "math", luaopen_math, 1 ); // или не подключаем
lua_pop( L, 1 );
luaL_requiref( L, "string", luaopen_string, 1 ); // или не подключаем
lua_pop( L, 1 );
luaL_requiref( L, "table", luaopen_table, 1 ); // или не подключаем
lua_pop( L, 1 );
luaL_requiref( L, "os", luaopen_os, 1 ); // или не подключаем
lua_pop( L, 1 );
luaL_requiref( L, "utf8", luaopen_utf8, 1 ); // или не подключаем
lua_pop( L, 1 );
... и т. д. для debug, io, etc.
Если же нужно отключить функции индивидуально, а не библиотеками, то достаточно после создания стейта загрузить и выполнить в нем что-нибудь типа такого: