📄 ccompile.h
字号:
// CCompile.h: interface for the CCompile class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(HSS_CCOMPILE_H__38F0F52D_46C5_4CA6_9E3F_D2F04C81F076__INCLUDED_)
#define HSS_CCOMPILE_H__38F0F52D_46C5_4CA6_9E3F_D2F04C81F076__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//////////////////////////////////////////////////////////////////////////
// //
// 数学函数动态编译器CCompile类(由Delphi引入) 作者:侯思松 2003.3.19 //
// (包括数学函数、布尔运算和定积分函数) //
// 有改进意见或发现任何错误请转告我,本人不胜感激。 //
// E-Mail:HouSisong@263.net //
// ( 转载时请保留本说明:) ) //
// //
//////////////////////////////////////////////////////////////////////////
///<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<///
/// <<功能简介>>: ///
/// CCompile可以在程序运行过程中动态完成数学函数表达式字符串的编译执行, ///
/// (可以带参数,布尔运算,定积分;动态生成机器码执行,不是解释执行)执行速度超快!!! ///
///>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>///
/*
<<使用方法>>:
CCompile Compilation; // 声明Compilation为数学函数动态编译器CCompile类的实例
CString str="x+sin(y*PI/2)*3";
Compilation.SetText(str); //str为需要求值的数学表达式字符串
......
//如果有参数,可以获得参数地址,并赋值 (默认值为0)
//如:Extended* PExtendedX:=Compilation.GetParameterAddress('x');
//如:Extended* PExtendedY:=Compilation.GetParameterAddress('y');
// if (PExtendedX!=NULL) *PExtendedX=1.5;
// if (PExtendedY!=NULL) *PExtendedY=0.5;
//也可以一次获得所有的参数列表:Compilation.GetParameterList(PList);
......
Extended xValue:=Compilation.GetValue(); //获得表达式的值,
//可以多次改变参数值并多次调用(如放在循环中),这样才能显示出效率:)
......
简要声明:
任何用户使用本软件属于个人自愿选择,作者不会对用户使用本软件所引起
的对用户的任何形式的损失负责,作者也不承诺提供对本类的维护和服务等义务。
本类可以自由拷贝和使用,但必须包含完整的代码和说明,任何修改和用于
商业化目的的行为都应该尽量与作者取得联系,并得到授权。
( E-Mail: HouSisong@263.net )
本类的编写目的只是在程序运行过程中能够多次的快速的执行用户输入的
数学表达式,程序优化的目标是速度和高精度,所以基本数据类型采用的是80
位浮点型,很多地方的处理是以速度为首要目标,这样在计算的准确性和错误
处理方面就有所损失。
作者以前写过一个解释执行数学函数表达式的程序,因为使用到而解释执行太慢了满足不了要求,
所以编写了本编译类单元(数学函数动态编译器CCompile类)。
CCompile可以完成数学函数表达式的动态编译和执行(动态生成机器码),编译后的执行
速度比以前解释执行的版本快了5000倍左右!在多次执行和表达式复杂情况下,CCompile在程序
执行过程中动态编译的函数执行速度与VC或Delphi6在程序设计阶段静态编译后的函数执行速度
相当。
测试环境包括:Windows95、Win98、WindowsMe、Windows2000、WindowsXP。
测试过的CPU包括:奔腾、赛扬A、奔腾3、赛扬2、奔腾4。
*/
#include "Extended.h" //提供Extended高精度浮点数的VC支持,
// 你可以把Extended类看作double来使用,
// VC中不支持x86CPU内置10字节浮点数(至少我没有找到),
// 它与Delphi类置的Extended完全一样;
// CCompile的接口使用该种数据类型(特别是设置外部变量时一定要使用这种类型)
const char cm_DllName[] ="CompileDll.dll";
const int cm_Max_ParameterName_Length = 256;
typedef DWORD cm_Handle;
struct cm_TUserParameterList
{
char CName[cm_Max_ParameterName_Length]; //参数名称
Extended* CAddress; //参数地址
};
//错误号定义
const int csTCompile_NoError = 0; //没有发现错误!
const int csTCompile_NoKnownError = 1; //不知道的错误!
const int csTCompile_NoErrorCode = 2; //找不到错误号所对应的错误描述!
const int csTCompile_CompileHexCodeError = 3; //编译时指令的十六进制代码错误!
const int csTCompile_HexMod2_EQ_1_Error = 4; //编译时传入指令长度错误!
const int csTCompile_PMMarker_Error = 5; //编译得到参数名称时发生错误!
const int csTCompile_FMMarker_Error = 6; //编译得到函数名称时发生错误!
const int csTCompile_Wording_Error = 7; //语法发生错误!
const int csTCompile_Bracket_Error = 8; //语法错误,在 ( ) 处!
const int csTCompile_Optimize_Error = 9; //编译优化时发生错误!
const int csTCompile_Define_Error =10; //函数编译错误(或超出定义域)!
const int csTCompile_Handwriting_Error =11; //函数书写格式错误!
const int csTCompile_FFHandwriting_Error =12; //积分函数书写格式错误!
const int csTCompile_ReadFloat_Error =13; //编译读取常数数字时发生错误!
const int csTCompile_ReadMarker_Error =14; //编译读取标识符时发生错误!
const int csTCompile_Read_Error =15; //语法错误,有不识别的字符!
const int csTCompile_Note_Match_Error =16; //注释符号不匹配! { } 或 /* */
const int csTCompile_FPList_Error =17; //参数列表错误!
const int csTCompile_IFHandwriting_Error =18; //If函数书写格式错误!
//////////////////////////////////////////////////////
// 数学函数动态编译器CCompile类 //
//////////////////////////////////////////////////////
class CCompile
{
cm_Handle m_cmHandle; // 编译类句柄
static bool LoadCompileDll();
public:
CCompile();
virtual ~CCompile();
static CString ExtendedToStr(const Extended & x);
static Extended StrToExtended(LPCSTR s);
// 设置需要编译的字符串(要编译的字符串,虚参数列表字符串,是否自动编译);
// 比如:Value="Sqr(x)+Sqr(y)"; ParameterList="x,y" ;
bool SetText(LPCSTR TextValue,LPCSTR ParameterList=NULL,bool IfCompile=true); //(编译前调用,这是最先要做的)
// 编译当前字符串
bool Compile(); //一个表达式只能调用编译一次
// 调用函数返回表达式的值(实参数值列表); //等价于 cm_SetFunctionParameter + cm_GetValue
Extended GetFunctionValue(Extended* PList); // (编译后才能调用)
// 调用函数返回表达式的值;
Extended GetValue(); // (编译前后都能调用)
void GetValue(Extended* Result); //同上
// 按当前设置的参数表传入参数值(实参数值列表)
void SetFunctionParameter(Extended* PList);
// 测试是否使用了未定义的变量
bool IfHaveUnDefineParameter();//(编译后才能调用)
//设置一个外部变量(外部变量名称,外部变量地址); 这样就可以和高级语言或另一个编译类共享变量了
bool SetExteriorParameter(LPCSTR PName,Extended* PAddress); //(编译前调用,如果是在编译后,需要调用cm_RefreshExeAddressCodeInPointer刷新地址)
// 设置外部数组(数组名称,数组地址);
bool SetExteriorArrayParameter(LPCSTR ArrayPName,Extended* ArrayPAddress);
//刷新变更地址 //(设置完所有的外部变量以后需要调用一次该函数)
void RefreshExeAddressCodeInPointer();
// 处理预定义宏(要代换的标识符,代换为的描述字符串); // 可以用来处理常数,甚至定义新的函数!
// 如 Key="a"; Value="-0.5" , 或 Key="f(x,y)",Value="Max(x,Sin(y))"(即定义了一个函数f) 等;
bool Define(LPCSTR Key,LPCSTR Value); //(编译前调用)
// 处理常数定义(要代换的标识符,代换的值) // 常数定义, Value必须是一个可计算的值
// 如 Key="a"; Value="2" , 或 Key="b" , Value="2*sin(PI/2)" 等;
// 该功能完全可以用预定义宏(Define)来代替,
// 但当值为常数时这样处理有可能使最后得到的编译函数速度更快,并加快编译速度
bool DefineConst(LPCSTR Key,LPCSTR Value);//(编译前调用)
//根据参数名称PName得到参数地址值
Extended* GetParameterAddress(LPCSTR PName);
//按参数名称PName设置参数值dValue
bool SetParameter(LPCSTR PName,const Extended& dValue);
//按参数地址PAddress设置参数值dValue
void SetParameter(Extended* PAddress,const Extended& dValue);
//得到参数PName的值
Extended GetParameterValue(LPCSTR PName);
//得到参数的总数目(不包括常数)
DWORD GetUserParameterCount();
//通过PList返回参数列表(不包括常数)
void GetUserParameterList(cm_TUserParameterList* PList);
//测试参数PName是否已经存在
bool IfHaveParameter(LPCSTR PName);
//设置随机函数Rnd()的初始种子值为完全随机种子(系统用当前精确到毫秒的时间设置)
void SetRandomize();
//设置随机函数Random()的初始种子值
void SetRandomize(int RandomSeed);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -