1. Что такое BlackJava?
BlackJava - библиотека, ориентированная на приложения с применением собственного
языка программирования. Практически любое приложение требует каких-нибудь внешних файлов
конфигурации (например .ini файлы), с помощью которых оно легко и "безболезненно"
настраивается на любые мыслимые конфигурации. BlackJava обобщает подход, и любая константа
или алгоритм, в которых нуждается программа можно поместить во внешний файл и в процессе
работы происходит вызов функций библиотеки, которые возвращают всю требуемую в программе
информацию уже в упрощенном для чтения виде (как это может быть с файлами конфигураций) или
выполняя определенное пользователем действие (например, запуск внешнего макроса текстового
процессора). Библиотека содержит интерпритатор, который понимает небольшой (пока не
процедурный) язык, носящий название BlackJava (java - потому что слегка напоминает
его синтаксически). Обмен данными в программе представлен в двух направлениях: от программы
к интерпритатору и наоборот.
В случае, если Вы разрабатываете проект на C++ и хотите обеспечить доступ к внешним переменным,
алгоритмам или еще Бог знает чему, то наверняка BlackJava именно то, что Вам в данный момент
необходимо.
Текущая версия библиотеки позволяет реализовывать настройки в виде классов, с возможностями
использования функций (пока только C -> интерпритатор), блоков, переменных (разница между глобальными
и локальными отсутствует, хотя переменные разрешается описывать буквально везде) и констант,
if/while/for выражений. Переменные разделяются по наличию пяти встроенных типов: null, bool,
long, double и string, хотя отсутствует возможность кастомизации типов. Функции, написанные
на C++ легко добавляются в арсенал возможностей интерпритатора, а достаточно быстрая работа
делает BlackJava незаменимым во многих задачах.
Интерпритатор был написан в 1998 году в течении порядка 2-х недель (основной код). Использовались
ранее написанный код и опыт работы в этой же области со стороны. Библиотека написана на Borland C++
версии 3.1 и не является система/компилятор независимой.
2. Распостранение и гарантии
Библиотека BlackJava есть freeware продукт, Вы можете использовать, изменять и распространять
ее с единственным условием не убирать copyright сообщение из исходного кода.
НИКАКОЙ ГАРАНТИИ, ИСПОЛЬЗУЙТЕ НА СВОЙ СТРАХ И РИСК
Автор:
Дмитрий Шеленин, 21, Государственный Университет, город Красноярск
e-mail: Blackmail@mailexcite.com
Любые комментарии, предложения, расширения, информация об ошибках приветствуются.
3. Установка и запуск примеров
Для установки комплекта библиотеки, распакуйте содержимое архива bjava.rar.
DOS: rar x -va bjava.rar
Данная версия содержит следующие файлы:
bj.cpp |
lexparse.cpp |
string.cpp |
token.cpp |
type.cpp |
vars.cpp |
funcs.cpp |
userlib.cpp |
defs.h |- исходные тексты на C++
generic.h |
bj.hpp |
lexparse.hpp |
string.hpp |
type.hpp |
vars.hpp |
funcs.hpp |
list.hpp |
bj.prj |
step01.bj |
step02.bj |
step03.bj |
step04.bj |
step05.bj |- примеры программ
step06.bj |
step07.bj |
step08.bj |
primes.bj | подсчет простых чисел
readme.html файл, который Вы читаете
grammar.txt частичная грамматика языка в БНФ форме
Для компиляции, необходимо иметь Borland C++ версии не ниже 3.1. Библиотека тестировалась
только с компиляторм данной фирмы, причем только с версией 3.1. При возникновении проблем, пожалуйста,
обращайтесь к мне.
Первым делом, необходимо проверить работоспособность BlackJava.
Хотя среди примеров нет тех, которые проверяли бы работоспособность BlackJava
в целом, его не трудно написать самому, лишь дайте себе время ознакомиться со
всеми его возможностями, чего в частности можно достигнуть, прочитав данный файл
до конца.
a) bj step01.bj
Если все собралось OK, то вывод будет представлять что-то вроде:

В конце работы, в случае отсутсвия ошибок, после вывода программы, появляется
строка 'All Ok. (No errors, dunno 'about warnings)', символизирующая успешную
интерпритацию кода.
b) bj step04.bj
Показательным в некором смысле является пример, демнострирующий работу со встроенным
типом string, содержащийся в файле step04.bj. Канонический вывод представляет собой следующее (это не касается вывода случайных чисел ;):

4. Принципы работы библиотеки
BlackJava состоит из нескольких логически связанных основных частей:
лексический анализатор,
грамматический разбор (parsing),
иерархия встроенных типов,
иерархия языковых структур.
4.1 Лексический анализатор
Лексическим разбором занимается класс LexBuilder, по названию которого можно судить
с уверенностью о том, что результатом работы разборщика является список лексических единиц
языка.
Строковые константы можно заключать как в '...', так и в "...".
Комментарии поддерживаются в формате C++:
// This is a single line comment
/*
* That's on the other hand is a multi line one
*/
Анализатор чувствителен в регистрам букв.
4.2 Грамматический разбор (parsing)
Класс LexParser служит для разбора программы на BlackJava. Тонкости разбора можно получить
из знакомства с этапами построения класса по исходным текстам, я не буду углубляться в подробности
реализации в пределах этого текстового знакомства с библиотекой.
4.3 Иерархия типов CType
Класс CType является абстрактным по отношению к всем реализованным в интерпритаторе типам
данных: СNull, CBool, CLong, CDouble и CString. Во время грамматического разбора,
согласно семантике программы, LexParser размещает переменные в памяти соотвественно
описанным типам:
15 CLong
25.2e-2 CDouble
TRUE CBool
'aaa' CString
Новые классы также легко добавляются наследованием от CType. CType обладает хорошим набором
чисто виртуальных функций, большинство которых может и не понадобится, тогда их следует
забить "пустышками".
Что важно, типы должны себя идентифицировать. Уникальные числовые идетификаторы можно получить
из перечисления в файле type.hpp. Полученный идентификатор впоследствии возвращается функцией
type(). Метод name() позволяет получить символическое представление типа.
type() const;
const char *name() const;
Функция size() дает представление о размерах доступного типа.
size() const;
Методы ptr() и data() возвращают void указатели на содержимое типa, что, в частности, находит
свое применение в функции сравнения.
void *ptr();
const void *data() const;
Метод copy() используется для клонирования данных; обычно это вызов конструктора копирования:
CType* copy() { return CNewClass( *this ); }
Возможности считывания и записи своей информации в/из потоков обеспечиваются с помощью
методов print( ostream& ) и get( istream& ):
void get( istream& );
void print( ostream& ) const;
Классы типов в BlackJava достаточно примитивны, и за ответами га вопросы по реализации консультируйтесь
в исходных текстах в файле type.cpp.
4.4 Правила языка
Грамматику языка можно описать следующим набором правил, записанных в БНФ:
op_variable:
[variable]
| [variable] '++' /* постфиксная форма */
| [variable] '--'
;
unary_expression:
'++' cast_expression /* префиксная форма */
| '--' cast_expression
| unary_operator cast_expression
| '(' assignment_expression ')'
| [function_name] '(' [ assignment_expression [ ',' assignment_expression ] ... ] ')'
| [immediate_value]
| op_variable
;
unary_operator:
'+'
| '-'
| '%'
| '!'
;
cast_expression:
unary_expression
| '(' type_name ')' cast_expression
;
multiplicative_operator:
cast_expression
| multiplicative_operator '*' cast_expression
| multiplicative_operator '/' cast_expression
| multiplicative_operator '%' cast_expression
;
additive_expression:
multiplicative_expression
| additive_expression '+' multiplicative_expression
| additive_expression '-' multiplicative_expression
;
shift_expression:
additive_expression
| shift_expression '<<' additive_expression
| shift_expression '>>' additive_expression
;
relational_expression:
shift_expression
| relational_expression '<' shift_expression
| relational_expression '>' shift_expression
| relational_expression '<=' shift_expression
| relational_expression '>=' shift_expression
;
equality_expression:
relational_expression
| equality_expression '==' relational_expression
| equality_expression '!=' relational_expression
;
AND_expression:
equality_expression
| AND_expression '&' equality_expression
;
exclusive_OR_expression:
AND_expression
| exclusive_OR_expression '^' AND_expression
;
inclusive_OR_expression:
exclusive_OR_expression
| inclusive_OR_expression '|' exclusive_OR_expression
;
logical_AND_expression:
inclusive_OR_expression
| logical_AND_expression '&&' inclusive_OR_expression
;
logical_OR_expression:
logical_AND_expression
| logical_OR_expression '||' logical_AND_expression
;
conditional_expression:
logical_OR_expression
| conditional_expression '?' comma_expression ':'
conditional_expression
;
assignment_expression:
conditional_expression
| unary_expression assignment_operator assignment_expression
;
assignment_operator:
'='
| '*='
| '/='
| '%='
| '+='
| '-='
| '<<='
| '>>='
| '&='
| '^='
| '|='
;
comma_expression:
assignment_expression
| comma_expression ',' assignment_expression
;
constant_expression:
conditional_expression
;
comma_expression_opt
/* Nothing */
| comma_expression
;
statement_opt:
/* Nothing */ ';'
| statement
;
statement:
compound_statement
| expression_statement
| selection_statement
| iteration_statement
;
compound_statement:
'{' '}'
| '{' declaration_list '}'
| '{' statement_list '}'
| '{' declaration_list statement_list '}'
;
declaration_list:
declaration
| declaration_list declaration
;
statement_list:
statement
| statement_list statement
;
expression_statement:
comma_expression_opt ';'
;
selection_statement:
IF '(' comma_expression ')' statement
| IF '(' comma_expression ')' statement ELSE statement
;
iteration_statement:
WHILE '(' comma_expression ')' statement
| FOR '(' comma_expression_opt ';' comma_expression_opt ';'
comma_expression_opt ')' statement
;
program_body:
CLASS [class_name] compound_statement
;
4.5 Интерфейс с C++
Набор макросов полностью автоматизирует подход написания внешних функций для интерпритатора. Но все же
внутреннюю структуру каждого используемого инструмента рекомендуется если не детально изучить, то по-крайней мере бегло
просмотреть.
USER_FUNC( имя_функции ) - макрос, описывающий начало внешней пользовательской функции
USER_PROC( имя_функции ) - макрос, описывающий начало внешней пользовательской функции возвращающей void
RETURNS( тип_возврата ) - описание типа возврата
DEF_ARGV( параметр_№x, имя_параметра, тип_параметра ) - типизированный параметр №x
DEF_ARGX( параметр_№x, имя_параметра ) - нетипизированный параметр №x
Функция RegFunc и макрос RegProc производят регистрацию внешних функций. Вызов последних помещаются
в обязательную функцию UserLib, производящей общую регистрацию всех доступных извне пользоватедьских
добавок.
Прототипы:
RegFunc( const char* function_name, DefFunction p, int order = 1, int proc = 0 );
// function_name - имя регистрируемой функции
// p - ссылка на C-код
// order - если число параметров превышает 1, то укажите этот факт прямо здесь
// proc - 1, если функция ничего не возвращает, 0 - иначе
#define RegProc( function_name, p, order ) \
RegFunc( function_name, p, order, 1 );
На результат работы функции ссылается маркер ret, вводимый макросом RETURNS, описанный указанным типом возврата.
Возврат функции следует оставлять на ret.
Опишем функцию, возвращающую текущую дату в формате string:
USER_FUNC()
RETURNS( STRING, String )
time_t t; // структура данных, для хранения времени
time( &t ); // С-функция для чтения времени
ret = strdup( ctime( &t ) ); // возвращаем время в string.
USER_END
5. Известные ошибки
Самыми существенными на данный момент, пожалуй, являются ошибки, связанные с выделением
памяти - до сих пор теряется память на итерациях. Это ПЕРВЫЙ пункт в списке исправленных багов
последующих релизов.
6. Appendix. Описание языка
Программа на BlackJava одномодульна, то есть состоит из единственного файла.
Костяк любой программы выглядит вот-так:
class ClassName {
<опциональное_описание_переменных>
<опциональный_код>
}
В остальном, программы BlackJava напоминают C и Java (функциями print() и println(), а также
наличием внутреннего типа string). Из несказанного отмечу, что правилами также поддерживается
так называемая условная_конструкция, то есть выражения типа:
[условие] ? [вернуть_это_если_истина] : [вернуть_это_если_ложь] ';'
7. Appendix-2. Благодарности
-
- Особая благодарность Владимиру Шипунову за его CalcPlus. Владимир, Ваша библиотека служит скрытым прообразом
данного творения и практически всем обязана Вам ;)
- Также благодарю Корощенко Александра за скрытую поддержку и бета-testing.
- Спасибо авторам книги "Компьютерная математика" господам D. Cooke'у и H. Bez'у за книгу.
Copyright (c) Blackmail 1998