欢迎访问 Forcal程序设计

FORCAL32W.DLL V9.0 编程指南

目 录

1 输出函数 2 简单计算 3 FORCAL二级函数设计 | 4 FORCAL的基本用法 5 Forcal软件组成与使用 6 用FORCAL保存和检索数据
Forcal 输 出 函 数
1.1 版本信息函数：ForcalVer 1.2 初始化FORCAL：InitForcal 1.3 释放FORCAL：FreeForcal 1.4 获得FORCAL运行错误：GetRunErr 1.5 测试FORCAL运行错误：TestRunErr 1.6 设置FORCAL运行错误：SetRunErr 1.7 编译实数表达式：RealCom 1.8 计算实数表达式的值：RealCal 1.9 编译整数表达式：IntCom 1.10 计算整数表达式的值：IntCal 1.11 编译复数表达式：ComplexCom 1.12 计算复数表达式的值：ComplexCal 1.13 锁定一个模块：LockModule 1.14 设置外部二级函数：SetFunction 1.15 设置常量：SetConst 1.16 删除常量或二级函数：DeleteConstOrFunction | 1.17 判断一个表达式是否有效：IsFor 1.18 获得表达式信息：GetFor 1.19 判断表达式的自变量是否重新赋值：ParaModify 1.20 获得表达式中的字符串：GetForStr 1.21 删除一个表达式：DeleteFor 1.22 插入一个键：InsertKey 1.23 查找一个键：SearchKey 1.24 删除一个键：DeleteKey 1.25 删除一个私有键：DeletePrivateKey 1.26 枚举指定键值类型所对应的所有字符串及键值：EnumKeyTypeValue 1.27 锁定键的类型：LockKeyType 1.28 与Forcal交换信息：ExMsgWithForcal 1.29 插入一个指针键：InsertKeyP 1.30 垃圾收集时标记一个指针键（对象）：SignGoodObj 1.31 垃圾收集：GC

FORCAL 用Win32标准函数调用方式（stdcall调用协议）输出了动态库函数，可供C/C++、VB、delphi、FORTRAN等程序使用。

除了GetRunErr()、TestRunErr()和SetRunErr()三个函数外，其余的函数只能在单线程中使用（不允许两个及两个以上的线程同时运行这些函数），在设计多线程应用程序时必须注意这一点。

Forcal不抛出异常，如果在主调程序中检测到了异常，可能来自于外部模块向Forcal注册的函数，此时，可尝试对Forcal重新进行初始化。

并行计算设想：在多核计算机中进行并行运算时，可复制Forcal32W.dll为多个副本Forcal32W1.dll、Forcal32W2.dll、... ...，同时加载Forcal32W.dll及各个副本，Forcal32W.dll及各个副本都有自己的地址空间，可独立运行互不影响，这样可实现并行计算。

以下是FORCAL中使用的一些整数类型定义：

typedef __int64 fcIFOR; //FORCAL表达式中的整数类型定义
typedef __int32 fcVOID; //FORCAL的指针型整数定义
typedef __int32 fcINT; //FORCAL的通用整数定义
typedef __int32 fcKEY; //FORCAL的键值定义

在编写代码时，应注意能方便地移植到64位平台。为此约定：指针总是保存在Forcal数据（整数、实数或复数）前面的字节中，例如在32位平台上，指针应保存在数据的前4个字节中。保存一个指针的代码如下：

fcIFOR fci; //定义一个FORCAL整数
void *p; //定义一个指针

p=... ...; //指针赋值
*(fcVOID *)&fci=(fcVOID)p; //指针p保存在整数fci的前面的字节中，无论32位平台还是64位平台均可正常编译

1 输出函数 [返回页首]

1.1 版本信息函数：ForcalVer

const wchar_t * _stdcall ForcalVer(void);

1.2 初始化FORCAL：InitForcal

bool _stdcall InitForcal(void);

在使用Forcal前必须先用该函数进行初始化。初始化成功时返回true，否则返回false。
可在任何时刻使用该函数对Forcal进行重新初始化，使Forcal恢复到第一次调用该函数时的状态。
重新初始化时，若在Forcal键树中有未删除的表达式，在删除表达式之前将不会重置静态变量free为1并执行该表达式，也不会销毁由静态变量free或函数free标识的对象。要实现删除表达式之前的这种自动执行效果，应使用函数DeleteFor自己删除表达式。关于在删除一个表达式前要做的这些工作，请参考函数 DeleteFor 的说明。

1.3 释放 FORCAL：FreeForcal

void _stdcall FreeForcal(void);

只要使用了FORCAL动态库函数，在卸载动态库之前，必须用该函数释放动态库。
释放Forcal时，若在Forcal键树中有未删除的表达式，在删除表达式之前将不会重置静态变量free为1并执行该表达式，也不会销毁由静态变量free或函数free标识的对象。要实现删除表达式之前的这种自动执行效果，应使用函数DeleteFor自己删除表达式。关于在删除一个表达式前要做的这些工作，请参考函数 DeleteFor 的说明。

1.4 获得FORCAL运行错误：GetRunErr

void _stdcall GetRunErr(int &ErrType,wchar_t *&FunName,int &FunCode,int &ForType,void *&ForHandle);

ErrType：返回运行错误的类型。ErrType=0：没有运行错误；ErrType=1：整数 函数运行错误；ErrType=2：实数函数运行错误；ErrType=3：复数函数运行错误；ErrType=4：父表达式被删除，父表达式即该表达式中所调用的表达式，也称基表达式；ErrType=5：该表达式中所调用的二级函数被删除；ErrType=其它值：其它类型运行错误。
FunName：当ErrType=1、ErrType=2或ErrType=3时，返回出错函数名。当ErrType=4或ErrType=5时，返回0。
FunCode：当ErrType=1、ErrType=2或ErrType=3时，返回函数错误代码。当ErrType=4或ErrType=5时， 返回0。
ForType：返回出错表达式的类型。ForType=1表示整数表达式，ForType=2表示实数表达式，ForType=3表示复数表达式。
ForHandle：返回出错表达式的句柄，该句柄即编译表达式时获得的句柄。

FORCAL在运行时，将记录出现的第一个运行错误。
通常在编译表达式前后和执行表达式前后使用该函数。使用该函数后，FORCAL将恢复为无错状态。
在编译和执行表达式后使用该函数，是为了检测发生的运行错误。之所以还要在编译和执行表达式前使用该函数（在编译和执行表达式前，应保证没有运行错误，如果确信无错，也可以不用该函数），是因为该函数可将FORCAL恢复为无错状态；当然，也可以用SetRunErr()函数直接设为无错状态。

1.5 测试FORCAL运行错误：TestRunErr

int _stdcall TestRunErr(void);

该函数返回FORCAL运行错误的类型，当返回0时表示没有错误。该函数仅仅测试是否有运行错误，并不改变错误的状态。
通常在二级函数设计中要用到该函数。

1.6 设置FORCAL运行错误：SetRunErr

void _stdcall SetRunErr(int ErrType,wchar_t *FunName,int FunCode,int ForType,void *ForHandle);

ErrType：设置运行错误的类型。ErrType=1：整数函数运行错误； ErrType=2：实数函数运行错误； ErrType=3：复数函数运行错误； 不要设置ErrType=4或ErrType=5，这两个值由系统自动设置；ErrType=其它值：其它类型运行错误。
FunName：设置出错的函数名，要求传递一个静态字符串。
FunCode：设置函数错误代码。
ForType：设置出错表达式的类型。ForType=0表示任意表达式。ForType=1表示整数表达式，ForType=2表示实数表达式，ForType=3表示复数表达式。
ForHandle：设置出错表达式的句柄。当ForType=0时的句柄为从二级函数获得的表达式句柄。当ForType=1、ForType=2或ForType=3时的句柄为编译表达式时获得的句柄。

在设计自定义的二级函数时，可以用该函数设置FORCAL运行错误。由于FORCAL只保存出现的第一个运行错误，因此在设置之前，先用TestRunErr函数测试是否出现过运行错误，如果还没有出现，可以进行设置，否则，不能进行设置。

FORCAL允许另一个线程修改运行时的出错状态，以便退出FORCAL运行，因此可在其它线程中使用SetRunErr()函数设置运行错误。

1.7 编译实数表达式：RealCom

int _stdcall RealCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,double *&Para,fcINT &ErrBegin,fcINT &ErrEnd);

ForStr：字符串表达式。
nModule：模块号。每一个模块都有自己的模块变量空间，为了提高存储效率，编译时尽量减少模块的数目。
hFor：输入参数为加锁模块的函数指针，可以为0。返回时获得一个表达式句柄，标识一个表达式，计算表达式的值时要用到该参数。该参数必须为变量，不能为常量。
typedef void (_stdcall *FcNullLock)(void); //加锁模块的函数指针；
void _stdcall NullLock(void){}; //加锁模块的函数定义；
如果预先用函数LockModule(hModule,NullLock,true)对一个模块hModule加锁，则编译表达式时必须提供加锁函数的指针，否则无法编译。缺省情况下，Forcal对任何模块都不会加锁。
nPara：该参数必须为变量，不能为常量。该参数返回表达式的自变量个数。当nPara=-1时表示有0个自变量，当nPara=0时表示有1个自变量，当nPara=1时表示有2个自变量，依次类推。
Para：该参数必须为变量，不能为常量。该参数返回用于输入自变量的数组指针。计算表达式的值时要用到该参数。当然，也可以不用该参数，而用自己的数组输入自变量。
ErrBegin：该参数必须为变量，不能为常量。该参数返回出错的初始位置。
ErrEnd：该参数必须为变量，不能为常量。该参数返回出错的结束位置。
该函数返回编译代码，当返回值为0时，表示没有错误，当返回其它值时，表示存在编译错误，出错位置由ErrBegin和ErrEnd确定。编译错误代码的意义如下：

-2：模块加锁函数不正确。该返回值由程序员进行处理！
-1：未用！
0：没有错误，编译成功！
1：内存分配失败！
2：括号不成对！
3：（等号后）没有表达式！
4：复数表达式中不能使用i作为参数！
5：字符串中转义字符错误！
6：字符串无效，即"..."不匹配！
7：不可识别字符！
8：表达式名称定义错误！
9：不可识别的自变量,自变量只能以字母、中文字符或下画线开头！
10：不可识别的自变量定义方法，“(,:,:,:,:,...)”冒号过多！
11：自变量定义错误！
12：continue()函数只能有0个参数！
13：只能在while,until中使用continue函数！
14：break()函数只能有0个参数！
15：只能在while,until中使用break函数！
16：if,while,until,which中的参数个数至少为2个！
17：表达式中的数字错误！
18：&单目取地址运算符只能用于单独的变量！
19：单目运算符++、--错误！
20：括号内没有数字！
21：单目运算符+、-、!错误！
22：赋值“=”错误！
23：不正确的运算方式或其他语法错误！
24：不可识别变量名或常量名！
25：不可识别函数名！
26：一级函数参数不匹配！
27：二级函数参数不匹配！
28：关键字Static或Common的位置非法！
29：（模块中）表达式有重名！
30：对形如“-2^3”的式子，须用括号给前置单目运算符“-”和乘方运算符“^”指出运算顺序！
31：类成员运算符（函数参数运算符）后只能是变量名、字符串、括号运算符或者类成员函数！
32：调用整数表达式时参数不匹配！
33：调用实数表达式时参数不匹配！
34：调用复数表达式时参数不匹配！
35：自变量重名！
36：因检测到运行错误而退出！
37：运算符重载函数oo有0个自变量或嵌套使用！
38：未用！
39：源代码太长或字符串太多！

通常在编译前用SetRunErr()函数或GetRunErr()函数使FORCAL处于无错状态，编译后用GetRunErr()检测运行错误。其他线程的错误设置可使FORCAL退出漫长的编译过程，返回错误代码36。

FORCAL支持表达式的模块化编译。在用FORCAL编译表达式时，要给该表达式指定一个模块号，模块号用整数进行标识。 如果用模块加锁函数LockModule对一个模块号进行了加锁，则编译表达式时必须提供加锁函数。

在FORCAL中，一个模块由一个或多个表达式组成。模块用一个整数标识，整数可正可负，只要绝对值相等，就属于同一个模块。一般用正整数表示该模块名。模块共有两类，即主模块（0#模块）和普通模块（其他标号的模块）。

同一模块中，模块号为负的表达式称私有表达式，只能被本模块的表达式所访问（即调用），在其他模块中是不可见的；模块号为正的表达式称公有表达式或全局表达式，能被任何一个表达式所访问。主模块（0#模块）中的表达式都是私有表达式。任何一个表达式，既可以访问本模块中的表达式，也可以访问其他模块中的全局表达式，如果本模块中的一个私有表达式与其他模块的一个全局表达式重名，将优先调用本模块中的私有表达式。

由以上规定可以看出，主模块可以访问本模块中的表达式，也可以访问其他模块中的全局表达式。因此，主模块常常用在主程序中。

注：在编译表达式时，缺省情况下，所有用到的模块变量必须预先定义。可用函数 ExMsgWithForcal（Type为12，hMsg非0）通知编译器使用未定义的模块变量（若一个标识符没有定义，且不是常量，将被解释为模块变量）；也可用函数 ExMsgWithForcal（Type为12，hMsg为0）通知编译器取消这种设置。无论表达式编译是否成功，将恢复缺省设置，即：所有用到的模块变量必须预先声明。

表达式hFor的销毁：（1）使用函数 DeleteFor 销毁表达式；（2）重新初始化Forcal时由函数 InitForcal 销毁所有表达式；（3）释放Forcal时由函数 FreeForcal 销毁所有表达式。

1.8 计算实数表达式的值：RealCal

double _stdcall RealCal(void *hFor,double *d);

计算实数表达式hFor，hFor是实数表达式的句柄；数组d中依次存放自变量，参数d不可为NULL。可以用任意的数组存放自变量参数。
注意自变量可能被重新赋值。可以用 ParaModify()函数判断一个表达式的自变量是否重新赋值。
通常在计算前用SetRunErr()函数或GetRunErr()函数使FORCAL处于无错状态，计算后用GetRunErr()检测运行错误。

1.9 编译整数表达式：IntCom

int _stdcall IntCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,fcIFOR *&Para,fcINT &ErrBegin,fcINT &ErrEnd);

ForStr：字符串表达式。
nModule：模块号。每一个模块都有自己的模块变量空间，为了提高存储效率，编译时尽量减少模块的数目。
hFor：输入参数为加锁模块的函数指针，可以为0。返回时获得一个表达式句柄，标识一个表达式，计算表达式的值时要用到该参数。该参数必须为变量，不能为常量。
typedef void (_stdcall *FcNullLock)(void); //加锁模块的函数指针；
void _stdcall NullLock(void){}; //加锁模块的函数定义；
如果预先用函数LockModule(hModule,NullLock)对一个模块hModule加锁，则编译表达式时必须提供加锁函数的指针，否则无法编译。缺省情况下，Forcal对任何模块都不会加锁。
nPara：该参数必须为变量，不能为常量。该参数返回表达式的自变量个数。当nPara=-1时表示有0个自变量，当nPara=0时表示有1个自变量，当nPara=1时表示有2个自变量，依次类推。
Para：该参数必须为变量，不能为常量。该参数返回用于输入自变量的数组指针。计算表达式的值时要用到该参数。当然，也可以不用该参数，而用自己的数组输入自变量。
ErrBegin：该参数必须为变量，不能为常量。该参数返回出错的初始位置。
ErrEnd：该参数必须为变量，不能为常量。该参数返回出错的结束位置。
该函数返回编译代码，当返回值为0时，表示没有错误，当返回其它值时，表示存在编译错误，出错位置由ErrBegin和ErrEnd确定。
通常在编译前用SetRunErr()函数或GetRunErr()函数使FORCAL处于无错状态，编译后用GetRunErr()检测运行错误。

其它请参考“1.7 编译实数表达式”中的说明。

1.10 计算整数表达式的值：IntCal

fcIFOR _stdcall IntCal(void *hFor,fcIFOR *d);

计算整数表达式hFor，hFor是整数表达式的句柄；数组d中依次存放自变量，参数d不可为NULL。可以用任意的数组存放自变量参数。
注意自变量可能被重新赋值。可以用 ParaModify()函数判断一个表达式的自变量是否重新赋值。
通常在计算前用SetRunErr()函数或GetRunErr()函数使FORCAL处于无错状态，计算后用GetRunErr()检测运行错误。

1.11 编译复数表达式：ComplexCom

int _stdcall ComplexCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,_complex *&Para,fcINT &ErrBegin,fcINT &ErrEnd);

ForStr：字符串表达式。
nModule：模块号。每一个模块都有自己的模块变量空间，为了提高存储效率，编译时尽量减少模块的数目。
hFor：输入参数为加锁模块的函数指针，可以为0。返回时获得一个表达式句柄，标识一个表达式，计算表达式的值时要用到该参数。该参数必须为变量，不能为常量。
typedef void (_stdcall *FcNullLock)(void); //加锁模块的函数指针；
void _stdcall NullLock(void){}; //加锁模块的函数定义；
如果预先用函数LockModule(hModule,NullLock)对一个模块hModule加锁，则编译表达式时必须提供加锁函数的指针，否则无法编译。缺省情况下，Forcal对任何模块都不会加锁。
nPara：该参数必须为变量，不能为常量。该参数返回表达式的自变量个数。当nPara=-1时表示有0个自变量，当nPara=0时表示有1个自变量，当nPara=1时表示有2个自变量，依次类推。
Para：该参数必须为变量，不能为常量。该参数返回用于输入自变量的数组指针。计算表达式的值时要用到该参数。当然，也可以不用该参数，而用自己的数组输入自变量。
ErrBegin：该参数必须为变量，不能为常量。该参数返回出错的初始位置。
ErrEnd：该参数必须为变量，不能为常量。该参数返回出错的结束位置。
该函数返回编译代码，当返回值为0时，表示没有错误，当返回其它值时，表示存在编译错误，出错位置由ErrBegin和ErrEnd确定。
通常在编译前用SetRunErr()函数或GetRunErr()函数使FORCAL处于无错状态，编译后用GetRunErr()检测运行错误。

其它请参考“1.7 编译实数表达式”中的说明。

1.12 计算复数表达式的值：ComplexCal

_complex _stdcall ComplexCal(void *hFor,_complex * d);

计算复数表达式hFor，hFor是复数表达式的句柄；数组d中依次存放自变量，参数d不可为NULL。可以用任意的数组存放自变量参数。
注意自变量可能被重新赋值。可以用 ParaModify()函数判断一个表达式的自变量是否重新赋值。
通常在计算前用SetRunErr()函数或GetRunErr()函数使FORCAL处于无错状态，计算后用GetRunErr()检测运行错误。

1.13 锁定一个模块：LockModule

bool _stdcall LockModule(fcVOID hModule,void (_stdcall *NullLock)(void),bool bLock);

hModule：模块号。
NullLock：模块加锁函数指针。模块加锁函数在主程序中定义，格式如下：

void _stdcall NullLock(void){}; //加锁模块的函数定义；

bLock：bLock=true，加锁模块；bLock=false，解锁模块。

如果预先用函数LockModule(hModule,NullLock,true)对一个模块hModule加锁，则编译表达式时必须提供加锁函数的指针，否则无法编译。缺省情况下，Forcal对任何模块都不会加锁。

通常，模块加锁后无需解锁，模块中没有表达式时将自动解锁。但如果模块加锁后从未使用（没有一个表达式编译成功），则需用函数LockModule(hModule,NullLock,false)进行解锁。

加锁一个模块使得其他线程无法向该模块中增加表达式，这在设计多线程程序时特别有用。

1.14 设置外部二级函数：SetFunction

int _stdcall SetFunction(fcKEY FunType,wchar_t *FunName,void *Fun,fcINT ParaNum);

FunType：二级函数类型。只能取Key_IntFunction（标识整数二级函数）、Key_RealFunction（标识实数二级函数）、Key_ComplexFunction（标识复数二级函数）。这三个标识符的值在头文件FORCAL32W.h中定义。
FunName：二级函数名称，要符合Forcal标识符的命名规定。
Fun：二级函数指针。整数、实数、复数二级函数的函数说明格式如下：

fcIFOR IntFun(fcINT m,fcIFOR *Para,void *hFor); //FORCAL标准整数二级函数；
double RealFun(fcINT m,double *Para,void *hFor); //FORCAL标准实数二级函数；
_complex ComplexFun(fcINT m,_complex *Para,void *hFor);//FORCAL标准复数二级函数；

其中m为Forcal传递给该函数的实际的参数个数，-1表示有0个自变量，0表示有1个自变量，依次类推。Para为存放参数的数组。hFor为调用该函数的表达式句柄（与编译表达式时返回的表达式句柄并不相同）。
在FORCAL表达式中，函数的一般形式为FunName(X1,X2,...,Xn)。
ParaNum：存放二级函数的自变量个数。数组ParaNum的对应项存放每个函数的自变量个数，其中-2表示有不确定的多个自变量，-1表示有0个自变量，0表示有1个自变量，依次类推。
该函数返回值的意义如下：

0：设置成功。
1：已存在该函数。
2：内存分配失败。
3：不能用空字符串作为函数名。
4：非法的二级函数类型标识。

例子：

double _stdcall asd(fcINT ,double *,void *); //自定义实数二级函数；
SetFunction(Key_RealFunction,"asd",asd,2); //设置实数二级函数；

注意：

1、在设计二级函数时，通常要用SetRunErr(...)向FORCAL报告运行错误。
2、通常在初始化FORCAL之后，立即进行二级函数的设置。
3、设计二级函数必须使用_stdcall调用协议（Win32标准函数调用方式）。
4、函数参数如果是一个指针，约定指针保存在参数的前4个字节中。
5、可以在整数和实数二级函数中返回一些临时对象，参考函数 ExMsgWithForcal（Type为15、16）的说明。

取消设置的外部二级函数：（1）使用函数 DeleteConstOrFunction；（2）重新初始化Forcal时由函数 InitForcal 取消所有外部二级函数；（3）释放Forcal时由函数 FreeForcal 取消所有外部二级函数。

1.15 设置常量：SetConst

int _stdcall SetConst(fcKEY Const Type,wchar_t *Const Name,void *ConstValue);

ConstType：常量类型。只能取Key_IntConst（标识整数常量）、Key_RealConst（标识实数常量）、Key_ComplexConst（标识复数常量）。这三个标识符的值在头文件FORCAL32W.h中定义。
ConstStr：常量名，要符合Forcal标识符的命名规定。
ConstValue：指向常量的值的指针。
该函数返回值的意义如下：

0：设置成功。
1：已存在该常量。
2：内存分配失败。
3：不能用空字符串作为常量名。
4：非法的常量类型标识。

例如：

double *pi=3.14; //设置常量的值；
SetConst(Key_RealConst,"pi",pi); //设置常量；

销毁设置的常量：（1）使用函数 DeleteConstOrFunction；（2）重新初始化Forcal时由函数 InitForcal 销毁所有常量；（3）释放Forcal时由函数 FreeForcal 销毁所有常量。

1.16 删除常量或二级函数：DeleteConstOrFunction

bool _stdcall DeleteConstOrFunction(fcKEY Type,wchar_t *Name);

Type：常量或函数类型。只能取Key_IntConst（标识整数常量）、Key_RealConst（标识实数常量）、Key_ComplexConst（标识复数常量）、Key_IntFunction（标识整数二级函数）、Key_RealFunction（标识实数二级函数）、Key_ComplexFunction（标识复数二级函数）。这六个标识符的值在头文件FORCAL32W.h中定义。
Name：常量或函数名称，要符合Forcal标识符的命名规定。

返回值：操作成功返回true，否则返回false。

1.17 判断一个表达式是否有效：IsFor

bool _stdcall IsFor(wchar_t *ForName,fcKEY ForType,fcVOID nModule,void *hFor,void *Para,fcINT PareNum);

用法1：

ForName：表达式的名称，只能是简单名称，不能包含模块命名空间访问符::。
ForType：表达式的类型。只能取Key_IntFor（标识整数表达式）、Key_RealFor（标识实数表达式）、Key_ComplexFor（标识复数表达式）。这三个标识符的值在头文件FORCAL32W.h中定义。
nModule：表达式所属的模块。
hFor：表达式句柄，该句柄即编译表达式得到的表达式句柄，可用于表达式的计算。
Para：存放表达式自变量的数组指针。
ParaNum：表达式自变量的个数。
该函数返回true时表达式有效，返回false不是一个有效的表达式。

用法2：

ForName：ForName=NULL。
ForType：表达式的类型。只能取Key_IntFor（标识整数表达式）、Key_RealFor（标识实数表达式）、Key_ComplexFor（标识复数表达式）。这三个标识符的值在头文件FORCAL32W.h中定义。
nModule：表达式所属的模块。
hFor：表达式句柄，该句柄即编译表达式得到的表达式句柄，但必须由二级函数HFor获得，可用于表达式的计算。
Para：存放表达式自变量的数组指针。
ParaNum：表达式自变量的个数。
该函数返回true时表达式有效，返回false不是一个有效的表达式。

1.18 获得表达式信息：GetFor

bool _stdcall GetFor(wchar_t *ForName,fcKEY ForType,void *hFor,fcVOID &nModule,void *&myFor,void *&Para,fcINT &PareNum);

用法1：

ForName：所查询的表达式的名称。可以是简单名称，也可以是包含模块命名空间访问符::（该访问符可简化为一个或多个:）的复杂名称。
ForType：所查询的表达式的类型。如果是简单名称，只能取Key_IntFor（标识整数表达式）、Key_RealFor（标识实数表达式）、Key_ComplexFor（标识复数表达式） 。如果名称包含模块命名空间访问符::，只能取-Key_IntFor（标识整数表达式）、-Key_RealFor（标识实数表达式）、-Key_ComplexFor（标识复数表达式） 。标识符Key_IntFor、Key_RealFor、Key_ComplexFor的值在头文件Forcal32W.h中定义。
hFor：若hFor!=NULL，hFor必须是从二级函数获得的表达式句柄，不能使用编译表达式得到的表达式句柄。若hFor=NULL，只能获得0号模块中的表达式的信息，或者是一个全局表达式的信息。
nModule：该参数必须为变量，不能为常量。该参数返回一个表达式所属的模块。
myFor：该参数必须为变量，不能为常量。该参数返回一个表达式句柄，该句柄与编译表达式得到的表达式句柄的类型相同，可用于表达式的计算。
Para：该参数必须为变量，不能为常量。该参数返回一个存放表达式自变量的数组指针，可用于输入自变量。
ParaNum：该参数必须为变量，不能为常量。该参数返回表达式自变量的个数。当ParaNum=-1时表示有0个自变量，当ParaNum=0时表示有1个自变量，当ParaNum=1时表示有2个自变量，依次类推。
该函数返回true时查询成功，否则返回false。
注意：若hFor!=NULL，则只能在二级函数中使用该函数；若hFor=NULL，可在任何时候使用该函数。

用法2：

ForName：ForName=NULL。
ForType：表达式的类型。只能取Key_IntFor（标识整数表达式）、Key_RealFor（标识实数表达式）、Key_ComplexFor（标识复数表达式） 。标识符Key_IntFor、Key_RealFor、Key_ComplexFor的值在头文件Forcal32W.h中定义。
hFor：使用编译表达式得到的表达式句柄，但必须由二级函数HFor获得该句柄。
nModule：该参数必须为变量，不能为常量。该参数返回一个表达式所属的模块。
myFor：该参数必须为变量，不能为常量。该参数返回一个表达式句柄，该句柄即hFor，可用于表达式的计算。
Para：该参数必须为变量，不能为常量。该参数返回一个存放表达式自变量的数组指针，可用于输入自变量。
ParaNum：该参数必须为变量，不能为常量。该参数返回表达式自变量的个数。当ParaNum=-1时表示有0个自变量，当ParaNum=0时表示有1个自变量，当ParaNum=1时表示有2个自变量，依次类推。
该函数返回true时查询成功，否则返回false。

1.19 判断表达式的自变量是否重新赋值：ParaModify

bool _stdcall ParaModify(fcKEY ForType,void *vFor);

ForType：所查询的表达式的类型。只能取Key_IntFor（标识整数表达式）、Key_RealFor（标识实数表达式）、Key_ComplexFor（标识复数表达式）。这三个标识符的值在头文件FORCAL32W.h中定义。
vFor：编译表达式时得到的表达式句柄。
若表达式的自变量重新赋值，该函数返回true，否则返回false。
该函数不能判断是否对局部变量或全局变量进行了赋值。

在设计某些程序时，如果在表达式中不对自变量进行重新赋值，可以简化程序的设计，并可加快程序的执行速度。对表达式有此要求者可用该函数进行判断。

1.20 获得表达式中的字符串：GetForStr

void _stdcall GetForStr(void *hFor,wchar_t *&ForStr,fcINT &StrMin,fcINT &StrMax);

用法1：

hFor：从二级函数获得的表达式句柄。不能使用编译表达式得到的表达式句柄。
ForStr：该参数必须为变量，不能为常量。该参数返回一个字符串指针，表达式中的所有字符串的首地址都可由该指针加一个在[StrMin～StrMax]之间的正整数得到。表达式中的所有字符串都是连续存放的。
StrMin：该参数必须为变量，不能为常量。该参数返回ForStr中可用字符的最小偏移量。StrMin>0。
StrMax：该参数必须为变量，不能为常量。该参数返回ForStr中可用字符的最大偏移量。StrMax>0。
注意：只能在二级函数中使用该函数。

用法2：

hFor：hFor=NULL。
ForStr：该参数必须为变量，不能为常量。输入参数为由二级函数HFor获得的表达式句柄。该参数返回一个字符串指针，表达式中的所有字符串的首地址都可由该指针加一个 在[StrMin～StrMax]之间的正整数得到。表达式中的所有字符串都是连续存放的。
StrMin：该参数必须为变量，不能为常量。该参数返回ForStr中可用字符的最小偏移量。StrMin>0。
StrMax：该参数必须为变量，不能为常量。输入参数为表达式类型，只能取1（标识整数表达式）、2（标识实数表达式）、3（标识复数表达式）。该参数返回ForStr中 可用字符的最大偏移量。StrMax>0。
注意：函数工作失败时ForStr和StrMax返回0。

1.21 删除一个表达式：DeleteFor

void _stdcall DeleteFor(fcKEY ForType,void *hFor);

ForType：表达式类型。只能取Key_IntFor（标识整数表达式）、Key_RealFor（标识实数表达式）、Key_ComplexFor（标识复数表达式）。这三个标识符的值在头文件FORCAL32W.h中定义。
hFor：表达式句柄，该句柄为编译表达式时获得的句柄。

设有如下表达式定义：

> f(x:y,p,static,a1,a2,a3,free,b1,b2:c) = ..., free(p), ...;

当用函数 DeleteFor 删除该表达式时，将设置静态变量free=1，然后按缺省参数自动调用该表达式 ，但也可能由于某种原因表达式不可执行（父表达式或该表达式中所调用的二级函数被删除）。任何情况下，在static与free之间的静态变量 a1,a2,a3 标识的对象将被销毁。

若表达式中没有静态变量free，将不会自动调用该表达式，也不会自动销毁任何静态变量所标识的对象。

若使用二级函数free(p)对p做了标记，在用函数 DeleteFor 删除该表达式时，将销毁对象p。

注意1：用函数 DeleteFor 删除一个表达式时，只有用 InsertKeyP 函数注册的对象（用指针标识）才能被静态变量free或函数free所销毁。

注意2：为了使Forcal在删除表达式时能按正确的次序自动执行表达式，要遵守后编译的表达式要先删除的原则。但即便没有遵循“后进先出”的删除原则，也不会产生灾难性的后果。

1.22 插入一个键：InsertKey

int _stdcall InsertKey(char *KeyStr,fcINT ByteNum,fcKEY KeyType,void *KeyValue,void (_stdcall *DelKey)(void *),void *&NowKey);

KeyStr：键的名称。区分大小写，可包含任意字符，包括NULL（'\0'）。
ByteNum：键的长度。ByteNum>0。
KeyType：用户自定义键的类型。KeyType>=FC_Key_User（公有键、普通键） 或者 KeyType<=FC_PrivateKey_User（私有键）。约定用FC_Key_User 和FC_PrivateKey_User保存一些特殊的数据，作为多个函数、线程、动态库等之间联系的通道。FC_Key_User 和FC_PrivateKey_User在头文件FORCAL32W.h中定义。
KeyValue：键值。由用户定义，标识某种数据类型。
DelKey：删除该键值的函数指针。该函数由用户定义，但由Forcal调用，即：DelKey(KeyValue); 可将KeyValue删除。如果不需要Forcal删除该键值，该参数可设为NULL。
NowKey：该参数必须为变量，不能为常量。存在同名同类型的键时，如果 NowKey=0，不更新键值，该参数返回已存在的键值；如果 NowKey!=0，且KeyType<=FC_PrivateKey_User（私有键），同时新键和老键的删除函数不相同，不更新键值；其余情况下更新键值。即：

NowKey=0，不更新键值，NowKey返回已存在的键值。
NowKey!=0，且 KeyType>=FC_Key_User：更新键值。
NowKey!=0，且 KeyType<=FC_PrivateKey_User，新键和老键的删除函数相同：更新键值。
NowKey!=0，且 KeyType<=FC_PrivateKey_User，新键和老键的删除函数不相同：不更新键值，NowKey返回已存在的键值。

该函数返回值的意义如下：

0：插入成功。
1：已存在该键。参数 NowKey=0，没有更新键值，由参数 NowKey 返回已存在的键值。或者 NowKey!=0，KeyType<=FC_PrivateKey_User（私有键），且新键和老键的删除函数不相同，没有更新键值，参数 NowKey 返回了已存在的键值。
2：已存在该键。参数 NowKey!=0，当KeyType>=FC_Key_User时，更新了键值；或者当KeyType<=FC_PrivateKey_User（私有键），且新键和老键的删除函数相同时，更新了键值。
3：键的类型参数 KeyType 非法。
4：键值类型被唯一指定，删除该键值的函数指针 DelKey 非法，必须使用被唯一指定的函数指针。
5：内存分配失败。
6：插入失败，ByteNum<=0 或其他错误。

删除函数 InsertKey 插入的键：（1）使用函数 DeleteKey 或 DeletePrivateKey；（2）用函数 LockKeyType 解锁键时将删除所有指定类型的键值；（3）重新初始化Forcal时由函数 InitForcal 销毁所有键值；（4）释放Forcal时由函数 FreeForcal 销毁所有键值。

1.23 查找一个键：SearchKey

void * _stdcall SearchKey(char *KeyStr,fcINT ByteNum,fcKEY KeyType);

KeyStr：键的名称。区分大小写 ，可包含任意字符，包括NULL（'\0'）。
ByteNum：键的长度。ByteNum>0。
KeyType：用户自定义键的类型。KeyType>=FC_Key_User 或者 KeyType<=FC_PrivateKey_User。FC_Key_User和FC_PrivateKey_User在头文件FORCAL32W.h中定义。
如果查找成功，该函数返回键值的指针，否则返回false。

1.24 删除一个键：DeleteKey

bool _stdcall DeleteKey(char *KeyStr,fcINT ByteNum,fcKEY KeyType);

KeyStr：键的名称。区分大小写，可包含任意字符，包括NULL（'\0'）。
ByteNum：键的长度。ByteNum>0。
KeyType：用户自定义键的类型。该类型值的最小值为FC_Key_User。FC_Key_User在头文件FORCAL32W.h中定义。

返回值：操作成功返回true，否则返回false。

1.25 删除一个私有键：DeletePrivateKey

bool _stdcall DeletePrivateKey(char *KeyStr,fcINT ByteNum,fcKEY KeyType,void (_stdcall *DelKey)(void *));

KeyStr：键的名称。区分大小写，可包含任意字符，包括NULL（'\0'）。
ByteNum：键的长度。ByteNum>0。
KeyType：用户自定义键的类型。该类型值的最大值为FC_PrivateKey_User。FC_PrivateKey_User 在头文件FORCAL32W.h中定义。
DelKey：删除该键值的函数指针。该指针与插入键时用到的函数指针相同，否则不能删除键值。

返回值：操作成功返回true，否则返回false。

1.26 枚举指定键值类型所对应的所有字符串及键值：EnumKeyTypeValue

void _stdcall EnumKeyTypeValue(fcKEY KeyType,char *KeyStr,int n KeyStr Max,bool (_stdcall *GetKeyTypeValue)(char *,int ,void *));

KeyType：指定键的类型。KeyType>=FC_Key_User（公有键、普通键） 或者 KeyType<=FC_PrivateKey_User（私有键）。FC_Key_User和FC_PrivateKey_User在头文件FORCAL32W.h中定义。
KeyStr：存放键的名称的缓冲区。如果缓冲区不够用，仅存放键的名称的前面部分字符。
n KeyStr Max：存放键的名称的缓冲区的最大长度（n KeyStrMax>=1）。
GetKeyTypeValue：回调函数。每当找到指定键的类型对应的键时就调用该函数。该回调函数的说明格式如下：

bool _stdcall GetKeyTypeValue(char *KeyStr,int ByteNum,void *KeyValue);
KeyStr：键的名称。区分大小写 ，可包含任意字符，包括NULL（'\0'）。该函数被调用时，将自动在键的名称后面添加一个NULL（'\0'）。
ByteNum： 键的长度。同时指出键的名称的完整性。当 ByteNum=nKeyStrMax-1 时，键的名称可能不完整，仅存放了名称的前面部分字符。使用更大的缓冲区可使该函数返回键的完整名称。
KeyValue：键值。标识某种数据类型。
当 GetKeyTypeValue 返回true时，继续枚举其他键值，否则停止枚举。
注意：不要在该函数中调用除了GetRunErr()、TestRunErr()和SetRunErr()三个函数之外的Forcal输出函数。

1.27 锁定键的类型：LockKeyType

int _stdcall LockKeyType(fcKEY KeyType,void (_stdcall *DelKey)(void *),void (_stdcall *NullLock)(void));

KeyType：被锁定的键的类型。KeyType>=FC_Key_User（公有键、普通键） 或者 KeyType<=FC_PrivateKey_User（私有键）。FC_Key_User和FC_PrivateKey_User在头文件FORCAL32W.h中定义。
DelKey：删除键值的函数指针，用于标识要加锁的键。该函数由用户定义，但由Forcal调用。若 DelKey＝NULL，表示解锁指定的键。
NullLock：有效的函数指针，该函数仅在加锁或解锁键的类型时被调用一次，一般将该函数设置为空函数。解锁和加锁所用的 NullLock 函数必须相同。
如果加锁或解锁成功，该函数返回0，否则返回非0值。
说明：锁定键的类型后，该键只能存储一种数据类型，该数据类型用删除函数标识。如果没有锁定键的类型，则该键可以存储任意多种类型的数据。只有欲加锁的键没有使用，也没有存储任何类型的数据时，才能将该键加锁；解锁时将删除所有的键值，将键恢复为加锁前未用时的状态。通常在主调程序中锁定的键无需解锁，Forcal会自动删除键树中的所有数据。在动态库中锁定的键必须解锁，否则将导致不可预知的错误。

1.28 与Forcal交换信息：ExMsgWithForcal

void * _stdcall ExMsgWithForcal(int Type,void *hMsg,void *&Msg1,void *&Msg2);

Type：输入参数，信息交换的类型。
hMsg：输入参数，信息句柄，其意义取决于 Type。
Msg1：该参数必须为变量，不能为常量。输入值及返回值取决于 Type。
Msg2：该参数必须为变量，不能为常量。输入值及返回值取决于 Type。
返回值：NULL表示失败，非0值表示成功。成功时返回值的意义取决于 Type。
说明：与Forcal进行信息交换，向Forcal传送信息或者从Forcal获得信息。信息的类型及意义如下表所示：

Type | hMsg | Msg1 | Msg2 | 返回值 | 说明
1 | 从二级函数获得的表达式句柄 | 返回表达式类型： Msg1=1：整数表达式 Msg1=2：实数表达式 Msg1=3：复数表达式 | 返回表达式句柄 | 指向表达式名称的字符串指针 | 得到表达式名称、类型、句柄
2 | 编译表达式得到的表达式句柄 | 输入表达式类型： Msg1=1：整数表达式 Msg1=2：实数表达式 Msg1=3：复数表达式 | 无意义 | 指向表达式名称的字符串指针 | 得到表达式名称
3 | 从二级函数获得的表达式句柄 | 返回表达式类型： Msg1=1：整数表达式 Msg1=2：实数表达式 Msg1=3：复数表达式 | 返回表达式句柄 | 表达式模块号 | 得到表达式模块号、类型、句柄
4 | 编译表达式得到的表达式句柄 | 输入表达式类型： Msg1=1：整数表达式 Msg1=2：实数表达式 Msg1=3：复数表达式 | 无意义 | 表达式模块号 | 得到表达式模块号
5 | 无意义 | 无意义 | 无意义 | 无意义 | 未使用
6 | 无意义 | 无意义 | 无意义 | 无意义 | 未使用
7 | 字符串指针 | 无意义 | 无意义 | 指向整数常量的指针 | 得到Forcal中的整数常量
8 | 字符串指针 | 无意义 | 无意义 | 指向实数常量的指针 | 得到Forcal中的实数常量
9 | 字符串指针 | 无意义 | 无意义 | 指向复数常量的指针 | 得到Forcal中的复数常量
10 | 模块号 | 无意义 | 无意义 | 模块中的表达式数目 | 得到模块中的表达式数目
11 | 无意义 | 无意义 | 无意义 | 无意义 | 未使用
12 | 当hMsg非0时编译未说明的模块变量 | 无意义 | 无意义 | 无意义 | 设置是否编译未说明的模块变量，参考[注1]
13 | 无意义 | 无意义 | 无意义 | 无意义 | 未使用
14 | 无意义 | 无意义 | 无意义 | 无意义 | 未使用
15 | 从二级函数获得的表达式句柄 | Msg1!=0：二级函数将返回一个临时对象 Msg1==0：二级函数不返回临时对象 | 无意义 | 返回非0表示操作成功，只有在oo函数中试图返回临时对象时才会操作成功 | 在整数或实数二级函数中通知Forcal，二级函数是否返回临时对象[注2]。二级函数默认将返回一个值，即Msg1=0。
16 | 从二级函数获得的表达式句柄 | Msg1=0或指向临时对象的指针(fcIFOR *) | 二级函数存放参数的数组指针，即二级函数第二个参数 | 返回非0表示操作成功 | 在二级函数内首次调用时Msg1=0，通知Forcal做好准备。Msg1!=0时保存二级函数申请的临时对象[注2]，以便oo函数可自动销毁它。
17 | 从二级函数获得的表达式句柄 | 指向临时对象的指针(fcIFOR *) | 无意义 | 返回非0表示操作成功 | 销毁在当前二级函数中已通过Type=16注册保存但不想再用的临时对象[注2][注3]。

[注1]：在用函数 IntCom、RealCom 或 ComplexCom 编译表达式时，缺省情况下，所有用到的模块变量必须预先定义。可用函数 ExMsgWithForcal（Type=12，hMsg非0）通知编译器使用未定义的模块变量（若一个标识符没有定义，且不是常量，将被解释为模块变量）；也可用函数 ExMsgWithForcal（Type=12，hMsg为0）通知编译器取消这种设置。无论表达式编译是否成功，将恢复缺省设置，即：所有用到的模块变量必须预先声明。

[注2]：临时对象都是直接或间接由函数 InsertKeyP 创建的，且都用指针标识。

[注3]：如果在二级函数设计中通过Type=16注册保存 了临时对象，当打算不再使用该对象时，可用Type=17销毁该对象，Forcal将调用合适的函数销毁该临时对象，并取消原先的注册标识。当然你可以自行销毁该对象，但Forcal还将进行销毁该对象的尝试；或者你可以等待垃圾收集器回收该对象。

1.29 插入一个指针键：InsertKeyP

int _stdcall InsertKeyP(char *KeyStr,fcINT ByteNum,fcKEY KeyType,void *KeyValue,void (_stdcall *DelKey)(void *),FcOperator oo,void (_stdcall *SignKey)(void *),unsigned int mode,void *&NowKey);

KeyStr：键的名称。区分大小写，可包含任意字符，包括NULL（'\0'）。 通常键的名称是一个指针（标识一个对象）的地址，例如对于指针 void *me，KeyStr 为(char *)&me。
ByteNum：键的长度。ByteNum>0。如果键的名称是一个指针，在32位平台上，ByteNum=4。
KeyType：用户自定义键的类型。KeyType>=FC_Key_User（公有键、普通键） 或者 KeyType<=FC_PrivateKey_User（私有键）。约定用FC_Key_User和FC_PrivateKey_User保存一些特殊的数据，作为多个函数、线程、动态库等之间联系的通道。FC_Key_User和FC_PrivateKey_User在头文件FORCAL32W.h中定义。
KeyValue：键值。由用户定义，标识某种数据类型。
DelKey：删除该键值的函数指针。该函数由用户定义，但由Forcal调用，即：DelKey(KeyValue); 可将KeyValue删除。如果不需要Forcal删除该键值，该参数可设为NULL。
oo：FcOperator 类型的函数指针，用于对象（用指针标识）的运算符重载，必须提供该参数。参考[注1]。
SignKey：标记子键值（对象）的函数指针 ，所有标记过的子对象都是有效（可达）对象，不会被垃圾收集器所回收。该函数由用户定义，但由Forcal调用，即：SignKey(KeyValue); KeyValue若包含另外的对象，则调用该函数可对其他对象做标记，应在函数 SignKey 中对每一个对象调用函数SignGoodObj做标记。 若 KeyValue 不能包含子对象，该参数设为NULL。参考[注2]。
mode：该参数必须为变量，不能为常量。该参数指出键值（对象）的属性。mode 共32位，从左往右，第1位必须为0；第2位表示该对象是否会包含子对象（当第2位为1且提供了函数 SignKey 时，SignKey 将被自动调用；该位的值可由二级函数SaveSubObj重新设置）；其他位必须为0。
NowKey：该参数必须为变量，不能为常量。存在同名同类型的键时，如果 NowKey=0，不更新键值，该参数返回已存在的键值；如果 NowKey!=0，且KeyType<=FC_PrivateKey_User（私有键），同时新键和老键的删除函数不相同，不更新键值；其余情况下更新键值。即：

NowKey=0，不更新键值，NowKey返回已存在的键值。
NowKey!=0，且 KeyType>=FC_Key_User：更新键值。
NowKey!=0，且 KeyType<=FC_PrivateKey_User，新键和老键的删除函数相同：更新键值。
NowKey!=0，且 KeyType<=FC_PrivateKey_User，新键和老键的删除函数不相同：不更新键值，NowKey返回已存在的键值。

该函数返回值的意义如下：

0：插入成功。
1：已存在该键。参数 NowKey=0，没有更新键值，由参数 NowKey 返回已存在的键值。或者 NowKey!=0，KeyType<=FC_PrivateKey_User（私有键），且新键和老键的删除函数不相同，没有更新键值，参数 NowKey 返回了已存在的键值。
2：已存在该键。参数 NowKey!=0，当KeyType>=FC_Key_User时，更新了键值；或者当KeyType<=FC_PrivateKey_User（私有键），且新键和老键的删除函数相同时，更新了键值。
3：键的类型参数 KeyType 非法。
4：键值类型被唯一指定，删除该键值的函数指针 DelKey 非法，必须使用被唯一指定的函数指针。
5：内存分配失败。
6：插入失败，其他类型的指针键已经存在，或者 ByteNum<=0，或者其他错误。

删除函数 InsertKeyP 插入的指针键：（1）使用函数 DeleteKey 或 DeletePrivateKey；（2）用函数 LockKeyType 解锁键时将删除所有指定类型的键值；（3）系统自动销毁oo函数中的临时对象（临时对象都是用指针标识的）时，将设置 theOperator=0 销毁该指针键；（4）垃圾收集器GC将直接调用函数 DelKey 删除该指针键；（5）重新初始化Forcal时由函数 InitForcal 销毁所有键值；（6）释放Forcal时由函数 FreeForcal 销毁所有键值。

说明：

（1）只有用 InsertKeyP 函数注册的对象（用指针标识）才能在oo函数中进行运算符重载。

（2）只有用 InsertKeyP 函数注册的对象（用指针标识）才能被垃圾收集器回收。

（3）用函数 DeleteFor 删除一个表达式时，只有用 InsertKeyP 函数注册的对象（用指针标识）才能被静态变量free或函数free所销毁。

设有如下表达式定义：

> f(x:y,p,static,a1,a2,a3,free,b1,b2:c) = ..., free(p), ...;

当用函数 DeleteFor 删除该表达式时，将设置静态变量free=1，然后按缺省参数自动调用该表达式 ，但也可能由于某种原因表达式不可执行 （父表达式或该表达式中所调用的二级函数被删除）。任何情况下，在static与free之间的静态变量 a1,a2,a3 标识的对象将被销毁。

若表达式中没有静态变量free，将不会自动调用该表达式，也不会自动销毁任何静态变量所标识的对象。

若使用二级函数free(p)对p做了标记，在用函数 DeleteFor 删除该表达式时，将销毁对象p。

[注1]：在Forcal脚本中，函数oo{..., a+b, ...}中的运算符将被重载（该函数不可嵌套使用），运算符的第一操作数（例如a+b中的a）将被看作是一个指针（指向一个对象），Forcal在运算时将查找该指针的运算符重载函数，如果找到就调用该函数，否则将返回一个运行错误。有些重载运算符会返回一个临时对象，该临时对象在生命期结束时自动销毁。

运算符重载函数 FcOperator 函数格式如下：

> //m指出数组Para的参数个数（也即操作数的个数，0表示1个，1表示2个，以此类推），数组Para的类型取决于iForType：iForType=1为整数fcIFOR类型；iForType=2为实数double类型。
> //hFor为调用该函数的表达式句柄（与编译表达式时返回的表达式句柄并不相同 ，如果有意义，与二级函数中的表达式句柄相同）。
> //reVal为指向返回值的指针（必须返回一个值），指针的类型取决于iForType：iForType=1为整数fcIFOR类型；iForType=2为实数double类型。
> //theOperator指出运算符的类型或操作类型：+、-、*、/、^、... ...。
> //返回值=0：未定义；返回值=1：临时对象；返回值=2：当前对象；返回值=3：逻辑值；返回值=其他值：未定义。
> int (_stdcall *FcOperator)(fcINT m,void *Para,void *hFor,void *reVal,int iForType,int theOperator);
> int _stdcall oo(fcINT m,void *Para,void *hFor,void *reVal,int iForType,int theOperator)
> {
> //... ...
> switch(theOperator)
> {
> case 0: //销毁临时对象
> //... ...
> case 1: //将临时对象转为一般对象
> //... ...
> case 2: //将一般对象转为临时对象
> //... ...
> case 4: //重载运算符+
> //... ...
> case 5: //重载运算符-
> //... ...
> ... ...
> }
> }

Forcal中可重载的运算符、函数及操作如下表：

theOperator | 运算符 | 功 能 | 参数个数m | 默认返回值 | 说 明
0 |  | 销毁临时对象 | 0 | 无意义 | 该临时对象的生命期已结束，需要销毁该对象；通常用函数 DeleteKey 或 DeletePrivateKey 销毁该对象；也可以将该对象放到缓冲区中暂存，以提高运行效率。注意不要使用 hFor 参数，该参数无意义。
1 | to(p) | 将临时对象转为一般对象 | 0 | 当前对象 | 临时对象指由oo函数自动销毁的对象，否则为一般对象。当在脚本中使用函数to(p)时，将收到该通知。
2 | oofree(p) | 将一般对象转为临时对象 | 0 | 当前对象 | 当在脚本中使用函数oofree(p)时，将收到该通知。
3 | 未使用 |  |  |  |
4 | + | 加 | 1 | 临时对象 | 双目运算符。
5 | - | 减 | 1 | 临时对象 | 双目运算符。
6 | * | 乘 | 1 | 临时对象 | 双目运算符。
7 | / | 除 | 1 | 临时对象 | 双目运算符。
8 | % 或 ^ | 求模 或 乘方 | 1 | 临时对象 | 双目运算符。运算符%用在整数表达式中；运算符^用在实数表达式中。
9 | - | 负 | 0 | 临时对象 | 单目运算符。
10 | ++ | 前置自增 ++i | 0 | 当前对象 | 单目运算符。
11 | ++ | 后置自增 i++ | 0 | 临时对象 | 单目运算符。 申请临时变量，将输入参数赋值给临时变量，然后将输入参数增1，返回临时变量。
12 | -- | 前置自减 --i | 0 | 当前对象 | 单目运算符。
13 | -- | 后置自减 i-- | 0 | 临时对象 | 单目运算符。 申请临时变量，将输入参数赋值给临时变量，然后将输入参数减1，返回临时变量。
14 | > | 大于 | 1 | 逻辑值 | 双目运算符。
15 | >= | 大于等于 | 1 | 逻辑值 | 双目运算符。
16 | < | 小于 | 1 | 逻辑值 | 双目运算符。
17 | <= | 小于等于 | 1 | 逻辑值 | 双目运算符。
18 | == | 等于 | 1 | 逻辑值 | 双目运算符。
19 | != | 不等于 | 1 | 逻辑值 | 双目运算符。
20 | & | 与 | 1 | 逻辑值 | 双目运算符。
21 | | | 或 | 1 | 逻辑值 | 双目运算符。
22 | ! | 非 | 0 | 逻辑值 | 单目运算符。
30 | 内部使用 | 在o函数中调用外部函数 |  |  |
31 | o{...} | 重载函数 | 不确定 | 被忽略 | 该函数一般用于获得对象信息，至少需要一个参数，第一个参数即要操作的对象。可接受任意多个参数。 由于返回值被忽略，若函数o{...}要返回临时对象，必须用函数 ExMsgWithForcal（Type为15）通知Forcal。
32 | oset{...} | 重载函数 | 不确定 | 被忽略 | 该函数一般用于对象赋值，至少需要一个参数，第一个参数即要赋值的对象。可接受任意多个参数。 由于返回值被忽略，若函数oset{...}要返回临时对象，必须用函数 ExMsgWithForcal（Type为15）通知Forcal。
33 | oget{...} | 重载函数 | 不确定 | 被忽略 | 该函数一般用于获得对象的值，至少需要一个参数，第一个参数即要操作的对象。可接受任意多个参数。 由于返回值被忽略，若函数oget{...}要返回临时对象，必须用函数 ExMsgWithForcal（Type为15）通知Forcal。

[注2]：标记子键值（对象）的函数 SignKey 格式如下：

> void _stdcall SignKey(void *me)
> {
> ...
> SignGoodObj(p); //p是me的子对象，用函数 SignGoodObj标记该子对象
> ...
> }

1.30 垃圾收集时标记一个指针键（对象）：SignGoodObj

bool _stdcall SignGoodObj(void *me);

通知Forcal的垃圾收集器，me是一个可达的（有效的）对象。标记成功返回true。

1.31 垃圾收集：GC

int _stdcall GC(int n);

立即启动Forcal垃圾收集器，n设为0，返回值无意义。Forcal使用标记清除算法进行垃圾回收。只有用 InsertKeyP 函数注册的对象（用指针标识）才能被垃圾收集器回收。

在Forcal中，一个对象用一个指针标识，在32位平台上，一个指针是存放在一个数（整数、实数或复数）的前4个字节中，此时，我们也称这个数为指向该对象的指针。若Forcal系统中的静态变量、模块变量、全局变量以及正在运行的表达式的数据区（自变量、动态变量及数据堆栈）中存在一个数指向一个对象时，该对象是有效的，否则视为垃圾对象，会被垃圾收集器所回收。

一个对象的子对象能否被垃圾收集器回收，可参考 InsertKeyP 函数 的 SignKey 参数和mode参数的说明。所有用函数 SignKey 标记过的对象都是有效（可达）对象，不会被垃圾收集器所回收。

由于只要有一个指针（直接或间接）指向某对象，该对象就不会被垃圾收集器回收，故若要确保立即销毁某对象，应使用delete之类的专用函数，而不要依赖垃圾收集器。

2 简单计算 [返回页首]

2.1 使用FORCAL进行简单的整数计算

1、用InitForcal()初始化Forcal；
2、用 IntCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,fcIFOR *&Para,fcINT &ErrBegin,fcINT &ErrEnd)编译表达式，模块号nModule根据实际情况设置；
3、用 IntCal(void *hFor,fcIFOR *d)计算表达式；
4、用FreeForcal()释放Forcal。

2.2 使用FORCAL进行简单的实数计算

1、用InitForcal()初始化Forcal；
2、用 RealCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,double *&Para,fcINT &ErrBegin,fcINT &ErrEnd)编译表达式，模块号nModule根据实际情况设置；
3、用 RealCal(void *hFor,double *d)计算表达式；
4、用FreeForcal()释放Forcal。

2.3 使用FORCAL进行简单的复数计算

1、用InitForcal()初始化Forcal；
2、用 ComplexCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,_complex *&Para,fcINT &ErrBegin,fcINT &ErrEnd)编译表达式，模块号nModule根据实际情况设置；
3、用 ComplexCal(void *hFor,_complex *d)计算表达式；
4、用FreeForcal()释放Forcal。

2.4 使用FORCAL进行简单的实数、整数和复数计算

1、用InitForcal()初始化Forcal。

2、编译表达式

用 IntCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,fcIFOR *&Para,fcINT &ErrBegin,fcINT &ErrEnd)编译整数表达式，模块号nModule根据实际情况设置；
用 RealCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,double *&Para,fcINT &ErrBegin,fcINT &ErrEnd)编译实数表达式，模块号nModule根据实际情况设置；
用 ComplexCom(wchar_t *ForStr,fcVOID nModule,void *&hFor,fcINT &nPara,_complex *&Para,fcINT &ErrBegin,fcINT &ErrEnd)编译复数表达式，模块号nModule根据实际情况设置；

3、计算表达式

用 IntCal(void *hFor,fcIFOR *d)计算整数表达式；
用 RealCal(void *hFor,double *d)计算实数表达式；
用 ComplexCal(void *hFor,_complex *d)计算复数表达式；

4、用 FreeForcal() 释放Forcal。

3 FORCAL二级函数设计 [返回页首]

以设计实数二级函数为例进行说明，复数、整数的二级函数设计与此类似。

二级函数的一般形式是：

double _stdcall Fun2Name(fcINT n,double *d,void *hFor);

相应地，在表达式中二级函数的使用形式是：

Fun2Name(X1,X2,... ...,Xn)

数组d中依次存放各个自变量 X1,X2,... ...,Xn；整数n指出自变量的个数，其大小为自变量的个数减1。

hFor 是由Forcal传送过来的调用该二级函数的表达式的句柄，该句柄与编译表达式所获得的句柄不同。由该句柄可以获得更多的信息。

以下是二级函数设计中可能用到的FORCAL输出函数及注意事项：

1、用 GetForStr(...)函数获得表达式中的字符串。
2、用GetFor(...)函数获得各个表达式并进行计算。
3、用 TestRunErr(void)测试是否有运行错误。由于FORCAL允许另一个线程修改运行时的出错状态，以便退出FORCAL运行，因此在二级函数设计中，在可能导致无限循环的循环体内，要使用TestRunErr()函数检测运行错误，如果检测到任何错误，就退出该二级函数。
4、用 SetRunErr(...)设置外部函数的运行错误。
5、Forcal不鼓励在二级函数中抛出异常，二级函数中产生的异常最好在本函数内检测，然后转换成Forcal运行错误。如果在二级函数中抛出了异常，通常主调程序需要重新初始化Forcal。 实际上，如果进行混合语言编程，二级函数中抛出异常可能导致不可预知的错误。

4 FORCAL的基本用法 [返回页首]

尽管FORCAL表达式的用法可以非常灵活，但以下两种用法可能是最基本的。

4.1 动态使用字符串表达式

程序在运行过程中，动态地使用字符串表达式并进行计算。例如根据需要计算字符串数学表达式的值，或者执行一定的命令等。

在这种方法中，对于一种特定的运算，仅在需要的时候使用FORCAL，而其他的代码要用C/C++或FORTRAN等高级语言来写。

用这种方法得到的数值计算程序，其执行速度约为C/C++或FORTRAN执行速度的50%左右。但程序一经生成，即可脱离高级语言编译器独立运行，象使用Matlab和Mathematics一样方便。

4.2 按次序依次执行表达式进行运算

这是用FORCAL进行编程的一种方式。程序文件中的表达式用分隔符（通常用分号“;”）分隔，按某种次序依次编译各个表达式，编译成功后，按编译次序依次执行各个表达式。

无论哪种使用方式，在编译表达式前后和计算表达式前后都要检查FORCAL运行错误。

Forcal始终记着编译过的表达式，这使得同名的表达式将不能再被编译，除非你释放了该表达式所占据的空间。可以用 DeleteFor(...)函数释放一个表达式所占据的空间。如果使用初始化函数InitForcal()，将连同注册的二级函数、常量、申请的数组、注册的所有自定义数据等一并删除。

5 Forcal软件组成与使用 [返回页首]

Forcal由核心库Forcal32W.dll和一组Forcal扩展动态库组成。实际应用中可以单独使用Forcal32W.dll，也可以使用Forcal32W.dll与各种扩展库的组合。
5.1 仅使用Forcal32W.dll
程序在运行过程中，动态地使用字符串表达式并进行计算。例如根据需要计算字符串数学表达式的值，或者执行一定的命令等。
在这种方法中，对于一种特定的运算，仅在需要的时候使用FORCAL，而其他的代码要用C/C++或FORTRAN等高级语言来写。
用这种方法得到的数值计算程序，其执行速度约为C/C++或FORTRAN执行速度的50%左右。但程序一经生成，即可脱离高级语言编译器独立运行，像使用Matlab和Mathematics一样方便。
5.2 使用Forcal扩展数据类型
需要加载FcData32W，该库是Forcal数据扩展动态库。在FcData中可以创建使用任意的数据类型，但FcData中定义的直接对数据进行计算或操作的函数较少，FcData主要向Forcal提供更加丰富的数据类型，对FcData数据的计算或操作更多地依赖其他动态库的函数进行。因而，在加载FcData32W的同时，很可能还要加载其他一些对FcData数据操作的动态库。例如：FcString32W或XSLSF32W等等。
5.3 使用Forcal模块化编译功能
需要加载MForcalW。MForcalW对Forcal源程序进行模块化编译，能够编译运行具有固定格式的源程序（字符串表达式），源程序中可以使用C++风格的注释。
5.4 使用Forcal模块并使用Forcal扩展数据类型
同时加载MForcalW和FcData32W，这两个库相互独立，因而先加载哪个都可以。一般还要加载其他一些对FcData数据操作的动态库。例如：FcString32W或XSLSF32W等等。
5.5 使用Forcal用于某种特殊目的
举例来说，如果绘制OpenGL图形，须加载OpenFcGl32W，这是一个基于OpenGL的进行图形绘制的动态库。如果进行数值计算，须加载XSLSF32W，这是 一个数值计算动态库。以此类推。
一般用于某种特殊目的的动态库需要FcData32W的支持，而为了方便对源代码的模块化编译则需要MForcalW的支持，因而一般也少不了这两个动态库。
5.6 仍不能满足要求
需要自己编写Forcal扩展动态库。也不一定局限于动态库的形式，对Forcal进行功能扩展可以在主程序或任意的模块中进行。只要获得一个Forcal32W.dll句柄，就可以对Forcal进行任意的功能扩展。
对Forcal的功能扩展没有任何限制，FcData32W、MForcalW等所有这些动态库都是通过Forcal32W.dll的输出函数实现的。Forcal对功能扩展提供了很好的支持，以充分满足各种实际需要。对Forcal的功能扩展不会降低Forcal的编译和运行效率。发挥您的想象力，Forcal会使您的程序获得非凡的功能。

6 用FORCAL保存和检索数据 [返回页首]

Forcal用多键值字符串键树保存和检索数据信息，具有存储效率高、查询速度快的优点。用户可将自定义的数据信息保存到该键树中，并与Forcal融为一体。用户可通过InsertKey(...)、SearchKey(...)、DeleteKey(...)、DeletePrivateKey(...)等函数往键树中插入、查询和删除数据信息。

版权所有© Forcal程序设计 2002-2011，保留所有权利
E-mail: forcal@sina.com QQ：630715621
最近更新: 2011年05月03日