循序渐进Forcal例程
目 录
| 1 概述 2 预备知识 3 最简单的例子 4 安全的例子及Forcal扩展动态库的用法 5 完整的例子 |
6 添加常量和二级函数 7 能计算多个表达式的例子 8 结语 |
健壮的东西通常是复杂的,Forcal也是如此。如果你喜欢Forcal,想用Forcal编程而又无从下手,那么本文的例子将会对你有所帮助。
本文所有的例子均在VC++ 6.0环境下编译通过,编译时请使用Build->Set Active Configuration->Win32 Release选项。这都是些完整的例子,复制下来直接编译运行即可。为了减少代码,这些例子都是控制台应用程序,简单地加以改写,将它应用到实用的Windows程序中去是不难的。
第一个例子是最简单的,其他的例子基本上都是在前面例子的基础上添加代码实现的。认真地完成每个例子后的习题将有助于加深对的Forcal理解。
本文没有穷尽Forcal的所有用法和功能,而且还很不够。如果你还有什么不明白的,可以直接与我联系:forcal@sina.com 。
使用Forcal的预备知识并不多,只要你会加载和卸载动态库(dll),而且懂一点多线程编程的知识就可以了。
2.1 加载和卸载Forcal
应用程序可调用LoadLibrary直接加载Forcal.dll。
HANDLE hForcal; //动态库模块句柄;
hForcal=LoadLibrary("forcal.dll");
//加载动态库forcal.dll;
加载Forcal.dll成功后,需调用函数GetProcAddress获取Forcal输出函数的地址。例如:
fcInitForcal
pInitForcal; //fcInitForcal
在头文件forcal7.h中定义,为初始化Forcal的函数指针;
pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal");
该函数获得了初始化Forcal的函数地址,保存在指针pInitForcal中。
当程序不再需要访问Forcal.dll时,应调用函数FreeLibrary将其卸载。
FreeLibrary(hForcal); //释放动态库Forcal.dll;
2.2 在多线程中使用Forcal
Forcal可以用在单线程程序中,但不能及时退出漫长的计算过程或无限循环。没人愿意使用一个经常失去响应的程序。
为了安全地使用Forcal,应用程序至少有两个线程,一个用于Forcal计算,另一个用于监视Forcal运行。
也许你会感到奇怪,本文所有的例子好像都是单线程的。确实,本文的例子中没有关于多线程的函数或语句。但除了第一个例子,从第二个例子开始,都加载了一个Forcal扩展动态库QuitFc.dll,该库中启动了一个线程,专门用于监视Forcal运行。
多线程是一个更高级的概念,本文作为使用Forcal的引玉之砖,没有提供这方面的例子。
从这一节开始给出使用Forcal的例子,这是最简单的。
这个例子有三个函数:加载并初始化Forcal的函数InitForcal,释放Forcal的函数FreeForcal和主函数main,主函数编译并计算了一个实数表达式的值。前两个函数的内容完全可以并入主函数,但分开写显得更清晰一些。
这个例子只用到了Forcal的四个输出函数:初始化Forcal的函数InitForcal,释放Forcal的函数FreeForcal,编译实数表达式的函数RealCom和计算实数表达式的函数RealCal。例子的完整源代码如下:
#include <windows.h> #include <math.h> #include <iomanip.h> #include "forcal7.h"
HINSTANCE hForcal=NULL; //动态库forcal.dll的句柄;
//动态库输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal;
bool InitForcal(void) //初始化Forcal;
{
hForcal=LoadLibrary("forcal.dll"); //加载动态库forcal.dll;
if(!hForcal)
{
cout<<"找不到forcal.dll!请将该库放到WINDOWS的搜索路径内!";
return false;
}
//以下几个语句获取forcal.dll中所调用函数的地址; pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal"); pFreeForcal=(fcFreeForcal) GetProcAddress(hForcal,"FreeForcal"); pRealCom=(fcRealCom) GetProcAddress(hForcal,"RealCom"); pRealCal=(fcRealCal) GetProcAddress(hForcal,"RealCal");
if(!pInitForcal||!pFreeForcal||!pRealCom||!pRealCal)
{
cout<<"无效的动态库函数!"<<endl;
FreeLibrary(hForcal); //释放动态库Forcal.dll;
hForcal=NULL;
return false;
}
pInitForcal(); //初始化Forcal.dll;
return true; }
void FreeForcal(void) //释放Forcal
{
pFreeForcal(); //释放Forcal申请的空间;
FreeLibrary(hForcal); //释放动态库;
}
void main(void)
{
void *vFor; //表达式句柄;
fcINT nPara; //存放表达式的自变量个数;
double *pPara; //存放输入自变量的数组指针;
fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置;
int ErrCode; //错误代码;
char ForStr[]="1+2"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
ErrCode=pRealCom(ForStr,0,vFor,nPara,pPara,ErrBegin,ErrEnd); //编译实数表达式;
if(ErrCode)
{
cout<<"表达式有错误!错误代码:"<<ErrCode<<endl;
}
else
{
cout<<pRealCal(vFor,pPara)<<endl; //计算实数表达式的值;
}
FreeForcal(); //释放Forcal; }
习题:
(1)更换不同的字符串表达式ForStr,重新编译运行程序,观察计算结果。
(2)将本例计算实数表达式改为计算整数表达式或复数表达式的例子。
在第一个例子中,如果计算表达式"while[1,1]",程序将陷入无限循环,这在实用程序中是不能容忍的。将Forcal程序设计成多线程程序可以避免这一点。为了简单,本例中将加载一个Forcal扩展动态库QuitFc.dll,该库中启动了一个线程,专门用于监视Forcal运行。另外更重要的是,通过本节可以学习到Forcal扩展动态库的用法,这是Forcal进行功能扩展的最主要的方式。
Forcal扩展动态库只有一个输出函数ForcalDll。用法相当简单,以QuitFc.dll为例:(1)加载QuitFc.dll;(2)使用函数ForcalDll对动态库初始化;(3)用完后仍然用函数ForcalDll释放动态库;(4)卸载动态库。具体应用详见程序中的红字部分。
程序中的红字部分是在前一个例子的基础上新添加的内容,后面的例子中亦是如此,不再特别说明。
例子的完整源代码如下:
#include <windows.h> #include <math.h> #include <iomanip.h> #include "forcal7.h"
HINSTANCE hForcal=NULL; //动态库forcal.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc.dll的句柄;
//动态库forcal.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal;
//Forcal扩展动态库的输出函数; fcForcalDll pForcalDll;
bool InitForcal(void) //初始化Forcal;
{
hForcal=LoadLibrary("forcal.dll"); //加载动态库forcal.dll;
if(!hForcal)
{
cout<<"找不到forcal.dll!请将该库放到WINDOWS的搜索路径内!";
return false;
}
//以下几个语句获取forcal.dll中所调用函数的地址; pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal"); pFreeForcal=(fcFreeForcal) GetProcAddress(hForcal,"FreeForcal"); pRealCom=(fcRealCom) GetProcAddress(hForcal,"RealCom"); pRealCal=(fcRealCal) GetProcAddress(hForcal,"RealCal");
if(!pInitForcal||!pFreeForcal||!pRealCom||!pRealCal)
{
cout<<"无效的动态库函数!"<<endl;
FreeLibrary(hForcal); //释放动态库Forcal.dll;
hForcal=NULL;
return false;
}
pInitForcal(); //初始化Forcal.dll;
hQuitFc=LoadLibrary("QuitFc.dll"); //加载动态库QuitFc.dll;
if(hQuitFc)
{
//获得Forcal扩展动态库输出函数的地址;
pForcalDll=(fcForcalDll) GetProcAddress(hQuitFc,"ForcalDll");
if(pForcalDll)
{
if(!pForcalDll(hForcal,true)) //初始化QuitFc;
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
else
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
return true;
}
void FreeForcal(void) //释放Forcal;
{
if(hQuitFc) //释放QuitFc
{
pForcalDll(hForcal,false);
}
pFreeForcal(); //释放Forcal申请的空间;
FreeLibrary(hForcal); //释放动态库;
}
void main(void)
{
void *vFor; //表达式句柄;
fcINT nPara; //存放表达式的自变量个数;
double *pPara; //存放输入自变量的数组指针;
fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置;
int ErrCode; //错误代码;
char ForStr[]="1+2"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
ErrCode=pRealCom(ForStr,0,vFor,nPara,pPara,ErrBegin,ErrEnd); //编译实数表达式;
if(ErrCode)
{
cout<<"表达式有错误!错误代码:"<<ErrCode<<endl;
}
else
{
cout<<pRealCal(vFor,pPara)<<endl; //计算实数表达式的值;
}
FreeForcal(); //释放Forcal; }
习题:
(1)更换字符串表达式ForStr的内容为"while[1,1]"或者其他可长时间运行的内容,重新编译运行程序,在QuitFc窗口中按Esc键中断Forcal运行,观察运行结果。
(2)在本例的基础上,改为能加载软件包中FcConst.dll的例子。然后将ForStr的内容改为"Key_RealFunction"或者FcConst.dll中的其他常量,重新编译运行程序,观察计算结果。
(3)在本例的基础上,改为能加载软件包中Example.dll的例子。然后将ForStr的内容改为"GetRunTime()"或者"(:i,k)=SetRunTime(),{i=0,k=0,while{i<=1000000,k=k+i,i++},k},GetRunTime()",重新编译运行程序,观察计算结果。
在前面的例子中,程序的计算结果有些是错误的。因为Forcal在遇到运行错误时,就会停止计算而退出,其计算结果是不正确的。
在这个例子中,我们将添加运行错误检测功能。为此,只需要增加Forcal的一个输出函数GetRunErr就可以了。
到这里为止,我们的程序能够计算,能够退出无限循环,能够检测运行错误,因此称之为完整的例子。
本例的完整源代码如下:
#include <windows.h> #include <math.h> #include <iomanip.h> #include "forcal7.h"
HINSTANCE hForcal=NULL; //动态库forcal.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc.dll的句柄;
//动态库forcal.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal; fcGetRunErr pGetRunErr;
//Forcal扩展动态库的输出函数; fcForcalDll pForcalDll;
bool InitForcal(void) //初始化Forcal;
{
hForcal=LoadLibrary("forcal.dll"); //加载动态库forcal.dll;
if(!hForcal)
{
cout<<"找不到forcal.dll!请将该库放到WINDOWS的搜索路径内!";
return false;
}
//以下几个语句获取forcal.dll中所调用函数的地址; pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal"); pFreeForcal=(fcFreeForcal) GetProcAddress(hForcal,"FreeForcal"); pRealCom=(fcRealCom) GetProcAddress(hForcal,"RealCom"); pRealCal=(fcRealCal) GetProcAddress(hForcal,"RealCal"); pGetRunErr=(fcGetRunErr) GetProcAddress(hForcal,"GetRunErr");
if(!pInitForcal||!pFreeForcal||!pRealCom||!pRealCal||!pGetRunErr)
{
cout<<"无效的动态库函数!"<<endl;
FreeLibrary(hForcal); //释放动态库Forcal.dll;
hForcal=NULL;
return false;
}
pInitForcal(); //初始化Forcal.dll;
hQuitFc=LoadLibrary("QuitFc.dll"); //加载动态库QuitFc.dll;
if(hQuitFc)
{
//获得Forcal扩展动态库输出函数的地址;
pForcalDll=(fcForcalDll) GetProcAddress(hQuitFc,"ForcalDll");
if(pForcalDll)
{
if(!pForcalDll(hForcal,true)) //初始化QuitFc;
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
else
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
return true;
}
void FreeForcal(void) //释放Forcal;
{
if(hQuitFc) //释放QuitFc
{
pForcalDll(hForcal,false);
}
pFreeForcal(); //释放Forcal申请的空间;
FreeLibrary(hForcal); //释放动态库;
}
void main(void)
{
void *vFor; //表达式句柄;
fcINT nPara; //存放表达式的自变量个数;
double *pPara; //存放输入自变量的数组指针;
fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置;
int ErrCode; //错误代码;
int ForType; //运行错误类型;
char *FunName; //出错函数名;
char ForStr[]="1+2"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
pGetRunErr(ForType,FunName,ErrCode); //设置运行错误为无错状态;
ErrCode=pRealCom(ForStr,0,vFor,nPara,pPara,ErrBegin,ErrEnd); //编译实数表达式;
if(ErrCode)
{
cout<<"表达式有错误!错误代码:"<<ErrCode<<endl;
}
else
{
cout<<pRealCal(vFor,pPara)<<endl; //计算实数表达式的值;
pGetRunErr(ForType,FunName,ErrCode); //检查运行错误;
if(ForType) cout<<"出现运行错误!错误类型:"<<ForType<<";出错函数名:"<<FunName
<<";错误代码:"<<ErrCode<<endl;
}
FreeForcal(); //释放Forcal; }
习题:
(1)更换字符串表达式ForStr的内容为"while[1,1]",重新编译运行程序,观察计算结果。
(2)更换字符串表达式ForStr的内容为"which[0,1]",重新编译运行程序,观察计算结果。
在这个例子中,我们将往Forcal中添加常量和二级函数。
使用Forcal的输出函数SetConst可以往Forcal中添加常量,本例中只添加了一个实型常量PI。
使用Forcal的输出函数SetFunction可以往Forcal中添加二级函数,本例中只添加了一个实型二级函数add。
本例的完整源代码如下:
#include <windows.h> #include <math.h> #include <iomanip.h> #include "forcal7.h"
HINSTANCE hForcal=NULL; //动态库forcal.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc.dll的句柄;
//动态库forcal.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal; fcGetRunErr pGetRunErr; fcSetConst pSetConst; fcSetFunction pSetFunction;
//Forcal扩展动态库的输出函数; fcForcalDll pForcalDll;
//实数二级函数定义;
double _stdcall Fun2_add(fcINT m,double *x,void *rFor) //计算两个数的和;
{
return x[0]+x[1];
}
bool InitForcal(void) //初始化Forcal;
{
hForcal=LoadLibrary("forcal.dll"); //加载动态库forcal.dll;
if(!hForcal)
{
cout<<"找不到forcal.dll!请将该库放到WINDOWS的搜索路径内!";
return false;
}
//以下几个语句获取forcal.dll中所调用函数的地址; pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal"); pFreeForcal=(fcFreeForcal) GetProcAddress(hForcal,"FreeForcal"); pRealCom=(fcRealCom) GetProcAddress(hForcal,"RealCom"); pRealCal=(fcRealCal) GetProcAddress(hForcal,"RealCal"); pGetRunErr=(fcGetRunErr) GetProcAddress(hForcal,"GetRunErr"); pSetConst=(fcSetConst) GetProcAddress(hForcal,"SetConst"); pSetFunction=(fcSetFunction) GetProcAddress(hForcal,"SetFunction");
if(!pInitForcal||!pFreeForcal||!pRealCom||!pRealCal||!pGetRunErr||!pSetConst||!pSetFunction)
{
cout<<"无效的动态库函数!"<<endl;
FreeLibrary(hForcal); //释放动态库Forcal.dll;
hForcal=NULL;
return false;
}
pInitForcal(); //初始化Forcal.dll;
hQuitFc=LoadLibrary("QuitFc.dll"); //加载动态库QuitFc.dll;
if(hQuitFc)
{
//获得Forcal扩展动态库输出函数的地址;
pForcalDll=(fcForcalDll) GetProcAddress(hQuitFc,"ForcalDll");
if(pForcalDll)
{
if(!pForcalDll(hForcal,true)) //初始化QuitFc;
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
else
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
double PI=3.1416; //实型常量定义; pSetConst(Key_RealConst,"PI",&PI); //设置实型常量;
pSetFunction(Key_RealFunction,"add",Fun2_add,1); //设置实数二级函数;
return true; }
void FreeForcal(void) //释放Forcal;
{
if(hQuitFc) //释放QuitFc
{
pForcalDll(hForcal,false);
}
pFreeForcal(); //释放Forcal申请的空间;
FreeLibrary(hForcal); //释放动态库;
}
void main(void)
{
void *vFor; //表达式句柄;
fcINT nPara; //存放表达式的自变量个数;
double *pPara; //存放输入自变量的数组指针;
fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置;
int ErrCode; //错误代码;
int ForType; //运行错误类型;
char *FunName; //出错函数名;
char ForStr[]="add[5,6]"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
pGetRunErr(ForType,FunName,ErrCode); //设置运行错误为无错状态;
ErrCode=pRealCom(ForStr,0,vFor,nPara,pPara,ErrBegin,ErrEnd); //编译实数表达式;
if(ErrCode)
{
cout<<"表达式有错误!错误代码:"<<ErrCode<<endl;
}
else
{
cout<<pRealCal(vFor,pPara)<<endl; //计算实数表达式的值;
pGetRunErr(ForType,FunName,ErrCode); //检查运行错误;
if(ForType) cout<<"出现运行错误!错误类型:"<<ForType<<";出错函数名:"<<FunName
<<";错误代码:"<<ErrCode<<endl;
}
FreeForcal(); //释放Forcal; }
习题:
(1)在本例的基础上再添加一个实型常量_E=2.718,更换字符串表达式ForStr的内容为"_E",重新编译运行程序,观察计算结果。
(2)在本例的基础上再添加一个实型二级函数average,该函数已在下面给出。这稍稍提高了一点难度,因为你要同时添加Forcal的两个输出函数TestRunErr和SetRunErr,否则编译是不能通过的。不要忘了更换字符串表达式ForStr的内容为"average(1,2,3)",以便检查运行效果。
double _stdcall average(fcINT m,double *x,void *rFor) //计算平均值函数;
{
fcINT i;
double ave;
static char pFunName[]="average";
//如果average()没有参数,返回一个FORCAL运行错误;
if(m==-1) {if(!pTestRunErr()) pSetRunErr(2,pFunName,1); return 0.0;}
ave=0.0;
for(i=0;i<=m;i++) ave=ave+x[i];
return ave/(m+1);
}
(3)在本例的基础上再添加一个实型二级函数PrintStr,该函数已在下面给出。这也是提高了一点难度的,你需要同时添加Forcal的一个输出函数GetForStr以使编译通过。记着更换字符串表达式ForStr的内容为"PrintStr(\"hello forcal!\")",观察运行效果。
double _stdcall PrintStr(fcINT m,double *x,void *rFor) //输出一个字符串;
{
char *pStr;
long k;
fcINT StrMax;
pGetForStr(rFor,pStr,StrMax); //获得字符串;
k=(long)x[0];
if(k>=0&&k<StrMax) cout<<&pStr[k];
return 0.0;
}
7 能计算多个表达式的例子 [返回页首]
在本例中,我们将使程序能计算10个表达式,程序输出的信息更详细,以便我们能输入更复杂的表达式进行检验。
注意:本例不是在上一例的基础上添加新内容,而是对上一例的主函数进行了改写。
本例的完整源代码如下:
#include <windows.h> #include <math.h> #include <iomanip.h> #include "forcal7.h"
HINSTANCE hForcal=NULL; //动态库forcal.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc.dll的句柄;
//动态库forcal.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal; fcGetRunErr pGetRunErr; fcSetConst pSetConst; fcSetFunction pSetFunction;
//Forcal扩展动态库的输出函数; fcForcalDll pForcalDll;
//实数二级函数定义;
double _stdcall Fun2_add(fcINT m,double *x,void *rFor) //计算两个数的和;
{
return x[0]+x[1];
}
bool InitForcal(void) //初始化Forcal;
{
hForcal=LoadLibrary("forcal.dll"); //加载动态库forcal.dll;
if(!hForcal)
{
cout<<"找不到forcal.dll!请将该库放到WINDOWS的搜索路径内!";
return false;
}
//以下几个语句获取forcal.dll中所调用函数的地址; pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal"); pFreeForcal=(fcFreeForcal) GetProcAddress(hForcal,"FreeForcal"); pRealCom=(fcRealCom) GetProcAddress(hForcal,"RealCom"); pRealCal=(fcRealCal) GetProcAddress(hForcal,"RealCal"); pGetRunErr=(fcGetRunErr) GetProcAddress(hForcal,"GetRunErr"); pSetConst=(fcSetConst) GetProcAddress(hForcal,"SetConst"); pSetFunction=(fcSetFunction) GetProcAddress(hForcal,"SetFunction");
if(!pInitForcal||!pFreeForcal||!pRealCom||!pRealCal||!pGetRunErr||!pSetConst||!pSetFunction)
{
cout<<"无效的动态库函数!"<<endl;
FreeLibrary(hForcal); //释放动态库Forcal.dll;
hForcal=NULL;
return false;
}
pInitForcal(); //初始化Forcal.dll;
hQuitFc=LoadLibrary("QuitFc.dll"); //加载动态库QuitFc.dll;
if(hQuitFc)
{
//获得Forcal扩展动态库输出函数的地址;
pForcalDll=(fcForcalDll) GetProcAddress(hQuitFc,"ForcalDll");
if(pForcalDll)
{
if(!pForcalDll(hForcal,true)) //初始化QuitFc;
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
else
{
FreeLibrary(hQuitFc); //释放动态库QuitFc;
hQuitFc=NULL;
}
}
double PI=3.1416; //实型常量定义; pSetConst(Key_RealConst,"PI",&PI); //设置实型常量;
pSetFunction(Key_RealFunction,"add",Fun2_add,1); //设置实数二级函数;
return true; }
void FreeForcal(void) //释放Forcal;
{
if(hQuitFc) //释放QuitFc
{
pForcalDll(hForcal,false);
}
pFreeForcal(); //释放Forcal申请的空间;
FreeLibrary(hForcal); //释放动态库;
}
void main(void)
{
const int nFor=10; //编译计算10个表达式;
void *vFor[nFor]; //表达式句柄;
fcINT nPara[nFor]; //存放表达式的自变量个数;
double *pPara[nFor]; //存放输入自变量的数组指针;
fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置;
int ErrCode; //错误代码;
int ForType; //运行错误类型;
char *FunName; //出错函数名;
char *ForStr[nFor]={ //nFor个字符串表达式;
"add[5,6]",
"=5--9",
"1+2",
"a(x,y)=x+y",
"a[6,6]",
"a(x,y)=8",
"a[8,8]",
"while[1,1]",
"",
"pi"
};
int i,j;
if(!InitForcal()) return; //初始化Forcal;
pGetRunErr(ForType,FunName,ErrCode); //设置运行错误为无错状态;
for(i=0;i<nFor;i++)
{
cout<<endl<<">> 编译计算第"<<i<<"个式子:"<<ForStr[i]<<endl;
ErrCode=pRealCom(ForStr[i],0,vFor[i],nPara[i],pPara[i],ErrBegin,ErrEnd);//编译实数表达式;
if(ErrCode)
{
cout<<"表达式有错误!错误代码:"<<ErrCode<<endl;
}
else
{
cout<<"编译通过,请输入"<<nPara[i]+1<<"个自变量(自变量间用空格分隔):";
for(j=0;j<=nPara[i];j++) cin>>pPara[i][j]; //输入自变量;
cout<<endl<<"计算值:"<<pRealCal(vFor[i],pPara[i])<<endl;//计算实数表达式的值;
pGetRunErr(ForType,FunName,ErrCode); //检查运行错误;
if(ForType) cout<<"出现运行错误!错误类型:"<<ForType<<";出错函数名:"<<FunName
<<";错误代码:"<<ErrCode<<endl;
}
}
FreeForcal(); //释放Forcal; }
习题:
(1)程序运行时,第6个表达式"a(x,y)=8";没有语法错误,为什么编译不能通过?
(2)程序运行时,第9个表达式"";为空,不能通过编译,提示你在设计程序时注意什么?
(3)在本例的基础上修改程序,使之能计算20个表达式。
(4)在本例的基础上修改程序,使之在编译出错时直接给出错误提示而不是错误代码。
(5)在本例的基础上再添加实型二级函数PrintStr和CalFor,这两个函数已在下面给出。这有一点难度,你需要同时添加Forcal的四个输出函数TestRunErr、SetRunErr、GetForStr和GetFor以使编译通过。同时在字符串表达式ForStr中包含以下内容,检查运行情况。
aa(x)=x+8;
calfor["aa",7];
.
.
.
SetRealStackMax(1000);
//设置实数堆栈为1000;
a(x)=PrintStr["a..."],if(x<1,return[x]),CalFor["b",x-1];
//a(...)函数中调用了b(...)函数;
b(x)=PrintStr["b..."],if(x<1,return[x]),CalFor["a",x-1];
//b(...)函数中调用了a(...)函数;
a[10]; //启动递归程序;
.
.
.
double _stdcall PrintStr(fcINT m,double *x,void *rFor) //输出一个字符串;
{
char *pStr;
long k;
fcINT StrMax;
pGetForStr(rFor,pStr,StrMax); //获得字符串;
k=(long)x[0];
if(k>=0&&k<StrMax) cout<<&pStr[k];
return 0.0;
}
//二级函数CalFor("f",x1,x2,...,xn)在运行时调用实数表达式"f",x1,x2,...,xn为表达式的参数。
double _stdcall fc_CalFor(fcINT m,double *x,void *rFor)
{
static char pFunName[]="CalFor";
char *pStr;
fcINT nModule,StrMax;
long i;
void *vFor,*vPara;
//如果CalFor()没有参数,返回一个FORCAL运行错误;
if(m==-1) {if(!pTestRunErr()) pSetRunErr(2,pFunName,1); return 0.0;}
pGetForStr(rFor,pStr,StrMax); //获得字符串;
i=(long)x[0];
if(i>=0&&i<StrMax)
{
if(pGetFor(&pStr[i],Key_RealFor,rFor,nModule,vFor,vPara,StrMax))
{
//如果参数不匹配,返回一个FORCAL运行错误;
if(StrMax!=m-1) {if(!pTestRunErr()) pSetRunErr(2,pFunName,2); return 0.0;}
return pRealCal(vFor,&x[1]);
}
}
if(!pTestRunErr()) pSetRunErr(2,pFunName,3); //如果无法定位表达式,返回一个FORCAL运行错误;
return 0.0;
}
虽然还可以添加更多的例子,但是作为一个入门教程,就先写到这儿了。
如果你对本文有什么意见或建议,请给我发E-mail:forcal@sina.com 。
版权所有© Forcal数学软件
2002-2008,保留所有权利
E-mail: forcal@sina.com
QQ:630715621
最近更新: 2008年02月28日