歡迎訪問 Forcal程序設計

循序漸進Forcal例程

目  錄

1 概述
2 預備知識
3
最簡單的例子
4 安全的例子及Forcal擴展動態庫的用法
5 完整的例子
6 添加常量和二級函數
7 能計算多個表達式的例子
8 結語

1 概述 [返回頁首]

    如果你喜歡Forcal,想用Forcal編程而又無從下手,那么本文的例子將會對你有所幫助。

    本文所有的例子均在VS C++ 2008環境下編譯通過,編譯時請將活動解決方案配置為“Release”。這都是些完整的例子,復制下來直接編譯運行即可。為了減少代碼,這些例子都是控制臺應用程序,簡單地加以改寫,將它應用到實用的Windows程序中去是不難的。

    第一個例子是最簡單的,其他的例子基本上都是在前面例子的基礎上添加代碼實現的。認真地完成每個例子后的習題將有助于加深對的Forcal理解。

    本文沒有窮盡Forcal的所有用法和功能,而且還很不夠。如果你還有什么不明白的,可以直接與我聯系:[email protected]

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:[email protected]


版權所有© Forcal程序設計 2002-2010,保留所有權利
E-mail: [email protected]
  QQ:630715621
最近更新: 2010年01月23日

福利彩票22选5走势图