- - * - WhiteUnicorn - * - -




* #WhiteUnicorn/ StartPage/ Programming/ Clipper+Asm >



Clipper + Assembler

Совместное разведение и получение работоспособного потомства :)

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

Возможность подключить к Клиппер-программе Асм-модули (на уровне объектников) описана почти в любом руководстве Клиппер. Но _очень_ в общих чертах. И практически без живых примеров, которые можно было бы использовать в качестве шаблона. Попытки разобраться с этим всем налету осложняются тем, что большинство ошибочных действий подвешивают компьютер и приходится каждые пять минут перегружаться. (Если есть как минимум два компа, объединенных в сеть, то все становиться несколько проще ;)

Итак. Проблема возникла следующая. Есть БД на Клиппере. При регистрации клиентов они пишут свои фамилию/имя/отчество кто как - то маленькими буквами, то большими, то вообще со сменой регистра по-хакерски :) Это приводит к возникновению следующих проблем:

  1. БД выглядит совершенно жутким образом (ну и все отчеты, ессно, тоже)
  2. Клиппер сугубо case-sensitive система, поэтому при попытке повторной регистрации, если ФИО введено не в том же регистре, что и в первый раз, происходит добавление чела в БД еще разик, вместо выдачи ему его кода.
  3. Ну и все прочие удовольствия чувствительности к регистру символов - неправильные сортировки, выборки etc.

Короче, регулярно приходилось просто ручками все ФИО исправлять как положено.

Наконец руки дошли написать функцию, конвертирующую строку в правильный вид прямо при вводе. Чтобы в БД она добавлялась в человеческом виде.

И вот тут выяснилось несколько веселых вещей:

  1. В Клиппере функций работы со строками раз-два и обчелся.
  2. Клиппер русские буквы _буквами_ не считает. :(
  3. Строка в Клиппер не может быть нормально обработана как массив символов. Т.е. это именно строка, а символы из нее можно, конечно, выковырять, но это через [skip]

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

Собственно процесс поиска решения методом научного и не очень научного тыка к теме солюшена отношения особо не имеет, поэтому я его опускаю :)
(Комп остался жив :)

После решения основной задачи заодно уж были на Асме же переписаны все Клипперовские функции, чувствительные к языку (русский/английский 866CP)


Итак, в результате получился следующий набор:

StrConv.asm

Набор функций, конвертирующий переданную строку одним из трех способов:

char FirstUp   (char szLine) // Конвертит строку в нижний  регистр, первая буква заглавная
char All2Upper (char szLine) // Конвертит строку в верхний регистр (аналог Upper(szLine))
char All2Lower (char szLine) // Конвертит строку в нижний  регистр (аналог Lower(szLine))

Поскольку все функции пользуются одним и тем же типом и количеством :) входного параметра, то и используют они все фактически общий код (FirstUp), предварительно установив флаг признака вызванной функции

Собственно рабочие функции U2Lower и L2Upper живут в StrWFunc.asm

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

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

  szLine := FirsUp(szLine)

В функциях All2Upper и All2Lower происходит просто установка флажка, какая из трех функций модуля вызвана, а потОм мы уходим навсегда :) в FirsUp и там все делаем в зависимости от значения этого флажка.

Чтобы не плодить лишний код, All2Upper и All2Lower описываются, как void. (Возврат все равно идет через FirsUp)

И заодно в All2Upper сделана метка ErrorExit, позволяющая выйти из любой функции без возврата значения и без каких-либо лишних движений.

Ограничение: предельная длина обрабатываемой строки - 0ffh символов. Все лишние символы остануться в исходном состоянии (ну не умею я пока делать динамические буферы на Асме :)


StrConvR.asm

Набор функций, конвертирующий переданную строку одним из трех способов:

 void FirstUpR   (char szLine) // Конвертит строку в нижний  регистр, первая буква заглавная
 void All2UpperR (char szLine) // Конвертит строку в верхний регистр (аналог Upper(szLine))
 void All2LowerR (char szLine) // Конвертит строку в нижний  регистр (аналог Lower(szLine))

Отличие от предыдущих функций в том, что меняется исходная строка.
Соответственно принцип работы существенно отличается.

Все три функции точно так же пользуются телом FirstUpR для работы, а в своих рамках просто устанавливают флажок вызванной функции.
И точно также рабочие функции U2Lower и L2Upper живут в StrWFunc.asm

Но. Поскольку свои данные тут не нужны, то не нужны и свои ds,es.
Работа ведется напрямую со строкой-источником. Она же становиться строкой-приемником.
В конце функции там лежит измененное значение, поэтому возвращать ничего не нужно и мы просто выходим в Клипперную программу.
Т.е. использовать это можно прямо вот так:

 FirstUp(szLine) // szLine теперь изменился

ErrorExit совпадает с обычным, но не восстанавливает ds и es (они должны сохраняться после того, как мы проверили исходные данные, и собираемся менять эти регистры)


StrWFunc.asm

Две рабочие функции для предыдущих модулей:

L2Upper  // Конвертит строку в верхний регистр
U2Lower  // Конвертит строку в нижний  регистр

Ессно, объявляем их здесь, как public, а в вызывющих файлах - как extrn

Чистый Асм, никаких извратов - просто проверяем соответствующие диапазоны символов и меняем нужные нужным образом.
Параметры передаются через регистры:

ds:[si]	- Строка-источник
es:[di]	- Строка-приемник
cx	- Счетчик


StrCheck.asm

Функция, проверяющая тип любого символа в строке.

int WhatIs (char szLine, int iNum)

Возвращаемые значения:

0 - error (чего-то не так вызывали)
1 - ни один из следующих
2 - цифра
3 - заглавная буква
4 - строчная буква

При отсутствии второго параметра (номер символа, начинаются с 1) проверяется первый символ.
Если заданный номер символа вылезает за пределы длины строки, то вернется код 0.

Заменяет собой четыре Клипперовские функции:

boolean IsDigit(char szLine) // первый символ цифра ?
boolean IsAlpha(char szLine) // первый символ буква ?
boolean IsLower(char szLine) // первый символ строчная  буква ?
boolean IsUpper(char szLine) // первый символ заглавная буква ?

Соответственно, вызовы будут соотноситься так:

if IsDigit(szLine) = .T.
if WhatIs (szLine) =  2 

if IsAlpha(szLine) = .T.
if WhatIs (szLine) >  2

if IsLower(szLine) = .T.
if WhatIs (szLine) =  4

if IsUpper(szLine) = .T.
if WhatIs (szLine) =  3

Или можно еще вот так:

if IsAlpha(szLine) = .F. .and. IsDigit(szLine) = .F.
if WhatIs (szLine) = 1

if IsAlpha(szLine) = .T. .or.  IsDigit(szLine) = .T.
if WhatIs (szLine) > 1

Все. На этом Ассемблер заканчивается. :)


В Клипперной проге все эти функции вызываются самым обычным образом.

Для того, чтобы все это можно было проверить, сделан небольшой полигончик:

Main.prg - собственно проект,
и еще есть функция печати в файл Print.prg


Чтобы собрать вместе Асм и Клиппер файлы, просто компилим те и другие родными компайлерами в объектники, а потОм Клипперовским RTLink-ом собираем вместе, как обычную Клипперскую прогу.

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

Файлы сценариев:

StrConv.lnk,
StrConv.rmk,
Make.bat


И два файла определений системы расширения Clipper+Asm:

Extasm.inc,
Extenda.inc

Теоретически они должны быть в комплекте MAsm, но на всякий случай кладу здесь, мало ли.. У меня, например, они битые оказались, пришлось искать отдельно.

Они должны жить там, где компайлер ищет инклуд-файлы.


Sources:

StrCheck.asm	- Character checker
StrConv.asm	- String converter
StrConvR.asm	- String converter (replacer)
StrWFunc.asm	- Working functions for StrConv & StrConvR

Extasm.inc	- Extend System definitions for assembly language
Extenda.inc

StrConv.lnk	- Linker file
StrConv.rmk	- RTLink file
Make.bat	- Make file

StrConv.zip	- All (все вместе, включая это описание)



* #WhiteUnicorn/ StartPage/ Programming/ Clipper+Asm >



- - * - Anastasija aka WhiteUnicorn - * - - LJLiveJournal
PFPhotoFile