- Введение в FSHELL
- Описание языка FSHELL
- Варианты реализации
- Встроенные функции
- Особенности программирования
Введение в FSHELL
Программная реализация
Интерпретатор FSHELL предназначен для выполнения сценариев по управлению разнообразными ресурсами прикладных систем в операционной среде Windows. FSHELL реализован в нескольких вариантах:
- EXE — консольное приложение;
- DLL — многопоточная динамическая библиотека;
- OCX — ActiveX элемент.
Область применения
FSHELL имеет возможность задания в сценариях (программах) обращений к достаточно большому набору функций библиотеки периода выполнения Visual C++.
FSHELL обеспечивает возможность подключения динамических библиотек — пользовательских и системных. Ограничением является обращение к функциям из динамических библиотек, работающих с уже установленным окном Windows (поскольку FSHELL своего собственного окна не имеет).
FSHELL может быть использован как отдельное приложение, так и в качестве многопоточной динамической библиотеки, обеспечивающей сервис по интерпретации сценариев для другой прикладной задачи. При этом предоставляются средства для экспорта переменных и функций прикладной задачи на уровень FSHELL — программы.
FSHELL полезен при разработке INTERNET/INTRANET — проектов для формирования клиентских страниц, как CGI — приложение, так и в составе динамических библиотек стандарта ISAPI.
Синтаксис языка FSHELL
Переменные программы объявляются оператором присваивания := , либо с помощью функции выделения памяти _newchar.
FSHELL распознает только два типа переменных — целое и указатель обобщенного вида. Этого достаточно для вызова различных системных функций, типы параметров которых могут отличаться, но все равно передаются в Windows через 32-х разрядные слова.
FSHELL предоставляет возможность использования циклов for и while, выхода из циклов по оператору break, безусловного перехода goto, вызова FSHELL — процедуры без параметров оператором call.
Логика программы задается с помощью операторов if.
Точка входа в программу определяется меткой main:. Выход из цикла интерпретации осуществляется оператором exit либо leave.
Препроцессор FSHELL обрабатывает операторы #define, #include (вложенные операторы #include не поддерживаются), #import.
Стратегия выполнения сценария
На этапе предкомпилляции FSHELL осуществляет:
- преобразование условных операторов, операторов организации циклов в команды псевдокода;
- формирование таблицы переменных и литералов;
- заполнение таблицы встроенных функций;
- заполнение таблицы меток и процедур FSHELL.
Предкомпиляция выражений не производится.
Информация об ошибках, обнаруженных во время предкомпилляции, выводится в STDOUT. После этого производится выполнение FSHELL — программы (вне зависимости от наличия ошибок).
Выполнение функций (встроенных и импортируемых из других библиотек) защищено операторами обработки исключений. Возникновение исключения при выполнении функции не приводит к аварийному завершению сценария.
В общем виде стратегия выполнения сценария сводится к попытке выполнить его «ВО ЧТО БЫ ТО НИ СТАЛО». Во многих случаях это оказывается удобным.
FSHELL (как динамическая библиотека) допускает повторный запуск из приложения с помощью функции fshell_run(). При этом выполнение сценария продолжается с точки, определяемой последним выполненным оператором exit или leave. Это дает возможность управлять поведением приложения из сценария.
Описание языка FSHELL
Ключевые слова
FSELL использует следующие ключевые слова:
Ключевое слово | Описание |
---|---|
break call do else endif endwhile end exit for goto if jnt leave next return tst then to while |
Выход из циклов for и while Вызов процедуры FSHELL Используется в операторах for, while Используется в операторе if Используется в операторе if Используется в операторе while Синоним exit Выход из сценария Оператор цикла Безусловный переход к метке Условный оператор Псевдокод (jump not true) Выход из сценария Используется в операторе for Возврат из процедуры Псевдокод (test) Используется в операторе if Используется в операторе for Оператор цикла |
Переменные
Идентификатор — это последовательность символов, начинающаяся с латинской буквы на любом регистре.
Переменная представляет собой идентификатор.
Возможны два типа переменных — целое (4 байта) и указатель обобщенного вида. Тип указателя определяется контекстом используемой функции.
Переменные объявляются четырьмя способами.
Первый способ — оператор присваивания:
Var1 := 100 // десятичная константа
FileName := «d:\fshell\fshell.exe»
Второй способ — оператор #define:
#define LF 0x0A // шестнадцатеричная константа
#define Signature «SMF-70»
Третий способ — оператор _newchar:
pArray := _newchar(256)
_strcpy(pArray,»Hello World»)
puts(pArray)
_delete(pArray)
Четвертый способ — вызов функции fshell_export_var из приложения. Пример для Visual C++:
int fh = fshell_alloc()
char VarToExport[MAX_PATH]; // экспортируемая переменная>
strcpy(VarToExport, «Welcome to FSHELL programming !»);
fshell_export_var(fh, «ApplicationVar», VarToExport, MAX_PATH, 1);
fshell_compile(fh, «script.f»);
fshell_run(fh);
fshell_free(fh);
Во время выполнения сценария переменная VarToExport будет доступна из скрипта «script.f» под именем ApplicationVar:
_strcpy(ApplicationVar, «Новое значение»)
_printf(«Переменная VarToExport: %s», ApplicationVar)
ЗАМЕЧАНИЕ 1
Предусмотрен доступ к встроенным переменным с именами a … z. Доступ к этим переменным осуществляется быстрее, так как не связан с поиском в общей таблице переменных.
ЗАМЕЧАНИЕ 2
При задании строковых переменных обработка символов вида ‘\<значение>’ не производится (‘\n’, ‘\t’, …). Например, в строке «\\\\» будет содержаться четыре обратных косых черты, а не две, как это было бы в программе на языке С.
Выражения
Выражения состоят из подвыражений, связанных знаками операций. Отдельные элементы выражения могут быть заключены в круглые скобки.
Вычисление выражений производится методом рекурсивного спуска на этапе выполнения сценария. Обнаружение ошибок вычисления не приводит к завершению сценария.
Допустимыми операциями являются:
Арифметические целочисленные операции: | + сложение — вычитание * умножение / деление % остаток от деления ^ возведение в степень |
Арифметические целочисленные унарные операции: | + унарный плюс — унарный минус |
Логические унарные операции | ! логическое отрицание |
Логические операции | & логическое И| логическое ИЛИ |
Операции сравнения | > больше< меньше = равно # не равно |
Битовые операции | ~ побитовая инверсия |
Оператор присваивания | <переменная>:=<выражение> |
Пример использования логических операций:
_printf( «*** Операция ‘|’ » )
x1 := 0 | 0
x2 := 0 | 1
x3 := 1 | 0
x4 := 1 | 1
_printf( «0 | 0 = %d», x1 )
_printf( «0 | 1 = %d», x2 )
_printf( «1 | 0 = %d», x3 )
_printf( «1 | 1 = %d», x4 )
РЕЗУЛЬТАТ:
*** Операция ‘|’
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
_printf( «*** Операция ‘&’ » )
x1 := 0 & 0
x2 := 0 & 1
x3 := 1 & 0
x4 := 1 & 1
_printf( «0 & 0 = %d», x1 )
_printf( «0 & 1 = %d», x2 )
_printf( «1 & 0 = %d», x3 )
_printf( «1 & 1 = %d», x4 )
РЕЗУЛЬТАТ:
*** Операция ‘&’
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
_printf( «*** Унарные операции» )
_printf( «— ‘НЕ’ » )
x1 := !0
x2 := !1
x3 := !2
_printf( «!0 = %d», x1 )
_printf( «!1 = %d», x2 )
_printf( «!2 = %d», x3 )
РЕЗУЛЬТАТ:
*** Унарные операции
— ‘НЕ’
!0 = 1
!1 = 0
!2 = 0
_printf( «— ‘Инверсия’ » )
x1 := ~0
x2 := ~1
_printf( «~0 = %d», x1 )
_printf( «~1 = %d», x2 )
x1 := 100
_printf( «x = %d (%.8X)», x1, x1 )
y1 := ~x1
_printf( «~x = %d (%.8X)», y1, y1 )
z1 := ~y1
_printf( «~~x = %d (%.8X)», z1, z1 )
РЕЗУЛЬТАТ:
— ‘Инверсия’
~0 = -1
~1 = -2
x = 100 (00000064)
~x = -101 (FFFFFF9B)
Условный оператор
Условный оператор имеет следующий вид:
if ( условие ) then
// действие, если условие = 1
else
// действие, если условие = 0
endif
Допускается до 50 уровней вложенности операторов if.
Пример:
a := 100
b := 200
If ( a = 100) then
If (b = 200 ) then
Res := 1
else
Res := -1
endif
else
Res := -1
endif
_printf(«Result equals %d», res);
Операторы циклов
Предусмотрены два вида операторов цикла: while и for.
Оператор while имеет следующую структуру:
while ( <выражение> ) do
// тело цикла
endwhile
Оператор for имеет следующую структуру:
for i := <переменная> := <начальное значение> to <конечное значение> do
// тело цикла
next
Допускается до 50 уровней вложенности операторов while и for.
Выход из цикла может быть осуществлен оператором break.
Пример:
i := 0
while (1) do
i := i + 1
if ( i = 100 ) then break endif
endwhile
_printf(«while cycle iterated %d times», i)
Метки, процедуры, операторы безусловного перехода
Метка определяется следующим образом:
<идентификатор>:
Начало процедуры определяется меткой, обозначающей точку входа, завершается процедура оператором ‘return’, обозначающим выход из процедуры. Процедура может иметь несколько точек входа.
Оператор call предназначен для организации в программе перехода на начало процедуры, которая завершается оператором ‘return’.
call <метка>
Оператор безусловного перехода ‘ goto ‘ предназначен для организации в программе безусловного перехода к метке.
Вызов функций
При вызове функций ( встроенных и импортируемых ) используется следующий синтаксис:
_<имя функции>([<список параметров, разделенных запятыми>])
Такая форма вызова позволяют ускорить поиск в таблицах описаний функций.
ЗАМЕЧАНИЕ 1
При объявлении импортируемой функции следует добавлять префикс ‘_’ перед именем, например для доступа к функции ‘ WSAStartup ‘ необходимо указать
_import(«_WSAStartup», «wsock32.dll», 2)
либо
#import _WSAStartup wsock32.dll 2
ЗАМЕЧАНИЕ 2
В данной версии интерпретатора FSHELL не обеспечивается вычисление выражений в аргументах и , как следствие, указание вызова функции как аргумента другой функции.
Препроцессор
Препроцессор FSHELL обрабатывает следующие директивы:
#define ABC 123
— определяет константу. Директива представляет собой полный аналог оператора присваивания ( ABC := 123 ) с той разницей, что директива #define заносит значение переменной до выполнения программы, при этом сам код оператора присваивания отсутствует.
#import _Function func.dll 3
— определяет импортируемую функцию. Директива представляет собой полный аналог вызова _import с той разницей, что директива #import регистрирует функцию до выполнения программы, при этом сам вызов _import отсутствует.
#include «header.h»
— включает файл заголовка. Вложенные вызовы #include не поддерживаются.
Комментарии
Строки комментария начинаются двумя символами «//» и могут быть размещены в любом месте программы.
Структура программы
Программа ( сценарий, скрипт ) FSHELL имеет следующую структуру:
//// директивы препроцессора
//// определения констант
#define LF 0x0A
//// указание включаемых файлов, которые могут содержать
//// операторы #define , #import и описания процедур
#include «prg.h»
//// описания функций, импортируемых из динамических библиотек
#import _ExtraFunction extra.dll 1
//// главный модуль, определяемый меткой main:
main:
// тело главного модуля
// может содержать дополнительные операторы exit,
// вызовы импортируемых и встроенных функций
// и объявленных процедур
//// выход, может быть осуществлен оператором leave (<выражение>)
exit
//// описания процедур
procedure_1:
// тело процедуры
return
ЗАМЕЧАНИЕ
Оператор exit всегда возвращает 0 в вызывающую программу, оператор leave — выражение, указанное вторым операндом.
БНФ
Для любителей русской словесности приводим сокращенное описание правил образования выражений языка FSHELL в форме Бэкуса-Наура.
<буква> ::= a | b … | z | A | B … | Z
<цифра> ::= 1 | 2 … | 9
<подчеркивание> ::= ‘_’
<пробел> ::= ‘ ‘
<разделитель> ::= один из {;,+-<>/*%^=()&|!~#:\n\r\t} | <пробел>
<символ> ::= { любой ASCII символ, имеющий визуальное представление }
<идентификатор> ::= <буква> |
< идентификатор > <подчеркивание> |
< идентификатор > <буква> |
< идентификатор ><цифра>
<число> ::= <цифра> | <число><цифра> | 0x< число > | 0X< число >
<строка> ::= «<символ> | < строка ><символ >|»
<аргумент> ::= <идентификатор> | <число> | <строка>
<список аргументов> ::=[] | [ <аргумент>] | [<список аргументов>, <аргумент>]
<вызов функции> ::= _<идентификатор>(<список аргументов>)
<унарная операция> ::= + | — | ~ | !
<степень> ::= ^
<мультипликативная операция> ::= * | / | %
<аддитивная операция> ::= + | —
<логическая операция> ::= | & | < | > | = | #
<операнд> ::= [<унарная операция>]<идентификатор> |
[<унарная операция>]<вызов функции> |
[<унарная операция>]<выражение в скобках>
<множитель> ::= <операнд><степень><операнд>
< слагаемое > ::= <множитель> <мультипликативная операция> <множитель>
< выражение > ::= < слагаемое ><аддитивная операция>< слагаемое > |
< слагаемое ><логическая операция>< слагаемое >
<выражение в скобках > ::= (< выражение >)
ЗАМЕЧАНИЕ
В данной версии интерпретатора FSHELL не обеспечивается указание вызова функции как аргумента другой функции.
Варианты реализации
FSHELL.EXE
FSHELL.EXE представляет собой консольное приложение. В данной версии единственным аргументом командной строки является имя файла сценария.
fshell.exe script.f
Расширение файла сценария не анализируется.
При запуске без аргументов FSHELL.EXE предполагает, что он используется как CGI — приложение. В этом случае производится попытка доступа к переменной среды ‘PATH_INFO’. Значение этой переменной интерпретируется как имя файла сценария. Данная схема применяется при вызове FSHELL.EXE сервером Web.
FSHELL.DLL
FSHELL.DLL представляет собой многопоточную динамическую библиотеку, экспортирующую следующие функции:
fshell_alloc — распределение блока управления сценарием
fshell_add_var — добавление переменной в сценарий
fshell_export_var — экспорт переменной приложения в сценарий
fshell_export_func — экспорт функции приложения в сценарий
fshell_step_func — указание функции приложения для трассировки
fshell_compile — предкомпиляция сценария
fshell_run — запуск сценария
fshell_free — удаление блока управления сценарием
Таким образом предоставляется возможность выполнения разных сценариев в разных потоках приложения и вызов нескольких сценариев внутри одного потока.
FSHELL.OCX
FSHELL.OCX представляет собой AciveX — элемент, построенный с использованием MFC ActiveX ControlWizard среды Visual C++ версии 5.0.
Работа с этим элементом осуществляется с использованием следующих методов:
Alloc, ExportVar, ExportFunc, StepFunc, Compile, Run, Free
Эти методы являются функциональными аналогами функций FSHELL.DLL.
FSHELL.OCX легко встраивается в пользовательское приложение, а также — в HTML страницу. Для этого достаточно добавить к странице следующий тег:
<OBJECT ID=»Fshell1″ WIDTH=100 HEIGHT=50
CLASSID=»CLSID:223DE972-61B2-11D1-8763-484F4D005CDA»>
<PARAM NAME=»_Version» VALUE=»65536″>
<PARAM NAME=»_ExtentX» VALUE=»2117″>
<PARAM NAME=»_ExtentY» VALUE=»1058″>
<PARAM NAME=»_StockProps» VALUE=»0″>
Встроенные функции
Введение
В настоящем разделе перечислены встроенные функции FSHELL. Все функции возвращают значение — 4-х байтовый код, который может быть либо числом, либо указателем на область памяти.
В том случае, если «C» — аналог рассматриваемой функции, не возвращает значения, исполнительная система FSHELL все равно его формирует (только в этом случае он будет равным нулю).
Параметры функций также могут быть либо числами, либо указателями на области памяти, что определяется контекстом используемой функции.
Если программист сталкивается с необходимостью доступа к структурам данных, он может производить выборку и запись значений байтов, коротких слов (2 байта) и длинных слов (4 байта) с помощью функций _byte, _short, _long и _setbyte, _setshort, _setlong.
Вызов любой функции распознается FSHELL по префиксу ‘_’.
ЗАМЕЧАНИЕ:
В данной версии FSHELL допускается передавать функциям до 10 параметров.
Функции общего назначения
Ниже перечислены функции библиотеки периода выполнения «C» (runtime), общие для многих компиляторов «C». Их описание можно получить в оперативной справке любого компилятора.
_srand, _rand, _printf, _sprintf, _fprintf, _scanf, _sscanf, _fscanf, _gets, _puts, _strchr, _strrchr, _strstr, _strcmp, _strncmp, _stricmp, _strnicmp, _toupper, _tolower, _strlen, _strcat, _strncat, _strcpy, _strncpy, _strset, _strnset, _access, _fopen, _fclose, _fgets, _fputs, _feof, _fflush, _fseek, _ftell, _fread, _fwrite, _time, _ctime, _localtime, _asctime, _strftime, _findfirst, _findnext, _findclose, _system, _kbhit, _getch, _getche, _rename, _unlink, _setvbuf, _getenv
Функции Microsoft® Win32® API
Данные функции предназначены для работы с ядром Windows. Их описание лучше всего посмотреть в оперативной справке Visual C++ версии 5.0.
_Sleep, _CreateSemaphore, _ReleaseSemaphore, _WaitForSingleObject, _CloseHandle, _InitializeCriticalSection, _EnterCriticalSection, _LeaveCriticalSection, _DeleteCriticalSection, _GetCurrentThread, _MoveFile, _MoveFileEx, _CopyFile, _DeleteFile, _CreateDirectory, _RemoveDirectory, _GetCurrentDirectory, _SetCurrentDirectory, _GetFullPathName, _MultiByteToWideChar, SystemParametersInfo, _GetCommandLine
Специальные функции
Данная группа функций обеспечивает работу с памятью, импортом функций из других динамических библиотек, переносом и копированием файлов, а также — решением других общественно необходимых задач.
_import(fname, dllname, qa)
Указывает FSHELL, в какой динамической библиотеке искать указанную функцию.
ПАРАМЕТРЫ:
fname — имя функции, должно начинаться с символа ‘_’;
dllname — имя динамической библиотеки (короткое либо полное);
qa — количество аргументов (в данной версии не используется).
_stop()
Переводит FSHELL в режим пошагового выполнения сценария. При этом выводится диалоговое окно с кнопками управления выполнением.
_offset(addr, off)
Формирует новый адрес, складывая адрес addr и смещение off.
Несколько устарела.
_byte(addr, off)
Производит выборку байта из области памяти, задаваемой адресом addr со смещением off.
ПАРАМЕТРЫ:
addr — адрес области памяти;
off — смещение.
_short(addr, off)
Производит выборку короткого слова (2 байта) из области памяти, задаваемой адресом addr со смещением off.
ПАРАМЕТРЫ:
addr — адрес области памяти;
off — смещение.
_long(addr, off)
Производит выборку длинного слова (4 байта) из области памяти, задаваемой адресом addr со смещением off.
ПАРАМЕТРЫ:
addr — адрес области памяти;
off — смещение.
_setbyte(addr, off, value)
Производит запись байта со значением value в область памяти, задаваемой адресом addr со смещением off.
ПАРАМЕТРЫ:
addr — адрес области памяти;
off — смещение;
value — значение байта.
_setshort(addr, off, value)
Производит запись короткого слова (2 байта) со значением value в область памяти, задаваемой адресом addr со смещением off.
ПАРАМЕТРЫ:
addr — адрес области памяти;
off — смещение;
value — значение байта.
_setlong(addr, off, value)
Производит запись длинного слова (4 байта) со значением value в область памяти, задаваемой адресом addr со смещением off.
ПАРАМЕТРЫ:
addr — адрес области памяти;
off — смещение;
value — значение байта.
_newchar(size)
Распределяет память заданного объема.
ПАРАМЕТРЫ:
size — размер запрашиваемой памяти.
_delete(addr)
Освобождает память, распределенную функцией _newchar.
ПАРАМЕТРЫ:
addr — адрес памяти, который вернула функция _newchar.
_fmove (source, dest)
Аналог MoveFileEx с установленными режимами MOVEFILE_COPY_ALLOWED и MOVEFILE_REPLACE_EXISTING (см. справку по Visual C++).
_fmovetodir (p_source, p_destdir)
Производит перенос файла в заданный каталог.
ПАРАМЕТРЫ:
p_source — имя файла;
p_destdir — имя каталога.
_fcopytodir (source, destdir)
Производит копирование файла в заданный каталог.
ПАРАМЕТРЫ:
source — имя файла;
destdir — имя каталога.
_MessageBox(text, title, style)
Выводит диалоговое окно с кнопками.
ПАРАМЕТРЫ:
text — текст окна;
title — заголовок окна;
style — стиль окна (см. справку Visual C++ по функции MessаgeBox).
_findvar(varname)- Ищет переменную с именем varname в словаре переменных FSHELL. Возвращает 1 в случае успеха и 0 в противном случае.
_fork() — Производит запуск копии FSHELL с сохраненными значениями переменных и счетчика команд в отдельном потоке (а не в процессе, как в UNIX).
_gettid() — Возвращает идентификатор потока, запущенного функцией fork.
Другие полезные функции
Эти функции помогут украсить Ваши сценарии.
_PlaySound(file, mode)
Аналог функции sndPlaySound (см. справку по Visual C++).
ПАРАМЕТРЫ:
file — «проигрываемый» файл;
mode — режим (0 — синхронный, 1 — асинхронный, …)
_ShellExecute(fname, pars, dir, sh)
«Выполняет» файл с расширением, зарегистрированным в системе (*.wav, *.avi, *.doc …). Возможности несколько урезаны по сравнению с оригиналом функции из SHELLAPI.
ПАРАМЕТРЫ:
fname — имя «выполняемого» файла
pars -дополнительные параметры (если fname является именем программы)
dir — рабочий каталог по умолчанию
sh — вид окна (если fname является именем программы). Допустимые значения описаны в справке Visual C++ по функции ShellExecute.
Особенности программирования
Многопоточные приложения
FSHELL.DLL является многопоточной библиотекой. Каждый вызов функции fshell_alloc() формирует в памяти новый блок управления интерпретацией. Таким образом предоставляется возможность запускать из потоков Вашего приложения FSHELL — сценарии параллельно.
Запуска сценария производится в следующей последовательности:
int fh; // дескриптор блока управления сценарием
fh = fshell_alloc(); // распределение блока управления
// здесь можно произвести настройку сценария
// — добавить либо экспортировать переменные приложения
// — экспортировать функции
fshell_compile(fh, «first.f») // предкомпиляция сценария «first.f»
fshell_run(fh); // запуск сценария
fshell_free(fh); //удаление блока управления сценарием
При использовании FSHELL.OCX применяется такая же схема запуска.
Методика отладки
Сценарии FSHELL легко отлаживаются с помощью тестовых сообщений вызовом функций _printf, _puts, _MessageBox.
При отладке оконного приложения, разработанного в среде Visual C++, использующего FSHELL как динамическую библиотеку можно использовать функцию _MessageBox, либо присоединение консоли с помощью функции AllocConsole(). В последнем случае вывод функций _printf и _puts будет перенаправлен в новое консольное окно.
Если возникает необходимость трассировки выполнения скрипта, вставьте в его текст вызов функции _stop. После каждого выполненного оператора будет выводиться окно с информацией об этом операторе (в предкомпилированном виде).
В сложных случаях отладки, например — для ISAPI — приложений можно рекомендовать вывод тестовой информации в файл.
Необходимые динамические библиотеки
Для работы FSHELL требуются следующие библиотеки:
— mfc42.dll;
— msvcirt.dll;
— msvcrt.dll.