欢迎访问 Forcal程序设计

循序渐进Forcal 例程

目 录

1 概述 2 预备知识 3 最简单的例子 4 安全的例子及Forcal扩展动态库的用法 5 完整的例子 | 6 添加常量和二级函数 7 能计算多个表达式的例子 8 结语

1 概述 [返回页首]

如果你喜欢Forcal，想用Forcal编程而又无从下手，那么本文的例子将会对你有所帮助。

本文所有的例子均在VS C++ 2008环境下编译通过，编译时请将活动解决方案配置为“Release”。这都是些完整的例子，复制下来直接编译运行即可。为了减少代码，这些例子都是控制台应用程序，简单地加以改写，将它应用到实用的Windows程序中去是不难的。

第一个例子是最简单的，其他的例子基本上都是在前面例子的基础上添加代码实现的。认真地完成每个例子后的习题将有助于加深对的Forcal理解。

本文没有穷尽Forcal的所有用法和功能，而且还很不够。如果你还有什么不明白的，可以直接与我联系：forcal@sina.com 。

2 预备知识 [返回页首]

使用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的引玉之砖，没有提供这方面的例子。

3 最简单的例子 [返回页首]

从这一节开始给出使用Forcal的例子，这是最简单的。
这个例子有三个函数：加载并初始化Forcal的函数 InitForcal，释放Forcal的函数Free Forcal和主函数main，主函数编译并计算了一个实数表达式的值。前两个函数的内容完全可以并入主函数，但分开写显得更清晰一些。
这个例子只用到了Forcal的四个输出函数：初始化 Forcal的函数 InitForcal，释放 Forcal 的函数 Free Forcal，编译实数表达式的函数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）将本例计算实数表达式改为计算整数表达式或复数表达式的例子。

4 安全的例子及Forcal扩展动态库的用法 [返回页首]

在第一个例子中，如果计算表达式"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()"，重新编译运行程序，观察计算结果。

5 完整的例子 [返回页首]

在前面的例子中，程序的计算结果有些是错误的。因为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]"，重新编译运行程序，观察计算结果。

6 添加常量和二级函数 [返回页首]

在这个例子中，我们将往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;
    }

8 结语 [返回页首]

虽然还可以添加更多的例子，但是作为一个入门教程，就先写到这儿了。

如果你对本文有什么意见或建议，请给我发E-mail：forcal@sina.com 。

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