循序渐进Forcal例程
目 录
1 概述 2 预备知识 3 最简单的例子 4 安全的例子及Forcal扩展动态库的用法 5 完整的例子 |
6 添加常量和二级函数 7 能计算多个表达式的例子 8 结语 |
如果你喜欢Forcal,想用Forcal编程而又无从下手,那么本文的例子将会对你有所帮助。
本文所有的例子均在VS C++ 2008环境下编译通过,编译时请将活动解决方案配置为“Release”。这都是些完整的例子,复制下来直接编译运行即可。为了减少代码,这些例子都是控制台应用程序,简单地加以改写,将它应用到实用的Windows程序中去是不难的。
第一个例子是最简单的,其他的例子基本上都是在前面例子的基础上添加代码实现的。认真地完成每个例子后的习题将有助于加深对的Forcal理解。
本文没有穷尽Forcal的所有用法和功能,而且还很不够。如果你还有什么不明白的,可以直接与我联系:forcal@sina.com 。
使用Forcal的预备知识并不多,只要你会加载和卸载动态库(dll),而且懂一点多线程编程的知识就可以了。
2.1 加载和卸载Forcal
应用程序可调用LoadLibrary直接加载Forcal32W.dll。
HANDLE hForcal; //动态库模块句柄;
hForcal=LoadLibrary(L"Forcal32W.dll");
//加载动态库Forcal32W.dll;
加载Forcal32W.dll成功后,需调用函数GetProcAddress获取Forcal输出函数的地址。例如:
fcInitForcal
pInitForcal; //fcInitForcal
在头文件forcal32w.h中定义,为初始化Forcal的函数指针;
pInitForcal=(fcInitForcal) GetProcAddress(hForcal,"InitForcal");
该函数获得了初始化Forcal的函数地址,保存在指针pInitForcal中。
当程序不再需要访问Forcal32W.dll时,应调用函数FreeLibrary将其卸载。
FreeLibrary(hForcal); //释放动态库Forcal32W.dll;
2.2 在多线程中使用Forcal
Forcal可以用在单线程程序中,但不能及时退出漫长的计算过程或无限循环。没人愿意使用一个经常失去响应的程序。
为了安全地使用Forcal,应用程序至少有两个线程,一个用于Forcal计算,另一个用于监视Forcal运行。
也许你会感到奇怪,本文所有的例子好像都是单线程的。确实,本文的例子中没有关于多线程的函数或语句。但除了第一个例子,从第二个例子开始,都加载了一个Forcal扩展动态库QuitFc32W.dll,该库中启动了一个线程,专门用于监视Forcal运行。
多线程是一个更高级的概念,本文作为使用Forcal的引玉之砖,没有提供这方面的例子。
从这一节开始给出使用Forcal的例子,这是最简单的。
这个例子有三个函数:加载并初始化Forcal的函数InitForcal,释放Forcal的函数FreeForcal和主函数main,主函数编译并计算了一个实数表达式的值。前两个函数的内容完全可以并入主函数,但分开写显得更清晰一些。
这个例子只用到了Forcal的四个输出函数:初始化Forcal的函数InitForcal,释放Forcal的函数FreeForcal,编译实数表达式的函数RealCom和计算实数表达式的函数RealCal。例子的完整源代码如下:
#include <windows.h> #include <cmath> #include <iostream> #include <iomanip> #include "forcal32w.h" using namespace std;
HINSTANCE hForcal=NULL; //动态库Forcal32W.dll的句柄;
//动态库输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal;
bool InitForcal(void) //初始化Forcal; { hForcal=LoadLibrary(L"Forcal32W.dll"); //加载动态库Forcal32W.dll; if(!hForcal) { cout<<"找不到Forcal32W.dll!请将该库放到WINDOWS的搜索路径内!"; return false; }
//以下几个语句获取Forcal32W.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); //释放动态库Forcal32W.dll; hForcal=NULL; return false; }
pInitForcal(); //初始化Forcal32W.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; //错误代码; wchar_t ForStr[]=L"1+2"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
vFor=0; 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扩展动态库QuitFc32W.dll,该库中启动了一个线程,专门用于监视Forcal运行。另外更重要的是,通过本节可以学习到Forcal扩展动态库的用法,这是Forcal进行功能扩展的最主要的方式。
Forcal扩展动态库只有一个输出函数FcDll32W。用法相当简单,以QuitFc32W.dll为例:(1)加载QuitFc32W.dll;(2)使用函数FcDll32W对动态库初始化;(3)用完后仍然用函数FcDll32W释放动态库;(4)卸载动态库。具体应用详见程序中的红字部分。
程序中的红字部分是在前一个例子的基础上新添加的内容,后面的例子中亦是如此,不再特别说明。
例子的完整源代码如下:
#include <windows.h> #include <cmath> #include <iostream> #include <iomanip> #include "forcal32w.h" using namespace std;
HINSTANCE hForcal=NULL; //动态库Forcal32W.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc32W.dll的句柄;
//动态库Forcal32W.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal;
//Forcal扩展动态库的输出函数; fcFcDll32W pFcDll32W;
bool InitForcal(void) //初始化Forcal; { hForcal=LoadLibrary(L"Forcal32W.dll"); //加载动态库Forcal32W.dll; if(!hForcal) { cout<<"找不到Forcal32W.dll!请将该库放到WINDOWS的搜索路径内!"; return false; }
//以下几个语句获取Forcal32W.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); //释放动态库Forcal32W.dll; hForcal=NULL; return false; }
pInitForcal(); //初始化Forcal32W.dll;
hQuitFc=LoadLibrary(L"QuitFc32W.dll"); //加载动态库QuitFc32W.dll; if(hQuitFc) { //获得Forcal扩展动态库输出函数的地址; pFcDll32W=(fcFcDll32W) GetProcAddress(hQuitFc,"FcDll32W"); if(pFcDll32W) { if(!pFcDll32W(hForcal,true,0)) //初始化QuitFc; { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } } else { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } } return true; }
void FreeForcal(void) //释放Forcal; { if(hQuitFc) //释放QuitFc { pFcDll32W(hForcal,false,0); } pFreeForcal(); //释放Forcal申请的空间; FreeLibrary(hForcal); //释放动态库; }
void main(void) { void *vFor; //表达式句柄; fcINT nPara; //存放表达式的自变量个数; double *pPara; //存放输入自变量的数组指针; fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置; int ErrCode; //错误代码; wchar_t ForStr[]=L"1+2"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
vFor=0; 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 <cmath> #include <iostream> #include <iomanip> #include "forcal32w.h" using namespace std;
HINSTANCE hForcal=NULL; //动态库Forcal32W.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc32W.dll的句柄;
//动态库Forcal32W.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal; fcGetRunErr pGetRunErr;
//Forcal扩展动态库的输出函数; fcFcDll32W pFcDll32W;
bool InitForcal(void) //初始化Forcal; { hForcal=LoadLibrary(L"Forcal32W.dll"); //加载动态库Forcal32W.dll; if(!hForcal) { cout<<"找不到Forcal32W.dll!请将该库放到WINDOWS的搜索路径内!"; return false; }
//以下几个语句获取Forcal32W.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); //释放动态库Forcal32W.dll; hForcal=NULL; return false; }
pInitForcal(); //初始化Forcal32W.dll;
hQuitFc=LoadLibrary(L"QuitFc32W.dll"); //加载动态库QuitFc32W.dll; if(hQuitFc) { //获得Forcal扩展动态库输出函数的地址; pFcDll32W=(fcFcDll32W) GetProcAddress(hQuitFc,"FcDll32W"); if(pFcDll32W) { if(!pFcDll32W(hForcal,true,0)) //初始化QuitFc; { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } } else { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } } return true; }
void FreeForcal(void) //释放Forcal; { if(hQuitFc) //释放QuitFc { pFcDll32W(hForcal,false,0); } pFreeForcal(); //释放Forcal申请的空间; FreeLibrary(hForcal); //释放动态库; }
void main(void) { void *vFor; //表达式句柄; fcINT nPara; //存放表达式的自变量个数; double *pPara; //存放输入自变量的数组指针; fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置; int ErrCode; //错误代码; int ErrType; //运行错误类型; wchar_t *FunName; //出错函数名; int ForType; //运行出错的表达式类型; void *ForHandle; //运行出错的表达式句柄; wchar_t ForStr[]=L"1+2"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
pGetRunErr(ErrType,FunName,ErrCode,ForType,ForHandle); //设置运行错误为无错状态;
wcout.imbue(locale("chs")); //设置输出的locale为中文 vFor=0; ErrCode=pRealCom(ForStr,0,vFor,nPara,pPara,ErrBegin,ErrEnd); //编译实数表达式; if(ErrCode) { cout<<"表达式有错误!错误代码:"<<ErrCode<<endl; } else { cout<<pRealCal(vFor,pPara)<<endl; //计算实数表达式的值; pGetRunErr(ErrType,FunName,ErrCode,ForType,ForHandle); //检查运行错误; if(ErrType) wcout<<"出现运行错误!错误类型:"<<ErrType<<";出错函数名:"<<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 <cmath> #include <iostream> #include <iomanip> #include "forcal32w.h" using namespace std;
HINSTANCE hForcal=NULL; //动态库Forcal32W.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc32W.dll的句柄;
//动态库Forcal32W.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal; fcGetRunErr pGetRunErr; fcSetConst pSetConst; fcSetFunction pSetFunction;
//Forcal扩展动态库的输出函数; fcFcDll32W pFcDll32W;
//实数二级函数定义; double _stdcall Fun2_add(fcINT m,double *x,void *rFor) //计算两个数的和; { return x[0]+x[1]; }
bool InitForcal(void) //初始化Forcal; { hForcal=LoadLibrary(L"Forcal32W.dll"); //加载动态库Forcal32W.dll; if(!hForcal) { cout<<"找不到Forcal32W.dll!请将该库放到WINDOWS的搜索路径内!"; return false; }
//以下几个语句获取Forcal32W.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); //释放动态库Forcal32W.dll; hForcal=NULL; return false; }
pInitForcal(); //初始化Forcal32W.dll;
hQuitFc=LoadLibrary(L"QuitFc32W.dll"); //加载动态库QuitFc32W.dll; if(hQuitFc) { //获得Forcal扩展动态库输出函数的地址; pFcDll32W=(fcFcDll32W) GetProcAddress(hQuitFc,"FcDll32W"); if(pFcDll32W) { if(!pFcDll32W(hForcal,true,0)) //初始化QuitFc; { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } } else { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } }
double PI=3.1416; //实型常量定义; pSetConst(Key_RealConst,L"PI",&PI); //设置实型常量;
pSetFunction(Key_RealFunction,L"add",Fun2_add,1); //设置实数二级函数;
return true; }
void FreeForcal(void) //释放Forcal; { if(hQuitFc) //释放QuitFc { pFcDll32W(hForcal,false,0); } pFreeForcal(); //释放Forcal申请的空间; FreeLibrary(hForcal); //释放动态库; }
void main(void) { void *vFor; //表达式句柄; fcINT nPara; //存放表达式的自变量个数; double *pPara; //存放输入自变量的数组指针; fcINT ErrBegin,ErrEnd; //表达式编译出错的初始位置和结束位置; int ErrCode; //错误代码; int ErrType; //运行错误类型; wchar_t *FunName; //出错函数名; int ForType; //运行出错的表达式类型; void *ForHandle; //运行出错的表达式句柄; wchar_t ForStr[]=L"add[5,6]"; //字符串表达式;
if(!InitForcal()) return; //初始化Forcal;
pGetRunErr(ErrType,FunName,ErrCode,ForType,ForHandle); //设置运行错误为无错状态; wcout.imbue(locale("chs")); //设置输出的locale为中文 vFor=0; ErrCode=pRealCom(ForStr,0,vFor,nPara,pPara,ErrBegin,ErrEnd); //编译实数表达式; if(ErrCode) { cout<<"表达式有错误!错误代码:"<<ErrCode<<endl; } else { cout<<pRealCal(vFor,pPara)<<endl; //计算实数表达式的值; pGetRunErr(ErrType,FunName,ErrCode,ForType,ForHandle); //检查运行错误; if(ErrType) wcout<<"出现运行错误!错误类型:"<<ErrType<<";出错函数名:"<<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 wchar_t pFunName[]="average";
//如果average()没有参数,返回一个FORCAL运行错误; if(m==-1) {if(!pTestRunErr()) pSetRunErr(2,pFunName,1,0,rFor); 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) //输出一个字符串; { wchar_t *pStr; fcINT k; fcINT StrMin,StrMax; pGetForStr(rFor,pStr,StrMin,StrMax); //获得字符串; k=(fcINT)x[0]; if(k>=StrMin&&k<=StrMax) wcout<<&pStr[k]; return 0.0; }
7 能计算多个表达式的例子 [返回页首]
在本例中,我们将使程序能计算10个表达式,程序输出的信息更详细,以便我们能输入更复杂的表达式进行检验。
注意:本例不是在上一例的基础上添加新内容,而是对上一例的主函数进行了改写。
本例的完整源代码如下:
#include <windows.h> #include <cmath> #include <iostream> #include <iomanip> #include "forcal32w.h" using namespace std;
HINSTANCE hForcal=NULL; //动态库Forcal32W.dll的句柄; HINSTANCE hQuitFc=NULL; //动态库QuitFc32W.dll的句柄;
//动态库Forcal32W.dll的输出函数; fcInitForcal pInitForcal; fcFreeForcal pFreeForcal; fcRealCom pRealCom; fcRealCal pRealCal; fcGetRunErr pGetRunErr; fcSetConst pSetConst; fcSetFunction pSetFunction;
//Forcal扩展动态库的输出函数; fcFcDll32W pFcDll32W;
//实数二级函数定义; double _stdcall Fun2_add(fcINT m,double *x,void *rFor) //计算两个数的和; { return x[0]+x[1]; }
bool InitForcal(void) //初始化Forcal; { hForcal=LoadLibrary(L"Forcal32W.dll"); //加载动态库Forcal32W.dll; if(!hForcal) { cout<<"找不到Forcal32W.dll!请将该库放到WINDOWS的搜索路径内!"; return false; }
//以下几个语句获取Forcal32W.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); //释放动态库Forcal32W.dll; hForcal=NULL; return false; }
pInitForcal(); //初始化Forcal32W.dll;
hQuitFc=LoadLibrary(L"QuitFc32W.dll"); //加载动态库QuitFc32W.dll; if(hQuitFc) { //获得Forcal扩展动态库输出函数的地址; pFcDll32W=(fcFcDll32W) GetProcAddress(hQuitFc,"FcDll32W"); if(pFcDll32W) { if(!pFcDll32W(hForcal,true,0)) //初始化QuitFc; { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } } else { FreeLibrary(hQuitFc); //释放动态库QuitFc; hQuitFc=NULL; } }
double PI=3.1416; //实型常量定义; pSetConst(Key_RealConst,L"PI",&PI); //设置实型常量;
pSetFunction(Key_RealFunction,L"add",Fun2_add,1); //设置实数二级函数;
return true; }
void FreeForcal(void) //释放Forcal; { if(hQuitFc) //释放QuitFc { pFcDll32W(hForcal,false,0); } 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 ErrType; //运行错误类型; wchar_t *FunName; //出错函数名; int ForType; //运行出错的表达式类型; void *ForHandle; //运行出错的表达式句柄; wchar_t *ForStr[nFor]={ //nFor个字符串表达式; L"add[5,6]", L"=5--9", L"1+2", L"a(x,y)=x+y", L"a[6,6]", L"a(x,y)=8", L"a[8,8]", L"while[1,1]", L"", L"PI" }; int i,j;
if(!InitForcal()) return; //初始化Forcal;
pGetRunErr(ErrType,FunName,ErrCode,ForType,ForHandle); //设置运行错误为无错状态; wcout.imbue(locale("chs")); //设置输出的locale为中文 for(i=0;i<nFor;i++) { wcout<<endl<<L">> 编译计算第"<<i<<L"个式子:"<<ForStr[i]<<endl; vFor[i]=0; 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(ErrType,FunName,ErrCode,ForType,ForHandle); //检查运行错误; if(ErrType) wcout<<"出现运行错误!错误类型:"<<ErrType<<";出错函数名:"<<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; fcINT k; fcINT StrMin,StrMax; pGetForStr(rFor,pStr,StrMin,StrMax); //获得字符串; k=(fcINT)x[0]; if(k>=StrMin&&k<=StrMax) wcout<<&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 wchar_t pFunName[]=L"CalFor"; wchar_t *pStr; fcVOID nModule; fcINT i,StrMin,StrMax; void *vFor,*vPara; if(m==-1) {if(!pTestRunErr()) pSetRunErr(2,pFunName,1,0,rFor); return 0.0;} //如果CalFor()没有参数,返回一个FORCAL运行错误; pGetForStr(rFor,pStr,StrMin,StrMax); //获得字符串; i=(fcINT)(x[0]); if(i>=StrMin&&i<=StrMax) { if(pGetFor(&pStr[i],Key_RealFor,rFor,nModule,vFor,vPara,StrMax)) { if(StrMax!=m-1) {if(!pTestRunErr()) pSetRunErr(2,pFunName,2,0,rFor); return 0.0;} //如果参数不匹配,返回一个FORCAL运行错误; return pRealCal(vFor,&x[1]); } } if(!pTestRunErr()) pSetRunErr(2,pFunName,3,0,rFor); //如果无法定位表达式,返回一个FORCAL运行错误; return 0.0; }
虽然还可以添加更多的例子,但是作为一个入门教程,就先写到这儿了。
如果你对本文有什么意见或建议,请给我发E-mail:forcal@sina.com 。
版权所有© Forcal程序设计
2002-2010,保留所有权利
E-mail: forcal@sina.com
QQ:630715621
最近更新:
2010年01月23日