欢迎访问 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的函数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)将本例计算实数表达式改为计算整数表达式或复数表达式的例子。

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的两个输出函数TestRunErrSetRunErr,否则编译是不能通过的。不要忘了更换字符串表达式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)在本例的基础上再添加实型二级函数PrintStrCalFor,这两个函数已在下面给出。这有一点难度,你需要同时添加Forcal的四个输出函数TestRunErr、SetRunErr、GetForStrGetFor以使编译通过。同时在字符串表达式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日