Хочу сразу предупредить, что все нижеизложенное — альфа-версия, сделано за несколько вечеров. Поэтому по поводу маленьких возможностей сильно не ругайтесь и вопросов про отсутствие лямбда-исчисления не задавайте.
1. Предназначение
Как мне кажется, большинство инструментов дополненной реальности напрочь оторваны от реальности. Они красивые, интересные, но бесполезны для практического применения. И мне захотелось сделать технологию, которая была бы крайне проста и удобна для повседневного пользования. Лучшее, что пришло на ум — это встроить интерпретируемый язык в QR-коды. Они уже широко распространены, и не вызывают у людей отторжения. Их можно распечатать и прилепить в любое место, будь то столик кафе или витрина магазина. Они считываются почти мгновенно, и поэтому с помощью Google Glass можно будет отображать программы в реальном времени.
Плюсы такого подхода очевидны:
- нужна лишь программа-интерпретатор и сам QR-код, не нужно никакого дополнительного оборудования
- стандартизированность интерфейсов; людям не нужно обучаться заново каждый раз
- огромные потенциальные возможности: например, можно сделать заказ в кафе, посмотрев на столик, или заказать билеты на рок-концерт, посмотрев на афишу
- элементарная простота и дешевизна создания и распространения программок
Но есть и минусы:
- маленький размер программы. Решается выкачкой дополнительной логики по сети
- возможно легче было бы скачивать из интернета по QR-ссылке код на каком-нибудь скриптовом языке, хоть это и медленнее
- вспоминается роман Стивенсона «Лавина», в котором люди, посмотрев на черно-белое изображение, плавили себе мозги
2. Структура языка
В QR-коды информация записывается с помощью последовательности участков по 8 бит каждый. Поэтому язык я решил создать на основе байтового исчисления, то бишь на основе шестнадцатеричных символов от 00 до FF. Сначала в голову пришла идея записи в штрих-код байт-кода Java, но я отказался от нее из-за избыточности данного подхода. Интерпретируемый язык для QR должен быть очень краток, так штрих-код может содержать в себе в лучшем случае лишь 2 килобайта памяти. Да и много возможностей этому языку много не надо.
Пока что в языке используются лишь три вида конструкций: переменные, процедуры и компоненты Андроид. У каждого объекта этих трех типов есть свой подтип (например, для переменных это 00-boolean, 01 — int, 02-float, 03-String), однобайтовое имя и тело. Для удобство парсера перед каждой конструкцией ставится байт длины.
Например в синтаксической конструкции {06,01,AA,00,00,00,03
} содержится следующее:
- Первый байт — байт длины, равный 6, и парсер считывает 6 байтов после него
- Второй байт — байт типа данных. Он равен 01, что означает integer
- Третий байт означает имя переменной. Здесь переменная названа AA, и после интерпретатор будет знать ее именно под этим прозвищем
- После идет 4 байта тела. Означают, что переменной изначально присвоено значение равное 3
В процедурах же задается список примитивных операций. Например {4,14,АА,АА,ВВ
} означает АА = АА + ВВ;
Так как Google Glass еще не вышли, то я написал программу-интерпретатор под Андроид. Поэтому в QuRavе сейчас поддерживаются именно компоненты Андроид. Пока что только Button, TextView и Edit Text. Можно задать их положение на экране, текст на них, а для кнопок добавить указание на процедуру, вызываемую при нажатии. Например, {05,09,05,02,03,08
} означает создание кнопки (код 09) с именем 05, положением на экране 02 (вверху по центру, по системе старых телефонных хардварных клавиатур от 1 до 9), с текстом строки по имени 03 и вызовом процедуры по имени 08 при нажатии.
Если честно, сейчас синтаксис выглядит просто ужасно. Он чертовски сложен и имеет очень мало возможностей. Но это же просто прототип. В будущем планирую распихать все примитивные операции по библиотекам, сделав более короткой и удобной их конструкцию. Еще нету возможности вызывать процедуру из другой процедуры, что обусловлено глупо написанным компилятором. Сейчас кстати о нем.
3. Интерпретатор
Основной парсер интерпретатора читает программу, разбивает ее на куски и рассылает их субпарсерам, которые в свою очередь могут иметь свои субпарсеры. На основе результатов работы многочисленных парсеров программа по кусочкам собирается на не менее малочисленных фабриках. Готовые процедуры, переменные и компоненты попадают в класс Main.
В классе Main все содержится в отдельных HashMap’ах. Примером такой HashMap’ы является namesOfVariables:
public Object getVariable(Byte name) { return namesOfVariables.get(name); }
А чтобы доступ к переменным и компонентам был из процедур и примитивных операций, класс Procedure является наследником класса ProgramUnit (на рисунке обозначен как Main), а примитивная операция расширяет класс Procedure.
В классе процедуры переопределен метод взятия переменной. Добавив к нему еще пару строк, можно реализовать механизм локальных переменных.
@Override public Object getVariable(Byte name) { return superiorUnit.getVariable(name); }
Если честно, то интерпретатор самая скучная часть сделанного, поэтому хватит о нем.
4. Пример использования
А сейчас покажу Вам то, ради чего Вы собственно и начали читать эту статью. Пример действующей программы на языке QuRava.
В данном примере использованы числа типа byte, а не их hex-эквиваленты!
02,03,00
— объявление пустой строки по имени 00
02,01,01
— объявление переменной типа int по имени 01
02,01,02
— объявление переменной типа int по имени 02
06,03,03,80,108,117,115
— объявление строки с текстом «Plus»
04,11,04,01,00
— создание изменяемого текстового поля по имени 04
05,09,05,02,03,08
— создание кнопки по имени 05 вызывающей при нажатии процедуру 08
04,11,06,03,00
— создание изменяемого текстового поля по имени 06
04,13,07,08,00
— создание неизменяемого текстового поля по имени 07
31,04,08
— объявление процедуры по имени 08
........03,42,00,04
— читаем текст, записанный в поле 04 и кладем его в строку 00
........03,41,01,00
— переводим строку 00 в int и записываем результат в переменную 01
........03,42,00,06
— читаем текст, записанный в поле 06 и кладем его в строку 00
........03,41,02,00
— переводим строку 00 в int и записываем результат в переменную 02
........04,14,01,01,02
— складываем переменные 01 и 02 и записываем результат в 01
........03,40,00,01
— переводим значение 01 в строку и записываем результат в 00
........03,43,07,00
— выводим в текстовое поле 07 строку 00
Ну и собственно демонстрация работы: (извините за качество)
5. Дальнейшее развитие
Сейчас я показал Вам лишь альфа-версию прототипа того, что я хочу сделать. В будущем я бы хотел добавить много интересных вещей в язык QuRava:
- разработать простой и мощный синтаксис
- добавить регулярные выражения, массивы, циклы и многое другое
- распределить все примитивные операции по библиотекам, дублирующим основные классы-библиотеки самой Java (такие как Math или Arrays например.
- добавить возможность вызова процедур из других процедур и локальных переменных
- добавить работу с сетью, функцию скачивания из сети дополнительного контента к программе или даже логики
- написать кучу стандартных библиотек
- написать компилятор под desktop и маленькую, но удобную IDE к нему
- написать всеобъемлюющую справку к языку
- выложить проект на github
К сожалению пока что показывать еще почти нечего, поэтому не выложу никаких ссылок. Если будет интересно, то поработаю над этим и напишу еще одну статью.
А пока что хочу провести опрос.
ссылка на оригинал статьи http://habrahabr.ru/post/180989/
Добавить комментарий