BlackJava

THE BLACKJAVA CLASS LIBRARY

Дмитрий Шеленин
Copyright (c) 1998.
Версия 1.0бета, 29 Мая, 1998 г.

СОДЕРЖАНИЕ




    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. Благодарности

  1. Особая благодарность Владимиру Шипунову за его CalcPlus. Владимир, Ваша библиотека служит скрытым прообразом данного творения и практически всем обязана Вам ;)
  2. Также благодарю Корощенко Александра за скрытую поддержку и бета-testing.
  3. Спасибо авторам книги "Компьютерная математика" господам D. Cooke'у и H. Bez'у за книгу.


  4. Copyright (c) Blackmail 1998