Встраиваемый скриптовой язык – попытка объединить гибкость командной строки и простоту графического интерфейса.

 

Немного истории вопроса

 

Много лет идут споры между поклонниками Unix и Windows о преимуществах и недостатках двух концепций пользовательского интерфейса – командной строки и оконного интерфейса с набором кнопок.

 

Хорошо известны преимущества и недостатки обоих подходов.

 

На стороне командной строки – удобство и гибкость масштабирования и автоматизации задач с помощью объединения команд в сценарии.

 

Но командная строка требует изучения используемого языка, тем более долгого, чем сложнее решаемые на нем задачи. Часто, чтобы полностью овладеть инструментом и грамотно составить сценарий,   нельзя обойтись без изучения предметной области. А это означает значительные затраты на обучение персонала.

 

На стороне оконного интерфейса – простота освоения. В случае необходимости однократного применения программы, когда несколько нажатий на кнопки еще не превращается в проблему для оператора, оконный интерфейс позволяет быстро получить результат.

 

Но оконный интерфейс трудно расширять, при необходимости добавить новые функции нужно дорабатывать графический дизайн приложения.

 

Часто предпринимаются попытки объединить преимущества этих подходов и избавиться от присущих им недостатков.

 

Многие производители ПО снабжают свои продукты командным языком. Этот язык имеет набор команд, оперирующий понятиями предметной области, с которой работает ПО. В качестве примера можно привести широко распространенную в нашей стране бухгалтерскую систему 1С, которая имеет такой встроенный язык.

 

Решение, предлагаемое фирмой MKTMK Software Company.

 

Наша фирма занимается разработкой скриптовых языков с 1996 года. Первая версия под названием “интерпретатор Open Basic v1.00” была выложен в интернете в 1998 году на сайте www.sedfin.da.ru .

Слово “Open” в названии появилось потому, что интерпретатор имеет средства для подключения пользовательских функций к своей исполняющей системе.

 

Отличительные особенности интерпретатора:

 

-         входной язык представляет подмножество команд языка BASIC

-         полный интерпретатор (без трансляции в байт-код и без использования виртуальных машин). Входная BASIC-программа представляет собой текстовый файл или текстовый буфер в памяти.

-         возможность подключения пользовательских функций к исполняющей системе интерпретатора. Есть возможность передать параметры из BASIC-программы в пользовательскую функцию и вернуть значение из пользовательской функции в BASIC-программу.

-         отсутствие привязки с оконному интерфейсу

-         реализация полностью на языке C++, без ассемблерных и других вставок

-         возможность стыковки с разными оконными системами в терминах потоков языка C++

-         нетребовательность к транслятору. Первая версия транслировалась на Borland C++ v3.1

-         реализация интерпретатора в виде класса ob_obasic

-         возможность работы в мультипотоковой среде

-         возможность доступа по чтению и записи из пользовательских функций к переменным и массивам BASIC-программы

 

При разработке интерпретатора преследовались следующие основные цели:

 

-         необходимо дать возможность пользователю добавлять пользовательские функции к исполняющей системе языка. Задач для скриптового языка много, от сбора данных до управления окнами GUI. На этапе разработки языка невозможно предусмотреть потребности всех областей его применения. Соответственно невозможно разработать специализированные команды для всех областей применения. Но можно и нужно дать пользователю механизм для добавления собственных команд.

-         необходимо разнести исполняющую систему языка и оконную систему

-         нужно сделать скриптовой язык кросплатформенным. Linux наступает и промышленные системы все чаще на него ориентируются. Трансляторы C++ реализуются для многих систем, использующих отличную от x86 архитектуру, таких как наладонные компьютеры на базе ARM или процессоров фирмы Motorola.

-         в качестве входного языка желательно использовать язык со стандартным синтаксисом, широко известный среди профессионалов и любителей. Поэтому было выбрано подмножество команд BASIC

-         необходимо наличие переменных разных типов на уровне скриптового языка. Для начала нужны целые, строковые и переменные с плавающей точкой. Многие интерпретаторы командных оболочек в разных ОС не имеют поддержки переменных разных типов. Это сильно ограничивает возможности этих инструментов.

 

Анализируя опыт применения первых версий программы, мы выявили некоторые недостатки реализации:

 

-         объектные контейнеры Borland, примененные в первой версии интерпретатора, не транслировались на других трансляторах из-за многочисленных Borland language extension конструкций, использованных в них.

-         из-за отсутствия поддержки шаблонов в ранних версиях трансляторов C++, объектные контейнеры Borland построены на основе иерархии классов и виртуальных функциях. Такой подход снижал быстродействие интерпретатора.

-         при сопряжении интерпретатора с оконной системой возникали проблемы с реализацией ввода-вывода операторами PRINT и INPUT. В частности, при интеграции в оконную систему из-за отсутствия механизма идентификации выполнения операторов ввода-вывода приходилось запускать интерпретатор в пошаговом режиме и после выполнения каждой строки анализировать тип последнего выполненного оператора. Это также снижало общее быстродействие интерпретатора.

 

С момента выхода первой версии Open Basic нами были реализованы уже четыре версии интерпретатора. Это были промежуточные версии, в которых устранялись текущие ошибки и неточности. В интернете эти версии не были представлены.

В настоящее время на сайте www.mktmk.narod.ru доступны библиотеки и описание последней, пятой версии интерпретатора Open Basic (Open Basic v1.50). В них устранены многие ошибки предыдущих версий и добавлены новые возможности, в частности:

 

-         улучшена совместимость программы. Новые контейнеры на основе шаблонов удовлетворяют последним стандартам языка C++ и транслируются на наиболее популярных трансляторах

-         расширен набор методов для доступа к переменным BASIC-программы

-         для более удобного сопряжения интерпретатора с ОС и оконными системами введены режимы останова до и после выполнения некоторых BASIC-операторов

-         введена вторая форма (блоковая) для оператора IF

-         упрощен интерфейс пользовательских функций

 

Сейчас интерпретатор транслируется на трех системах:

 

-         Borland C++ Builder 6.0

-         MSVC 7.0

-         GCC 3.2.2

 

К сожалению, в данный момент нет транслятора для DOS, который бы поддерживал последние расширения стандарта C++. Ведущие фирмы – производители компиляторов прекратили поддержку и развитие систем для DOS. Последний транслятор Borland C++ v5.02, который генерировал код для DOS, не понимает многих шаблонных конструкций и не может транслировать интерпретатор Open Basic v1.50.

 

Кроме библиотек и описания на сайте www.mktmk.narod.ru есть исполняемый файл, представляющий реализацию  интерпретатора в виде утилиты командной строки. Так же есть несколько тестовых BASIC-программ. Их можно выполнять из командной строки с помощью интерпретатора.

 

IDE for Open Basic

 

Долгое время интерпретатор существовал в виде утилиты командной строки. В реальных системах приходилось состыковавать его с разными оконными системами, в том числе Turbo Vision. Часто при работе под DOS приходилось применять пакеты, обеспечивающие многозадачность. В этих случаях интерпретатор запускался как одна из задач или один из потоков системы.

К сожалению, все эти варианты сопряжения интерпретатора и других частей системы сбора данных были очень сильно привязаны к конкретной задаче и не могли служить образцом, рекомендованным для широкого применения.

 

Последняя версия интерпретатора также может работать в режиме командной строки. Но кроме этого, для последней версии интерпретатора разработана специальная IDE для работы в ОС Windows. Эта программа называется “IDE for Open Basic v1.00” Она предоставляет сервис по загрузке, запуску и останову BASIC-программ. Можно назначить точки останова и посмотреть значения BASIC-переменных в отдельном окне в Watch-листе. Можно модифицировать BASIC-переменные в том же Watch-листе.

 

Эта  IDE написана на Borland C++ Builder 6.0 с использованием VLC и может рассматриваться в качестве примера сопряжения интерпретатора и ОС Windows или любой другой ОС. Эта  IDE и также доступна на сайте www.mktmk.narod.ru в виде исходных текстов и в виде инсталляционнного файла. Там же можно скачать Users Guide для этой программы.

 

IDE for Open Basic является отдельной программой. Нумерация ее версий не совпадает с нумерацией версией самого интерпретатора. Текущий номер версии IDE for Open Basic -   v1.00. IDE for Open Basic включает в себя интерпретатор Open Basic как составную часть, но интерпретатор Open Basic может работать и без IDE.

 

В составе поставки IDE есть несколько тестовых BASIC-программ. Их можно выполнять в IDE. Большинство из них будут работать и в версии командной строки и в IDE. Некоторые из них, в частности те, в которых производится манипуляция окнами Windows,  будут работать только только в IDE. В начале каждой BASIC-программы есть комментарий, в котором указаны ограничения по среде запуска, если они существуют.

 

Структура интерпретатора

 

Во время работы интерпретатор, как и положено каждому интерпретатору, создает и поддерживает несколько таблиц. В этих таблицах, в частности, хранятся:

 

-         переменные BASIC-программы

-         массивы BASIC-программы

 

Во время работы пользователь имеет доступ ко всем переменным и массивам BASIC-программы. Доступ осуществляется по именам и по типам переменных.

 

Типы переменных и массивов в BASIC-программе определяются по последнему символу имени. Если последний символ имени переменной или массива это знак процента “%”, то это переменная целого типа. Если последний символ имени переменной или массива это знак денежной единицы “$”, то это переменная строкового типа. Остальные переменные это переменные с плавающей точкой.

 

Класс ob_obasic имеет два основных метода. Метод load обеспечивает загрузку программы в интерпретатор. Метод run обеспечивает запуск программы на выполнение или продолжение программы после останова.

 

Кроме двух методов для загрузки и запуска программ, класс ob_obasic имеет много других методов. Часть методов предназначена для организации отладочных режимов работы, в частности метод setstep устанавливает и снимает режим пошагового выполнения. Из других методов можно упомянуть:

 

-         setfun – подключает пользовательскую функцию к исполняющей системе интерпретатора

-         typevar – определяет тип BASIC-переменной по ее имени

-         createvar – создает переменную с указанным именем в таблице переменных интерпретатора

-         readvar – читает BASIC-переменную

-         writevar – записывает BASIC-переменную новым значением

 

Масштабируемость типов

 

Все типы Open Basic это типы соответствующего транслятора C++, на котором транслируется интерпретатор. В начале заголовочного файла интерпретатор ob.h они объявлены с помощью typedef. В версии 1.50 BASIC-переменные с плавающей точкой это float переменные C++, а BASIC-переменные целого типа это int переменные C++. При необходимости легко можно изменить масштаб чисел, переопределив, например, BASIC-переменные с плавающей точкой как double переменные C++.

Отличия от стандартного BASIC

 

Основным семантическим отличием Open Basic от стандартного BASIC является то, что оператор описания массивов DIM в Open Basic является исполнимым. Это означает, что при повторном описании уже существующего массива оператором DIM старый массив удаляется, а новый создается, возможно с другой размерностью. Все данные из старого массива при этом теряются.

 

Такая возможность сохранена со времен DOS. В то время, в условиях недостатка памяти, с помощью повторного описания массивов оператором DIM можно было освободить ранее занятую память для повторного использования.

 

Операции, операторы и встроенные функции Open Basic

 

Как уже отмечалось, Open Basic поддерживает переменные трех типов - целые, строковые и переменные с плавающей точкой. Для этих переменных определены следующие операции:

 

 + - сложение

 - - вычитание

 * - умножение

 / - деление

 ^ - возведение в степень

 - - унарный минус

 + - унарный плюс

 = - присвоение

 <, >, =, <>, <=, >= - выражения отношения 'меньше', "больше", "равно",

 "не равно", "меньше или равно", "больше или равно". Выражения отношения

 используются в операторе IF.

 

Для строковых переменных определены только операции сложения и сравнения. При попытке применить к строковым переменным другие операции, а также при попытке деления на ноль исполняющая система Open Basic генерирует исключение.

 

Open Basic реализует большинство операторов стандартного языка BASIC. Не реализованы сложные операторы вывода типа PRINT USING. Это сделано потому, что большинство применений Open Basic не используют стандартные средства ввода-вывода, а используя возможности подключения пользовательских функций, реализуют собственные алгоритмы ввода вывода. Например, вместо ввода в строку, типичного для систем с командной строкой, пользователь создает функцию, открывающую модальное окно и запрашивающую ввод какого-либо параметра. Вывод в большинстве случаев тоже осуществляется в рамках оконной системы конкретной ОС.

 

Список операторов Open Basic

 

  1. PRINT печать в выходной поток или файл
  2. INPUT – ввод из входного потока или из файла
  3. FOR и NEXT – операторы организации цикла
  4. GOTO – безусловный переход
  5. GOSUB и RETURN – вызов подпрограммы
  6. LET – присвоение
  7. DIM – описание массива
  8. STOP и END – останов программы
  9. REM – комментарий
  10. OPEN и CLOSE – открытие и закрытие файлов
  11. KILL – удаление файлов
  12. READ, DATA и RESTORE – организация блока данных для ввода
  13. RANDOMIZE – инициализация случайного генератора
  14. IF – организация условных переходов

 

Список встроенных функций Open Basic

 

  1. SGN% возвращает знак аргумента
  2. ABS – возвращает абсолютное значение аргумента
  3. INT% – возвращает целую часть аргумента
  4. SIN, COS, ATN, SQR, EXP, LOG и LOG10 – возвращают синус, косинус, арктангенс, квадратный корень, экспоненту, натуральный и десятичный логарифм соответственно
  5. RND – возвращает случайное число из диапазона 0-1
  6. LEN% – возвращает длину строки или строковой переменной
  7. DAT$ и CLK$ – возвращает текущую дату и время в виде строки
  8. D2STR$, D2HEXSTR$, STR2FLOAT и STR2INT% - конвертирует число в строку, в шестнадцатиричную строку, строку в число с плавающей точкой и строку в целое число соответственно

 

Подключение пользовательских функций

 

В Open Basic имеется три типа пользовательских функций. Все пользовательские функции имеют одинаковый набор параметров и различаются типом возвращаемого результата.

Пользовательские функции могут возвращать в BASIC-программу переменные или целого или строкового типа или переменные с плавающей точкой.

 

Подключение пользовательской функции к исполняющей системе Open Basic производится с помощью метода setfun. При подключении пользовательской функции она получает имя, под которым потом ее можно вызывать из BASIC-программы.

 

Параметры пользовательских функций включают в себя несколько массивов. Перед запуском пользовательской функции в эти массивы заносится информация о количестве, месте расположения и типе всех BASIC-параметров в текущем вызове пользовательской функции и о значениях этих параметров.

Обработка ошибок

 

При возникновении ошибок исполняющая система Open Basic генерирует исключение типа ob_err с соответствующим кодом ошибки. Пользователь должен перехватить это исключение и обработать его. Класс ob_err имеет метод getcode() для определения кода ошибки. Кроме этого, Open Basic предоставляет таблицу ob_englmessage, содержащую диагностические сообщения на английском языке. Индексируя эту таблицу кодом ошибки пользователь получает указатель на текстовую строку, содержащую описание причин данной ошибки.

Рекомендации по применению

 

Если переделка GUI Вашей программы начала занимать все больше времени, если заказчик постоянно меняет техническое задание, настаивая на включении в систему все новых возможностей, значит Вам пора задуматься о применении скриптового языка.

 

Если Ваши конфигурационные файлы большие как седельный тягач MAN с полной нагрузкой и сложные как теория суперструн, подумайте о применении Open Basic в качестве среды для чтения и интерпретации конфигурационных файлов.

 

При применении Open Basic в составе системы рекомендуется разместить экземпляр класса ob_obasic в области глобальных переменных. Выполнение методов load и run рекомендуется оформить в виде отдельных нитей с приоритетом ниже, чем приоритет основной нити. Такой подход позволяет безболезненно завершить BASIC-программу при фатальной ошибке в ней или в пользовательской функции. Также при таком подходе к построению системы исключается блокирование пользовательского интерфейса при работе BASIC-программы.

 

Нужно иметь ввиду, что в составе Open Basic есть несколько статических констант, имеющих нетривиальные конструкторы. Эти константы используются только для чтения и не влияют на возможность интерпретатора работать в мультипотоковой среде. Но при попытке запустить методы интерпретатора до выполнения функции main возможны проблемы из-за порядка инициализации глобальных объектов в программе.

 

В качестве примера сопряжения интерпретатора и ОС Windows можно воспользоваться IDE for Open Basic, доступной в том числе и в исходных текстах. Если же Ваша система написана на Borland C++ Builder 6.0, то Вы можете просто включить модули из этой программы в свой проект.

 

 

Сайт создан в системе uCoz