目 录
1、OpenForcal的输出函数
2、如何加载使用OpenForcal
3、二级函数
4、模块源文件
5、例子
注意:本文假定您使用过forcal v7.0,如果您还没有使用过,请先阅读forcal v7.0使用说明。
OpenForcal能够编译运行具有固定格式的源程序(字符串表达式),源程序中可以使用C++风格的注释。
OpenForcal使得Forcal能更好地用在没有指针的编程语言中,例如 VB 。
1、OpenForcal的输出函数 [目录]
OpenForcal是一个标准的Forcal扩展动态库,共输出了六个函数,其中一个即标准的Forcal扩展动态库输出函数ForcalDll(...)。在加载OpenForcal并初始化之后,也可以用SearchKey("UseForcal",FC_PrivateKey_User);、SearchKey("ComFor",FC_PrivateKey_User);、SearchKey("ExeFor",FC_PrivateKey_User);和SearchKey("DeleteModule",FC_PrivateKey_User);、SearchKey("ExeForcalDll",FC_PrivateKey_User);获得另外五个函数的句柄。这五个函数的功能和用法如下:
1.1 申请进入或退出Forcal工作区:int _stdcall UseForcal(int iUse);
iUse=1时,表示要申请使用Forcal,若函数返回值
UseForcal=0:申请成功;UseForcal=1:申请不成功,某线程正在使用Forcal,稍后再进行申请;UseForcal=-1:申请不成功,表示应用程序要释放Forcal,因此要做好退出前的准备工作。
iUse=2时,表示要申请使用Forcal,如果其他线程正在使用Forcal,函数不返回,进行等待,直至申请成功。若函数返回值
UseForcal=0:申请成功;UseForcal=1:申请不成功,线程本身正在使用Forcal,不能重复进行申请;UseForcal=-1:申请不成功,表示应用程序要释放Forcal,因此要做好退出前的准备工作。
iUse=0时,表示要归还Forcal的使用权,函数返回值无意义。
iUse=3时,设置安全标志,表示Forcal运行正常,函数返回值无意义。 一般在二级函数中设置该标志,当该函数在较长时间内运行时,可用此标志通知Forcal,此时的运行是正常的,没有陷入无限循环等情况。
iUse=4时,取消安全标志,表示Forcal运行处于不可控制阶段(有陷入无限循环的可能),函数返回值无意义。
iUse=5时,查询安全标志,UseForcal=0:运行正常;UseForcal=1:运行情况无法预测(有陷入无限循环的可能),这是Forcal运行的一般情况。
注意:Forcal是极为重要而有限的资源,用完后要及时归还。UseForcal(1)(或者UseForcal(2))和UseForcal(0)必须成对使用,注意不能在二级函数中使用该功能,因为二级函数本身就是在Forcal工作区中运行的。UseForcal(3)和UseForcal(4)也要成对使用,且一般在二级函数中使用。
可以在主调程序或Forcal扩展动态库中使用该函数。在多线程程序中,必须通过申请Forcal工作区的方法来使用Forcal,因为在任何时刻,只允许一个线程使用Forcal(GetRunErr()、TestRunErr()和SetRunErr()三个函数除外)。
1.2 编译源程序:int _stdcall ComFor(char *FcStr,char *ModuleName,int key,void (_stdcall *DeleteMe)(void *),void *&hModule,fcINT &err1,fcINT &err2);
编译时,将所有源程序中的表达式编译为同一模块。以~开头的表达式被编译为正模块号表达式,能被其他模块访问到,其余的表达式均被编译为负模块号表达式,其他模块无法访问。所有模块的模块号由该函数自动指定(起始模块号为1,以后不断递增,但不一定连续,因为每次执行该函数,不管是否执行成功,模块号均加1),不会重复,也不会被编译为0#模块。任何时候,可用InsertKey("OFC_NewModuleId",FC_Key_User,NewModuleId,NULL,v)传送给OpenForcal一个起始模块号(必须大于0),以后的模块号将在该模块号的基础上递增,从而改变模块号序列。若要自己指定模块号,则每次编译源程序前,均指定一个起始模块号。
FcStr:指向源程序字符串的指针;
ModuleName:模块的名称。
key:模块的键值。
DeleteMe:删除模块的函数指针。当key>=FC_Key_User时,由OpenForcal指定删除函数,此值无意义;当KeyType<=FC_PrivateKey_User时,由用户定义删除函数,格式如下:
void _stdcall DeleteMe(void *me) //删除模块。用户不能调用该函数,该函数只能由OpenForcal调用。
{
DeleteModule(me);
//该函数由SearchKey("DeleteModule",FC_PrivateKey_User);获得。
}
hModule:模块的句柄,用于执行该模块。
err1和err2:返回编译出错位置,该值是否有意义取决于函数的返回值(返回值为-1、0、1、3时无意义)。
该函数返回值的意义如下:
-7:递归调用指定的模块。(由OfcLoadModule(...)函数判断,见本文第2部分:如何加载使用OpenForcal)
-6:找不到指定的模块。(由OfcLoadModule(...)函数判断,见本文第2部分:如何加载使用OpenForcal)
-5:缺少模块名。(当模块键值Key非法或删除模块的函数指针DeleteMe非法时也返回该值,由程序员处理,不返回给用户)
-4:注释符号/* ... */不成对。
-3:未使用模块编译功能,不能编译指定的模块。
-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:***未定义***!
31:***未定义***!
32:调用整数表达式时参数不匹配!
33:调用实数表达式时参数不匹配!
34:调用复数表达式时参数不匹配!
35:自变量重名!
36:因检测到运行错误而退出!
注意:编译后的模块放在Forcal键树中,因此用户删除一个模块就是从Forcal键树中删除一个键。当模块键值key>=FC_Key_User时,用DeleteKey(ModuleName,key)删除该模块;当模块键值key<=FC_PrivateKey_User时,用DeletePrivateKey(ModuleName,key,DeleteMe)删除该模块。
模块源文件的格式如下:
//单行注释:模块名:myModule
/*
多行注释:在同一模块源文件中的所有表达式属于同一个模块;
多行注释:以~开头的表达式的模块号为正,可被其他模块的表达式所访问;
多行注释:不以~开头的表达式的模块号为负,只能被该模块的表达式所访问。
*/
i:a(x)=10+x;
//模块号为负,只能被该模块的表达式所访问;
c:b()=100+100i; //模块号为负,只能被该模块的表达式所访问;
~_c(x)=x-5;
//模块号为正,任意模块包括本模块均可访问;
~_f(x)=a(x)+b();
//模块号为正,任意模块包括本模块均可访问;
~i:g(x)=a(x)+_c(x);
//模块号为正,任意模块包括本模块均可访问;
#USE# Module1;
//使用模块Module1;
~_ff(5)+_gg(6); //函数_ff()和_gg()在模块Module1中定义;
在其他模块中使用该模块的格式如下:
#USE# myModule;
//关键字USE必须为大写,myModule是模块名称;
~_f(2)+g(3);
//调用myModule模块中定义的函数;
1.3 执行程序:void _stdcall ExeFor(void *vModule,void (_stdcall *outl)(long ),void (_stdcall *outd)(double ),void (_stdcall *outc)(_complex ));
vModule:编译源程序时得到的模块的句柄。
outl(输出整数表达式的值)、outd(输出实数表达式的值)、outc(输出复数表达式的值):这三个回调函数在执行表达式时被调用,输出信息,这三个参数也可设为NULL。
注意1:该函数只执行模块中的无参表达式。
注意2:当Forcal键树中有一个被锁定为字符串的键给出运行错误说明时,OpenForcal将试图找出出现运行错误的原因。请参考“2.2 OpenForcal使用说明”部分。
1.4 删除模块:void _stdcall DeleteModule(void *me);
该函数不能由用户直接调用,只能用在用户自定义的删除模块的函数中。请参考1.2 编译源程序。
用户删除模块时,可直接从Forcal键树中删除。请参考1.2 编译源程序。
1.5 执行Forcal动态库的输出函数ForcalDll:int _stdcall ExeForcalDll(int (_stdcall *pForcalDll)(HINSTANCE ,bool ),HINSTANCE hFC,bool bInit);
pForcalDll:指向Forcal扩展动态库输出函数ForcalDll的指针,该指针通常在加载Forcal扩展动态库后通过GetProcAddress(hFcDll,"ForcalDll")函数获得。
hFC:Forcal.dll的句柄。
bInit=true:初始化动态库,bInit=false:释放动态库。
说明:该函数通常用在没有指针的编程语言中,例如 VB 。
2 如何加载使用OpenForcal [目录]
2.1 OpenForcal的加载及初始化
OpenForcal是一个标准的Forcal扩展动态库,其加载和初始化的方法与其他的Forcal扩展动态库相同,但为了使其他的Forcal扩展动态库能够使用OpenForcal,OpenForcal应紧跟在Forcal之后加载。OpenForcal应在Forcal卸载之前卸载。
2.2 OpenForcal使用说明
在主调程序中可以设置一个全局变量bool OFC_Quit=false;。然后将该变量的地址用InsertKey("OFC_Quit",FC_PrivateKey_User,&OFC_Quit,DelKey,v)传送给Forcal。当OFC_Quit=true时将退出OpenForcal。规定仅在主线程中设置和修改该变量,但该变量可被任一线程所访问。
在主调程序或任一个Forcal扩展动态库中均可以设置一个函数int _stdcall OfcLoadModule(char *ModuleName);。然后将该函数的地址用InsertKey("OFC_LoadModule",FC_Key_User,OfcLoadModule,NULL,v)传送给Forcal,这样OpenForcal就可以编译模块(每当遇到#USE# myModule; 语句,就将myModule传送给该函数进行处理);若不传送该函数,OpenForcal就不能编译模块。该函数接受一个模块名,然后返回该模块的编译代码,代码的意义与函数ComFor(...)返回的编译代码意义相同(实际上,只有-6和-7两个代码须由该函数处理)。该函数必须能判断是否进行了模块的递归调用。任一线程均可设置该函数。
在主调程序或任一个Forcal扩展动态库中均可以设置一个函数void _stdcall DllMessage(char *);。然后将该函数的地址用InsertKey("DllMessage",FC_Key_User,DllMessage,NULL,v)传送给Forcal。约定所有Forcal扩展动态库都使用该函数发送信息。任一线程均可根据需要设置该函数。
在主调程序中可用Forcal的加锁函数LockKeyType锁定一个键的类型为字符串,然后将被锁定的键KeyType用InsertKey("OFC_LockKeyErrStr",FC_PrivateKey_User,KeyType,DelKey,v)传送给Forcal,同时约定将删除键值的函数DeleteStr用InsertKey("OFC_DeleteStr",FC_PrivateKey_User,DeleteStr,DelKey,v)传送给Forcal,这样OpenForcal就可以给出更详细的运行错误说明。实际上,当出现运行错误时,OpenForcal查找与出错函数名相同的键,键的类型为KeyType,其键值为一个字符串,该字符串包含了出错原因。该字符串格式如下:
#-2:...; #-1:...; #1:...; #2:错误2; #3:...; ... ...
例如,当运行错误代码为2时,将输出“#2:错误2;”中的“错误2”。每一个错误描述以“#”开头,后面紧跟错误代码和一个冒号“:”,冒号“:”后为错误说明,错误说明以分号“;”结尾。
请参考“1.3 执行程序:void _stdcall ExeFor...”和“3.2 检测Forcal运行错误:err...”部分。
该库中的函数均为实数函数。
3.1 OpenForcal版本信息:OpenForcalVer();
3.2 检测Forcal运行错误:err();
检测到错误时,该函数返回错误类型代码(逻辑真),否则返回 0 (逻辑假)。错误类型代码如下:
1:整数表达式运行错误!
2:实数表达式运行错误!
3:复数表达式运行错误!
4:父表达式(基表达式)被删除!
5:二级函数被删除!
其他非0值:其他运行错误!
注意:当Forcal键树中有一个被锁定为字符串的键给出运行错误说明时,OpenForcal将试图找出出现运行错误的原因。请参考“2.2 OpenForcal使用说明”部分。
3.3 输出控制函数:SetTalk[bool];
缺省情况下,OpenForcal的ExeFor()函数每计算完一个表达式,就输出该表达式的值。SetTalk[]函数用于设置是否输出表达式的值。当bool为真时,输出表达式的值;当bool为假时,不输出表达式的值,直到再一次遇到SetTalk[真]。注意当bool为假时,并不关闭其他函数的输出。
3.4 停止函数:stop[];
该函数并不立即停止执行程序,只是在执行完本表达式后停止程序的执行。
若要立即停止程序的执行,需要在stop[]函数后紧跟一个从表达式立即返回的函数return[]。
例如:
//假定存在一个输出字符串的函数outstr["...
..."];
{stop[],outstr["停止程序!"]};
//输出了字符串之后,停止程序执行;
{stop[],return[0],outstr["本字符串不会输出!"]};
//立即停止程序执行;
4.1 源程序的一般格式 [目录]
在OpenForcal源文件中,可以有多个FORCAL表达式,表达式之间用分号“;”隔开。
由于FORCAL数学表达式有三种,即整数表达式、实数表达式和复数表达式。为便于区分,OpenForcal将以i:开头的表达式作为整数表达式,以c:开头的表达式作为复数表达式,其余为实数表达式。
同时,在源文件中可以进行注释,注释方法与C++语言相似,即:每行两个//后的内容为注释内容;在一行内或者多行之间
/*...*/之间的内容为注释内容。注释不是源程序的有效部分,但可以使程序更易读。
举例如下:
//这是一个例子!灰色部分为注释,不会被执行;
i:2.2+3.3;
//以i:开头是整数表达式;
c:sin(2.2+3.3i); //以c:开头是复数表达式;
2.2+3.3;
//这是实数表达式。
2+3;/*
从这里开始,连续几行注释:
333+222;
. . . . . . ;
555-222;
*/ sin(2.5);
exp(2);
可以用加载OpenForcal的任何一个程序验证以上代码。
4.2 程序的执行 [目录]
由于表达式有些带有参数,有些不带参数,OpenForcal在进行处理时,对于有参数的表达式只进行编译,不进行计算。
OpenForcal只顺序执行不带参数的表达式。
但是,如果表达式以冒号“ : ”开头,则无论是有参表达式还是无参表达式,都是只编译,不执行,格式如下:
i:: 2+3;
//整数无参表达式,只编译,不执行;
i:: f1()=2+3;
//整数无参表达式,只编译,不执行;
c:: 2+3i;
//复数无参表达式,只编译,不执行;
c:: f2()=2+3i;
//复数无参表达式,只编译,不执行;
: 2+3;
//实数无参表达式,只编译,不执行;
: f3()=2+3;
//实数无参表达式,只编译,不执行。
无参表达式f1、f2和f3可以在其他可执行的表达式中被调用。
4.3 源程序的完整格式 [目录]
OpenForcal在进行编译时,将源程序中所有的表达式编译为同一模块。以~开头的表达式被编译为正模块号表达式,能被其他模块访问到,其余的表达式均被编译为负模块号表达式,其他模块无法访问。所有模块的模块号由OpenForcal或程序员指定,一般不会重复,也不会被编译为0#模块。
模块源文件的格式如下:
//单行注释:模块名:myModule
/*
多行注释:在同一模块源文件中的所有表达式属于同一个模块;
多行注释:以~开头的表达式的模块号为正,可被其他模块的表达式所访问;
多行注释:不以~开头的表达式的模块号为负,只能被该模块的表达式所访问。
*/
i:a(x)=10+x;
//模块号为负,只能被该模块的表达式所访问;
c:b()=100+100i; //模块号为负,只能被该模块的表达式所访问;
~_c(x)=x-5;
//模块号为正,任意模块包括本模块均可访问;
~_f(x)=a(x)+b();
//模块号为正,任意模块包括本模块均可访问;
~i:g(x)=a(x)+_c(x); //模块号为正,任意模块包括本模块均可访问;
#USE# Module1;
//使用模块Module1;
~_ff(5)+_gg(6);
//函数_ff()和_gg()在模块Module1中定义;
在其他模块中使用该模块的格式如下:
#USE# myModule;
//关键字USE必须为大写,myModule是模块名称;
~_f(2)+g(3);
//调用myModule模块中定义的函数;
例子1:简单的数值计算:
2+sin[2+3*sqrt(3)]*exp[5];
//实数表达式;
c:sin[2+3i]-ln[i];
//复数表达式;
例子2:变步长辛卜生一元积分:
f(x)=sin[x]+0.8;
//定义一元函数;
simpintegrate(1,2,0.0001,"f");
例子3:二元函数图象[须加载动态库扩展OpenFcGl.dll]
f(x,y)=(x^2-2*x)*exp[-(x^2)-y^2-x*y];
(::Rot)={Rot=0};
//设置一个全局变量;
Draw(::Rot)=
{
glClear[],
glLoadIdentity[],
glTranslated[0,0,-20],
glRotated[Rot++,1,1,1], //使图象连续旋转;
glColor3d[0,1,0],
plot3d["f",-3,3,-3,3]
};
DrawScene{"Draw"};
例子4:有一组测定数据:0.105、0.115、0.115、0.116、0.116、0.128,求其平均值和标准偏差:
DeleteArray[8,"a"];
NewRealArray["a",6,0.105,0.115,0.115,0.116,0.116,0.128];
//申请一个数组并给数组赋初值;
f(x)=x;
//定义计算平均值用到的函数;
DataArraySum("f",6,"a")/6;
//计算平均值;
g(x)=[x-DataArraySum("f",6,"a")/6]^2;
//定义计算标准偏差用到的函数;
sqrt{DataArraySum("g",6,"a")/5};
//计算标准偏差;
例子5:实验测得x与y的关系如下表:
| 序号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| X | 22 | 34 | 39 | 43 | 46 | 54 | 58 | 64 | 67 | 72 |
| Y | 11 | 13 | 16 | 16 | 17 | 15 | 20 | 19 | 24 | 23 |
求其回归方程y=a*x+b及相关系数r?
DeleteArray[8,"a"];
DeleteArray[8,"b"];
NewRealArray["a",10,22,
34,39,43,46,54,58,64,67,72]; //申请数组"a"并赋初值;
NewRealArray["b",10,11,13,16,16,17,15,20,19,24,23];
//申请数组"b"并赋初值;
x(x)=x;
//定义函数1;
xx(x)=x^2;
//定义函数2;
xy(x,y)=x*y;
//定义函数3;
//以下表达式求系数a;
a()=[DataArraySum("xy",10,"a","b")-DataArraySum("x",10,"a")*DataArraySum("x",10,"b")/10]/[DataArraySum("xx",10,"a")-DataArraySum("x",10,"a")^2/10];
//以下表达式求系数b;
DataArraySum("x",10,"b")/10-a()*DataArraySum("x",10,"a")/10;
//以下表达式求相关系数r;
[DataArraySum("xy",10,"a","b")-DataArraySum("x",10,"a")*DataArraySum("x",10,"b")/10]/sqrt{[DataArraySum("xx",10,"a")-DataArraySum("x",10,"a")^2/10]*[DataArraySum("xx",10,"b")-DataArraySum("x",10,"b")^2/10]};
例子6:控件演示:
请输入 SetEditText("结果输出1:","结果输出到了这里!"); ,观察程序运行情况。
//将全局变量DoStr定义为字符串;
(::DoStr)=
{DoStr=
"
(*计算时清屏*)clearFcFunWin[]; //在单击普通按钮时(*...*)中的字符串将被替换为指定的文本;
(*表达式*);
(*MB*);
",
//在FcFunWin[...]函数中定义各类控件及操作;
FcFunWin{"例子",0,0,500,550,//窗口名称为"例子";
//静态文本控件定义;
FFW_STATIC,"表达式:",10,10,70,20,
//编辑框控件定义;
FFW_EDIT,"表达式",1,80,10,380,100,"",
//组框控件定义;
FFW_GROUPBOX,"组框",10,120,90,60,
//单选按钮控件定义;
FFW_RADIOBUTTON,"消息框1",15,135,80,20,"MB","MessageBox(\"aaa\",\"消息框1\")",
FFW_RADIOBUTTON,"消息框2",15,155,80,20,"MB","MessageBox(\"bbb\",\"消息框2\")",
//复选框控件定义;
FFW_CHECKBOX,"计算时清屏",120,135,100,20,"","//",-1,
//普通按钮控件定义;
//注意字符串DoStr中的内容在前面进行了定义,DoStr表示该字符串的地址;
FFW_BUTTON,"计算",400,335,50,25,DoStr,"结果输出2:",
//位图控件定义,加载位图文件"函数图象.bmp";
FFW_BITMAP,"函数图象.bmp",245,120,220,180,
FFW_STATIC,"结果输出1:",10,310,100,20,
FFW_EDIT,"结果输出1:",-1,120,310,330,20,"aaaaaa",
FFW_STATIC,"结果输出2:",10,340,100,20,
FFW_EDIT,"结果输出2:",1,10,370,450,130,""
}
};
版权所有© Forcal数学软件
2002-2007,保留所有权利
E-mail: forcal@sina.com
QQ:630715621
最近更新: 2008年05月01日