OpenForcal V3.0 使用说明

目  录

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动态库的输出函数ForcalDllint _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锁定一个键的类型为字符串,然后将被锁定的键KeyTypeInsertKey("OFC_LockKeyErrStr",FC_PrivateKey_User,KeyType,DelKey,v)传送给Forcal,同时约定将删除键值的函数DeleteStrInsertKey("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 二级函数  [目录]

    该库中的函数均为实数函数。

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 模块源文件  [目录]

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模块中定义的函数;


5 例子  [目录]

例子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日